From 0fae24b5d0fa28e65c4ff96b44e53a019bc6508d Mon Sep 17 00:00:00 2001 From: nirenjan Date: Wed, 4 Aug 2021 13:13:12 -0700 Subject: [PATCH] Allow x52d to daemonize Prior to this change, x52d could only run in the foreground, regardless of the value of the foreground flag. This change adds the standard double-fork routine to daemonize the program. This change also adds a PID file argument to x52d, which is used to ensure that only one instance of the x52d daemon is running at any time. --- daemon/x52d_const.h | 2 + daemon/x52d_main.c | 136 +++++++++++++++++++++++++++++++++++++++++--- po/x52pro-linux.pot | 61 ++++++++++++-------- po/xx_PL.po | 68 +++++++++++++--------- 4 files changed, 208 insertions(+), 59 deletions(-) diff --git a/daemon/x52d_const.h b/daemon/x52d_const.h index f7702e5..16c3384 100644 --- a/daemon/x52d_const.h +++ b/daemon/x52d_const.h @@ -15,6 +15,8 @@ #define X52D_SYS_CFG_FILE SYSCONFDIR "/" X52D_APP_NAME "/" X52D_APP_NAME ".conf" +#define X52D_PID_FILE RUNDIR "/" X52D_APP_NAME ".pid" + #include "gettext.h" #define N_(x) gettext_noop(x) #define _(x) gettext(x) diff --git a/daemon/x52d_main.c b/daemon/x52d_main.c index 06a515d..14edc2d 100644 --- a/daemon/x52d_main.c +++ b/daemon/x52d_main.c @@ -10,6 +10,8 @@ #include #include #include +#include +#include #include #include #include @@ -74,11 +76,115 @@ __attribute__((noreturn)) static void usage(int exit_code) { fprintf(stderr, - _("Usage: %s [-f] [-v] [-q] [-l log-file] [-o override] [-c config-file]\n"), + _("Usage: %s [-f] [-v] [-q]\n" + "\t[-l log-file] [-o override]\n" + "\t[-c config-file] [-p pid-file]\n"), X52D_APP_NAME); exit(exit_code); } +static void start_daemon(bool foreground, const char *pid_file) +{ + pid_t pid; + FILE *pid_fd; + + if (pid_file == NULL) { + pid_file = X52D_PID_FILE; + } + + /* Check if there is an existing daemon process running */ + pid_fd = fopen(pid_file, "r"); + if (pid_fd != NULL) { + int rc; + + /* File exists, read the PID and check if it exists */ + rc = fscanf(pid_fd, "%u", &pid); + fclose(pid_fd); + + if (rc != 1) { + perror("fscanf"); + } else { + rc = kill(pid, 0); + if (rc == 0 || (rc < 0 && errno == EPERM)) { + PINELOG_FATAL(_("Daemon is already running as PID %u"), pid); + } + } + } + + if (!foreground) { + /* Fork off the parent process */ + pid = fork(); + if (pid < 0) { + /* Error occurred during first fork */ + perror("fork"); + exit(EXIT_FAILURE); + } else if (pid > 0) { + /* Terminate the parent process */ + exit(EXIT_SUCCESS); + } + + /* Make child process a session leader */ + if (setsid() < 0) { + perror("setsid"); + exit(EXIT_FAILURE); + } + } + + /* Initialize signal handlers. This step is the same whether in foreground + * or background mode + */ + listen_signal(SIGINT, termination_handler); + listen_signal(SIGTERM, termination_handler); + listen_signal(SIGQUIT, termination_handler); + listen_signal(SIGHUP, reload_handler); + + if (!foreground) { + /* Fork off for the second time */ + pid = fork(); + if (pid < 0) { + /* Error occurred during second fork */ + perror("fork"); + exit(EXIT_FAILURE); + } else if (pid > 0) { + /* Terminate the parent */ + exit(EXIT_SUCCESS); + } + } + + /* Write the PID to the pid_file */ + pid_fd = fopen(pid_file, "w"); + if (pid_fd == NULL) { + /* Unable to open PID file */ + perror("fopen"); + exit(EXIT_FAILURE); + } + if (fprintf(pid_fd, "%u\n", getpid()) < 0) { + perror("fprintf"); + exit(EXIT_FAILURE); + } + if (fclose(pid_fd) != 0) { + perror("fclose"); + exit(EXIT_FAILURE); + } + + if (!foreground) { + /* Set new file permissions */ + umask(0); + + /* Change the working directory */ + if (chdir("/")) { + /* Error changing the directory */ + perror("chdir"); + exit(EXIT_FAILURE); + } + + /* Close all open file descriptors */ + for (int x = sysconf(_SC_OPEN_MAX); x >= 0; x--) { + close(x); + } + } +} + int main(int argc, char **argv) { int verbosity = 0; @@ -86,6 +192,7 @@ int main(int argc, char **argv) bool foreground = false; char *log_file = NULL; char *conf_file = NULL; + const char *pid_file = NULL; int opt; /* Initialize gettext */ @@ -107,8 +214,9 @@ int main(int argc, char **argv) * -v verbose logging * -q silent behavior * -l path to log file + * -p path to PID file (only used if running in background) */ - while ((opt = getopt(argc, argv, "fvql:o:c:h")) != -1) { + while ((opt = getopt(argc, argv, "fvql:o:c:p:h")) != -1) { switch (opt) { case 'f': foreground = true; @@ -145,6 +253,10 @@ int main(int argc, char **argv) conf_file = optarg; break; + case 'p': + pid_file = optarg; + break; + case 'h': usage(EXIT_SUCCESS); break; @@ -161,15 +273,16 @@ int main(int argc, char **argv) PINELOG_DEBUG(_("Log file = %s"), log_file); PINELOG_DEBUG(_("Config file = %s"), conf_file); + /* Set default PID file */ + if (pid_file == NULL) { + pid_file = X52D_PID_FILE; + } + + start_daemon(foreground, pid_file); + set_log_file(foreground, log_file); x52d_config_load(conf_file); - // Initialize signal handlers - listen_signal(SIGINT, termination_handler); - listen_signal(SIGTERM, termination_handler); - listen_signal(SIGQUIT, termination_handler); - listen_signal(SIGHUP, reload_handler); - // Start device threads x52d_dev_init(); x52d_clock_init(); @@ -192,9 +305,16 @@ int main(int argc, char **argv) } } + PINELOG_INFO(_("Received termination signal %s"), strsignal(flag_quit)); + // Stop device threads x52d_clock_exit(); x52d_dev_exit(); + + // Remove the PID file + PINELOG_TRACE("Removing PID file %s", pid_file); + unlink(pid_file); + PINELOG_INFO(_("Shutting down X52 daemon")); return 0; diff --git a/po/x52pro-linux.pot b/po/x52pro-linux.pot index 301bfd0..09d7dcb 100644 --- a/po/x52pro-linux.pot +++ b/po/x52pro-linux.pot @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: x52pro-linux 0.2.2\n" "Report-Msgid-Bugs-To: https://github.com/nirenjan/x52pro-linux/issues\n" -"POT-Creation-Date: 2021-07-29 22:58-0700\n" +"POT-Creation-Date: 2021-08-04 13:11-0700\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -491,64 +491,77 @@ msgstr "" msgid "OK" msgstr "" -#: daemon/x52d_main.c:50 +#: daemon/x52d_main.c:52 #, c-format msgid "Error %d setting log file: %s\n" msgstr "" -#: daemon/x52d_main.c:66 +#: daemon/x52d_main.c:68 #, c-format msgid "Error %d installing handler for signal %d: %s" msgstr "" -#: daemon/x52d_main.c:77 +#: daemon/x52d_main.c:79 #, c-format -msgid "Usage: %s [-f] [-v] [-q] [-l log-file] [-o override] [-c config-file]\n" +msgid "" +"Usage: %s [-f] [-v] [-q]\n" +"\t[-l log-file] [-o override]\n" +"\t[-c config-file] [-p pid-file]\n" msgstr "" -#: daemon/x52d_main.c:138 +#: daemon/x52d_main.c:109 +#, c-format +msgid "Daemon is already running as PID %u" +msgstr "" + +#: daemon/x52d_main.c:246 #, c-format msgid "Unable to parse configuration override '%s'\n" msgstr "" -#: daemon/x52d_main.c:158 +#: daemon/x52d_main.c:270 #, c-format msgid "Foreground = %s" msgstr "" -#: daemon/x52d_main.c:158 daemon/x52d_main.c:159 +#: daemon/x52d_main.c:270 daemon/x52d_main.c:271 msgid "true" msgstr "" -#: daemon/x52d_main.c:158 daemon/x52d_main.c:159 +#: daemon/x52d_main.c:270 daemon/x52d_main.c:271 msgid "false" msgstr "" -#: daemon/x52d_main.c:159 +#: daemon/x52d_main.c:271 #, c-format msgid "Quiet = %s" msgstr "" -#: daemon/x52d_main.c:160 +#: daemon/x52d_main.c:272 #, c-format msgid "Verbosity = %d" msgstr "" -#: daemon/x52d_main.c:161 +#: daemon/x52d_main.c:273 #, c-format msgid "Log file = %s" msgstr "" -#: daemon/x52d_main.c:162 +#: daemon/x52d_main.c:274 #, c-format msgid "Config file = %s" msgstr "" -#: daemon/x52d_main.c:188 +#: daemon/x52d_main.c:301 msgid "Reloading X52 configuration" msgstr "" -#: daemon/x52d_main.c:198 +#: daemon/x52d_main.c:308 +#, c-format +msgid "Received termination signal %s" +msgstr "" + +#: daemon/x52d_main.c:318 msgid "Shutting down X52 daemon" msgstr "" @@ -557,7 +570,7 @@ msgstr "" msgid "Setting clock enable to %s" msgstr "" -#: daemon/x52d_clock.c:34 daemon/x52d_clock.c:112 +#: daemon/x52d_clock.c:34 daemon/x52d_clock.c:113 #, c-format msgid "Setting %s clock timezone to %s" msgstr "" @@ -570,39 +583,39 @@ msgstr "" msgid "UTC" msgstr "" -#: daemon/x52d_clock.c:53 +#: daemon/x52d_clock.c:54 msgid "Unable to allocate memory for timezone. Falling back to UTC" msgstr "" -#: daemon/x52d_clock.c:63 +#: daemon/x52d_clock.c:64 msgid "Unable to backup timezone environment. Falling back to UTC" msgstr "" -#: daemon/x52d_clock.c:129 +#: daemon/x52d_clock.c:130 #, c-format msgid "Setting %s clock format to %s" msgstr "" -#: daemon/x52d_clock.c:151 +#: daemon/x52d_clock.c:152 #, c-format msgid "Setting date format to %s" msgstr "" -#: daemon/x52d_clock.c:161 +#: daemon/x52d_clock.c:162 msgid "Starting X52 clock manager thread" msgstr "" -#: daemon/x52d_clock.c:172 +#: daemon/x52d_clock.c:173 #, c-format msgid "Error %d retrieving current time: %s" msgstr "" -#: daemon/x52d_clock.c:193 +#: daemon/x52d_clock.c:194 #, c-format msgid "Error %d initializing clock thread: %s" msgstr "" -#: daemon/x52d_clock.c:200 +#: daemon/x52d_clock.c:201 msgid "Shutting down X52 clock manager thread" msgstr "" diff --git a/po/xx_PL.po b/po/xx_PL.po index f5a4e9a..faf63dc 100644 --- a/po/xx_PL.po +++ b/po/xx_PL.po @@ -7,8 +7,8 @@ msgid "" msgstr "" "Project-Id-Version: x52pro-linux 0.2.1\n" "Report-Msgid-Bugs-To: https://github.com/nirenjan/x52pro-linux/issues\n" -"POT-Creation-Date: 2021-07-29 22:58-0700\n" -"PO-Revision-Date: 2021-07-27 02:08-0700\n" +"POT-Creation-Date: 2021-08-04 13:11-0700\n" +"PO-Revision-Date: 2021-08-04 13:12-0700\n" "Last-Translator: Nirenjan Krishnan \n" "Language-Team: Dummy Language for testing i18n\n" "Language: xx_PL\n" @@ -534,66 +534,80 @@ msgstr "Estingtay aracterchay 0x%02x..." msgid "OK" msgstr "OKay" -#: daemon/x52d_main.c:50 +#: daemon/x52d_main.c:52 #, c-format msgid "Error %d setting log file: %s\n" msgstr "Erroray %d ettingsay oglay ilefay: %s\n" -#: daemon/x52d_main.c:66 +#: daemon/x52d_main.c:68 #, c-format msgid "Error %d installing handler for signal %d: %s" msgstr "Erroray %d installingay andlerhay orfay ignalsay %d: %s" -#: daemon/x52d_main.c:77 +#: daemon/x52d_main.c:79 #, c-format -msgid "Usage: %s [-f] [-v] [-q] [-l log-file] [-o override] [-c config-file]\n" +msgid "" +"Usage: %s [-f] [-v] [-q]\n" +"\t[-l log-file] [-o override]\n" +"\t[-c config-file] [-p pid-file]\n" msgstr "" -"Usageay: %s [-f] [-v] [-q] [-l oglay-ilefay] [-o overrideay] [-c onfigcay-" -"ilefay]\n" +"Usageay: %s [-f] [-v] [-q]\n" +"\t[-l oglay-ilefay] [-o overrideay]\n" +"\t[-c onfigcay-ilefay] [-p idpay-ilefay]\n" -#: daemon/x52d_main.c:138 +#: daemon/x52d_main.c:109 +#, c-format +msgid "Daemon is already running as PID %u" +msgstr "Aemonday isay alreadyay unningray asay IDPay %u" + +#: daemon/x52d_main.c:246 #, c-format msgid "Unable to parse configuration override '%s'\n" msgstr "Unableay otay arsepay onfigurationcay overrideay '%s'\n" -#: daemon/x52d_main.c:158 +#: daemon/x52d_main.c:270 #, c-format msgid "Foreground = %s" msgstr "Oregroundfay = %s" -#: daemon/x52d_main.c:158 daemon/x52d_main.c:159 +#: daemon/x52d_main.c:270 daemon/x52d_main.c:271 msgid "true" msgstr "uetray" -#: daemon/x52d_main.c:158 daemon/x52d_main.c:159 +#: daemon/x52d_main.c:270 daemon/x52d_main.c:271 msgid "false" msgstr "alsefay" -#: daemon/x52d_main.c:159 +#: daemon/x52d_main.c:271 #, c-format msgid "Quiet = %s" msgstr "Uietqay = %s" -#: daemon/x52d_main.c:160 +#: daemon/x52d_main.c:272 #, c-format msgid "Verbosity = %d" msgstr "Erbosityvay = %d" -#: daemon/x52d_main.c:161 +#: daemon/x52d_main.c:273 #, c-format msgid "Log file = %s" msgstr "Oglay ilefay = %s" -#: daemon/x52d_main.c:162 +#: daemon/x52d_main.c:274 #, c-format msgid "Config file = %s" msgstr "Onfigcay ilefay = %s" -#: daemon/x52d_main.c:188 +#: daemon/x52d_main.c:301 msgid "Reloading X52 configuration" msgstr "Eloadingray X52 onfigurationcay" -#: daemon/x52d_main.c:198 +#: daemon/x52d_main.c:308 +#, c-format +msgid "Received termination signal %s" +msgstr "Eceivedray erminationtay ignalsay %s" + +#: daemon/x52d_main.c:318 msgid "Shutting down X52 daemon" msgstr "Uttingshay ownday X52 aemonday" @@ -602,7 +616,7 @@ msgstr "Uttingshay ownday X52 aemonday" msgid "Setting clock enable to %s" msgstr "Ettingsay ockclay enableay otay %s" -#: daemon/x52d_clock.c:34 daemon/x52d_clock.c:112 +#: daemon/x52d_clock.c:34 daemon/x52d_clock.c:113 #, c-format msgid "Setting %s clock timezone to %s" msgstr "Ettingsay %s ockclay imezonetay otay %s" @@ -615,42 +629,42 @@ msgstr "ocallay" msgid "UTC" msgstr "UTCay" -#: daemon/x52d_clock.c:53 +#: daemon/x52d_clock.c:54 msgid "Unable to allocate memory for timezone. Falling back to UTC" msgstr "" "Unableay otay allocateay emorymay orfay imezonetay. Allingfay ackbay otay " "UTCay" -#: daemon/x52d_clock.c:63 +#: daemon/x52d_clock.c:64 msgid "Unable to backup timezone environment. Falling back to UTC" msgstr "" "Unableay otay ackupbay imezonetay environmentay. Allingfay ackbay otay UTCay" -#: daemon/x52d_clock.c:129 +#: daemon/x52d_clock.c:130 #, c-format msgid "Setting %s clock format to %s" msgstr "Ettingsay %s ockclay ormatfay otay %s" -#: daemon/x52d_clock.c:151 +#: daemon/x52d_clock.c:152 #, c-format msgid "Setting date format to %s" msgstr "Ettingsay ateday ormatfay otay %s" -#: daemon/x52d_clock.c:161 +#: daemon/x52d_clock.c:162 msgid "Starting X52 clock manager thread" msgstr "Artingstay X52 ockclay anagermay eadthray" -#: daemon/x52d_clock.c:172 +#: daemon/x52d_clock.c:173 #, c-format msgid "Error %d retrieving current time: %s" msgstr "Erroray %d etrievingray urrentcay imetay: %s" -#: daemon/x52d_clock.c:193 +#: daemon/x52d_clock.c:194 #, c-format msgid "Error %d initializing clock thread: %s" msgstr "Erroray %d initializingay ockclay eadthray: %s" -#: daemon/x52d_clock.c:200 +#: daemon/x52d_clock.c:201 msgid "Shutting down X52 clock manager thread" msgstr "Uttingshay ownday X52 ockclay anagermay eadthray"