From e1fc8c1d3cca7e915a73cfe44462f71d2938ecba Mon Sep 17 00:00:00 2001 From: Maxim Biro Date: Thu, 31 Dec 2015 23:18:39 -0500 Subject: Add ability to run the daemon in foreground Useful for things like a Docker container or just running it in the terminal. Complements the stdout logging option. This is actually why the stdout logging was added in the first place -- to be used in the foreground mode, though nothing stops one from using stdout in the background mode, which one could redirect to a file. --- other/bootstrap_daemon/src/tox-bootstrapd.c | 142 ++++++++++++++++------------ 1 file changed, 81 insertions(+), 61 deletions(-) diff --git a/other/bootstrap_daemon/src/tox-bootstrapd.c b/other/bootstrap_daemon/src/tox-bootstrapd.c index 3bbddf98..a8098e41 100644 --- a/other/bootstrap_daemon/src/tox-bootstrapd.c +++ b/other/bootstrap_daemon/src/tox-bootstrapd.c @@ -523,6 +523,7 @@ bool print_help() { // 2 space ident // make sure all lines fit into 80 columns + // make sure options are listed in alphabetical order write_log(LOG_LEVEL_INFO, "Usage: tox-bootstrapd [OPTION]... --config=FILE_PATH\n" "\n" @@ -531,6 +532,8 @@ bool print_help() " This is a required option.\n" " Set FILE_PATH to a path to an empty file in order to\n" " use default settings.\n" + " --foreground Run the daemon in foreground. The daemon won't fork\n" + " (detach from the terminal) and won't use the PID file.\n" " --help Print this help message.\n" " --log-backend=BACKEND Specify which logging backend to use.\n" " Valid BACKEND values (case sensetive):\n" @@ -544,7 +547,7 @@ bool print_help() // Handels command line arguments, setting cfg_file_path and log_backend. // Terminates the application if incorrect arguments are specified. -void handle_command_line_arguments(int argc, char *argv[], char **cfg_file_path, LOG_BACKEND *log_backend) +void handle_command_line_arguments(int argc, char *argv[], char **cfg_file_path, LOG_BACKEND *log_backend, bool *run_in_foreground) { if (argc < 2) { write_log(LOG_LEVEL_ERROR, "Error: No arguments provided.\n\n"); @@ -557,6 +560,7 @@ void handle_command_line_arguments(int argc, char *argv[], char **cfg_file_path, static struct option long_options[] = { {"help", no_argument, 0, 'h'}, {"config", required_argument, 0, 'c'}, // required option + {"foreground", no_argument, 0, 'f'}, {"log-backend", required_argument, 0, 'l'}, // optional, defaults to syslog {"version", no_argument, 0, 'v'}, {0, 0, 0, 0 } @@ -565,6 +569,8 @@ void handle_command_line_arguments(int argc, char *argv[], char **cfg_file_path, bool cfg_file_path_set = false; bool log_backend_set = false; + *run_in_foreground = false; + int opt; while ((opt = getopt_long(argc, argv, ":", long_options, NULL)) != -1) { @@ -579,6 +585,10 @@ void handle_command_line_arguments(int argc, char *argv[], char **cfg_file_path, cfg_file_path_set = true; break; + case 'f': + *run_in_foreground = true; + break; + case 'l': if (strcmp(optarg, "syslog") == 0) { *log_backend = LOG_BACKEND_SYSLOG; @@ -620,16 +630,77 @@ void handle_command_line_arguments(int argc, char *argv[], char **cfg_file_path, } } +// Demonizes the process, appending PID to the PID file and closing file descriptors based on log backend +// Terminates the application if the daemonization fails. + +void daemonize(LOG_BACKEND log_backend, char *pid_file_path) +{ + // Check if the PID file exists + FILE *pid_file; + + if ((pid_file = fopen(pid_file_path, "r"))) { + write_log(LOG_LEVEL_WARNING, "Another instance of the daemon is already running, PID file %s exists.\n", pid_file_path); + fclose(pid_file); + } + + // Open the PID file for writing + pid_file = fopen(pid_file_path, "a+"); + if (pid_file == NULL) { + write_log(LOG_LEVEL_ERROR, "Couldn't open the PID file for writing: %s. Exiting.\n", pid_file_path); + exit(1); + } + + // Fork off from the parent process + const pid_t pid = fork(); + + if (pid > 0) { + fprintf(pid_file, "%d", pid); + fclose(pid_file); + write_log(LOG_LEVEL_INFO, "Forked successfully: PID: %d.\n", pid); + exit(0); + } else { + fclose(pid_file); + } + + if (pid < 0) { + write_log(LOG_LEVEL_ERROR, "Forking failed. Exiting.\n"); + exit(1); + } + + // Create a new SID for the child process + if (setsid() < 0) { + write_log(LOG_LEVEL_ERROR, "SID creation failure. Exiting.\n"); + exit(1); + } + + // Change the file mode mask + umask(0); + + // Change the current working directory + if ((chdir("/")) < 0) { + write_log(LOG_LEVEL_ERROR, "Couldn't change working directory to '/'. Exiting.\n"); + exit(1); + } + + // Go quiet + if (log_backend != LOG_BACKEND_STDOUT) { + close(STDOUT_FILENO); + close(STDIN_FILENO); + close(STDERR_FILENO); + } +} + int main(int argc, char *argv[]) { char *cfg_file_path; LOG_BACKEND log_backend; + bool run_in_foreground; // choose backend for printing command line argument parsing output based on whether the daemon is being run from a terminal log_backend = isatty(STDOUT_FILENO) ? LOG_BACKEND_STDOUT : LOG_BACKEND_SYSLOG; open_log(log_backend); - handle_command_line_arguments(argc, argv, &cfg_file_path, &log_backend); + handle_command_line_arguments(argc, argv, &cfg_file_path, &log_backend, &run_in_foreground); close_log(); open_log(log_backend); @@ -660,14 +731,12 @@ int main(int argc, char *argv[]) return 1; } - // Check if the PID file exists - FILE *pid_file; - - if ((pid_file = fopen(pid_file_path, "r"))) { - write_log(LOG_LEVEL_WARNING, "Another instance of the daemon is already running, PID file %s exists.\n", pid_file_path); - fclose(pid_file); + if (!run_in_foreground) { + daemonize(log_backend, pid_file_path); } + free(pid_file_path); + IP ip; ip_init(&ip, enable_ipv6); @@ -690,7 +759,6 @@ int main(int argc, char *argv[]) } } - DHT *dht = new_DHT(net); if (dht == NULL) { @@ -724,6 +792,8 @@ int main(int argc, char *argv[]) return 1; } + free(keys_file_path); + TCP_Server *tcp_server = NULL; if (enable_tcp_relay) { @@ -754,56 +824,6 @@ int main(int argc, char *argv[]) print_public_key(dht->self_public_key); - // Write the PID file - FILE *pidf = fopen(pid_file_path, "a+"); - - if (pidf == NULL) { - write_log(LOG_LEVEL_ERROR, "Couldn't open the PID file for writing: %s. Exiting.\n", pid_file_path); - return 1; - } - - free(pid_file_path); - free(keys_file_path); - - // Fork off from the parent process - const pid_t pid = fork(); - - if (pid > 0) { - fprintf(pidf, "%d", pid); - fclose(pidf); - write_log(LOG_LEVEL_INFO, "Forked successfully: PID: %d.\n", pid); - return 0; - } else { - fclose(pidf); - } - - if (pid < 0) { - write_log(LOG_LEVEL_ERROR, "Forking failed. Exiting.\n"); - return 1; - } - - // Change the file mode mask - umask(0); - - // Create a new SID for the child process - if (setsid() < 0) { - write_log(LOG_LEVEL_ERROR, "SID creation failure. Exiting.\n"); - return 1; - } - - // Change the current working directory - if ((chdir("/")) < 0) { - write_log(LOG_LEVEL_ERROR, "Couldn't change working directory to '/'. Exiting.\n"); - return 1; - } - - // Go quiet - if (log_backend != LOG_BACKEND_STDOUT) { - close(STDOUT_FILENO); - close(STDIN_FILENO); - close(STDERR_FILENO); - } - uint64_t last_LANdiscovery = 0; const uint16_t htons_port = htons(port); @@ -811,7 +831,7 @@ int main(int argc, char *argv[]) if (enable_lan_discovery) { LANdiscovery_init(dht); - write_log(LOG_LEVEL_INFO, "Initialized LAN discovery.\n"); + write_log(LOG_LEVEL_INFO, "Initialized LAN discovery successfully.\n"); } while (1) { @@ -829,7 +849,7 @@ int main(int argc, char *argv[]) networking_poll(dht->net); if (waiting_for_dht_connection && DHT_isconnected(dht)) { - write_log(LOG_LEVEL_INFO, "Connected to other bootstrap node successfully.\n"); + write_log(LOG_LEVEL_INFO, "Connected to another bootstrap node successfully.\n"); waiting_for_dht_connection = 0; } -- cgit v1.2.3