X-Git-Url: http://git.efficios.com/?a=blobdiff_plain;f=src%2Fbin%2Flttng-relayd%2Fmain.c;h=f5bb9409f29d56bcd68fea31033baed1df3b2aa8;hb=0a9eff096ef480f16445be173badc90f5b6540d2;hp=43498017dd0b41cbbafe908dbb69e1287c57d066;hpb=44a2fbf116008c62184cc12f144fc69d29d7f606;p=lttng-tools.git diff --git a/src/bin/lttng-relayd/main.c b/src/bin/lttng-relayd/main.c index 43498017d..f5bb9409f 100644 --- a/src/bin/lttng-relayd/main.c +++ b/src/bin/lttng-relayd/main.c @@ -34,11 +34,13 @@ #include #include #include +#include #include #include #include #include #include +#include #include #include @@ -57,8 +59,10 @@ #include #include #include +#include #include +#include "version.h" #include "cmd.h" #include "ctf-trace.h" #include "index.h" @@ -83,8 +87,10 @@ enum relay_connection_status { }; /* command line options */ -char *opt_output_path; -static int opt_daemon, opt_background; +char *opt_output_path, *opt_working_directory; +static int opt_daemon, opt_background, opt_print_version; +int opt_group_output_by_session; +int opt_group_output_by_host; /* * We need to wait for listener and live listener threads, as well as @@ -145,6 +151,9 @@ static uint64_t last_relay_stream_id; */ static struct relay_conn_queue relay_conn_queue; +/* Cap of file desriptors to be in simultaneous use by the relay daemon. */ +static unsigned int lttng_opt_fd_cap; + /* Global relay stream hash table. */ struct lttng_ht *relay_streams_ht; @@ -157,6 +166,9 @@ struct lttng_ht *sessions_ht; /* Relayd health monitoring */ struct health_app *health_relayd; +/* Global fd tracker. */ +struct fd_tracker *the_fd_tracker; + static struct option long_options[] = { { "control-port", 1, 0, 'C', }, { "data-port", 1, 0, 'D', }, @@ -164,16 +176,37 @@ static struct option long_options[] = { { "daemonize", 0, 0, 'd', }, { "background", 0, 0, 'b', }, { "group", 1, 0, 'g', }, + { "fd-cap", 1, 0, '\0', }, { "help", 0, 0, 'h', }, { "output", 1, 0, 'o', }, { "verbose", 0, 0, 'v', }, { "config", 1, 0, 'f' }, { "version", 0, 0, 'V' }, + { "working-directory", 1, 0, 'w', }, + { "group-output-by-session", 0, 0, 's', }, + { "group-output-by-host", 0, 0, 'p', }, { NULL, 0, 0, 0, }, }; static const char *config_ignore_options[] = { "help", "config", "version" }; +static void print_version(void) { + fprintf(stdout, "%s\n", VERSION); +} + +static void relayd_config_log(void) +{ + DBG("LTTng-relayd " VERSION " - " VERSION_NAME "%s%s", + GIT_VERSION[0] == '\0' ? "" : " - " GIT_VERSION, + EXTRA_VERSION_NAME[0] == '\0' ? "" : " - " EXTRA_VERSION_NAME); + if (EXTRA_VERSION_DESCRIPTION[0] != '\0') { + DBG("LTTng-relayd extra version description:\n\t" EXTRA_VERSION_DESCRIPTION "\n"); + } + if (EXTRA_VERSION_PATCHES[0] != '\0') { + DBG("LTTng-relayd extra patches:\n\t" EXTRA_VERSION_PATCHES "\n"); + } +} + /* * Take an option from the getopt output and set it in the right variable to be * used later. @@ -186,9 +219,33 @@ static int set_option(int opt, const char *arg, const char *optname) switch (opt) { case 0: - fprintf(stderr, "option %s", optname); - if (arg) { - fprintf(stderr, " with arg %s\n", arg); + if (!strcmp(optname, "fd-cap")) { + unsigned long v; + + errno = 0; + v = strtoul(arg, NULL, 0); + if (errno != 0 || !isdigit(arg[0])) { + ERR("Wrong value in --fd-cap parameter: %s", arg); + ret = -1; + goto end; + } + if (v < DEFAULT_RELAYD_MINIMAL_FD_CAP) { + ERR("File descriptor cap must be set to at least %d", + DEFAULT_RELAYD_MINIMAL_FD_CAP); + } + if (v >= UINT_MAX) { + ERR("File descriptor cap overflow in --fd-cap parameter: %s", arg); + ret = -1; + goto end; + } + lttng_opt_fd_cap = (unsigned int) v; + DBG3("File descriptor cap set to %u", lttng_opt_fd_cap); + + } else { + fprintf(stderr, "unknown option %s", optname); + if (arg) { + fprintf(stderr, " with arg %s\n", arg); + } } break; case 'C': @@ -264,8 +321,8 @@ static int set_option(int opt, const char *arg, const char *optname) } exit(EXIT_FAILURE); case 'V': - fprintf(stdout, "%s\n", VERSION); - exit(EXIT_SUCCESS); + opt_print_version = 1; + break; case 'o': if (lttng_is_setuid_setgid()) { WARN("Getting '%s' argument from setuid/setgid binary refused for security reasons.", @@ -279,6 +336,20 @@ static int set_option(int opt, const char *arg, const char *optname) } } break; + case 'w': + if (lttng_is_setuid_setgid()) { + WARN("Getting '%s' argument from setuid/setgid binary refused for security reasons.", + "-w, --working-directory"); + } else { + ret = asprintf(&opt_working_directory, "%s", arg); + if (ret < 0) { + ret = -errno; + PERROR("asprintf working_directory"); + goto end; + } + } + break; + case 'v': /* Verbose level can increase using multiple -v */ if (arg) { @@ -290,6 +361,20 @@ static int set_option(int opt, const char *arg, const char *optname) } } break; + case 's': + if (opt_group_output_by_host) { + ERR("Cannot set --group-output-by-session, --group-output-by-host already defined"); + exit(EXIT_FAILURE); + } + opt_group_output_by_session = 1; + break; + case 'p': + if (opt_group_output_by_session) { + ERR("Cannot set --group-output-by-host, --group-output-by-session already defined"); + exit(EXIT_FAILURE); + } + opt_group_output_by_host = 1; + break; default: /* Unknown option or other error. * Error is printed by getopt, just return */ @@ -359,6 +444,16 @@ end: return ret; } +static void parse_env_options(void) +{ + char *value = NULL; + + value = lttng_secure_getenv(DEFAULT_LTTNG_RELAYD_WORKING_DIRECTORY_ENV); + if (value) { + opt_working_directory = value; + } +} + static int set_options(int argc, char **argv) { int c, ret = 0, option_index = 0, retval = 0; @@ -476,6 +571,23 @@ static int set_options(int argc, char **argv) goto exit; } } + if (lttng_opt_fd_cap == 0) { + int ret; + struct rlimit rlimit; + + ret = getrlimit(RLIMIT_NOFILE, &rlimit); + if (ret) { + PERROR("Failed to get file descriptor limit"); + retval = -1; + } + + lttng_opt_fd_cap = rlimit.rlim_cur; + } + + if (!opt_group_output_by_session && !opt_group_output_by_host) { + /* Group by host by default */ + opt_group_output_by_host = 1; + } exit: free(optstring); @@ -484,13 +596,9 @@ exit: static void print_global_objects(void) { - rcu_register_thread(); - print_viewer_streams(); print_relay_streams(); print_sessions(); - - rcu_unregister_thread(); } /* @@ -513,7 +621,7 @@ static void relayd_cleanup(void) free(opt_output_path); /* Close thread quit pipes */ - utils_close_pipe(thread_quit_pipe); + (void) fd_tracker_util_pipe_close(the_fd_tracker, thread_quit_pipe); uri_free(control_uri); uri_free(data_uri); @@ -522,6 +630,7 @@ static void relayd_cleanup(void) if (tracing_group_name_override) { free((void *) tracing_group_name); } + fd_tracker_log(the_fd_tracker); } /* @@ -675,17 +784,26 @@ void lttng_relay_notify_ready(void) */ static int init_thread_quit_pipe(void) { - int ret; - - ret = utils_create_pipe_cloexec(thread_quit_pipe); + return fd_tracker_util_pipe_open_cloexec(the_fd_tracker, + "Quit pipe", thread_quit_pipe); +} - return ret; +/* + * Init health quit pipe. + * + * Return -1 on error or 0 if all pipes are created. + */ +static int init_health_quit_pipe(void) +{ + return fd_tracker_util_pipe_open_cloexec(the_fd_tracker, + "Health quit pipe", health_quit_pipe); } /* * Create a poll set with O_CLOEXEC and add the thread quit pipe to the set. */ -static int create_thread_poll_set(struct lttng_poll_event *events, int size) +static int create_named_thread_poll_set(struct lttng_poll_event *events, + int size, const char *name) { int ret; @@ -694,10 +812,8 @@ static int create_thread_poll_set(struct lttng_poll_event *events, int size) goto error; } - ret = lttng_poll_create(events, size, LTTNG_CLOEXEC); - if (ret < 0) { - goto error; - } + ret = fd_tracker_util_poll_create(the_fd_tracker, + name, events, 1, LTTNG_CLOEXEC); /* Add quit pipe */ ret = lttng_poll_add(events, thread_quit_pipe[0], LPOLLIN | LPOLLERR); @@ -795,7 +911,7 @@ static void *relay_thread_listener(void *data) * Pass 3 as size here for the thread quit pipe, control and * data socket. */ - ret = create_thread_poll_set(&events, 3); + ret = create_named_thread_poll_set(&events, 3, "Listener thread epoll"); if (ret < 0) { goto error_create_poll; } @@ -937,7 +1053,7 @@ exit: error: error_poll_add: error_testpoint: - lttng_poll_clean(&events); + (void) fd_tracker_util_poll_clean(the_fd_tracker, &events); error_create_poll: if (data_sock->fd >= 0) { ret = data_sock->ops->close(data_sock); @@ -1194,12 +1310,13 @@ static int relay_add_stream(const struct lttcomm_relayd_hdr *recv_hdr, switch (session->minor) { case 1: /* LTTng sessiond 2.1. Allocates path_name and channel_name. */ ret = cmd_recv_stream_2_1(payload, &path_name, - &channel_name); + &channel_name, session); break; case 2: /* LTTng sessiond 2.2. Allocates path_name and channel_name. */ default: ret = cmd_recv_stream_2_2(payload, &path_name, - &channel_name, &tracefile_size, &tracefile_count); + &channel_name, &tracefile_size, &tracefile_count, + session); break; } if (ret < 0) { @@ -2827,7 +2944,7 @@ static void *relay_thread_worker(void *data) goto relay_connections_ht_error; } - ret = create_thread_poll_set(&events, 2); + ret = create_named_thread_poll_set(&events, 2, "Worker thread epoll"); if (ret < 0) { goto error_poll_create; } @@ -3099,12 +3216,13 @@ error: } rcu_read_unlock(); - lttng_poll_clean(&events); + (void) fd_tracker_util_poll_clean(the_fd_tracker, &events); error_poll_create: lttng_ht_destroy(relay_connections_ht); relay_connections_ht_error: /* Close relay conn pipes */ - utils_close_pipe(relay_conn_pipe); + (void) fd_tracker_util_pipe_close(the_fd_tracker, + relay_conn_pipe); if (err) { DBG("Thread exited with error"); } @@ -3126,11 +3244,8 @@ error_testpoint: */ static int create_relay_conn_pipe(void) { - int ret; - - ret = utils_create_pipe_cloexec(relay_conn_pipe); - - return ret; + return fd_tracker_util_pipe_open_cloexec(the_fd_tracker, + "Relayd connection pipe", relay_conn_pipe); } /* @@ -3141,7 +3256,13 @@ int main(int argc, char **argv) int ret = 0, retval = 0; void *status; - /* Parse arguments */ + /* Parse environment variables */ + parse_env_options(); + + /* + * Parse arguments. + * Command line arguments overwrite environment. + */ progname = argv[0]; if (set_options(argc, argv)) { retval = -1; @@ -3153,6 +3274,19 @@ int main(int argc, char **argv) goto exit_options; } + relayd_config_log(); + + if (opt_print_version) { + print_version(); + retval = 0; + goto exit_options; + } + + ret = fclose(stdin); + if (ret) { + PERROR("Failed to close stdin"); + goto exit_options; + } /* Try to create directory if -o, --output is specified. */ if (opt_output_path) { if (*opt_output_path != '/') { @@ -3172,24 +3306,34 @@ int main(int argc, char **argv) /* Daemonize */ if (opt_daemon || opt_background) { - int i; - ret = lttng_daemonize(&child_ppid, &recv_child_signal, !opt_background); if (ret < 0) { retval = -1; goto exit_options; } + } - /* - * 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); + if (opt_working_directory) { + ret = utils_change_working_dir(opt_working_directory); + if (ret) { + ERR("Changing working directory"); + goto exit_options; } } + /* + * The RCU thread registration (and use, through the fd-tracker's + * creation) is done after the daemonization to allow us to not + * deal with liburcu's fork() management as the call RCU needs to + * be restored. + */ + rcu_register_thread(); + + the_fd_tracker = fd_tracker_create(lttng_opt_fd_cap); + if (!the_fd_tracker) { + retval = -1; + goto exit_options; + } /* Initialize thread health monitoring */ health_relayd = health_app_create(NR_HEALTH_RELAYD_TYPES); @@ -3239,7 +3383,7 @@ int main(int argc, char **argv) goto exit_init_data; } - ret = utils_create_pipe(health_quit_pipe); + ret = init_health_quit_pipe(); if (ret) { retval = -1; goto exit_health_quit_pipe; @@ -3335,7 +3479,7 @@ exit_dispatcher_thread: } exit_health_thread: - utils_close_pipe(health_quit_pipe); + (void) fd_tracker_util_pipe_close(the_fd_tracker, health_quit_pipe); exit_health_quit_pipe: exit_init_data: @@ -3353,6 +3497,9 @@ exit_options: /* Ensure all prior call_rcu are done. */ rcu_barrier(); + fd_tracker_destroy(the_fd_tracker); + rcu_unregister_thread(); + if (!retval) { exit(EXIT_SUCCESS); } else {