X-Git-Url: http://git.efficios.com/?a=blobdiff_plain;f=src%2Fbin%2Flttng-sessiond%2Fmain.c;h=7b2dd4cf3bfcbdd56873ce490f37d206e0be8386;hb=3ec36153b78b90b299a36003b61da074513a3e8e;hp=97677dd59e9a9a2bef55c693760b421b6b4b9b71;hpb=825535cc5864e9e7491e55cd203a643ced266658;p=lttng-tools.git diff --git a/src/bin/lttng-sessiond/main.c b/src/bin/lttng-sessiond/main.c index 97677dd59..7b2dd4cf3 100644 --- a/src/bin/lttng-sessiond/main.c +++ b/src/bin/lttng-sessiond/main.c @@ -37,6 +37,7 @@ #include #include #include +#include #include #include @@ -48,6 +49,7 @@ #include #include #include +#include #include "lttng-sessiond.h" #include "buffer-registry.h" @@ -72,6 +74,7 @@ #include "load-session-thread.h" #include "syscall.h" #include "agent.h" +#include "ht-cleanup.h" #define CONSUMERD_FILE "lttng-consumerd" @@ -88,6 +91,7 @@ static pid_t ppid; /* Parent PID for --sig-parent option */ static pid_t child_ppid; /* Internal parent PID use with daemonize. */ static char *rundir; static int lockfile_fd = -1; +static int opt_print_version; /* Set to 1 when a SIGUSR1 signal is received. */ static int recv_child_signal; @@ -189,7 +193,6 @@ static int kernel_poll_pipe[2] = { -1, -1 }; * for all threads when receiving an event on the pipe. */ static int thread_quit_pipe[2] = { -1, -1 }; -static int ht_cleanup_quit_pipe[2] = { -1, -1 }; /* * This pipe is used to inform the thread managing application communication @@ -312,9 +315,14 @@ struct lttng_ht *agent_apps_ht_by_sock = NULL; * NR_LTTNG_SESSIOND_READY must match the number of calls to * sessiond_notify_ready(). */ -#define NR_LTTNG_SESSIOND_READY 3 +#define NR_LTTNG_SESSIOND_READY 4 int lttng_sessiond_ready = NR_LTTNG_SESSIOND_READY; +int sessiond_check_thread_quit_pipe(int fd, uint32_t events) +{ + return (fd == thread_quit_pipe[0] && (events & LPOLLIN)) ? 1 : 0; +} + /* Notify parents that we are ready for cmd and health check */ LTTNG_HIDDEN void sessiond_notify_ready(void) @@ -421,47 +429,6 @@ int sessiond_set_thread_pollset(struct lttng_poll_event *events, size_t size) return __sessiond_set_thread_pollset(events, size, thread_quit_pipe); } -/* - * Create a poll set with O_CLOEXEC and add the thread quit pipe to the set. - */ -int sessiond_set_ht_cleanup_thread_pollset(struct lttng_poll_event *events, - size_t size) -{ - return __sessiond_set_thread_pollset(events, size, - ht_cleanup_quit_pipe); -} - -static -int __sessiond_check_thread_quit_pipe(int fd, uint32_t events, int a_pipe) -{ - if (fd == a_pipe && (events & LPOLLIN)) { - return 1; - } - return 0; -} - -/* - * Check if the thread quit pipe was triggered. - * - * Return 1 if it was triggered else 0; - */ -int sessiond_check_thread_quit_pipe(int fd, uint32_t events) -{ - return __sessiond_check_thread_quit_pipe(fd, events, - thread_quit_pipe[0]); -} - -/* - * Check if the ht_cleanup thread quit pipe was triggered. - * - * Return 1 if it was triggered else 0; - */ -int sessiond_check_ht_cleanup_quit(int fd, uint32_t events) -{ - return __sessiond_check_thread_quit_pipe(fd, events, - ht_cleanup_quit_pipe[0]); -} - /* * Init thread quit pipe. * @@ -494,11 +461,6 @@ static int init_thread_quit_pipe(void) return __init_thread_quit_pipe(thread_quit_pipe); } -static int init_ht_cleanup_quit_pipe(void) -{ - return __init_thread_quit_pipe(ht_cleanup_quit_pipe); -} - /* * Stop all threads by closing the thread quit pipe. */ @@ -604,8 +566,7 @@ static void wait_consumer(struct consumer_data *consumer_data) ret = waitpid(consumer_data->pid, &status, 0); if (ret == -1) { PERROR("consumerd waitpid pid: %d", consumer_data->pid) - } - if (!WIFEXITED(status)) { + } else if (!WIFEXITED(status)) { ERR("consumerd termination with error: %d", WEXITSTATUS(ret)); } @@ -800,12 +761,6 @@ static void sessiond_cleanup_options(void) free(kmod_extra_probes_list); run_as_destroy_worker(); - - /* */ - DBG("%c[%d;%dm*** assert failed :-) *** ==> %c[%dm%c[%d;%dm" - "Matthew, BEET driven development works!%c[%dm", - 27, 1, 31, 27, 0, 27, 1, 33, 27, 0); - /* */ } /* @@ -1397,7 +1352,6 @@ restart: consumer_data->metadata_sock.lock = zmalloc(sizeof(pthread_mutex_t)); if (consumer_data->metadata_sock.lock == NULL) { PERROR("zmalloc pthread mutex"); - ret = -1; goto error; } pthread_mutex_init(consumer_data->metadata_sock.lock, NULL); @@ -1902,6 +1856,8 @@ static void *thread_dispatch_ust_registration(void *data) .count = 0, }; + rcu_register_thread(); + health_register(health_sessiond, HEALTH_SESSIOND_TYPE_APP_REG_DISPATCH); if (testpoint(sessiond_thread_app_reg_dispatch)) { @@ -1914,12 +1870,16 @@ static void *thread_dispatch_ust_registration(void *data) DBG("[thread] Dispatch UST command started"); - while (!CMM_LOAD_SHARED(dispatch_thread_exit)) { + for (;;) { health_code_update(); /* Atomically prepare the queue futex */ futex_nto1_prepare(&ust_cmd_queue.futex); + if (CMM_LOAD_SHARED(dispatch_thread_exit)) { + break; + } + do { struct ust_app *app = NULL; ust_cmd = NULL; @@ -2135,6 +2095,7 @@ error_testpoint: ERR("Health error occurred in %s", __func__); } health_unregister(health_sessiond); + rcu_unregister_thread(); return NULL; } @@ -2242,10 +2203,12 @@ static void *thread_registration_apps(void *data) * lttcomm_setsockopt_snd_timeout expect msec as * parameter. */ - (void) lttcomm_setsockopt_rcv_timeout(sock, - app_socket_timeout * 1000); - (void) lttcomm_setsockopt_snd_timeout(sock, - app_socket_timeout * 1000); + if (app_socket_timeout >= 0) { + (void) lttcomm_setsockopt_rcv_timeout(sock, + app_socket_timeout * 1000); + (void) lttcomm_setsockopt_snd_timeout(sock, + app_socket_timeout * 1000); + } /* * Set the CLOEXEC flag. Return code is useless because @@ -2371,7 +2334,12 @@ static int spawn_consumer_thread(struct consumer_data *consumer_data) int ret, clock_ret; struct timespec timeout; - /* Make sure we set the readiness flag to 0 because we are NOT ready */ + /* + * Make sure we set the readiness flag to 0 because we are NOT ready. + * This access to consumer_thread_is_ready does not need to be + * protected by consumer_data.cond_mutex (yet) since the consumer + * management thread has not been started at this point. + */ consumer_data->consumer_thread_is_ready = 0; /* Setup pthread condition */ @@ -2401,8 +2369,8 @@ static int spawn_consumer_thread(struct consumer_data *consumer_data) goto error; } - ret = pthread_create(&consumer_data->thread, NULL, thread_manage_consumer, - consumer_data); + ret = pthread_create(&consumer_data->thread, default_pthread_attr(), + thread_manage_consumer, consumer_data); if (ret) { errno = ret; PERROR("pthread_create consumer"); @@ -2414,7 +2382,7 @@ static int spawn_consumer_thread(struct consumer_data *consumer_data) pthread_mutex_lock(&consumer_data->cond_mutex); /* Get time for sem_timedwait absolute timeout */ - clock_ret = clock_gettime(CLOCK_MONOTONIC, &timeout); + clock_ret = lttng_clock_gettime(CLOCK_MONOTONIC, &timeout); /* * Set the timeout for the condition timed wait even if the clock gettime * call fails since we might loop on that call and we want to avoid to @@ -2560,7 +2528,7 @@ static pid_t spawn_consumerd(struct consumer_data *consumer_data) } else { DBG("Could not find any valid consumerd executable"); ret = -EINVAL; - break; + goto error; } DBG("Using kernel consumer at: %s", consumer_to_use); ret = execl(consumer_to_use, @@ -2657,7 +2625,7 @@ static pid_t spawn_consumerd(struct consumer_data *consumer_data) break; } default: - PERROR("unknown consumer type"); + ERR("unknown consumer type"); exit(EXIT_FAILURE); } if (errno != 0) { @@ -2750,7 +2718,6 @@ static int init_kernel_tracer(void) kernel_tracer_fd = open(module_proc_lttng, O_RDWR); if (kernel_tracer_fd < 0) { DBG("Failed to open %s", module_proc_lttng); - ret = -1; goto error_open; } @@ -3039,7 +3006,8 @@ static int process_client_msg(struct command_ctx *cmd_ctx, int sock, case LTTNG_SNAPSHOT_RECORD: case LTTNG_SAVE_SESSION: case LTTNG_SET_SESSION_SHM_PATH: - case LTTNG_METADATA_REGENERATE: + case LTTNG_REGENERATE_METADATA: + case LTTNG_REGENERATE_STATEDUMP: need_domain = 0; break; default: @@ -3080,7 +3048,8 @@ static int process_client_msg(struct command_ctx *cmd_ctx, int sock, case LTTNG_LIST_CHANNELS: case LTTNG_LIST_EVENTS: case LTTNG_LIST_SYSCALLS: - case LTTNG_LIST_TRACKER_PIDS: + case LTTNG_LIST_TRACKER_IDS: + case LTTNG_DATA_PENDING: break; default: /* Setup lttng message with no payload */ @@ -3096,7 +3065,6 @@ static int process_client_msg(struct command_ctx *cmd_ctx, int sock, case LTTNG_CREATE_SESSION: case LTTNG_CREATE_SESSION_SNAPSHOT: case LTTNG_CREATE_SESSION_LIVE: - case LTTNG_CALIBRATE: case LTTNG_LIST_SESSIONS: case LTTNG_LIST_TRACEPOINTS: case LTTNG_LIST_SYSCALLS: @@ -3317,6 +3285,8 @@ skip_domain: if (cmd_ctx->lsm->cmd_type == LTTNG_START_TRACE || cmd_ctx->lsm->cmd_type == LTTNG_STOP_TRACE) { switch (cmd_ctx->lsm->domain.type) { + case LTTNG_DOMAIN_NONE: + break; case LTTNG_DOMAIN_JUL: case LTTNG_DOMAIN_LOG4J: case LTTNG_DOMAIN_PYTHON: @@ -3487,18 +3457,102 @@ error_add_context: &cmd_ctx->lsm->u.channel.chan, kernel_poll_pipe[1]); break; } - case LTTNG_TRACK_PID: + case LTTNG_TRACK_ID: { - ret = cmd_track_pid(cmd_ctx->session, + struct lttng_tracker_id id; + + memset(&id, 0, sizeof(id)); + id.type = cmd_ctx->lsm->u.id_tracker.id_type; + switch (id.type) { + case LTTNG_ID_ALL: + break; + case LTTNG_ID_VALUE: + id.value = cmd_ctx->lsm->u.id_tracker.u.value; + break; + case LTTNG_ID_STRING: + { + size_t var_len = cmd_ctx->lsm->u.id_tracker.u.var_len; + + id.string = zmalloc(var_len); + if (!id.string) { + ret = LTTNG_ERR_NOMEM; + goto error; + } + DBG("Receiving var len tracker id string from client."); + ret = lttcomm_recv_unix_sock(sock, id.string, var_len); + if (ret <= 0) { + DBG("Nothing received."); + *sock_error = 1; + free(id.string); + ret = LTTNG_ERR_INVALID; + goto error; + } + if (strnlen(id.string, var_len) != var_len - 1) { + DBG("Corrupted string."); + free(id.string); + ret = LTTNG_ERR_INVALID; + goto error; + } + break; + } + default: + ret = LTTNG_ERR_INVALID; + goto error; + } + ret = cmd_track_id(cmd_ctx->session, + cmd_ctx->lsm->u.id_tracker.tracker_type, cmd_ctx->lsm->domain.type, - cmd_ctx->lsm->u.pid_tracker.pid); + &id); + free(id.string); break; } - case LTTNG_UNTRACK_PID: + case LTTNG_UNTRACK_ID: { - ret = cmd_untrack_pid(cmd_ctx->session, + struct lttng_tracker_id id; + + memset(&id, 0, sizeof(id)); + id.type = cmd_ctx->lsm->u.id_tracker.id_type; + switch (id.type) { + case LTTNG_ID_ALL: + break; + case LTTNG_ID_VALUE: + id.value = cmd_ctx->lsm->u.id_tracker.u.value; + break; + case LTTNG_ID_STRING: + { + size_t var_len = cmd_ctx->lsm->u.id_tracker.u.var_len; + + id.string = zmalloc(var_len); + if (!id.string) { + ret = LTTNG_ERR_NOMEM; + goto error; + } + DBG("Receiving var len tracker id string from client."); + ret = lttcomm_recv_unix_sock(sock, id.string, var_len); + if (ret <= 0) { + DBG("Nothing received."); + *sock_error = 1; + free(id.string); + ret = LTTNG_ERR_INVALID; + goto error; + } + if (strnlen(id.string, var_len) != var_len - 1) { + DBG("Corrupted string."); + free(id.string); + ret = LTTNG_ERR_INVALID; + goto error; + } + break; + } + default: + ret = LTTNG_ERR_INVALID; + goto error; + } + ret = cmd_untrack_id(cmd_ctx->session, + cmd_ctx->lsm->u.id_tracker.tracker_type, cmd_ctx->lsm->domain.type, - cmd_ctx->lsm->u.pid_tracker.pid); + &id); + free(id.string); break; } case LTTNG_ENABLE_EVENT: @@ -3697,27 +3751,61 @@ error_add_context: ret = LTTNG_OK; break; } - case LTTNG_LIST_TRACKER_PIDS: + case LTTNG_LIST_TRACKER_IDS: { - int32_t *pids = NULL; - ssize_t nr_pids; - - nr_pids = cmd_list_tracker_pids(cmd_ctx->session, - cmd_ctx->lsm->domain.type, &pids); - if (nr_pids < 0) { + struct lttcomm_tracker_command_header cmd_header; + struct lttng_tracker_id *ids = NULL; + ssize_t nr_ids, i; + struct lttng_dynamic_buffer buf; + + nr_ids = cmd_list_tracker_ids(cmd_ctx->lsm->u.id_tracker.tracker_type, + cmd_ctx->session, + cmd_ctx->lsm->domain.type, &ids); + if (nr_ids < 0) { /* Return value is a negative lttng_error_code. */ - ret = -nr_pids; + ret = -nr_ids; goto error; } - /* - * Setup lttng message with payload size set to the event list size in - * bytes and then copy list into the llm payload. - */ - ret = setup_lttng_msg_no_cmd_header(cmd_ctx, pids, - sizeof(int32_t) * nr_pids); - free(pids); + lttng_dynamic_buffer_init(&buf); + for (i = 0; i < nr_ids; i++) { + struct lttng_tracker_id *id = &ids[i]; + struct lttcomm_tracker_id_header id_hdr; + size_t var_data_len = 0; + + memset(&id_hdr, 0, sizeof(id_hdr)); + id_hdr.type = id->type; + switch (id->type) { + case LTTNG_ID_ALL: + break; + case LTTNG_ID_VALUE: + id_hdr.u.value = id->value; + break; + case LTTNG_ID_STRING: + id_hdr.u.var_data_len = var_data_len = strlen(id->string) + 1; + break; + default: + ret = LTTNG_ERR_INVALID; + goto error; + } + ret = lttng_dynamic_buffer_append(&buf, &id_hdr, sizeof(id_hdr)); + if (ret) { + ret = LTTNG_ERR_NOMEM; + goto error; + } + ret = lttng_dynamic_buffer_append(&buf, id->string, var_data_len); + if (ret) { + ret = LTTNG_ERR_NOMEM; + goto error; + } + free(id->string); + } + cmd_header.nb_tracker_id = nr_ids; + ret = setup_lttng_msg(cmd_ctx, buf.data, buf.size, &cmd_header, + sizeof(cmd_header)); + free(ids); + lttng_dynamic_buffer_reset(&buf); if (ret < 0) { goto setup_error; } @@ -3936,12 +4024,6 @@ error_add_context: ret = LTTNG_OK; break; } - case LTTNG_CALIBRATE: - { - ret = cmd_calibrate(cmd_ctx->lsm->domain.type, - &cmd_ctx->lsm->u.calibrate); - break; - } case LTTNG_REGISTER_CONSUMER: { struct consumer_data *cdata; @@ -4147,9 +4229,14 @@ error_add_context: cmd_ctx->lsm->u.set_shm_path.shm_path); break; } - case LTTNG_METADATA_REGENERATE: + case LTTNG_REGENERATE_METADATA: { - ret = cmd_metadata_regenerate(cmd_ctx->session); + ret = cmd_regenerate_metadata(cmd_ctx->session); + break; + } + case LTTNG_REGENERATE_STATEDUMP: + { + ret = cmd_regenerate_statedump(cmd_ctx->session); break; } default: @@ -4200,7 +4287,6 @@ static void *thread_manage_health(void *data) sock = lttcomm_create_unix_sock(health_unix_sock_path); if (sock < 0) { ERR("Unable to create health check Unix socket"); - ret = -1; goto error; } @@ -4211,7 +4297,6 @@ static void *thread_manage_health(void *data) if (ret < 0) { ERR("Unable to set group on %s", health_unix_sock_path); PERROR("chown"); - ret = -1; goto error; } @@ -4220,7 +4305,6 @@ static void *thread_manage_health(void *data) if (ret < 0) { ERR("Unable to set permissions on %s", health_unix_sock_path); PERROR("chmod"); - ret = -1; goto error; } } @@ -4321,7 +4405,6 @@ restart: if (ret) { PERROR("close"); } - new_sock = -1; continue; } @@ -4350,7 +4433,6 @@ restart: if (ret) { PERROR("close"); } - new_sock = -1; } exit: @@ -4368,7 +4450,7 @@ error: } lttng_poll_clean(&events); - + stop_threads(); rcu_unregister_thread(); return NULL; } @@ -4414,12 +4496,41 @@ static void *thread_manage_clients(void *data) } sessiond_notify_ready(); + ret = sem_post(&load_info->message_thread_ready); if (ret) { PERROR("sem_post message_thread_ready"); goto error; } + /* + * Wait until all support threads are initialized before accepting + * commands. + */ + while (uatomic_read(<tng_sessiond_ready) != 0) { + fd_set read_fds; + struct timeval timeout; + + FD_ZERO(&read_fds); + FD_SET(thread_quit_pipe[0], &read_fds); + memset(&timeout, 0, sizeof(timeout)); + timeout.tv_usec = 1000; + + /* + * If a support thread failed to launch, it may signal that + * we must exit and the sessiond would never be marked as + * "ready". + * + * The timeout is set to 1ms, which serves as a way to + * pace down this check. + */ + ret = select(thread_quit_pipe[0] + 1, &read_fds, NULL, NULL, + &timeout); + if (ret > 0 || (ret < 0 && errno != EINTR)) { + goto exit; + } + } + /* This testpoint is after we signal readiness to the parent. */ if (testpoint(sessiond_thread_manage_clients)) { goto error; @@ -4669,18 +4780,11 @@ static int set_option(int opt, const char *arg, const char *optname) { int ret = 0; - if (arg && arg[0] == '\0') { - /* - * This only happens if the value is read from daemon config - * file. This means the option requires an argument and the - * configuration file contains a line such as: - * my_option = - */ - ret = -EINVAL; - goto end; - } - if (string_match(optname, "client-sock") || opt == 'c') { + if (!arg || *arg == '\0') { + ret = -EINVAL; + goto end; + } if (lttng_is_setuid_setgid()) { WARN("Getting '%s' argument from setuid/setgid binary refused for security reasons.", "-c, --client-sock"); @@ -4688,6 +4792,10 @@ static int set_option(int opt, const char *arg, const char *optname) snprintf(client_unix_sock_path, PATH_MAX, "%s", arg); } } else if (string_match(optname, "apps-sock") || opt == 'a') { + if (!arg || *arg == '\0') { + ret = -EINVAL; + goto end; + } if (lttng_is_setuid_setgid()) { WARN("Getting '%s' argument from setuid/setgid binary refused for security reasons.", "-a, --apps-sock"); @@ -4699,6 +4807,10 @@ static int set_option(int opt, const char *arg, const char *optname) } else if (string_match(optname, "background") || opt == 'b') { opt_background = 1; } else if (string_match(optname, "group") || opt == 'g') { + if (!arg || *arg == '\0') { + ret = -EINVAL; + goto end; + } if (lttng_is_setuid_setgid()) { WARN("Getting '%s' argument from setuid/setgid binary refused for security reasons.", "-g, --group"); @@ -4726,11 +4838,14 @@ static int set_option(int opt, const char *arg, const char *optname) } exit(ret ? EXIT_FAILURE : EXIT_SUCCESS); } else if (string_match(optname, "version") || opt == 'V') { - fprintf(stdout, "%s\n", VERSION); - exit(EXIT_SUCCESS); + opt_print_version = 1; } else if (string_match(optname, "sig-parent") || opt == 'S') { opt_sig_parent = 1; } else if (string_match(optname, "kconsumerd-err-sock")) { + if (!arg || *arg == '\0') { + ret = -EINVAL; + goto end; + } if (lttng_is_setuid_setgid()) { WARN("Getting '%s' argument from setuid/setgid binary refused for security reasons.", "--kconsumerd-err-sock"); @@ -4738,6 +4853,10 @@ static int set_option(int opt, const char *arg, const char *optname) snprintf(kconsumer_data.err_unix_sock_path, PATH_MAX, "%s", arg); } } else if (string_match(optname, "kconsumerd-cmd-sock")) { + if (!arg || *arg == '\0') { + ret = -EINVAL; + goto end; + } if (lttng_is_setuid_setgid()) { WARN("Getting '%s' argument from setuid/setgid binary refused for security reasons.", "--kconsumerd-cmd-sock"); @@ -4745,6 +4864,10 @@ static int set_option(int opt, const char *arg, const char *optname) snprintf(kconsumer_data.cmd_unix_sock_path, PATH_MAX, "%s", arg); } } else if (string_match(optname, "ustconsumerd64-err-sock")) { + if (!arg || *arg == '\0') { + ret = -EINVAL; + goto end; + } if (lttng_is_setuid_setgid()) { WARN("Getting '%s' argument from setuid/setgid binary refused for security reasons.", "--ustconsumerd64-err-sock"); @@ -4752,6 +4875,10 @@ static int set_option(int opt, const char *arg, const char *optname) snprintf(ustconsumer64_data.err_unix_sock_path, PATH_MAX, "%s", arg); } } else if (string_match(optname, "ustconsumerd64-cmd-sock")) { + if (!arg || *arg == '\0') { + ret = -EINVAL; + goto end; + } if (lttng_is_setuid_setgid()) { WARN("Getting '%s' argument from setuid/setgid binary refused for security reasons.", "--ustconsumerd64-cmd-sock"); @@ -4759,6 +4886,10 @@ static int set_option(int opt, const char *arg, const char *optname) snprintf(ustconsumer64_data.cmd_unix_sock_path, PATH_MAX, "%s", arg); } } else if (string_match(optname, "ustconsumerd32-err-sock")) { + if (!arg || *arg == '\0') { + ret = -EINVAL; + goto end; + } if (lttng_is_setuid_setgid()) { WARN("Getting '%s' argument from setuid/setgid binary refused for security reasons.", "--ustconsumerd32-err-sock"); @@ -4766,6 +4897,10 @@ static int set_option(int opt, const char *arg, const char *optname) snprintf(ustconsumer32_data.err_unix_sock_path, PATH_MAX, "%s", arg); } } else if (string_match(optname, "ustconsumerd32-cmd-sock")) { + if (!arg || *arg == '\0') { + ret = -EINVAL; + goto end; + } if (lttng_is_setuid_setgid()) { WARN("Getting '%s' argument from setuid/setgid binary refused for security reasons.", "--ustconsumerd32-cmd-sock"); @@ -4792,9 +4927,13 @@ static int set_option(int opt, const char *arg, const char *optname) if (arg) { opt_verbose_consumer = config_parse_value(arg); } else { - opt_verbose_consumer += 1; + opt_verbose_consumer++; } } else if (string_match(optname, "consumerd32-path")) { + if (!arg || *arg == '\0') { + ret = -EINVAL; + goto end; + } if (lttng_is_setuid_setgid()) { WARN("Getting '%s' argument from setuid/setgid binary refused for security reasons.", "--consumerd32-path"); @@ -4810,6 +4949,10 @@ static int set_option(int opt, const char *arg, const char *optname) consumerd32_bin_override = 1; } } else if (string_match(optname, "consumerd32-libdir")) { + if (!arg || *arg == '\0') { + ret = -EINVAL; + goto end; + } if (lttng_is_setuid_setgid()) { WARN("Getting '%s' argument from setuid/setgid binary refused for security reasons.", "--consumerd32-libdir"); @@ -4825,6 +4968,10 @@ static int set_option(int opt, const char *arg, const char *optname) consumerd32_libdir_override = 1; } } else if (string_match(optname, "consumerd64-path")) { + if (!arg || *arg == '\0') { + ret = -EINVAL; + goto end; + } if (lttng_is_setuid_setgid()) { WARN("Getting '%s' argument from setuid/setgid binary refused for security reasons.", "--consumerd64-path"); @@ -4840,6 +4987,10 @@ static int set_option(int opt, const char *arg, const char *optname) consumerd64_bin_override = 1; } } else if (string_match(optname, "consumerd64-libdir")) { + if (!arg || *arg == '\0') { + ret = -EINVAL; + goto end; + } if (lttng_is_setuid_setgid()) { WARN("Getting '%s' argument from setuid/setgid binary refused for security reasons.", "--consumerd64-libdir"); @@ -4855,6 +5006,10 @@ static int set_option(int opt, const char *arg, const char *optname) consumerd64_libdir_override = 1; } } else if (string_match(optname, "pidfile") || opt == 'p') { + if (!arg || *arg == '\0') { + ret = -EINVAL; + goto end; + } if (lttng_is_setuid_setgid()) { WARN("Getting '%s' argument from setuid/setgid binary refused for security reasons.", "-p, --pidfile"); @@ -4867,16 +5022,16 @@ static int set_option(int opt, const char *arg, const char *optname) } } } else if (string_match(optname, "agent-tcp-port")) { + if (!arg || *arg == '\0') { + ret = -EINVAL; + goto end; + } if (lttng_is_setuid_setgid()) { WARN("Getting '%s' argument from setuid/setgid binary refused for security reasons.", "--agent-tcp-port"); } else { unsigned long v; - if (!arg) { - ret = -EINVAL; - goto end; - } errno = 0; v = strtoul(arg, NULL, 0); if (errno != 0 || !isdigit(arg[0])) { @@ -4891,6 +5046,10 @@ static int set_option(int opt, const char *arg, const char *optname) DBG3("Agent TCP port set to non default: %u", agent_tcp_port); } } else if (string_match(optname, "load") || opt == 'l') { + if (!arg || *arg == '\0') { + ret = -EINVAL; + goto end; + } if (lttng_is_setuid_setgid()) { WARN("Getting '%s' argument from setuid/setgid binary refused for security reasons.", "-l, --load"); @@ -4903,6 +5062,10 @@ static int set_option(int opt, const char *arg, const char *optname) } } } else if (string_match(optname, "kmod-probes")) { + if (!arg || *arg == '\0') { + ret = -EINVAL; + goto end; + } if (lttng_is_setuid_setgid()) { WARN("Getting '%s' argument from setuid/setgid binary refused for security reasons.", "--kmod-probes"); @@ -4915,6 +5078,10 @@ static int set_option(int opt, const char *arg, const char *optname) } } } else if (string_match(optname, "extra-kmod-probes")) { + if (!arg || *arg == '\0') { + ret = -EINVAL; + goto end; + } if (lttng_is_setuid_setgid()) { WARN("Getting '%s' argument from setuid/setgid binary refused for security reasons.", "--extra-kmod-probes"); @@ -5011,6 +5178,23 @@ end: return ret; } +static void sessiond_config_log(void) +{ + DBG("LTTng-sessiond " 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-sessiond extra version description:\n\t" EXTRA_VERSION_DESCRIPTION "\n"); + } + if (EXTRA_VERSION_PATCHES[0] != '\0') { + DBG("LTTng-sessiond extra patches:\n\t" EXTRA_VERSION_PATCHES "\n"); + } +} + +static void print_version(void) { + fprintf(stdout, "%s\n", VERSION); +} + /* * daemon configuration loading and argument parsing */ @@ -5349,9 +5533,6 @@ error: static void sighandler(int sig) { switch (sig) { - case SIGPIPE: - DBG("SIGPIPE caught"); - return; case SIGINT: DBG("SIGINT caught"); stop_threads(); @@ -5383,9 +5564,10 @@ static int set_signal_handler(void) return ret; } - sa.sa_handler = sighandler; sa.sa_mask = sigset; sa.sa_flags = 0; + + sa.sa_handler = sighandler; if ((ret = sigaction(SIGTERM, &sa, NULL)) < 0) { PERROR("sigaction"); return ret; @@ -5396,12 +5578,13 @@ static int set_signal_handler(void) return ret; } - if ((ret = sigaction(SIGPIPE, &sa, NULL)) < 0) { + if ((ret = sigaction(SIGUSR1, &sa, NULL)) < 0) { PERROR("sigaction"); return ret; } - if ((ret = sigaction(SIGUSR1, &sa, NULL)) < 0) { + sa.sa_handler = SIG_IGN; + if ((ret = sigaction(SIGPIPE, &sa, NULL)) < 0) { PERROR("sigaction"); return ret; } @@ -5413,14 +5596,14 @@ static int set_signal_handler(void) /* * Set open files limit to unlimited. This daemon can open a large number of - * file descriptors in order to consumer multiple kernel traces. + * file descriptors in order to consume multiple kernel traces. */ static void set_ulimit(void) { int ret; struct rlimit lim; - /* The kernel does not allowed an infinite limit for open files */ + /* The kernel does not allow an infinite limit for open files */ lim.rlim_cur = 65535; lim.rlim_max = 65535; @@ -5441,7 +5624,10 @@ static int write_pidfile(void) assert(rundir); if (opt_pidfile) { - strncpy(pidfile_path, opt_pidfile, sizeof(pidfile_path)); + if (lttng_strncpy(pidfile_path, opt_pidfile, sizeof(pidfile_path))) { + ret = -1; + goto error; + } } else { /* Build pidfile path from rundir and opt_pidfile. */ ret = snprintf(pidfile_path, sizeof(pidfile_path), "%s/" @@ -5504,6 +5690,44 @@ error: return ret; } +static int set_clock_plugin_env(void) +{ + int ret = 0; + const char *original_env_value; + char *full_path = NULL; + char *new_env_value = NULL; + + original_env_value = getenv("LTTNG_UST_CLOCK_PLUGIN"); + if (!original_env_value) { + goto end; + } + + full_path = utils_expand_path(original_env_value); + if (!full_path) { + ERR("Failed to expand LTTNG_UST_CLOCK_PLUGIN path \"%s\"", + original_env_value); + ret = -1; + goto end; + } + ret = asprintf(&new_env_value, "LTTNG_UST_CLOCK_PLUGIN=%s", + full_path); + free(full_path); + if (ret < 0) { + PERROR("asprintf"); + goto end; + } + + DBG("Updating environment: %s", new_env_value); + ret = putenv(new_env_value); + if (ret) { + free(new_env_value); + PERROR("putenv of LTTNG_UST_CLOCK_PLUGIN"); + goto end; + } +end: + return ret; +} + /* * main */ @@ -5545,6 +5769,20 @@ int main(int argc, char **argv) goto exit_options; } + sessiond_config_log(); + + if (opt_print_version) { + print_version(); + retval = 0; + goto exit_options; + } + + ret = set_clock_plugin_env(); + if (ret) { + retval = -1; + goto exit_options; + } + /* Daemonize */ if (opt_daemon || opt_background) { int i; @@ -5586,29 +5824,8 @@ int main(int argc, char **argv) goto exit_health_sessiond_cleanup; } - if (init_ht_cleanup_quit_pipe()) { - retval = -1; - goto exit_ht_cleanup_quit_pipe; - } - - /* Setup the thread ht_cleanup communication pipe. */ - if (utils_create_pipe_cloexec(ht_cleanup_pipe)) { - retval = -1; - goto exit_ht_cleanup_pipe; - } - - /* Set up max poll set size */ - if (lttng_poll_set_max_size()) { - retval = -1; - goto exit_set_max_size; - } - /* Create thread to clean up RCU hash tables */ - ret = pthread_create(&ht_cleanup_thread, NULL, - thread_ht_cleanup, (void *) NULL); - if (ret) { - errno = ret; - PERROR("pthread_create ht_cleanup"); + if (init_ht_cleanup_thread(&ht_cleanup_thread)) { retval = -1; goto exit_ht_cleanup; } @@ -5976,7 +6193,7 @@ int main(int argc, char **argv) load_info->path = opt_load_session_path; /* Create health-check thread */ - ret = pthread_create(&health_thread, NULL, + ret = pthread_create(&health_thread, default_pthread_attr(), thread_manage_health, (void *) NULL); if (ret) { errno = ret; @@ -5986,7 +6203,7 @@ int main(int argc, char **argv) } /* Create thread to manage the client socket */ - ret = pthread_create(&client_thread, NULL, + ret = pthread_create(&client_thread, default_pthread_attr(), thread_manage_clients, (void *) NULL); if (ret) { errno = ret; @@ -5996,7 +6213,7 @@ int main(int argc, char **argv) } /* Create thread to dispatch registration */ - ret = pthread_create(&dispatch_thread, NULL, + ret = pthread_create(&dispatch_thread, default_pthread_attr(), thread_dispatch_ust_registration, (void *) NULL); if (ret) { errno = ret; @@ -6006,7 +6223,7 @@ int main(int argc, char **argv) } /* Create thread to manage application registration. */ - ret = pthread_create(®_apps_thread, NULL, + ret = pthread_create(®_apps_thread, default_pthread_attr(), thread_registration_apps, (void *) NULL); if (ret) { errno = ret; @@ -6016,7 +6233,7 @@ int main(int argc, char **argv) } /* Create thread to manage application socket */ - ret = pthread_create(&apps_thread, NULL, + ret = pthread_create(&apps_thread, default_pthread_attr(), thread_manage_apps, (void *) NULL); if (ret) { errno = ret; @@ -6026,7 +6243,7 @@ int main(int argc, char **argv) } /* Create thread to manage application notify socket */ - ret = pthread_create(&apps_notify_thread, NULL, + ret = pthread_create(&apps_notify_thread, default_pthread_attr(), ust_thread_manage_notify, (void *) NULL); if (ret) { errno = ret; @@ -6036,7 +6253,7 @@ int main(int argc, char **argv) } /* Create agent registration thread. */ - ret = pthread_create(&agent_reg_thread, NULL, + ret = pthread_create(&agent_reg_thread, default_pthread_attr(), agent_thread_manage_registration, (void *) NULL); if (ret) { errno = ret; @@ -6048,7 +6265,7 @@ int main(int argc, char **argv) /* Don't start this thread if kernel tracing is not requested nor root */ if (is_root && !opt_no_kernel) { /* Create kernel thread to manage kernel event */ - ret = pthread_create(&kernel_thread, NULL, + ret = pthread_create(&kernel_thread, default_pthread_attr(), thread_manage_kernel, (void *) NULL); if (ret) { errno = ret; @@ -6059,8 +6276,8 @@ int main(int argc, char **argv) } /* Create session loading thread. */ - ret = pthread_create(&load_session_thread, NULL, thread_load_session, - load_info); + ret = pthread_create(&load_session_thread, default_pthread_attr(), + thread_load_session, load_info); if (ret) { errno = ret; PERROR("pthread_create load_session_thread"); @@ -6152,6 +6369,12 @@ exit_client: exit_health: exit_init_data: + /* + * Wait for all pending call_rcu work to complete before tearing + * down data structures. call_rcu worker may be trying to + * perform lookups in those structures. + */ + rcu_barrier(); /* * sessiond_cleanup() is called when no other thread is running, except * the ht_cleanup thread, which is needed to destroy the hash tables. @@ -6161,38 +6384,24 @@ exit_init_data: rcu_thread_offline(); rcu_unregister_thread(); - ret = notify_thread_pipe(ht_cleanup_quit_pipe[1]); - if (ret < 0) { - ERR("write error on ht_cleanup quit pipe"); - retval = -1; - } + /* + * Ensure all prior call_rcu are done. call_rcu callbacks may push + * hash tables to the ht_cleanup thread. Therefore, we ensure that + * the queue is empty before shutting down the clean-up thread. + */ + rcu_barrier(); - ret = pthread_join(ht_cleanup_thread, &status); + ret = fini_ht_cleanup_thread(&ht_cleanup_thread); if (ret) { - errno = ret; - PERROR("pthread_join ht cleanup thread"); retval = -1; } exit_ht_cleanup: -exit_set_max_size: - - utils_close_pipe(ht_cleanup_pipe); -exit_ht_cleanup_pipe: - - /* - * Close the ht_cleanup quit pipe. - */ - utils_close_pipe(ht_cleanup_quit_pipe); -exit_ht_cleanup_quit_pipe: health_app_destroy(health_sessiond); exit_health_sessiond_cleanup: exit_create_run_as_worker_cleanup: exit_options: - /* Ensure all prior call_rcu are done. */ - rcu_barrier(); - sessiond_cleanup_options(); exit_set_signal_handler: