From 77a29c6bfef883cbbb23e45d8506a6cea91eb9cd Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Sat, 12 Feb 2022 07:01:50 +0100 Subject: [PATCH 01/25] #21 Rename --- DStarGateway/DStarGatewayDefs.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DStarGateway/DStarGatewayDefs.h b/DStarGateway/DStarGatewayDefs.h index 6739ab7..b62c727 100644 --- a/DStarGateway/DStarGatewayDefs.h +++ b/DStarGateway/DStarGatewayDefs.h @@ -21,7 +21,7 @@ #include -const std::string APPLICATION_NAME("ircDDB Gateway"); +const std::string APPLICATION_NAME("dstargateway"); const std::string CONFIG_FILE_NAME("dstargateway"); From b8d80b7b41dcb67cc64df3169987bd79197c5501 Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Sat, 12 Feb 2022 21:24:06 +0100 Subject: [PATCH 02/25] #21 add daemon --- BaseCommon/Daemon.cpp | 132 ++++++++++++++++++++++++++++++++++++++++++ BaseCommon/Daemon.h | 38 ++++++++++++ 2 files changed, 170 insertions(+) create mode 100644 BaseCommon/Daemon.cpp create mode 100644 BaseCommon/Daemon.h diff --git a/BaseCommon/Daemon.cpp b/BaseCommon/Daemon.cpp new file mode 100644 index 0000000..27978c9 --- /dev/null +++ b/BaseCommon/Daemon.cpp @@ -0,0 +1,132 @@ +/* + * Copyright (c) 2022 by Geoffrey Merck F4FXL / KC3FRA + * + * 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 2 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, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +/* + * Losely based on https://github.com/jirihnidek/daemon/blob/master/src/daemon.c + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "Daemon.h" +#include "Log.h" + +int CDaemon::m_pid_fd = -1; +std::string CDaemon::m_pidFileName(""); + +DAEMONIZE_RESULT CDaemon::daemonize(const std::string& pidFile) +{ + pid_t pid = 0; + int fd; + + /* Fork off the parent process */ + pid = fork(); + + /* An error occurred */ + if (pid < 0) { + return DR_FAILURE; + } + + /* Success: Let the parent terminate */ + if (pid > 0) { + return DR_PARENT; + } + + /* On success: The child process becomes session leader */ + if (setsid() < 0) { + return DR_FAILURE; + } + + /* Ignore signal sent from child to parent process */ + signal(SIGCHLD, SIG_IGN); + + /* Fork off for the second time*/ + pid = fork(); + + /* An error occurred */ + if (pid < 0) { + return DR_FAILURE; + } + + /* Success: Let the parent terminate */ + if (pid > 0) { + return DR_PARENT; + } + + /* Set new file permissions */ + umask(0); + + /* Change the working directory to the root directory */ + /* or another appropriated directory */ + chdir("/"); + + /* Close all open file descriptors */ + for (fd = sysconf(_SC_OPEN_MAX); fd > 0; fd--) { + close(fd); + } + + /* Reopen stdin (fd = 0), stdout (fd = 1), stderr (fd = 2) */ + stdin = fopen("/dev/null", "r"); + stdout = fopen("/dev/null", "w+"); + stderr = fopen("/dev/null", "w+"); + + /* Try to write PID of daemon to lockfile */ + if (!pidFile.empty()) + { + CLog::logInfo("pidfile"); + + m_pid_fd = open(pidFile.c_str(), O_RDWR|O_CREAT, 0640); + if (m_pid_fd < 0) { + /* Can't open lockfile */ + return DR_PIDFILE_FAILED; + } + if (lockf(m_pid_fd, F_TLOCK, 0) < 0) { + /* Can't lock file */ + return DR_PIDFILE_FAILED; + } + + m_pidFileName.assign(pidFile); + + /* Get current PID */ + char str[256]; + sprintf(str, "%d\n", getpid()); + /* Write PID to lockfile */ + write(m_pid_fd, str, strlen(str)); + } + + return DR_CHILD; +} + +void CDaemon::finalize() +{ + if(m_pid_fd != -1) { + lockf(m_pid_fd, F_ULOCK, 0); + close(m_pid_fd); + } + + if(!m_pidFileName.empty()) { + unlink(m_pidFileName.c_str()); + } +} \ No newline at end of file diff --git a/BaseCommon/Daemon.h b/BaseCommon/Daemon.h new file mode 100644 index 0000000..ae2dcf8 --- /dev/null +++ b/BaseCommon/Daemon.h @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2022 by Geoffrey Merck F4FXL / KC3FRA + * + * 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 2 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, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include + +enum DAEMONIZE_RESULT +{ + DR_PARENT, + DR_CHILD, + DR_FAILURE, + DR_PIDFILE_FAILED +}; + +class CDaemon +{ +public: + static DAEMONIZE_RESULT daemonize(const std::string& pidFile); + static void finalize(); + +private: + static int m_pid_fd; + static std::string m_pidFileName; +}; \ No newline at end of file From 12095eabb4bcc0f6e12887e0a5de926e35ec9664 Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Sat, 12 Feb 2022 21:24:25 +0100 Subject: [PATCH 03/25] #21 change service type to forking --- debian/dstargateway.service | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/debian/dstargateway.service b/debian/dstargateway.service index 4f8c069..beaa3c8 100644 --- a/debian/dstargateway.service +++ b/debian/dstargateway.service @@ -5,7 +5,7 @@ After=network.target,network-online.target Wants=network-online.target [Service] -Type=simple +Type=forking ExecStart=/usr/local/bin/dstargateway %CFG_DIR%/dstargateway.cfg Restart=on-failure RestartSec=5 From 88f51f75b347f81b20dd22ed910a6aae76f8faab Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Sun, 13 Feb 2022 07:51:03 +0100 Subject: [PATCH 04/25] #21 Also setsid on second fork, systemd seems to require it --- BaseCommon/Daemon.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/BaseCommon/Daemon.cpp b/BaseCommon/Daemon.cpp index 27978c9..f0d6335 100644 --- a/BaseCommon/Daemon.cpp +++ b/BaseCommon/Daemon.cpp @@ -75,6 +75,10 @@ DAEMONIZE_RESULT CDaemon::daemonize(const std::string& pidFile) return DR_PARENT; } + if (setsid() < 0) { + return DR_FAILURE; + } + /* Set new file permissions */ umask(0); From 75abc130c1baa3ad215b9a1c16c1241f2701ea1b Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Sun, 13 Feb 2022 07:55:14 +0100 Subject: [PATCH 05/25] #21 make it a real daemon --- DStarGateway/DStarGatewayApp.cpp | 107 +++++++++++++++++++--------- DStarGateway/DStarGatewayApp.h | 8 +-- DStarGateway/DStarGatewayConfig.cpp | 13 ++++ DStarGateway/DStarGatewayConfig.h | 9 +++ DStarGateway/Makefile | 1 + DStarGateway/example.cfg | 7 +- 6 files changed, 104 insertions(+), 41 deletions(-) diff --git a/DStarGateway/DStarGatewayApp.cpp b/DStarGateway/DStarGatewayApp.cpp index 8acfe2e..f0c4e3e 100644 --- a/DStarGateway/DStarGatewayApp.cpp +++ b/DStarGateway/DStarGatewayApp.cpp @@ -25,6 +25,8 @@ #include #include #include +#include +#include #ifdef DEBUG_DSTARGW #include #endif @@ -45,6 +47,7 @@ #include "LogConsoleTarget.h" #include "APRSGPSDIdFrameProvider.h" #include "APRSFixedIdFrameProvider.h" +#include "Daemon.h" CDStarGatewayApp * CDStarGatewayApp::g_app = nullptr; @@ -70,16 +73,52 @@ int main(int argc, char *argv[]) return 1; } + printf("\n%s Copyright (C) %s\n", FULL_PRODUCT_NAME.c_str(), VENDOR_NAME.c_str()); + printf("DStarGateway comes with ABSOLUTELY NO WARRANTY; see the LICENSE for details.\n"); + printf("This is free software, and you are welcome to distribute it\nunder certain conditions that are discussed in the LICENSE file.\n\n"); + if ('-' == argv[1][0]) { - printf("\n%s Copyright (C) %s\n", FULL_PRODUCT_NAME.c_str(), VENDOR_NAME.c_str()); - printf("DStarGateway comes with ABSOLUTELY NO WARRANTY; see the LICENSE for details.\n"); - printf("This is free software, and you are welcome to distribute it\nunder certain conditions that are discussed in the LICENSE file.\n\n"); return 0; } - std::string cfgFile(argv[1]); + CDStarGatewayConfig * config = new CDStarGatewayConfig(std::string((argv[1]))); + if(!config->load()) { + CLog::logFatal("Invalid configuration, aborting"); + return false; + } + + TDaemon daemon; + config->getGeneral(daemon); + + if (daemon.daemon) { + CLog::logInfo("Configured as a daemon, detaching ..."); + auto res = CDaemon::daemonize(daemon.pidFile); + + switch (res) + { + case DR_PARENT: + return 0; + case DR_CHILD: + break; + case DR_PIDFILE_FAILED: + break; + case DR_FAILURE: + [[fallthrough]]; + default: + CLog::logFatal("Fork failed, exiting"); + delete config; + return 1; + } + } + + // Setup Log + TLog logConf; + config->getLog(logConf); + CLog::finalise(); + if(logConf.m_displayLevel != LOG_NONE && !daemon.daemon) CLog::addTarget(new CLogConsoleTarget(logConf.m_displayLevel)); + if(logConf.m_fileLevel != LOG_NONE) CLog::addTarget(new CLogFileTarget(logConf.m_fileLevel, logConf.logDir, logConf.m_fileRotate)); - CDStarGatewayApp gateway(cfgFile); + CDStarGatewayApp gateway(config); if (!gateway.init()) { return 1; @@ -87,22 +126,30 @@ int main(int argc, char *argv[]) gateway.run(); + if(daemon.daemon) { + CDaemon::finalize(); + } + return 0; } -CDStarGatewayApp::CDStarGatewayApp(const std::string &configFile) : m_configFile(configFile), m_thread(NULL) +CDStarGatewayApp::CDStarGatewayApp(CDStarGatewayConfig * config) : +m_config(config), +m_thread(NULL) { + assert(config != nullptr); g_app = this; } CDStarGatewayApp::~CDStarGatewayApp() { + delete m_config; + delete m_thread; } bool CDStarGatewayApp::init() { return createThread(); - //2021-12-31 F4FXL This is ugly, if we failed to create the thread we do not clean up ... :( } void CDStarGatewayApp::run() @@ -115,30 +162,18 @@ void CDStarGatewayApp::run() bool CDStarGatewayApp::createThread() { - printf("\n%s Copyright (C) %s\n", FULL_PRODUCT_NAME.c_str(), VENDOR_NAME.c_str()); - printf("DStarGateway comes with ABSOLUTELY NO WARRANTY; see the LICENSE for details.\n"); - printf("This is free software, and you are welcome to distribute it\nunder certain conditions that are discussed in the LICENSE file.\n\n"); - - CDStarGatewayConfig config(m_configFile); - if(!config.load()) { - CLog::logFatal("Invalid configuration, aborting"); - return false; - } - - // Setup Log + // Log TLog log; - config.getLog(log); - CLog::finalise(); - if(log.m_displayLevel != LOG_NONE) CLog::addTarget(new CLogConsoleTarget(log.m_displayLevel)); - if(log.m_fileLevel != LOG_NONE) CLog::addTarget(new CLogFileTarget(log.m_fileLevel, log.logDir, log.m_fileRotate)); + m_config->getLog(log); + // Paths Tpaths paths; - config.getPaths(paths); + m_config->getPaths(paths); m_thread = new CDStarGatewayThread(log.logDir, paths.dataDir, ""); // Setup the gateway TGateway gatewayConfig; - config.getGateway(gatewayConfig); + m_config->getGateway(gatewayConfig); m_thread->setGateway(gatewayConfig.type, gatewayConfig.callsign, gatewayConfig.address); m_thread->setLanguage(gatewayConfig.language); m_thread->setLocation(gatewayConfig.latitude, gatewayConfig.longitude); @@ -146,12 +181,12 @@ bool CDStarGatewayApp::createThread() #ifdef USE_GPSD // Setup GPSD TGPSD gpsdConfig; - config.getGPSD(gpsdConfig); + m_config->getGPSD(gpsdConfig); #endif // Setup APRS TAPRS aprsConfig; - config.getAPRS(aprsConfig); + m_config->getAPRS(aprsConfig); CAPRSHandler * aprsWriter = NULL; if(aprsConfig.enabled && !aprsConfig.password.empty()) { aprsWriter = new CAPRSHandler(aprsConfig.hostname, aprsConfig.port, gatewayConfig.callsign, aprsConfig.password, gatewayConfig.address); @@ -176,9 +211,9 @@ bool CDStarGatewayApp::createThread() bool ddEnabled = false; bool atLeastOneRepeater = false; CRepeaterProtocolHandlerFactory repeaterProtocolFactory; - for(unsigned int i = 0U; i < config.getRepeaterCount(); i++) { + for(unsigned int i = 0U; i < m_config->getRepeaterCount(); i++) { TRepeater rptrConfig; - config.getRepeater(i, rptrConfig); + m_config->getRepeater(i, rptrConfig); auto repeaterProtocolHandler = repeaterProtocolFactory.getRepeaterProtocolHandler(rptrConfig.hwType, gatewayConfig, rptrConfig.address, rptrConfig.port); if(repeaterProtocolHandler == nullptr) continue; @@ -221,9 +256,9 @@ bool CDStarGatewayApp::createThread() // Setup ircddb auto ircddbVersionInfo = "linux_" + PRODUCT_NAME + "-" + VERSION; std::vector clients; - for(unsigned int i=0; i < config.getIrcDDBCount(); i++) { + for(unsigned int i=0; i < m_config->getIrcDDBCount(); i++) { TircDDB ircDDBConfig; - config.getIrcDDB(i, ircDDBConfig); + m_config->getIrcDDB(i, ircDDBConfig); CLog::logInfo("ircDDB Network %d set to %s user: %s, Quadnet %d", i + 1,ircDDBConfig.hostname.c_str(), ircDDBConfig.username.c_str(), ircDDBConfig.isQuadNet); CIRCDDB * ircDDB = new CIRCDDBClient(ircDDBConfig.hostname, 9007U, ircDDBConfig.username, ircDDBConfig.password, ircddbVersionInfo, gatewayConfig.address, ircDDBConfig.isQuadNet); clients.push_back(ircDDB); @@ -240,31 +275,31 @@ bool CDStarGatewayApp::createThread() // Setup Dextra TDextra dextraConfig; - config.getDExtra(dextraConfig); + m_config->getDExtra(dextraConfig); CLog::logInfo("DExtra enabled: %d, max. dongles: %u", int(dextraConfig.enabled), dextraConfig.maxDongles); m_thread->setDExtra(dextraConfig.enabled, dextraConfig.maxDongles); // Setup DCS TDCS dcsConfig; - config.getDCS(dcsConfig); + m_config->getDCS(dcsConfig); CLog::logInfo("DCS enabled: %d", int(dcsConfig.enabled)); m_thread->setDCS(dcsConfig.enabled); // Setup DPlus TDplus dplusConfig; - config.getDPlus(dplusConfig); + m_config->getDPlus(dplusConfig); CLog::logInfo("D-Plus enabled: %d, max. dongles: %u, login: %s", int(dplusConfig.enabled), dplusConfig.maxDongles, dplusConfig.login.c_str()); m_thread->setDPlus(dplusConfig.enabled, dplusConfig.maxDongles, dplusConfig.login); // Setup XLX TXLX xlxConfig; - config.getXLX(xlxConfig); + m_config->getXLX(xlxConfig); CLog::logInfo("XLX enabled: %d, Hosts file url: %s", int(xlxConfig.enabled), xlxConfig.url.c_str()); m_thread->setXLX(xlxConfig.enabled, xlxConfig.enabled ? CXLXHostsFileDownloader::download(xlxConfig.url) : ""); // Setup Remote TRemote remoteConfig; - config.getRemote(remoteConfig); + m_config->getRemote(remoteConfig); CLog::logInfo("Remote enabled: %d, port %u", int(remoteConfig.enabled), remoteConfig.port); m_thread->setRemote(remoteConfig.enabled, remoteConfig.password, remoteConfig.port); @@ -287,6 +322,8 @@ void CDStarGatewayApp::sigHandler(int sig) if(g_app != nullptr && g_app->m_thread != nullptr) { g_app->m_thread->kill(); } + + CDaemon::finalize(); } void CDStarGatewayApp::sigHandlerFatal(int sig) diff --git a/DStarGateway/DStarGatewayApp.h b/DStarGateway/DStarGatewayApp.h index 16df95f..6e5aa21 100644 --- a/DStarGateway/DStarGatewayApp.h +++ b/DStarGateway/DStarGatewayApp.h @@ -20,18 +20,18 @@ #pragma once #include "DStarGatewayThread.h" - +#include "DStarGatewayConfig.h" class CDStarGatewayApp { private: - std::string m_configFile; - CDStarGatewayThread *m_thread; + CDStarGatewayConfig * m_config; + CDStarGatewayThread * m_thread; bool createThread(); static CDStarGatewayApp * g_app; public: - CDStarGatewayApp(const std::string &configFile); + CDStarGatewayApp(CDStarGatewayConfig * config); ~CDStarGatewayApp(); bool init(); diff --git a/DStarGateway/DStarGatewayConfig.cpp b/DStarGateway/DStarGatewayConfig.cpp index a976c1f..5b35d4d 100644 --- a/DStarGateway/DStarGatewayConfig.cpp +++ b/DStarGateway/DStarGatewayConfig.cpp @@ -55,6 +55,7 @@ bool CDStarGatewayConfig::load() #ifdef USE_GPSD ret = loadGPSD(cfg) && ret; #endif + ret = loadDaemon(cfg) && ret; } if(ret) { @@ -69,6 +70,13 @@ bool CDStarGatewayConfig::load() return ret; } +bool CDStarGatewayConfig::loadDaemon(const CConfig & cfg) +{ + bool ret = cfg.getValue("daemon", "daemon", m_general.daemon, false); + ret = cfg.getValue("daemon", "pidfile", m_general.pidFile, 0, 1024, "") && ret; + return ret; +} + bool CDStarGatewayConfig::loadXLX(const CConfig & cfg) { bool ret = cfg.getValue("xlx", "enabled", m_xlx.enabled, true); @@ -438,3 +446,8 @@ void CDStarGatewayConfig::getGPSD(TGPSD & gpsd) const gpsd = m_gpsd; } #endif + +void CDStarGatewayConfig::getGeneral(TDaemon & gen) const +{ + gen = m_general; +} \ No newline at end of file diff --git a/DStarGateway/DStarGatewayConfig.h b/DStarGateway/DStarGatewayConfig.h index b27ca44..d8152f7 100644 --- a/DStarGateway/DStarGatewayConfig.h +++ b/DStarGateway/DStarGatewayConfig.h @@ -25,6 +25,11 @@ #include "Config.h" #include "LogSeverity.h" +typedef struct { + bool daemon; + std::string pidFile; +} TDaemon; + typedef struct { GATEWAY_TYPE type; std::string callsign; @@ -150,6 +155,7 @@ public: #ifdef USE_GPSD void getGPSD(TGPSD & gpsd) const; #endif + void getGeneral(TDaemon & gen) const; private: bool open(CConfig & cfg); @@ -167,6 +173,7 @@ private: #ifdef USE_GPSD bool loadGPSD(const CConfig & cfg); #endif + bool loadDaemon(const CConfig & cfg); std::string m_fileName; TGateway m_gateway; @@ -181,6 +188,8 @@ private: #ifdef USE_GPSD TGPSD m_gpsd; #endif + TDaemon m_general; + std::vector m_repeaters; std::vector m_ircDDB; }; diff --git a/DStarGateway/Makefile b/DStarGateway/Makefile index 73318d1..d5619c5 100644 --- a/DStarGateway/Makefile +++ b/DStarGateway/Makefile @@ -21,6 +21,7 @@ install: dstargateway @cp -fn example.cfg $(CFG_DIR)/dstargateway.cfg @sed -i "s|path=/var/log/dstargateway/|path=$(LOG_DIR)|g" $(CFG_DIR)/dstargateway.cfg @sed -i "s|data=/usr/local/share/dstargateway.d/|data=$(DATA_DIR)|g" $(CFG_DIR)/dstargateway.cfg + @sed -i "s|daemon=false|daemon=true|g" $(CFG_DIR)/dstargateway.cfg ../APRS/APRS.a: ../Common/Common.a: diff --git a/DStarGateway/example.cfg b/DStarGateway/example.cfg index b83f0d6..9ece63e 100644 --- a/DStarGateway/example.cfg +++ b/DStarGateway/example.cfg @@ -2,7 +2,6 @@ # The order of the sections or key/values pairs inside the sections does not matter nor does casing. # Boolean values can be set using true, false, 1 or 0 # Floating point values must use . (point) as decimal separator - [Gateway] type= # repeater, hotspot, dongle. Defaults to repeater callsign= @@ -22,7 +21,7 @@ language= # valid values: english_uk, deutsch, dansk, francais, ita [ircddb_1] enabled=true hostname=ircv4.openquad.net -username= # The ircDDB username default to the value defined for gateway callsign. +username= # The ircDDB username defaults to the value defined for gateway callsign. password= [ircddb_2] @@ -178,3 +177,7 @@ enabled=false port=4242 password=CHANGE_ME # If password is left blank, remote will be disabled regardless of the enabled field +[Daemon] +daemon=false +# pid file is in our case useless when running as a daemon using systemd as systemd handles all the pid stuff for us +pidfile=#/var/run/dstargateway/dstargateway.pid \ No newline at end of file From 7e7c45ea18fa6b5557d47f53e8f51d60b2f8e34b Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Mon, 14 Feb 2022 19:58:25 +0100 Subject: [PATCH 06/25] #21 flush console --- BaseCommon/LogConsoleTarget.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/BaseCommon/LogConsoleTarget.cpp b/BaseCommon/LogConsoleTarget.cpp index 78cdabc..f3fc385 100644 --- a/BaseCommon/LogConsoleTarget.cpp +++ b/BaseCommon/LogConsoleTarget.cpp @@ -30,4 +30,5 @@ CLogTarget(logLevel) void CLogConsoleTarget::printLogInt(const std::string& msg) { std::cout << msg; + std::cout.flush(); } \ No newline at end of file From 37298b9bfbd7302aea55ce4f1da52f0ba8e6c394 Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Mon, 14 Feb 2022 19:58:36 +0100 Subject: [PATCH 07/25] #21 follow fork --- .vscode/launch.json | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.vscode/launch.json b/.vscode/launch.json index 14711bb..5dced1b 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -25,6 +25,10 @@ "description": "Définir la version désassemblage sur Intel", "text": "-gdb-set disassembly-flavor intel", "ignoreFailures": true + }, + { + "description": "Tell GDB to follow forks child", + "text": "-gdb-set follow-fork-mode child" } ] }, From 42131c9b9703f042844e2fc89bc6a9e68d2fa5a7 Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Mon, 14 Feb 2022 20:00:11 +0100 Subject: [PATCH 08/25] #better pid file locking, only fork if can get everything to do so --- BaseCommon/Daemon.cpp | 120 +++++++++++++++++++++++++++++++++--------- BaseCommon/Daemon.h | 5 +- 2 files changed, 100 insertions(+), 25 deletions(-) diff --git a/BaseCommon/Daemon.cpp b/BaseCommon/Daemon.cpp index f0d6335..90a5c5a 100644 --- a/BaseCommon/Daemon.cpp +++ b/BaseCommon/Daemon.cpp @@ -27,8 +27,9 @@ #include #include #include -#include #include +#include +#include #include "Daemon.h" #include "Log.h" @@ -36,16 +37,63 @@ int CDaemon::m_pid_fd = -1; std::string CDaemon::m_pidFileName(""); -DAEMONIZE_RESULT CDaemon::daemonize(const std::string& pidFile) +DAEMONIZE_RESULT CDaemon::daemonize(const std::string& pidFile, const std::string& userName) { + // get user + struct passwd* user = nullptr; + if(!userName.empty()) { + user = getpwnam(userName.c_str()); + if(user == nullptr) { + CLog::logFatal("Failed to get %s user", userName.c_str()); + return DR_FAILURE; + } + } + + // Create PID file if needed + if (!pidFile.empty()) { + auto tempFd = tryGetLock(pidFile); + if (tempFd < 0) { + CLog::logFatal("Failed to acquire lock on pidfile %s : %s", pidFile.c_str(), strerror(errno)); + return DR_PIDFILE_FAILED; + } + releaseLock(tempFd, ""); + + if(user != nullptr) { + int res = chown(pidFile.c_str(), user->pw_uid, user->pw_gid); + if(res != 0) { + CLog::logFatal("Failed to set ownership of pidfile to user %s : %s", userName.c_str(), strerror(errno)); + return DR_FAILURE; + } + } + } + + // change process ownership + if(user != nullptr) { + if(setgid(user->pw_gid) != 0) { + CLog::logFatal("Failed to set %s GID : %s", userName.c_str(), strerror(errno)); + return DR_FAILURE; + } + + if(setuid(user->pw_uid) != 0) { + CLog::logFatal("Failed to set %s UID : %s", userName.c_str(), strerror(errno)); + return DR_FAILURE; + } + + // Double check it worked (AKA Paranoia) + if (::setuid(0) != -1){ + CLog::logFatal("It's possible to regain root - something is wrong!, exiting"); + return DR_FAILURE; + } + } + pid_t pid = 0; - int fd; /* Fork off the parent process */ pid = fork(); /* An error occurred */ if (pid < 0) { + CLog::logFatal("Forking failed, exiting"); return DR_FAILURE; } @@ -54,54 +102,56 @@ DAEMONIZE_RESULT CDaemon::daemonize(const std::string& pidFile) return DR_PARENT; } - /* On success: The child process becomes session leader */ + // On success: The child process becomes session leader if (setsid() < 0) { + CLog::logFatal("Failed to set session id, exiting"); return DR_FAILURE; } /* Ignore signal sent from child to parent process */ signal(SIGCHLD, SIG_IGN); - /* Fork off for the second time*/ +#ifdef DOUBLE FORK + // Fork off for the second time. Some litterature says it is best to fork 2 times so that the process never can open a terminal. + // However it messes up systemd, event when unit is set as forking pid = fork(); - /* An error occurred */ + // An error occurred if (pid < 0) { + CLog::logFatal("Second forking failed, exiting"); return DR_FAILURE; } - /* Success: Let the parent terminate */ + // Success: Let the parent terminate if (pid > 0) { return DR_PARENT; } +#endif - if (setsid() < 0) { - return DR_FAILURE; - } - - /* Set new file permissions */ + // Set new file permissions umask(0); /* Change the working directory to the root directory */ /* or another appropriated directory */ - chdir("/"); + if(chdir("/") != 0) { + CLog::logFatal("Faild to cd, exiting"); + return DR_FAILURE; + } - /* Close all open file descriptors */ - for (fd = sysconf(_SC_OPEN_MAX); fd > 0; fd--) { + // Close all open file descriptors + for (int fd = sysconf(_SC_OPEN_MAX); fd > 0; fd--) { close(fd); } - /* Reopen stdin (fd = 0), stdout (fd = 1), stderr (fd = 2) */ + // Reopen stdin (fd = 0), stdout (fd = 1), stderr (fd = 2) stdin = fopen("/dev/null", "r"); stdout = fopen("/dev/null", "w+"); stderr = fopen("/dev/null", "w+"); - /* Try to write PID of daemon to lockfile */ + // Try to write PID of daemon to lockfile if (!pidFile.empty()) { - CLog::logInfo("pidfile"); - - m_pid_fd = open(pidFile.c_str(), O_RDWR|O_CREAT, 0640); + m_pid_fd = tryGetLock(pidFile); if (m_pid_fd < 0) { /* Can't open lockfile */ return DR_PIDFILE_FAILED; @@ -125,12 +175,34 @@ DAEMONIZE_RESULT CDaemon::daemonize(const std::string& pidFile) void CDaemon::finalize() { - if(m_pid_fd != -1) { - lockf(m_pid_fd, F_ULOCK, 0); - close(m_pid_fd); - } + releaseLock(m_pid_fd, m_pidFileName); if(!m_pidFileName.empty()) { unlink(m_pidFileName.c_str()); } +} + +int CDaemon::tryGetLock( const std::string& file ) +{ + mode_t m = umask( 0 ); + int fd = open( file.c_str(), O_RDWR|O_CREAT, 0640 ); + umask( m ); + if( fd >= 0 && flock( fd, LOCK_EX | LOCK_NB ) < 0 ) { + close( fd ); + fd = -1; + } + return fd; +} + +/*! Release the lock obtained with tryGetLock( lockName ). + * + * @param fd File descriptor of lock returned by tryGetLock( lockName ). + * @param lockName Name of file used as lock (i.e. '/var/lock/myLock'). + */ +void CDaemon::releaseLock(int fd, const std::string& file) +{ + if( fd < 0 ) + return; + remove(file.c_str()); + close(fd); } \ No newline at end of file diff --git a/BaseCommon/Daemon.h b/BaseCommon/Daemon.h index ae2dcf8..0981896 100644 --- a/BaseCommon/Daemon.h +++ b/BaseCommon/Daemon.h @@ -29,10 +29,13 @@ enum DAEMONIZE_RESULT class CDaemon { public: - static DAEMONIZE_RESULT daemonize(const std::string& pidFile); + static DAEMONIZE_RESULT daemonize(const std::string& pidFile, const std::string& user); static void finalize(); private: + static int tryGetLock(const std::string& file ); + static void releaseLock(int fd, const std::string& file ); + static int m_pid_fd; static std::string m_pidFileName; }; \ No newline at end of file From a7d394196bbf07b787a1ae4eeadd770eb04c46c0 Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Mon, 14 Feb 2022 20:00:55 +0100 Subject: [PATCH 09/25] #21 start process as root, process will switch to specified user --- debian/dstargateway.service | 1 - 1 file changed, 1 deletion(-) diff --git a/debian/dstargateway.service b/debian/dstargateway.service index beaa3c8..8b8185a 100644 --- a/debian/dstargateway.service +++ b/debian/dstargateway.service @@ -1,5 +1,4 @@ [Unit] -User=dstar Description=D-STAR Gateway Daemon After=network.target,network-online.target Wants=network-online.target From 305723d3e95f17a3fb2b8973d2301460036487f0 Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Mon, 14 Feb 2022 20:01:11 +0100 Subject: [PATCH 10/25] #21 exit on pid file failure --- DStarGateway/DStarGatewayApp.cpp | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/DStarGateway/DStarGatewayApp.cpp b/DStarGateway/DStarGatewayApp.cpp index f0c4e3e..7a8628f 100644 --- a/DStarGateway/DStarGatewayApp.cpp +++ b/DStarGateway/DStarGatewayApp.cpp @@ -92,7 +92,7 @@ int main(int argc, char *argv[]) if (daemon.daemon) { CLog::logInfo("Configured as a daemon, detaching ..."); - auto res = CDaemon::daemonize(daemon.pidFile); + auto res = CDaemon::daemonize(daemon.pidFile, "dstar"); switch (res) { @@ -101,12 +101,11 @@ int main(int argc, char *argv[]) case DR_CHILD: break; case DR_PIDFILE_FAILED: - break; case DR_FAILURE: - [[fallthrough]]; default: - CLog::logFatal("Fork failed, exiting"); + CLog::logFatal("Failed to run as daemon"); delete config; + CLog::finalise(); return 1; } } From 027bbc1f6557cafe62f6c2c0f217d2e72c7b7ef5 Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Mon, 14 Feb 2022 20:01:44 +0100 Subject: [PATCH 11/25] #21 fix typo --- BaseCommon/Daemon.cpp | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/BaseCommon/Daemon.cpp b/BaseCommon/Daemon.cpp index 90a5c5a..6a2976a 100644 --- a/BaseCommon/Daemon.cpp +++ b/BaseCommon/Daemon.cpp @@ -111,7 +111,7 @@ DAEMONIZE_RESULT CDaemon::daemonize(const std::string& pidFile, const std::strin /* Ignore signal sent from child to parent process */ signal(SIGCHLD, SIG_IGN); -#ifdef DOUBLE FORK +#ifdef DOUBLE_FORK // Fork off for the second time. Some litterature says it is best to fork 2 times so that the process never can open a terminal. // However it messes up systemd, event when unit is set as forking pid = fork(); @@ -194,11 +194,7 @@ int CDaemon::tryGetLock( const std::string& file ) return fd; } -/*! Release the lock obtained with tryGetLock( lockName ). - * - * @param fd File descriptor of lock returned by tryGetLock( lockName ). - * @param lockName Name of file used as lock (i.e. '/var/lock/myLock'). - */ + void CDaemon::releaseLock(int fd, const std::string& file) { if( fd < 0 ) From 2328c31f775b5cdc55fcca54e24047ca5ab32dc9 Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Mon, 14 Feb 2022 20:12:13 +0100 Subject: [PATCH 12/25] #21 add daemon user --- DStarGateway/DStarGatewayApp.cpp | 4 ++-- DStarGateway/DStarGatewayConfig.cpp | 9 +++++---- DStarGateway/DStarGatewayConfig.h | 5 +++-- DStarGateway/example.cfg | 4 ++-- 4 files changed, 12 insertions(+), 10 deletions(-) diff --git a/DStarGateway/DStarGatewayApp.cpp b/DStarGateway/DStarGatewayApp.cpp index 7a8628f..8e7299b 100644 --- a/DStarGateway/DStarGatewayApp.cpp +++ b/DStarGateway/DStarGatewayApp.cpp @@ -88,11 +88,11 @@ int main(int argc, char *argv[]) } TDaemon daemon; - config->getGeneral(daemon); + config->getDaemon(daemon); if (daemon.daemon) { CLog::logInfo("Configured as a daemon, detaching ..."); - auto res = CDaemon::daemonize(daemon.pidFile, "dstar"); + auto res = CDaemon::daemonize(daemon.pidFile, daemon.user); switch (res) { diff --git a/DStarGateway/DStarGatewayConfig.cpp b/DStarGateway/DStarGatewayConfig.cpp index 5b35d4d..5d236ca 100644 --- a/DStarGateway/DStarGatewayConfig.cpp +++ b/DStarGateway/DStarGatewayConfig.cpp @@ -72,8 +72,9 @@ bool CDStarGatewayConfig::load() bool CDStarGatewayConfig::loadDaemon(const CConfig & cfg) { - bool ret = cfg.getValue("daemon", "daemon", m_general.daemon, false); - ret = cfg.getValue("daemon", "pidfile", m_general.pidFile, 0, 1024, "") && ret; + bool ret = cfg.getValue("daemon", "daemon", m_daemon.daemon, false); + ret = cfg.getValue("daemon", "pidfile", m_daemon.pidFile, 0, 1024, "") && ret; + ret = cfg.getValue("daemon", "user", m_daemon.user, 0, 1024, "") && ret; return ret; } @@ -447,7 +448,7 @@ void CDStarGatewayConfig::getGPSD(TGPSD & gpsd) const } #endif -void CDStarGatewayConfig::getGeneral(TDaemon & gen) const +void CDStarGatewayConfig::getDaemon(TDaemon & gen) const { - gen = m_general; + gen = m_daemon; } \ No newline at end of file diff --git a/DStarGateway/DStarGatewayConfig.h b/DStarGateway/DStarGatewayConfig.h index d8152f7..dec8ca5 100644 --- a/DStarGateway/DStarGatewayConfig.h +++ b/DStarGateway/DStarGatewayConfig.h @@ -28,6 +28,7 @@ typedef struct { bool daemon; std::string pidFile; + std::string user; } TDaemon; typedef struct { @@ -155,7 +156,7 @@ public: #ifdef USE_GPSD void getGPSD(TGPSD & gpsd) const; #endif - void getGeneral(TDaemon & gen) const; + void getDaemon(TDaemon & gen) const; private: bool open(CConfig & cfg); @@ -188,7 +189,7 @@ private: #ifdef USE_GPSD TGPSD m_gpsd; #endif - TDaemon m_general; + TDaemon m_daemon; std::vector m_repeaters; std::vector m_ircDDB; diff --git a/DStarGateway/example.cfg b/DStarGateway/example.cfg index 9ece63e..2683b19 100644 --- a/DStarGateway/example.cfg +++ b/DStarGateway/example.cfg @@ -179,5 +179,5 @@ password=CHANGE_ME # If password is left blank, remote will be disabled regardle [Daemon] daemon=false -# pid file is in our case useless when running as a daemon using systemd as systemd handles all the pid stuff for us -pidfile=#/var/run/dstargateway/dstargateway.pid \ No newline at end of file +pidfile=/var/run/dstargateway/dstargateway.pid # pid file is in our case useless when running as a daemon using systemd as systemd takes care of the service not being started twice +user=dstar # user account the daemon will run under, ideally a user with low privileges \ No newline at end of file From 00a2301ef6af3148533928dadd3c8e6c427187df Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Wed, 16 Feb 2022 09:26:00 +0100 Subject: [PATCH 13/25] #21 remove daemon finalize from sigHAndler --- DStarGateway/DStarGatewayApp.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/DStarGateway/DStarGatewayApp.cpp b/DStarGateway/DStarGatewayApp.cpp index 8e7299b..325e21b 100644 --- a/DStarGateway/DStarGatewayApp.cpp +++ b/DStarGateway/DStarGatewayApp.cpp @@ -321,8 +321,6 @@ void CDStarGatewayApp::sigHandler(int sig) if(g_app != nullptr && g_app->m_thread != nullptr) { g_app->m_thread->kill(); } - - CDaemon::finalize(); } void CDStarGatewayApp::sigHandlerFatal(int sig) From 635e629988a762b3516f3c7988eb0a349571e9be Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Wed, 16 Feb 2022 10:57:13 +0100 Subject: [PATCH 14/25] #21 force debug info to stderr, fix segfault on exit --- DStarGateway/DStarGatewayApp.cpp | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/DStarGateway/DStarGatewayApp.cpp b/DStarGateway/DStarGatewayApp.cpp index 325e21b..b88f2d8 100644 --- a/DStarGateway/DStarGatewayApp.cpp +++ b/DStarGateway/DStarGatewayApp.cpp @@ -142,8 +142,6 @@ m_thread(NULL) CDStarGatewayApp::~CDStarGatewayApp() { - delete m_config; - delete m_thread; } bool CDStarGatewayApp::init() @@ -326,12 +324,14 @@ void CDStarGatewayApp::sigHandler(int sig) void CDStarGatewayApp::sigHandlerFatal(int sig) { CLog::logFatal("Caught signal : %s", strsignal(sig)); + fprintf(stderr, "Caught signal : %s\n", strsignal(sig)); #ifdef DEBUG_DSTARGW std::stringstream stackTrace; stackTrace << boost::stacktrace::stacktrace(); CLog::logFatal("Stack Trace : \n%s", stackTrace.str().c_str()); + fprintf(stderr, "Stack Trace : \n%s\n", stackTrace.str().c_str()); #endif - exit(1); + exit(3); } void CDStarGatewayApp::terminateHandler() @@ -350,13 +350,15 @@ void CDStarGatewayApp::terminateHandler() } else { CLog::logFatal("Unhandled unknown exception occured"); + fprintf(stderr, "Unknown ex\n"); } } catch(const std::exception& e) { CLog::logFatal("Unhandled exception occured %s", e.what()); + fprintf(stderr, "Unhandled ex %s\n", e.what()); } #ifdef DEBUG_DSTARGW CLog::logFatal("Stack Trace : \n%s", stackTrace.str().c_str()); #endif - exit(1); + exit(2); } From 4eef7b2dcf52fca0b33f4a306acdce35af9098cf Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Wed, 16 Feb 2022 10:58:27 +0100 Subject: [PATCH 15/25] #21 do not close stdin,stdout and stderr --- BaseCommon/Daemon.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/BaseCommon/Daemon.cpp b/BaseCommon/Daemon.cpp index 6a2976a..5283040 100644 --- a/BaseCommon/Daemon.cpp +++ b/BaseCommon/Daemon.cpp @@ -138,6 +138,7 @@ DAEMONIZE_RESULT CDaemon::daemonize(const std::string& pidFile, const std::strin return DR_FAILURE; } +#ifdef CLOSE_FILE_DESC // Close all open file descriptors for (int fd = sysconf(_SC_OPEN_MAX); fd > 0; fd--) { close(fd); @@ -147,6 +148,7 @@ DAEMONIZE_RESULT CDaemon::daemonize(const std::string& pidFile, const std::strin stdin = fopen("/dev/null", "r"); stdout = fopen("/dev/null", "w+"); stderr = fopen("/dev/null", "w+"); +#endif // Try to write PID of daemon to lockfile if (!pidFile.empty()) From c05fcc936c7441213cec1f89505500aca451e92a Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Wed, 16 Feb 2022 13:17:39 +0100 Subject: [PATCH 16/25] #21 only change user if we are root --- BaseCommon/Daemon.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/BaseCommon/Daemon.cpp b/BaseCommon/Daemon.cpp index 5283040..46ad038 100644 --- a/BaseCommon/Daemon.cpp +++ b/BaseCommon/Daemon.cpp @@ -58,7 +58,7 @@ DAEMONIZE_RESULT CDaemon::daemonize(const std::string& pidFile, const std::strin } releaseLock(tempFd, ""); - if(user != nullptr) { + if(user != nullptr && getuid() == 0) { int res = chown(pidFile.c_str(), user->pw_uid, user->pw_gid); if(res != 0) { CLog::logFatal("Failed to set ownership of pidfile to user %s : %s", userName.c_str(), strerror(errno)); @@ -68,7 +68,7 @@ DAEMONIZE_RESULT CDaemon::daemonize(const std::string& pidFile, const std::strin } // change process ownership - if(user != nullptr) { + if(user != nullptr && getuid() == 0) { if(setgid(user->pw_gid) != 0) { CLog::logFatal("Failed to set %s GID : %s", userName.c_str(), strerror(errno)); return DR_FAILURE; From 721cdc130276330aae8e1cbc2eeff3f92bb72b04 Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Wed, 16 Feb 2022 13:19:12 +0100 Subject: [PATCH 17/25] #21 clarify user --- DStarGateway/example.cfg | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DStarGateway/example.cfg b/DStarGateway/example.cfg index 2683b19..a6d71c7 100644 --- a/DStarGateway/example.cfg +++ b/DStarGateway/example.cfg @@ -180,4 +180,4 @@ password=CHANGE_ME # If password is left blank, remote will be disabled regardle [Daemon] daemon=false pidfile=/var/run/dstargateway/dstargateway.pid # pid file is in our case useless when running as a daemon using systemd as systemd takes care of the service not being started twice -user=dstar # user account the daemon will run under, ideally a user with low privileges \ No newline at end of file +user=dstar # user account the daemon will run under, ideally a user with low privileges. Switching to this user will only happen when the program is started as root \ No newline at end of file From 757e62e3a3dc0a9417e10d53e180d4cb0c461845 Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Wed, 16 Feb 2022 13:29:19 +0100 Subject: [PATCH 18/25] #21 sipmlify root check --- BaseCommon/Daemon.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/BaseCommon/Daemon.cpp b/BaseCommon/Daemon.cpp index 46ad038..d0afc21 100644 --- a/BaseCommon/Daemon.cpp +++ b/BaseCommon/Daemon.cpp @@ -41,7 +41,7 @@ DAEMONIZE_RESULT CDaemon::daemonize(const std::string& pidFile, const std::strin { // get user struct passwd* user = nullptr; - if(!userName.empty()) { + if(!userName.empty() && getuid() == 0) { user = getpwnam(userName.c_str()); if(user == nullptr) { CLog::logFatal("Failed to get %s user", userName.c_str()); @@ -58,7 +58,7 @@ DAEMONIZE_RESULT CDaemon::daemonize(const std::string& pidFile, const std::strin } releaseLock(tempFd, ""); - if(user != nullptr && getuid() == 0) { + if(user != nullptr) { int res = chown(pidFile.c_str(), user->pw_uid, user->pw_gid); if(res != 0) { CLog::logFatal("Failed to set ownership of pidfile to user %s : %s", userName.c_str(), strerror(errno)); @@ -68,7 +68,7 @@ DAEMONIZE_RESULT CDaemon::daemonize(const std::string& pidFile, const std::strin } // change process ownership - if(user != nullptr && getuid() == 0) { + if(user != nullptr) { if(setgid(user->pw_gid) != 0) { CLog::logFatal("Failed to set %s GID : %s", userName.c_str(), strerror(errno)); return DR_FAILURE; @@ -80,7 +80,7 @@ DAEMONIZE_RESULT CDaemon::daemonize(const std::string& pidFile, const std::strin } // Double check it worked (AKA Paranoia) - if (::setuid(0) != -1){ + if (setuid(0) != -1){ CLog::logFatal("It's possible to regain root - something is wrong!, exiting"); return DR_FAILURE; } From 041e0f57d9b6fe4e58e9c3cbd3c0f3a6833d20d9 Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Fri, 18 Feb 2022 07:23:37 +0100 Subject: [PATCH 19/25] #21 finalise in Entry --- DStarGateway/DStarGatewayThread.cpp | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/DStarGateway/DStarGatewayThread.cpp b/DStarGateway/DStarGatewayThread.cpp index a2d4bc6..73ea87c 100644 --- a/DStarGateway/DStarGatewayThread.cpp +++ b/DStarGateway/DStarGatewayThread.cpp @@ -131,19 +131,7 @@ m_restrictList(NULL) CDStarGatewayThread::~CDStarGatewayThread() { - CHeaderData::finalise(); - CG2Handler::finalise(); - CDExtraHandler::finalise(); - CDPlusHandler::finalise(); - CDCSHandler::finalise(); - CRepeaterHandler::finalise(); -#ifdef USE_STARNET - CStarNetHandler::finalise(); -#endif -#ifdef USE_CCS - CCCSHandler::finalise(); -#endif - CAudioUnit::finalise(); + } void* CDStarGatewayThread::Entry() @@ -491,7 +479,19 @@ void* CDStarGatewayThread::Entry() delete headerLogger; } + CHeaderData::finalise(); + CG2Handler::finalise(); + CDExtraHandler::finalise(); CDPlusHandler::finalise(); + CDCSHandler::finalise(); + CRepeaterHandler::finalise(); +#ifdef USE_STARNET + CStarNetHandler::finalise(); +#endif +#ifdef USE_CCS + CCCSHandler::finalise(); +#endif + CAudioUnit::finalise(); return NULL; } From e7c89d81719522cad9396c95dd4766b375d12dce Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Fri, 18 Feb 2022 07:25:41 +0100 Subject: [PATCH 20/25] #21 close aprs in Gateway Thread --- Common/RepeaterHandler.cpp | 5 ----- 1 file changed, 5 deletions(-) diff --git a/Common/RepeaterHandler.cpp b/Common/RepeaterHandler.cpp index 7c486ee..35685a6 100644 --- a/Common/RepeaterHandler.cpp +++ b/Common/RepeaterHandler.cpp @@ -438,11 +438,6 @@ void CRepeaterHandler::finalise() m_repeaters[i] = NULL; } - if (m_aprsWriter != NULL) { - m_aprsWriter->close(); - delete m_aprsWriter; - } - delete[] m_repeaters; } From 8c4696ce2623722a74bb42ff5636e3f7f224b7b9 Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Fri, 18 Feb 2022 07:26:00 +0100 Subject: [PATCH 21/25] #21 stop and then clean --- Common/APRSHandler.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Common/APRSHandler.cpp b/Common/APRSHandler.cpp index 4d6b81a..c81a745 100644 --- a/Common/APRSHandler.cpp +++ b/Common/APRSHandler.cpp @@ -226,13 +226,13 @@ bool CAPRSHandler::isConnected() const void CAPRSHandler::close() { + m_thread->stop(); + if(m_idFrameProvider != nullptr) { m_idFrameProvider->close(); delete m_idFrameProvider; m_idFrameProvider = nullptr; } - - m_thread->stop(); } void CAPRSHandler::addReadAPRSCallback(IReadAPRSFrameCallback* cb) From 1dbdf5babb3a45eea57754b00bb4033b03ab834f Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Fri, 18 Feb 2022 07:51:07 +0100 Subject: [PATCH 22/25] #21 write banner do log files --- DStarGateway/DStarGatewayApp.cpp | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/DStarGateway/DStarGatewayApp.cpp b/DStarGateway/DStarGatewayApp.cpp index b88f2d8..9483208 100644 --- a/DStarGateway/DStarGatewayApp.cpp +++ b/DStarGateway/DStarGatewayApp.cpp @@ -50,6 +50,9 @@ #include "Daemon.h" CDStarGatewayApp * CDStarGatewayApp::g_app = nullptr; +const std::string BANNER_1 = CStringUtils::string_format("%s Copyright (C) %s\n", FULL_PRODUCT_NAME.c_str(), VENDOR_NAME.c_str()); +const std::string BANNER_2 = "DStarGateway comes with ABSOLUTELY NO WARRANTY; see the LICENSE for details.\n"; +const std::string BANNER_3 = "This is free software, and you are welcome to distribute it under certain conditions that are discussed in the LICENSE file.\n\n"; #ifdef UNIT_TESTS int fakemain(int argc, char *argv[]) @@ -73,9 +76,7 @@ int main(int argc, char *argv[]) return 1; } - printf("\n%s Copyright (C) %s\n", FULL_PRODUCT_NAME.c_str(), VENDOR_NAME.c_str()); - printf("DStarGateway comes with ABSOLUTELY NO WARRANTY; see the LICENSE for details.\n"); - printf("This is free software, and you are welcome to distribute it\nunder certain conditions that are discussed in the LICENSE file.\n\n"); + std::cout << std::endl << BANNER_1 << BANNER_2 << BANNER_3; if ('-' == argv[1][0]) { return 0; @@ -117,6 +118,13 @@ int main(int argc, char *argv[]) if(logConf.m_displayLevel != LOG_NONE && !daemon.daemon) CLog::addTarget(new CLogConsoleTarget(logConf.m_displayLevel)); if(logConf.m_fileLevel != LOG_NONE) CLog::addTarget(new CLogFileTarget(logConf.m_fileLevel, logConf.logDir, logConf.m_fileRotate)); + //write banner in log file if we are dameon + if(daemon.daemon) { + CLog::logInfo(BANNER_1); + CLog::logInfo(BANNER_2); + CLog::logInfo(BANNER_3); + } + CDStarGatewayApp gateway(config); if (!gateway.init()) { From 4eefd5c1ab7feb7b42d18fceae60ab2cf1d2578d Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Fri, 18 Feb 2022 07:53:48 +0100 Subject: [PATCH 23/25] #21 finalize -> finalise --- BaseCommon/Daemon.cpp | 2 +- BaseCommon/Daemon.h | 6 +++--- DStarGateway/DStarGatewayApp.cpp | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/BaseCommon/Daemon.cpp b/BaseCommon/Daemon.cpp index d0afc21..6fc09b0 100644 --- a/BaseCommon/Daemon.cpp +++ b/BaseCommon/Daemon.cpp @@ -175,7 +175,7 @@ DAEMONIZE_RESULT CDaemon::daemonize(const std::string& pidFile, const std::strin return DR_CHILD; } -void CDaemon::finalize() +void CDaemon::finalise() { releaseLock(m_pid_fd, m_pidFileName); diff --git a/BaseCommon/Daemon.h b/BaseCommon/Daemon.h index 0981896..3fa8809 100644 --- a/BaseCommon/Daemon.h +++ b/BaseCommon/Daemon.h @@ -30,11 +30,11 @@ class CDaemon { public: static DAEMONIZE_RESULT daemonize(const std::string& pidFile, const std::string& user); - static void finalize(); + static void finalise(); private: - static int tryGetLock(const std::string& file ); - static void releaseLock(int fd, const std::string& file ); + static int tryGetLock(const std::string& file); + static void releaseLock(int fd, const std::string& file); static int m_pid_fd; static std::string m_pidFileName; diff --git a/DStarGateway/DStarGatewayApp.cpp b/DStarGateway/DStarGatewayApp.cpp index 9483208..8604a00 100644 --- a/DStarGateway/DStarGatewayApp.cpp +++ b/DStarGateway/DStarGatewayApp.cpp @@ -134,7 +134,7 @@ int main(int argc, char *argv[]) gateway.run(); if(daemon.daemon) { - CDaemon::finalize(); + CDaemon::finalise(); } return 0; From e0af58fd971e32edb828857b15b3d69907e57be0 Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Fri, 18 Feb 2022 07:55:24 +0100 Subject: [PATCH 24/25] #21 daemonize -> daemonise --- BaseCommon/Daemon.cpp | 2 +- BaseCommon/Daemon.h | 2 +- DStarGateway/DStarGatewayApp.cpp | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/BaseCommon/Daemon.cpp b/BaseCommon/Daemon.cpp index 6fc09b0..aa34ed7 100644 --- a/BaseCommon/Daemon.cpp +++ b/BaseCommon/Daemon.cpp @@ -37,7 +37,7 @@ int CDaemon::m_pid_fd = -1; std::string CDaemon::m_pidFileName(""); -DAEMONIZE_RESULT CDaemon::daemonize(const std::string& pidFile, const std::string& userName) +DAEMONIZE_RESULT CDaemon::daemonise(const std::string& pidFile, const std::string& userName) { // get user struct passwd* user = nullptr; diff --git a/BaseCommon/Daemon.h b/BaseCommon/Daemon.h index 3fa8809..7f2556f 100644 --- a/BaseCommon/Daemon.h +++ b/BaseCommon/Daemon.h @@ -29,7 +29,7 @@ enum DAEMONIZE_RESULT class CDaemon { public: - static DAEMONIZE_RESULT daemonize(const std::string& pidFile, const std::string& user); + static DAEMONIZE_RESULT daemonise(const std::string& pidFile, const std::string& user); static void finalise(); private: diff --git a/DStarGateway/DStarGatewayApp.cpp b/DStarGateway/DStarGatewayApp.cpp index 8604a00..d0d5c52 100644 --- a/DStarGateway/DStarGatewayApp.cpp +++ b/DStarGateway/DStarGatewayApp.cpp @@ -93,7 +93,7 @@ int main(int argc, char *argv[]) if (daemon.daemon) { CLog::logInfo("Configured as a daemon, detaching ..."); - auto res = CDaemon::daemonize(daemon.pidFile, daemon.user); + auto res = CDaemon::daemonise(daemon.pidFile, daemon.user); switch (res) { From 48e2b492439eb668854e14ac14cf0488fa47d102 Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Fri, 18 Feb 2022 13:56:11 +0100 Subject: [PATCH 25/25] #21 revert back to simple systemd service --- DStarGateway/Makefile | 1 - DStarGateway/example.cfg | 3 +++ debian/dstargateway.service | 5 ++--- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/DStarGateway/Makefile b/DStarGateway/Makefile index d5619c5..73318d1 100644 --- a/DStarGateway/Makefile +++ b/DStarGateway/Makefile @@ -21,7 +21,6 @@ install: dstargateway @cp -fn example.cfg $(CFG_DIR)/dstargateway.cfg @sed -i "s|path=/var/log/dstargateway/|path=$(LOG_DIR)|g" $(CFG_DIR)/dstargateway.cfg @sed -i "s|data=/usr/local/share/dstargateway.d/|data=$(DATA_DIR)|g" $(CFG_DIR)/dstargateway.cfg - @sed -i "s|daemon=false|daemon=true|g" $(CFG_DIR)/dstargateway.cfg ../APRS/APRS.a: ../Common/Common.a: diff --git a/DStarGateway/example.cfg b/DStarGateway/example.cfg index a6d71c7..36e38de 100644 --- a/DStarGateway/example.cfg +++ b/DStarGateway/example.cfg @@ -177,6 +177,9 @@ enabled=false port=4242 password=CHANGE_ME # If password is left blank, remote will be disabled regardless of the enabled field +# Provided install routines install the program as a systemd unit. SystemD does not recommand "old-school" forking daemons nor does systemd +# require a pid file. Moreover system handles the user under which the program is started. This is provided as convenience for people who might +# run the program using sysv or any other old school init system. [Daemon] daemon=false pidfile=/var/run/dstargateway/dstargateway.pid # pid file is in our case useless when running as a daemon using systemd as systemd takes care of the service not being started twice diff --git a/debian/dstargateway.service b/debian/dstargateway.service index 8b8185a..314a11d 100644 --- a/debian/dstargateway.service +++ b/debian/dstargateway.service @@ -1,10 +1,11 @@ [Unit] +User=dstar Description=D-STAR Gateway Daemon After=network.target,network-online.target Wants=network-online.target [Service] -Type=forking +Type=simple ExecStart=/usr/local/bin/dstargateway %CFG_DIR%/dstargateway.cfg Restart=on-failure RestartSec=5 @@ -13,5 +14,3 @@ StartLimitBurst=0 [Install] WantedBy=multi-user.target - -