/* Copyright (C) 2020 Fredrik Öhrström This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include #include #include #include #include #include"serial.h" #include"shell.h" #include"ui.h" #include"util.h" #include"wmbus.h" bool running_as_root_ = false; bool member_of_dialout_ = false; #define LIST_OF_MAIN_MENU \ X(DETECT_WMBUS_RECEIVERS, "Detect wmbus receiver") \ X(RESET_WMBUS_RECEIVERS, "Reset wmbus receiver") \ X(LISTEN_FOR_METERS, "Listen for meters") \ X(EDIT_CONFIG, "Edit config") \ X(EDIT_METERS, "Edit meters") \ X(STOP_DAEMON, "Stop daemon") \ X(START_DAEMON, "Start daemon") \ X(EXIT_ADMIN, "Exit") enum class MainMenuType { #define X(name,description) name, LIST_OF_MAIN_MENU #undef X }; const char *main_menu[] = { #define X(name,description) description, LIST_OF_MAIN_MENU #undef X (char *)NULL, }; #define LIST_OF_WMBUS_RECEIVERS \ X(AMB8465, "amb8465") \ X(CUL, "cul") \ X(IM871A, "im871a") \ X(RC1180, "rc1180") enum class ReceiversType { #define X(name,description) name, LIST_OF_WMBUS_RECEIVERS #undef X }; const char *receivers_menu[] = { #define X(name,description) description, LIST_OF_WMBUS_RECEIVERS #undef X (char *)NULL, }; bool detectIfRoot(); string userName(); bool detectIfMemberOfGroup(string group); void detectWMBUSReceiver(); void resetWMBUSReceiver(); void probeFor(string type, AccessCheck(*func)(Detected*,shared_ptr)); void stopDaemon(); void startDaemon(); shared_ptr handler; WINDOW *status_window; WINDOW *serial_ports_window; WINDOW *processes_window; void alwaysOnScreen(); int main(int argc, char **argv) { if (argc == 2 && (!strcmp(argv[1], "--debug") || !strcmp(argv[1], "--trace"))) { if (!strcmp(argv[1], "--trace")) traceEnabled(true); else debugEnabled(true); setlogmask(LOG_UPTO (LOG_INFO)); openlog("wmbusmeters-admin", LOG_CONS | LOG_PID | LOG_NDELAY, LOG_LOCAL1); enableSyslog(); } // Handle exit on signals... onExit(exitUI); initUI(); clear(); /* refresh(); int x=0; int y=0; for (int i=0;i<10; ++i) { printAt(stdscr, y, x, "HEJSAN", COLOR_PAIR(BG_PAIR)); y++; x++; }; refresh(); for(;;) {} endwin(); return 0; */ running_as_root_ = detectIfRoot(); member_of_dialout_ = detectIfMemberOfGroup("dialout"); handler = createSerialCommunicationManager(0, 0); initUI(); bool running = true; registerUpdateCB(alwaysOnScreen); alwaysOnScreen(); do { int c = selectFromMenu("wmbusmeters admin", main_menu); switch (static_cast(c)) { case MainMenuType::DETECT_WMBUS_RECEIVERS: detectWMBUSReceiver(); break; case MainMenuType::RESET_WMBUS_RECEIVERS: resetWMBUSReceiver(); break; case MainMenuType::LISTEN_FOR_METERS: notImplementedYet("Listen for meters"); break; case MainMenuType::EDIT_CONFIG: notImplementedYet("Edit config"); break; case MainMenuType::EDIT_METERS: notImplementedYet("Edit meters"); break; case MainMenuType::STOP_DAEMON: stopDaemon(); break; case MainMenuType::START_DAEMON: startDaemon(); break; case MainMenuType::EXIT_ADMIN: running = false; break; } } while (running); exitUI(); } void alwaysOnScreen() { vector info; if (member_of_dialout_ == false) { info.push_back("Not member of dialout!"); } vector daemons; detectProcesses("wmbusmetersd", &daemons); if (daemons.size() == 0) { info.push_back("No daemons running."); } else { for (int i : daemons) { info.push_back("Daemon "+to_string(i)); } } vector processes; detectProcesses("wmbusmeters", &processes); if (processes.size() == 0) { } else { for (int i : processes) { info.push_back("Process "+to_string(i)); } } vector status; time_t now = time(NULL); struct tm nowt {}; localtime_r(&now, &nowt); status.push_back("wmbusmeters-admin"); status.push_back(strdatetimesec(&nowt)); string name = "["+userName()+"]"; status.push_back(name); displayStatusLineNoWait(&status_window, status, 0, 0); displayInformationNoWait(&status_window, "Problems", info, 2, 2); vector devices = handler->listSerialTTYs(); if (devices.size() == 0) { devices.push_back("No serial ports found!"); } //info.insert(info.end(), devices.begin(), devices.end()); displayInformationNoWait(&serial_ports_window, "Serial ports", devices, 1, 15); erase(); wrefresh(status_window); wrefresh(serial_ports_window); } void detectWMBUSReceiver() { int c = selectFromMenu("Select your wmbus radio device", receivers_menu); switch (static_cast(c)) { case ReceiversType::AMB8465: probeFor("amb8465", detectAMB8465); break; case ReceiversType::CUL: probeFor("cul", detectCUL); break; case ReceiversType::IM871A: probeFor("im871a/im170a", detectIM871AIM170A); break; case ReceiversType::RC1180: probeFor("rc1180", detectRC1180); break; } } void resetWMBUSReceiver() { int c = selectFromMenu("Select your wmbus radio device", receivers_menu); switch (static_cast(c)) { case ReceiversType::AMB8465: { vector devices = handler->listSerialTTYs(); if (devices.size() == 0) { vector entries; displayInformationAndWait("No serial ports!", entries); return; } int c = selectFromMenu("Select device", devices); string device = devices[c]; int was_baud = 0; AccessCheck ac = factoryResetAMB8465(device, handler, &was_baud); if (ac == AccessCheck::AccessOK) { vector entries; entries.push_back("amb8465 "+device+" using "+to_string(was_baud)); displayInformationAndWait("Factory reset successful", entries); } else { vector entries; entries.push_back(device); displayInformationAndWait("No amb8465 response from", entries); } break; } case ReceiversType::CUL: notImplementedYet("Resetting cul"); break; case ReceiversType::IM871A: notImplementedYet("Resetting im871a"); break; case ReceiversType::RC1180: notImplementedYet("Resetting RC1180"); break; } } void probeFor(string type, AccessCheck (*probe)(Detected*,shared_ptr)) { Detected detected {}; vector devices = handler->listSerialTTYs(); vector entries; for (string& device : devices) { string tty = "?"; AccessCheck ac = handler->checkAccess(device, handler, type, [&](string d, shared_ptr m){ detected.found_file=d; detected.specified_device.file=d; return probe(&detected, m);}); if (ac == AccessCheck::AccessOK) { tty = device+" DETECTED "+type; } else if (ac == AccessCheck::NoSuchDevice) { tty = device+" no such device"; } else if (ac == AccessCheck::NoProperResponse) { tty = device+" no response"; } else if (ac == AccessCheck::NotSameGroup) { tty = device+" not same group"; } else if (ac == AccessCheck::NoPermission) { tty = device+" same group but wrong permissions"; } entries.push_back(tty); } if (entries.size() == 0) { entries.push_back("No serial devices found."); } displayInformationAndWait("Probed serial devices", entries); } bool detectIfRoot() { vector args; vector envs; args.push_back("-u"); string out; invokeShellCaptureOutput("/usr/bin/id", args, envs, &out, true); return out == "0\n"; } string userName() { vector args; vector envs; args.push_back("-u"); args.push_back("-n"); string out; invokeShellCaptureOutput("/usr/bin/id", args, envs, &out, true); return out; } bool detectIfMemberOfGroup(string group) { vector args; vector envs; string out; invokeShellCaptureOutput("/usr/bin/groups", args, envs, &out, true); out = out+" "; // Guarantee that the line ends with space. size_t p = out.find(group+" "); if (p == 0) return true; p = out.find(" "+group+" "); if (p != string::npos) return true; return false; } void stopDaemon() { vector info; info.push_back("Enter sudo password to execute:"); info.push_back("systemctl stop wmbusmeters"); debug("(passowrd) calling inputfield\n"); string pwd = inputField("Stop daemon", info, "Password"); debug("(passowrd) GOT %s\n", pwd.c_str()); //string pwd = displayInformationAndInput("Stop daemon", info, 1, 1); //vector args; //vector envs; //args.push_back("gurka"); // string out; // invokeShellCaptureOutput("systemctl stop wmbusmeters", args, envs, &out, true); } void startDaemon() { } /* static char* trim_whitespaces(char *str) { char *end; // trim leading space while(isspace(*str)) str++; if(*str == 0) // all spaces? return str; // trim trailing space end = str + strnlen(str, 128) - 1; while(end > str && isspace(*end)) end--; // write new null terminator *(end+1) = '\0'; return str; } */