diff --git a/.vscode/launch.json b/.vscode/launch.json index 03f8b49..bd85764 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" } ] }, diff --git a/BaseCommon/Daemon.cpp b/BaseCommon/Daemon.cpp new file mode 100644 index 0000000..aa34ed7 --- /dev/null +++ b/BaseCommon/Daemon.cpp @@ -0,0 +1,206 @@ +/* + * 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 + +#include "Daemon.h" +#include "Log.h" + +int CDaemon::m_pid_fd = -1; +std::string CDaemon::m_pidFileName(""); + +DAEMONIZE_RESULT CDaemon::daemonise(const std::string& pidFile, const std::string& userName) +{ + // get user + struct passwd* user = nullptr; + if(!userName.empty() && getuid() == 0) { + 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; + + /* Fork off the parent process */ + pid = fork(); + + /* An error occurred */ + if (pid < 0) { + CLog::logFatal("Forking failed, exiting"); + 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) { + CLog::logFatal("Failed to set session id, exiting"); + return DR_FAILURE; + } + + /* Ignore signal sent from child to parent process */ + signal(SIGCHLD, SIG_IGN); + +#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 + if (pid < 0) { + CLog::logFatal("Second forking failed, exiting"); + return DR_FAILURE; + } + + // Success: Let the parent terminate + if (pid > 0) { + return DR_PARENT; + } +#endif + + // Set new file permissions + umask(0); + + /* Change the working directory to the root directory */ + /* or another appropriated directory */ + if(chdir("/") != 0) { + CLog::logFatal("Faild to cd, exiting"); + return DR_FAILURE; + } + +#ifdef CLOSE_FILE_DESC + // 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) + 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()) + { + m_pid_fd = tryGetLock(pidFile); + 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::finalise() +{ + 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; +} + + +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 new file mode 100644 index 0000000..7f2556f --- /dev/null +++ b/BaseCommon/Daemon.h @@ -0,0 +1,41 @@ +/* + * 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 daemonise(const std::string& pidFile, const std::string& user); + static void finalise(); + +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 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 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) 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; } diff --git a/DStarGateway/DStarGatewayApp.cpp b/DStarGateway/DStarGatewayApp.cpp index 8acfe2e..d0d5c52 100644 --- a/DStarGateway/DStarGatewayApp.cpp +++ b/DStarGateway/DStarGatewayApp.cpp @@ -25,6 +25,8 @@ #include #include #include +#include +#include #ifdef DEBUG_DSTARGW #include #endif @@ -45,8 +47,12 @@ #include "LogConsoleTarget.h" #include "APRSGPSDIdFrameProvider.h" #include "APRSFixedIdFrameProvider.h" +#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[]) @@ -70,16 +76,56 @@ int main(int argc, char *argv[]) return 1; } + std::cout << std::endl << BANNER_1 << BANNER_2 << BANNER_3; + 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->getDaemon(daemon); + + if (daemon.daemon) { + CLog::logInfo("Configured as a daemon, detaching ..."); + auto res = CDaemon::daemonise(daemon.pidFile, daemon.user); + + switch (res) + { + case DR_PARENT: + return 0; + case DR_CHILD: + break; + case DR_PIDFILE_FAILED: + case DR_FAILURE: + default: + CLog::logFatal("Failed to run as daemon"); + delete config; + CLog::finalise(); + 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)); + + //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(cfgFile); + CDStarGatewayApp gateway(config); if (!gateway.init()) { return 1; @@ -87,11 +133,18 @@ int main(int argc, char *argv[]) gateway.run(); + if(daemon.daemon) { + CDaemon::finalise(); + } + 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; } @@ -102,7 +155,6 @@ CDStarGatewayApp::~CDStarGatewayApp() 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 +167,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 +186,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 +216,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 +261,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 +280,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); @@ -292,12 +332,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() @@ -316,13 +358,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); } 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..5d236ca 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,14 @@ bool CDStarGatewayConfig::load() return ret; } +bool CDStarGatewayConfig::loadDaemon(const CConfig & cfg) +{ + 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; +} + bool CDStarGatewayConfig::loadXLX(const CConfig & cfg) { bool ret = cfg.getValue("xlx", "enabled", m_xlx.enabled, true); @@ -438,3 +447,8 @@ void CDStarGatewayConfig::getGPSD(TGPSD & gpsd) const gpsd = m_gpsd; } #endif + +void CDStarGatewayConfig::getDaemon(TDaemon & gen) const +{ + gen = m_daemon; +} \ No newline at end of file diff --git a/DStarGateway/DStarGatewayConfig.h b/DStarGateway/DStarGatewayConfig.h index b27ca44..dec8ca5 100644 --- a/DStarGateway/DStarGatewayConfig.h +++ b/DStarGateway/DStarGatewayConfig.h @@ -25,6 +25,12 @@ #include "Config.h" #include "LogSeverity.h" +typedef struct { + bool daemon; + std::string pidFile; + std::string user; +} TDaemon; + typedef struct { GATEWAY_TYPE type; std::string callsign; @@ -150,6 +156,7 @@ public: #ifdef USE_GPSD void getGPSD(TGPSD & gpsd) const; #endif + void getDaemon(TDaemon & gen) const; private: bool open(CConfig & cfg); @@ -167,6 +174,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 +189,8 @@ private: #ifdef USE_GPSD TGPSD m_gpsd; #endif + TDaemon m_daemon; + std::vector m_repeaters; std::vector m_ircDDB; }; 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"); 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; } diff --git a/DStarGateway/example.cfg b/DStarGateway/example.cfg index b83f0d6..36e38de 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,10 @@ 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 +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 diff --git a/debian/dstargateway.service b/debian/dstargateway.service index 4f8c069..314a11d 100644 --- a/debian/dstargateway.service +++ b/debian/dstargateway.service @@ -14,5 +14,3 @@ StartLimitBurst=0 [Install] WantedBy=multi-user.target - -