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_PID_FILE RUNDIR "/" X52D_APP_NAME ".pid"
#include "gettext.h"
#define N_(x) gettext_noop(x)
#define _(x) gettext(x)

View File

@ -10,6 +10,8 @@
#include <stdio.h>
#include <stdbool.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <signal.h>
#include <unistd.h>
#include <errno.h>
@ -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;

View File

@ -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 <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\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 ""

View File

@ -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 <nirenjan@gmail.com>\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"