X-Git-Url: http://git.efficios.com/?p=lttng-tools.git;a=blobdiff_plain;f=src%2Fbin%2Flttng-sessiond%2Fmain.c;h=4d9b22de2d4d93e3def0cd43597c61c8b33db87b;hp=3bf91b0faf2a0bda9b8d8d56d57af19d61d32d87;hb=996de3c771ebf249a9a40e5ff76daf60d55cb02f;hpb=aeb162609d6ef1f16ec0e818d3750eb6dfff8b30 diff --git a/src/bin/lttng-sessiond/main.c b/src/bin/lttng-sessiond/main.c index 3bf91b0fa..4d9b22de2 100644 --- a/src/bin/lttng-sessiond/main.c +++ b/src/bin/lttng-sessiond/main.c @@ -1,6 +1,7 @@ /* * Copyright (C) 2011 - David Goulet * Mathieu Desnoyers + * 2013 - Jérémie Galarneau * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License, version 2 only, @@ -20,6 +21,7 @@ #include #include #include +#include #include #include #include @@ -44,6 +46,7 @@ #include #include #include +#include #include "lttng-sessiond.h" #include "buffer-registry.h" @@ -69,15 +72,20 @@ const char *progname; static const char *tracing_group_name = DEFAULT_TRACING_GROUP; -static const char *opt_pidfile; +static int tracing_group_name_override; +static char *opt_pidfile; static int opt_sig_parent; static int opt_verbose_consumer; static int opt_daemon; static int opt_no_kernel; static int is_root; /* Set to 1 if the daemon is running as root */ static pid_t ppid; /* Parent PID for --sig-parent option */ +static pid_t child_ppid; /* Internal parent PID use with daemonize. */ static char *rundir; +/* Set to 1 when a SIGUSR1 signal is received. */ +static int recv_child_signal; + /* * Consumer daemon specific control data. Every value not initialized here is * set to 0 by the static definition. @@ -116,6 +124,38 @@ static struct consumer_data ustconsumer32_data = { .cond_mutex = PTHREAD_MUTEX_INITIALIZER, }; +/* Command line options */ +static const struct option long_options[] = { + { "client-sock", 1, 0, 'c' }, + { "apps-sock", 1, 0, 'a' }, + { "kconsumerd-cmd-sock", 1, 0, 'C' }, + { "kconsumerd-err-sock", 1, 0, 'E' }, + { "ustconsumerd32-cmd-sock", 1, 0, 'G' }, + { "ustconsumerd32-err-sock", 1, 0, 'H' }, + { "ustconsumerd64-cmd-sock", 1, 0, 'D' }, + { "ustconsumerd64-err-sock", 1, 0, 'F' }, + { "consumerd32-path", 1, 0, 'u' }, + { "consumerd32-libdir", 1, 0, 'U' }, + { "consumerd64-path", 1, 0, 't' }, + { "consumerd64-libdir", 1, 0, 'T' }, + { "daemonize", 0, 0, 'd' }, + { "sig-parent", 0, 0, 'S' }, + { "help", 0, 0, 'h' }, + { "group", 1, 0, 'g' }, + { "version", 0, 0, 'V' }, + { "quiet", 0, 0, 'q' }, + { "verbose", 0, 0, 'v' }, + { "verbose-consumer", 0, 0, 'Z' }, + { "no-kernel", 0, 0, 'N' }, + { "pidfile", 1, 0, 'p' }, + { "jul-tcp-port", 1, 0, 'J' }, + { "config", 1, 0, 'f' }, + { NULL, 0, 0, 0 } +}; + +/* Command line options to ignore from configuration file */ +static const char *config_ignore_options[] = { "help", "version", "config" }; + /* Shared between threads */ static int dispatch_thread_exit; @@ -187,6 +227,10 @@ static const char *consumerd32_bin = CONFIG_CONSUMERD32_BIN; static const char *consumerd64_bin = CONFIG_CONSUMERD64_BIN; static const char *consumerd32_libdir = CONFIG_CONSUMERD32_LIBDIR; static const char *consumerd64_libdir = CONFIG_CONSUMERD64_LIBDIR; +static int consumerd32_bin_override; +static int consumerd64_bin_override; +static int consumerd32_libdir_override; +static int consumerd64_libdir_override; static const char *module_proc_lttng = "/proc/lttng"; @@ -238,6 +282,8 @@ struct health_app *health_sessiond; /* JUL TCP port for registration. Used by the JUL thread. */ unsigned int jul_tcp_port = DEFAULT_JUL_TCP_PORT; +const char * const config_section_name = "sessiond"; + static void setup_consumerd_path(void) { @@ -538,6 +584,30 @@ static void cleanup(void) close_consumer_sockets(); + /* + * If the override option is set, the pointer points to a *non* const thus + * freeing it even though the variable type is set to const. + */ + if (tracing_group_name_override) { + free((void *) tracing_group_name); + } + if (consumerd32_bin_override) { + free((void *) consumerd32_bin); + } + if (consumerd64_bin_override) { + free((void *) consumerd64_bin); + } + if (consumerd32_libdir_override) { + free((void *) consumerd32_libdir); + } + if (consumerd64_libdir_override) { + free((void *) consumerd64_libdir); + } + + if (opt_pidfile) { + free(opt_pidfile); + } + /* */ DBG("%c[%d;%dm*** assert failed :-) *** ==> %c[%dm%c[%d;%dm" "Matthew, BEET driven development works!%c[%dm", @@ -1340,10 +1410,6 @@ static void *thread_manage_apps(void *data) } DBG("Apps with sock %d added to poll set", sock); - - health_code_update(); - - break; } } else { /* @@ -1359,7 +1425,6 @@ static void *thread_manage_apps(void *data) /* Socket closed on remote end. */ ust_app_unregister(pollfd); - break; } } @@ -2932,9 +2997,74 @@ skip_domain: } case LTTNG_ENABLE_EVENT: { + struct lttng_event_exclusion *exclusion = NULL; + struct lttng_filter_bytecode *bytecode = NULL; + + /* Handle exclusion events and receive it from the client. */ + if (cmd_ctx->lsm->u.enable.exclusion_count > 0) { + size_t count = cmd_ctx->lsm->u.enable.exclusion_count; + + exclusion = zmalloc(sizeof(struct lttng_event_exclusion) + + (count * LTTNG_SYMBOL_NAME_LEN)); + if (!exclusion) { + ret = LTTNG_ERR_EXCLUSION_NOMEM; + goto error; + } + + DBG("Receiving var len exclusion event list from client ..."); + exclusion->count = count; + ret = lttcomm_recv_unix_sock(sock, exclusion->names, + count * LTTNG_SYMBOL_NAME_LEN); + if (ret <= 0) { + DBG("Nothing recv() from client var len data... continuing"); + *sock_error = 1; + free(exclusion); + ret = LTTNG_ERR_EXCLUSION_INVAL; + goto error; + } + } + + /* Handle filter and get bytecode from client. */ + if (cmd_ctx->lsm->u.enable.bytecode_len > 0) { + size_t bytecode_len = cmd_ctx->lsm->u.enable.bytecode_len; + + if (bytecode_len > LTTNG_FILTER_MAX_LEN) { + ret = LTTNG_ERR_FILTER_INVAL; + free(exclusion); + goto error; + } + + bytecode = zmalloc(bytecode_len); + if (!bytecode) { + free(exclusion); + ret = LTTNG_ERR_FILTER_NOMEM; + goto error; + } + + /* Receive var. len. data */ + DBG("Receiving var len filter's bytecode from client ..."); + ret = lttcomm_recv_unix_sock(sock, bytecode, bytecode_len); + if (ret <= 0) { + DBG("Nothing recv() from client car len data... continuing"); + *sock_error = 1; + free(bytecode); + free(exclusion); + ret = LTTNG_ERR_FILTER_INVAL; + goto error; + } + + if ((bytecode->len + sizeof(*bytecode)) != bytecode_len) { + free(bytecode); + free(exclusion); + ret = LTTNG_ERR_FILTER_INVAL; + goto error; + } + } + ret = cmd_enable_event(cmd_ctx->session, &cmd_ctx->lsm->domain, cmd_ctx->lsm->u.enable.channel_name, - &cmd_ctx->lsm->u.enable.event, NULL, kernel_poll_pipe[1]); + &cmd_ctx->lsm->u.enable.event, bytecode, exclusion, + kernel_poll_pipe[1]); break; } case LTTNG_ENABLE_ALL_EVENT: @@ -3258,46 +3388,6 @@ skip_domain: cmd_ctx->lsm->u.reg.path, cdata); break; } - case LTTNG_ENABLE_EVENT_WITH_FILTER: - { - struct lttng_filter_bytecode *bytecode; - - if (cmd_ctx->lsm->u.enable.bytecode_len > LTTNG_FILTER_MAX_LEN) { - ret = LTTNG_ERR_FILTER_INVAL; - goto error; - } - if (cmd_ctx->lsm->u.enable.bytecode_len == 0) { - ret = LTTNG_ERR_FILTER_INVAL; - goto error; - } - bytecode = zmalloc(cmd_ctx->lsm->u.enable.bytecode_len); - if (!bytecode) { - ret = LTTNG_ERR_FILTER_NOMEM; - goto error; - } - /* Receive var. len. data */ - DBG("Receiving var len data from client ..."); - ret = lttcomm_recv_unix_sock(sock, bytecode, - cmd_ctx->lsm->u.enable.bytecode_len); - if (ret <= 0) { - DBG("Nothing recv() from client var len data... continuing"); - *sock_error = 1; - ret = LTTNG_ERR_FILTER_INVAL; - goto error; - } - - if (bytecode->len + sizeof(*bytecode) - != cmd_ctx->lsm->u.enable.bytecode_len) { - free(bytecode); - ret = LTTNG_ERR_FILTER_INVAL; - goto error; - } - - ret = cmd_enable_event(cmd_ctx->session, &cmd_ctx->lsm->domain, - cmd_ctx->lsm->u.enable.channel_name, - &cmd_ctx->lsm->u.enable.event, bytecode, kernel_poll_pipe[1]); - break; - } case LTTNG_DATA_PENDING: { ret = cmd_data_pending(cmd_ctx->session); @@ -3696,11 +3786,17 @@ static void *thread_manage_clients(void *data) /* * Notify parent pid that we are ready to accept command for client side. + * This ppid is the one from the external process that spawned us. */ if (opt_sig_parent) { kill(ppid, SIGUSR1); } + /* Notify the parent of the fork() process that we are ready. */ + if (opt_daemon) { + kill(child_ppid, SIGUSR1); + } + if (testpoint(thread_manage_clients_before_loop)) { goto error; } @@ -3921,157 +4017,257 @@ static void usage(void) fprintf(stderr, " -d, --daemonize Start as a daemon.\n"); fprintf(stderr, " -g, --group NAME Specify the tracing group name. (default: tracing)\n"); fprintf(stderr, " -V, --version Show version number.\n"); - fprintf(stderr, " -S, --sig-parent Send SIGCHLD to parent pid to notify readiness.\n"); + fprintf(stderr, " -S, --sig-parent Send SIGUSR1 to parent pid to notify readiness.\n"); fprintf(stderr, " -q, --quiet No output at all.\n"); fprintf(stderr, " -v, --verbose Verbose mode. Activate DBG() macro.\n"); fprintf(stderr, " -p, --pidfile FILE Write a pid to FILE name overriding the default value.\n"); fprintf(stderr, " --verbose-consumer Verbose mode for consumer. Activate DBG() macro.\n"); fprintf(stderr, " --no-kernel Disable kernel tracer\n"); fprintf(stderr, " --jul-tcp-port JUL application registration TCP port\n"); + fprintf(stderr, " -f --config Load daemon configuration file\n"); } /* - * daemon argument parsing + * Take an option from the getopt output and set it in the right variable to be + * used later. + * + * Return 0 on success else a negative value. */ -static int parse_args(int argc, char **argv) +static int set_option(int opt, const char *arg, const char *optname) { - int c; - - static struct option long_options[] = { - { "client-sock", 1, 0, 'c' }, - { "apps-sock", 1, 0, 'a' }, - { "kconsumerd-cmd-sock", 1, 0, 'C' }, - { "kconsumerd-err-sock", 1, 0, 'E' }, - { "ustconsumerd32-cmd-sock", 1, 0, 'G' }, - { "ustconsumerd32-err-sock", 1, 0, 'H' }, - { "ustconsumerd64-cmd-sock", 1, 0, 'D' }, - { "ustconsumerd64-err-sock", 1, 0, 'F' }, - { "consumerd32-path", 1, 0, 'u' }, - { "consumerd32-libdir", 1, 0, 'U' }, - { "consumerd64-path", 1, 0, 't' }, - { "consumerd64-libdir", 1, 0, 'T' }, - { "daemonize", 0, 0, 'd' }, - { "sig-parent", 0, 0, 'S' }, - { "help", 0, 0, 'h' }, - { "group", 1, 0, 'g' }, - { "version", 0, 0, 'V' }, - { "quiet", 0, 0, 'q' }, - { "verbose", 0, 0, 'v' }, - { "verbose-consumer", 0, 0, 'Z' }, - { "no-kernel", 0, 0, 'N' }, - { "pidfile", 1, 0, 'p' }, - { "jul-tcp-port", 1, 0, 'J' }, - { NULL, 0, 0, 0 } - }; + int ret = 0; - while (1) { - int option_index = 0; - c = getopt_long(argc, argv, "dhqvVSN" "a:c:g:s:C:E:D:F:Z:u:t:p:J:", - long_options, &option_index); - if (c == -1) { - break; + switch (opt) { + case 0: + fprintf(stderr, "option %s", optname); + if (arg) { + fprintf(stderr, " with arg %s\n", arg); } - - switch (c) { - case 0: - fprintf(stderr, "option %s", long_options[option_index].name); - if (optarg) { - fprintf(stderr, " with arg %s\n", optarg); - } - break; - case 'c': - snprintf(client_unix_sock_path, PATH_MAX, "%s", optarg); - break; - case 'a': - snprintf(apps_unix_sock_path, PATH_MAX, "%s", optarg); - break; - case 'd': - opt_daemon = 1; - break; - case 'g': - tracing_group_name = optarg; - break; - case 'h': - usage(); - exit(EXIT_FAILURE); - case 'V': - fprintf(stdout, "%s\n", VERSION); - exit(EXIT_SUCCESS); - case 'S': - opt_sig_parent = 1; - break; - case 'E': - snprintf(kconsumer_data.err_unix_sock_path, PATH_MAX, "%s", optarg); - break; - case 'C': - snprintf(kconsumer_data.cmd_unix_sock_path, PATH_MAX, "%s", optarg); - break; - case 'F': - snprintf(ustconsumer64_data.err_unix_sock_path, PATH_MAX, "%s", optarg); - break; - case 'D': - snprintf(ustconsumer64_data.cmd_unix_sock_path, PATH_MAX, "%s", optarg); - break; - case 'H': - snprintf(ustconsumer32_data.err_unix_sock_path, PATH_MAX, "%s", optarg); - break; - case 'G': - snprintf(ustconsumer32_data.cmd_unix_sock_path, PATH_MAX, "%s", optarg); - break; - case 'N': - opt_no_kernel = 1; - break; - case 'q': - lttng_opt_quiet = 1; - break; - case 'v': - /* Verbose level can increase using multiple -v */ + break; + case 'c': + snprintf(client_unix_sock_path, PATH_MAX, "%s", arg); + break; + case 'a': + snprintf(apps_unix_sock_path, PATH_MAX, "%s", arg); + break; + case 'd': + opt_daemon = 1; + break; + case 'g': + tracing_group_name = strdup(arg); + break; + case 'h': + usage(); + exit(EXIT_FAILURE); + case 'V': + fprintf(stdout, "%s\n", VERSION); + exit(EXIT_SUCCESS); + case 'S': + opt_sig_parent = 1; + break; + case 'E': + snprintf(kconsumer_data.err_unix_sock_path, PATH_MAX, "%s", arg); + break; + case 'C': + snprintf(kconsumer_data.cmd_unix_sock_path, PATH_MAX, "%s", arg); + break; + case 'F': + snprintf(ustconsumer64_data.err_unix_sock_path, PATH_MAX, "%s", arg); + break; + case 'D': + snprintf(ustconsumer64_data.cmd_unix_sock_path, PATH_MAX, "%s", arg); + break; + case 'H': + snprintf(ustconsumer32_data.err_unix_sock_path, PATH_MAX, "%s", arg); + break; + case 'G': + snprintf(ustconsumer32_data.cmd_unix_sock_path, PATH_MAX, "%s", arg); + break; + case 'N': + opt_no_kernel = 1; + break; + case 'q': + lttng_opt_quiet = 1; + break; + case 'v': + /* Verbose level can increase using multiple -v */ + if (arg) { + lttng_opt_verbose = config_parse_value(arg); + } else { lttng_opt_verbose += 1; - break; - case 'Z': + } + break; + case 'Z': + if (arg) { + opt_verbose_consumer = config_parse_value(arg); + } else { opt_verbose_consumer += 1; - break; - case 'u': - consumerd32_bin= optarg; - break; - case 'U': - consumerd32_libdir = optarg; - break; - case 't': - consumerd64_bin = optarg; - break; - case 'T': - consumerd64_libdir = optarg; - break; - case 'p': - opt_pidfile = optarg; - break; - case 'J': /* JUL TCP port. */ - { - unsigned long v; + } + break; + case 'u': + consumerd32_bin = strdup(arg); + consumerd32_bin_override = 1; + break; + case 'U': + consumerd32_libdir = strdup(arg); + consumerd32_libdir_override = 1; + break; + case 't': + consumerd64_bin = strdup(arg); + consumerd64_bin_override = 1; + break; + case 'T': + consumerd64_libdir = strdup(arg); + consumerd64_libdir_override = 1; + break; + case 'p': + opt_pidfile = strdup(arg); + break; + case 'J': /* JUL TCP port. */ + { + unsigned long v; - errno = 0; - v = strtoul(optarg, NULL, 0); - if (errno != 0 || !isdigit(optarg[0])) { - ERR("Wrong value in --jul-tcp-port parameter: %s", optarg); - return -1; - } - if (v == 0 || v >= 65535) { - ERR("Port overflow in --jul-tcp-port parameter: %s", optarg); - return -1; + errno = 0; + v = strtoul(arg, NULL, 0); + if (errno != 0 || !isdigit(arg[0])) { + ERR("Wrong value in --jul-tcp-port parameter: %s", arg); + return -1; + } + if (v == 0 || v >= 65535) { + ERR("Port overflow in --jul-tcp-port parameter: %s", arg); + return -1; + } + jul_tcp_port = (uint32_t) v; + DBG3("JUL TCP port set to non default: %u", jul_tcp_port); + break; + } + default: + /* Unknown option or other error. + * Error is printed by getopt, just return */ + ret = -1; + } + + return ret; +} + +/* + * config_entry_handler_cb used to handle options read from a config file. + * See config_entry_handler_cb comment in common/config/config.h for the + * return value conventions. + */ +static int config_entry_handler(const struct config_entry *entry, void *unused) +{ + int ret = 0, i; + + if (!entry || !entry->name || !entry->value) { + ret = -EINVAL; + goto end; + } + + /* Check if the option is to be ignored */ + for (i = 0; i < sizeof(config_ignore_options) / sizeof(char *); i++) { + if (!strcmp(entry->name, config_ignore_options[i])) { + goto end; + } + } + + for (i = 0; i < (sizeof(long_options) / sizeof(struct option)) - 1; + i++) { + + /* Ignore if not fully matched. */ + if (strcmp(entry->name, long_options[i].name)) { + continue; + } + + /* + * If the option takes no argument on the command line, we have to + * check if the value is "true". We support non-zero numeric values, + * true, on and yes. + */ + if (!long_options[i].has_arg) { + ret = config_parse_value(entry->value); + if (ret <= 0) { + if (ret) { + WARN("Invalid configuration value \"%s\" for option %s", + entry->value, entry->name); + } + /* False, skip boolean config option. */ + goto end; } - jul_tcp_port = (uint32_t) v; - DBG3("JUL TCP port set to non default: %u", jul_tcp_port); + } + + ret = set_option(long_options[i].val, entry->value, entry->name); + goto end; + } + + WARN("Unrecognized option \"%s\" in daemon configuration file.", entry->name); + +end: + return ret; +} + +/* + * daemon configuration loading and argument parsing + */ +static int set_options(int argc, char **argv) +{ + int ret = 0, c = 0, option_index = 0; + int orig_optopt = optopt, orig_optind = optind; + char *optstring; + const char *config_path = NULL; + + optstring = utils_generate_optstring(long_options, + sizeof(long_options) / sizeof(struct option)); + if (!optstring) { + ret = -ENOMEM; + goto end; + } + + /* Check for the --config option */ + while ((c = getopt_long(argc, argv, optstring, long_options, + &option_index)) != -1) { + if (c == '?') { + ret = -EINVAL; + goto end; + } else if (c != 'f') { + /* if not equal to --config option. */ + continue; + } + + config_path = utils_expand_path(optarg); + if (!config_path) { + ERR("Failed to resolve path: %s", optarg); + } + } + + ret = config_get_section_entries(config_path, config_section_name, + config_entry_handler, NULL); + if (ret) { + if (ret > 0) { + ERR("Invalid configuration option at line %i", ret); + ret = -1; + } + goto end; + } + + /* Reset getopt's global state */ + optopt = orig_optopt; + optind = orig_optind; + while (1) { + c = getopt_long(argc, argv, optstring, long_options, &option_index); + if (c == -1) { break; } - default: - /* Unknown option or other error. - * Error is printed by getopt, just return */ - return -1; + + ret = set_option(c, optarg, long_options[option_index].name); + if (ret < 0) { + break; } } - return 0; +end: + free(optstring); + return ret; } /* @@ -4342,6 +4538,9 @@ static void sighandler(int sig) DBG("SIGTERM caught"); stop_threads(); break; + case SIGUSR1: + CMM_STORE_SHARED(recv_child_signal, 1); + break; default: break; } @@ -4380,7 +4579,12 @@ static int set_signal_handler(void) return ret; } - DBG("Signal handler set for SIGTERM, SIGPIPE and SIGINT"); + if ((ret = sigaction(SIGUSR1, &sa, NULL)) < 0) { + PERROR("sigaction"); + return ret; + } + + DBG("Signal handler set for SIGTERM, SIGUSR1, SIGPIPE and SIGINT"); return ret; } @@ -4464,6 +4668,107 @@ error: return; } +/* + * Daemonize this process by forking and making the parent wait for the child + * to signal it indicating readiness. Once received, the parent successfully + * quits. + * + * The child process undergoes the same action that daemon(3) does meaning + * setsid, chdir, and dup /dev/null into 0, 1 and 2. + * + * Return 0 on success else -1 on error. + */ +static int daemonize(void) +{ + int ret; + pid_t pid; + + /* Get parent pid of this process. */ + child_ppid = getppid(); + + pid = fork(); + if (pid < 0) { + PERROR("fork"); + goto error; + } else if (pid == 0) { + int fd; + pid_t sid; + + /* Child */ + + /* + * Get the newly created parent pid so we can signal that process when + * we are ready to operate. + */ + child_ppid = getppid(); + + sid = setsid(); + if (sid < 0) { + PERROR("setsid"); + goto error; + } + + /* Try to change directory to /. If we can't well at least notify. */ + ret = chdir("/"); + if (ret < 0) { + PERROR("chdir"); + } + + fd = open(_PATH_DEVNULL, O_RDWR, 0); + if (fd < 0) { + PERROR("open %s", _PATH_DEVNULL); + /* Let 0, 1 and 2 open since we can't bind them to /dev/null. */ + } else { + (void) dup2(fd, STDIN_FILENO); + (void) dup2(fd, STDOUT_FILENO); + (void) dup2(fd, STDERR_FILENO); + if (fd > 2) { + ret = close(fd); + if (ret < 0) { + PERROR("close"); + } + } + } + goto end; + } else { + /* Parent */ + + /* + * Waiting for child to notify this parent that it can exit. Note that + * sleep() is interrupted before the 1 second delay as soon as the + * signal is received, so it will not cause visible delay for the + * user. + */ + while (!CMM_LOAD_SHARED(recv_child_signal)) { + int status; + pid_t ret; + + /* + * Check if child exists without blocking. If so, we have to stop + * this parent process and return an error. + */ + ret = waitpid(pid, &status, WNOHANG); + if (ret < 0 || (ret != 0 && WIFEXITED(status))) { + /* The child exited somehow or was not valid. */ + goto error; + } + sleep(1); + } + + /* + * From this point on, the parent can exit and the child is now an + * operationnal session daemon ready to serve clients and applications. + */ + exit(EXIT_SUCCESS); + } + +end: + return 0; + +error: + return -1; +} + /* * main */ @@ -4477,6 +4782,10 @@ int main(int argc, char **argv) rcu_register_thread(); + if ((ret = set_signal_handler()) < 0) { + goto error; + } + setup_consumerd_path(); page_size = sysconf(_SC_PAGESIZE); @@ -4486,9 +4795,9 @@ int main(int argc, char **argv) WARN("Fallback page size to %ld", page_size); } - /* Parse arguments */ + /* Parse arguments and load the daemon configuration file */ progname = argv[0]; - if ((ret = parse_args(argc, argv)) < 0) { + if ((ret = set_options(argc, argv)) < 0) { goto error; } @@ -4496,20 +4805,15 @@ int main(int argc, char **argv) if (opt_daemon) { int i; - /* - * fork - * child: setsid, close FD 0, 1, 2, chdir / - * parent: exit (if fork is successful) - */ - ret = daemon(0, 0); + ret = daemonize(); if (ret < 0) { - PERROR("daemon"); goto error; } + /* - * We are in the child. Make sure all other file - * descriptors are closed, in case we are called with - * more opened file descriptors than the standard ones. + * We are in the child. Make sure all other file descriptors are + * closed, in case we are called with more opened file descriptors than + * the standard ones. */ for (i = 3; i < sysconf(_SC_OPEN_MAX); i++) { (void) close(i); @@ -4702,10 +5006,6 @@ int main(int argc, char **argv) goto exit; } - if ((ret = set_signal_handler()) < 0) { - goto exit; - } - /* Setup the needed unix socket */ if ((ret = init_daemon_socket()) < 0) { goto exit; @@ -4787,7 +5087,7 @@ int main(int argc, char **argv) goto exit_health_sessiond_cleanup; } - /* Create thread to manage the client socket */ + /* Create thread to clean up RCU hash tables */ ret = pthread_create(&ht_cleanup_thread, NULL, thread_ht_cleanup, (void *) NULL); if (ret != 0) { @@ -4795,7 +5095,7 @@ int main(int argc, char **argv) goto exit_ht_cleanup; } - /* Create thread to manage the client socket */ + /* Create health-check thread */ ret = pthread_create(&health_thread, NULL, thread_manage_health, (void *) NULL); if (ret != 0) {