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.
This commit is contained in:
Maxim Biro 2015-12-31 23:18:39 -05:00
parent 2ef1ce9421
commit e1fc8c1d3c

View File

@ -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;
}