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.
reverse-scroll
nirenjan 2021-08-04 13:13:12 -07:00
parent f5331cdef3
commit 0fae24b5d0
4 changed files with 208 additions and 59 deletions

View File

@ -15,6 +15,8 @@
#define X52D_SYS_CFG_FILE SYSCONFDIR "/" X52D_APP_NAME "/" X52D_APP_NAME ".conf" #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" #include "gettext.h"
#define N_(x) gettext_noop(x) #define N_(x) gettext_noop(x)
#define _(x) gettext(x) #define _(x) gettext(x)

View File

@ -10,6 +10,8 @@
#include <stdio.h> #include <stdio.h>
#include <stdbool.h> #include <stdbool.h>
#include <string.h> #include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <signal.h> #include <signal.h>
#include <unistd.h> #include <unistd.h>
#include <errno.h> #include <errno.h>
@ -74,11 +76,115 @@ __attribute__((noreturn))
static void usage(int exit_code) static void usage(int exit_code)
{ {
fprintf(stderr, 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); X52D_APP_NAME);
exit(exit_code); 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 main(int argc, char **argv)
{ {
int verbosity = 0; int verbosity = 0;
@ -86,6 +192,7 @@ int main(int argc, char **argv)
bool foreground = false; bool foreground = false;
char *log_file = NULL; char *log_file = NULL;
char *conf_file = NULL; char *conf_file = NULL;
const char *pid_file = NULL;
int opt; int opt;
/* Initialize gettext */ /* Initialize gettext */
@ -107,8 +214,9 @@ int main(int argc, char **argv)
* -v verbose logging * -v verbose logging
* -q silent behavior * -q silent behavior
* -l path to log file * -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) { switch (opt) {
case 'f': case 'f':
foreground = true; foreground = true;
@ -145,6 +253,10 @@ int main(int argc, char **argv)
conf_file = optarg; conf_file = optarg;
break; break;
case 'p':
pid_file = optarg;
break;
case 'h': case 'h':
usage(EXIT_SUCCESS); usage(EXIT_SUCCESS);
break; break;
@ -161,15 +273,16 @@ int main(int argc, char **argv)
PINELOG_DEBUG(_("Log file = %s"), log_file); PINELOG_DEBUG(_("Log file = %s"), log_file);
PINELOG_DEBUG(_("Config file = %s"), conf_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); set_log_file(foreground, log_file);
x52d_config_load(conf_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 // Start device threads
x52d_dev_init(); x52d_dev_init();
x52d_clock_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 // Stop device threads
x52d_clock_exit(); x52d_clock_exit();
x52d_dev_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")); PINELOG_INFO(_("Shutting down X52 daemon"));
return 0; return 0;

View File

@ -8,7 +8,7 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: x52pro-linux 0.2.2\n" "Project-Id-Version: x52pro-linux 0.2.2\n"
"Report-Msgid-Bugs-To: https://github.com/nirenjan/x52pro-linux/issues\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" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n" "Language-Team: LANGUAGE <LL@li.org>\n"
@ -491,64 +491,77 @@ msgstr ""
msgid "OK" msgid "OK"
msgstr "" msgstr ""
#: daemon/x52d_main.c:50 #: daemon/x52d_main.c:52
#, c-format #, c-format
msgid "Error %d setting log file: %s\n" msgid "Error %d setting log file: %s\n"
msgstr "" msgstr ""
#: daemon/x52d_main.c:66 #: daemon/x52d_main.c:68
#, c-format #, c-format
msgid "Error %d installing handler for signal %d: %s" msgid "Error %d installing handler for signal %d: %s"
msgstr "" msgstr ""
#: daemon/x52d_main.c:77 #: daemon/x52d_main.c:79
#, c-format #, 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 "" 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 #, c-format
msgid "Unable to parse configuration override '%s'\n" msgid "Unable to parse configuration override '%s'\n"
msgstr "" msgstr ""
#: daemon/x52d_main.c:158 #: daemon/x52d_main.c:270
#, c-format #, c-format
msgid "Foreground = %s" msgid "Foreground = %s"
msgstr "" msgstr ""
#: daemon/x52d_main.c:158 daemon/x52d_main.c:159 #: daemon/x52d_main.c:270 daemon/x52d_main.c:271
msgid "true" msgid "true"
msgstr "" msgstr ""
#: daemon/x52d_main.c:158 daemon/x52d_main.c:159 #: daemon/x52d_main.c:270 daemon/x52d_main.c:271
msgid "false" msgid "false"
msgstr "" msgstr ""
#: daemon/x52d_main.c:159 #: daemon/x52d_main.c:271
#, c-format #, c-format
msgid "Quiet = %s" msgid "Quiet = %s"
msgstr "" msgstr ""
#: daemon/x52d_main.c:160 #: daemon/x52d_main.c:272
#, c-format #, c-format
msgid "Verbosity = %d" msgid "Verbosity = %d"
msgstr "" msgstr ""
#: daemon/x52d_main.c:161 #: daemon/x52d_main.c:273
#, c-format #, c-format
msgid "Log file = %s" msgid "Log file = %s"
msgstr "" msgstr ""
#: daemon/x52d_main.c:162 #: daemon/x52d_main.c:274
#, c-format #, c-format
msgid "Config file = %s" msgid "Config file = %s"
msgstr "" msgstr ""
#: daemon/x52d_main.c:188 #: daemon/x52d_main.c:301
msgid "Reloading X52 configuration" msgid "Reloading X52 configuration"
msgstr "" 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" msgid "Shutting down X52 daemon"
msgstr "" msgstr ""
@ -557,7 +570,7 @@ msgstr ""
msgid "Setting clock enable to %s" msgid "Setting clock enable to %s"
msgstr "" msgstr ""
#: daemon/x52d_clock.c:34 daemon/x52d_clock.c:112 #: daemon/x52d_clock.c:34 daemon/x52d_clock.c:113
#, c-format #, c-format
msgid "Setting %s clock timezone to %s" msgid "Setting %s clock timezone to %s"
msgstr "" msgstr ""
@ -570,39 +583,39 @@ msgstr ""
msgid "UTC" msgid "UTC"
msgstr "" msgstr ""
#: daemon/x52d_clock.c:53 #: daemon/x52d_clock.c:54
msgid "Unable to allocate memory for timezone. Falling back to UTC" msgid "Unable to allocate memory for timezone. Falling back to UTC"
msgstr "" msgstr ""
#: daemon/x52d_clock.c:63 #: daemon/x52d_clock.c:64
msgid "Unable to backup timezone environment. Falling back to UTC" msgid "Unable to backup timezone environment. Falling back to UTC"
msgstr "" msgstr ""
#: daemon/x52d_clock.c:129 #: daemon/x52d_clock.c:130
#, c-format #, c-format
msgid "Setting %s clock format to %s" msgid "Setting %s clock format to %s"
msgstr "" msgstr ""
#: daemon/x52d_clock.c:151 #: daemon/x52d_clock.c:152
#, c-format #, c-format
msgid "Setting date format to %s" msgid "Setting date format to %s"
msgstr "" msgstr ""
#: daemon/x52d_clock.c:161 #: daemon/x52d_clock.c:162
msgid "Starting X52 clock manager thread" msgid "Starting X52 clock manager thread"
msgstr "" msgstr ""
#: daemon/x52d_clock.c:172 #: daemon/x52d_clock.c:173
#, c-format #, c-format
msgid "Error %d retrieving current time: %s" msgid "Error %d retrieving current time: %s"
msgstr "" msgstr ""
#: daemon/x52d_clock.c:193 #: daemon/x52d_clock.c:194
#, c-format #, c-format
msgid "Error %d initializing clock thread: %s" msgid "Error %d initializing clock thread: %s"
msgstr "" msgstr ""
#: daemon/x52d_clock.c:200 #: daemon/x52d_clock.c:201
msgid "Shutting down X52 clock manager thread" msgid "Shutting down X52 clock manager thread"
msgstr "" msgstr ""

View File

@ -7,8 +7,8 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: x52pro-linux 0.2.1\n" "Project-Id-Version: x52pro-linux 0.2.1\n"
"Report-Msgid-Bugs-To: https://github.com/nirenjan/x52pro-linux/issues\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: 2021-07-27 02:08-0700\n" "PO-Revision-Date: 2021-08-04 13:12-0700\n"
"Last-Translator: Nirenjan Krishnan <nirenjan@gmail.com>\n" "Last-Translator: Nirenjan Krishnan <nirenjan@gmail.com>\n"
"Language-Team: Dummy Language for testing i18n\n" "Language-Team: Dummy Language for testing i18n\n"
"Language: xx_PL\n" "Language: xx_PL\n"
@ -534,66 +534,80 @@ msgstr "Estingtay aracterchay 0x%02x..."
msgid "OK" msgid "OK"
msgstr "OKay" msgstr "OKay"
#: daemon/x52d_main.c:50 #: daemon/x52d_main.c:52
#, c-format #, c-format
msgid "Error %d setting log file: %s\n" msgid "Error %d setting log file: %s\n"
msgstr "Erroray %d ettingsay oglay ilefay: %s\n" msgstr "Erroray %d ettingsay oglay ilefay: %s\n"
#: daemon/x52d_main.c:66 #: daemon/x52d_main.c:68
#, c-format #, c-format
msgid "Error %d installing handler for signal %d: %s" msgid "Error %d installing handler for signal %d: %s"
msgstr "Erroray %d installingay andlerhay orfay ignalsay %d: %s" msgstr "Erroray %d installingay andlerhay orfay ignalsay %d: %s"
#: daemon/x52d_main.c:77 #: daemon/x52d_main.c:79
#, c-format #, 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 "" msgstr ""
"Usageay: %s [-f] [-v] [-q] [-l oglay-ilefay] [-o overrideay] [-c onfigcay-" "Usageay: %s [-f] [-v] [-q]\n"
"ilefay]\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 #, c-format
msgid "Unable to parse configuration override '%s'\n" msgid "Unable to parse configuration override '%s'\n"
msgstr "Unableay otay arsepay onfigurationcay overrideay '%s'\n" msgstr "Unableay otay arsepay onfigurationcay overrideay '%s'\n"
#: daemon/x52d_main.c:158 #: daemon/x52d_main.c:270
#, c-format #, c-format
msgid "Foreground = %s" msgid "Foreground = %s"
msgstr "Oregroundfay = %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" msgid "true"
msgstr "uetray" msgstr "uetray"
#: daemon/x52d_main.c:158 daemon/x52d_main.c:159 #: daemon/x52d_main.c:270 daemon/x52d_main.c:271
msgid "false" msgid "false"
msgstr "alsefay" msgstr "alsefay"
#: daemon/x52d_main.c:159 #: daemon/x52d_main.c:271
#, c-format #, c-format
msgid "Quiet = %s" msgid "Quiet = %s"
msgstr "Uietqay = %s" msgstr "Uietqay = %s"
#: daemon/x52d_main.c:160 #: daemon/x52d_main.c:272
#, c-format #, c-format
msgid "Verbosity = %d" msgid "Verbosity = %d"
msgstr "Erbosityvay = %d" msgstr "Erbosityvay = %d"
#: daemon/x52d_main.c:161 #: daemon/x52d_main.c:273
#, c-format #, c-format
msgid "Log file = %s" msgid "Log file = %s"
msgstr "Oglay ilefay = %s" msgstr "Oglay ilefay = %s"
#: daemon/x52d_main.c:162 #: daemon/x52d_main.c:274
#, c-format #, c-format
msgid "Config file = %s" msgid "Config file = %s"
msgstr "Onfigcay ilefay = %s" msgstr "Onfigcay ilefay = %s"
#: daemon/x52d_main.c:188 #: daemon/x52d_main.c:301
msgid "Reloading X52 configuration" msgid "Reloading X52 configuration"
msgstr "Eloadingray X52 onfigurationcay" 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" msgid "Shutting down X52 daemon"
msgstr "Uttingshay ownday X52 aemonday" msgstr "Uttingshay ownday X52 aemonday"
@ -602,7 +616,7 @@ msgstr "Uttingshay ownday X52 aemonday"
msgid "Setting clock enable to %s" msgid "Setting clock enable to %s"
msgstr "Ettingsay ockclay enableay otay %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 #, c-format
msgid "Setting %s clock timezone to %s" msgid "Setting %s clock timezone to %s"
msgstr "Ettingsay %s ockclay imezonetay otay %s" msgstr "Ettingsay %s ockclay imezonetay otay %s"
@ -615,42 +629,42 @@ msgstr "ocallay"
msgid "UTC" msgid "UTC"
msgstr "UTCay" msgstr "UTCay"
#: daemon/x52d_clock.c:53 #: daemon/x52d_clock.c:54
msgid "Unable to allocate memory for timezone. Falling back to UTC" msgid "Unable to allocate memory for timezone. Falling back to UTC"
msgstr "" msgstr ""
"Unableay otay allocateay emorymay orfay imezonetay. Allingfay ackbay otay " "Unableay otay allocateay emorymay orfay imezonetay. Allingfay ackbay otay "
"UTCay" "UTCay"
#: daemon/x52d_clock.c:63 #: daemon/x52d_clock.c:64
msgid "Unable to backup timezone environment. Falling back to UTC" msgid "Unable to backup timezone environment. Falling back to UTC"
msgstr "" msgstr ""
"Unableay otay ackupbay imezonetay environmentay. Allingfay ackbay otay UTCay" "Unableay otay ackupbay imezonetay environmentay. Allingfay ackbay otay UTCay"
#: daemon/x52d_clock.c:129 #: daemon/x52d_clock.c:130
#, c-format #, c-format
msgid "Setting %s clock format to %s" msgid "Setting %s clock format to %s"
msgstr "Ettingsay %s ockclay ormatfay otay %s" msgstr "Ettingsay %s ockclay ormatfay otay %s"
#: daemon/x52d_clock.c:151 #: daemon/x52d_clock.c:152
#, c-format #, c-format
msgid "Setting date format to %s" msgid "Setting date format to %s"
msgstr "Ettingsay ateday ormatfay otay %s" msgstr "Ettingsay ateday ormatfay otay %s"
#: daemon/x52d_clock.c:161 #: daemon/x52d_clock.c:162
msgid "Starting X52 clock manager thread" msgid "Starting X52 clock manager thread"
msgstr "Artingstay X52 ockclay anagermay eadthray" msgstr "Artingstay X52 ockclay anagermay eadthray"
#: daemon/x52d_clock.c:172 #: daemon/x52d_clock.c:173
#, c-format #, c-format
msgid "Error %d retrieving current time: %s" msgid "Error %d retrieving current time: %s"
msgstr "Erroray %d etrievingray urrentcay imetay: %s" msgstr "Erroray %d etrievingray urrentcay imetay: %s"
#: daemon/x52d_clock.c:193 #: daemon/x52d_clock.c:194
#, c-format #, c-format
msgid "Error %d initializing clock thread: %s" msgid "Error %d initializing clock thread: %s"
msgstr "Erroray %d initializingay ockclay eadthray: %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" msgid "Shutting down X52 clock manager thread"
msgstr "Uttingshay ownday X52 ockclay anagermay eadthray" msgstr "Uttingshay ownday X52 ockclay anagermay eadthray"