X-Git-Url: https://git.lttng.org/?p=lttng-tools.git;a=blobdiff_plain;f=src%2Fbin%2Flttng-sessiond%2Fmain.c;h=7a8b5ae42dcfedb4c7af6a159997d3eaa98dd02f;hp=b2a8f555c5fc072b39e1e922a5eef84a2b1b8f43;hb=2001793c1141e89b34e70efb28b27ec0cc8e6d47;hpb=a5dfbb9db7ba31913657ed921006b13977b7b426 diff --git a/src/bin/lttng-sessiond/main.c b/src/bin/lttng-sessiond/main.c index b2a8f555c..7a8b5ae42 100644 --- a/src/bin/lttng-sessiond/main.c +++ b/src/bin/lttng-sessiond/main.c @@ -17,7 +17,6 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ -#define _GNU_SOURCE #define _LGPL_SOURCE #include #include @@ -38,7 +37,6 @@ #include #include #include -#include #include #include @@ -49,7 +47,7 @@ #include #include #include -#include +#include #include "lttng-sessiond.h" #include "buffer-registry.h" @@ -73,6 +71,7 @@ #include "save.h" #include "load-session-thread.h" #include "syscall.h" +#include "agent.h" #define CONSUMERD_FILE "lttng-consumerd" @@ -133,34 +132,34 @@ static struct consumer_data ustconsumer32_data = { /* 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' }, - { "background", 0, 0, 'b' }, - { "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' }, - { "agent-tcp-port", 1, 0, 'J' }, - { "config", 1, 0, 'f' }, - { "load", 1, 0, 'l' }, - { "kmod-probes", 1, 0, 'P' }, - { "extra-kmod-probes", 1, 0, 'e' }, + { "client-sock", required_argument, 0, 'c' }, + { "apps-sock", required_argument, 0, 'a' }, + { "kconsumerd-cmd-sock", required_argument, 0, '\0' }, + { "kconsumerd-err-sock", required_argument, 0, '\0' }, + { "ustconsumerd32-cmd-sock", required_argument, 0, '\0' }, + { "ustconsumerd32-err-sock", required_argument, 0, '\0' }, + { "ustconsumerd64-cmd-sock", required_argument, 0, '\0' }, + { "ustconsumerd64-err-sock", required_argument, 0, '\0' }, + { "consumerd32-path", required_argument, 0, '\0' }, + { "consumerd32-libdir", required_argument, 0, '\0' }, + { "consumerd64-path", required_argument, 0, '\0' }, + { "consumerd64-libdir", required_argument, 0, '\0' }, + { "daemonize", no_argument, 0, 'd' }, + { "background", no_argument, 0, 'b' }, + { "sig-parent", no_argument, 0, 'S' }, + { "help", no_argument, 0, 'h' }, + { "group", required_argument, 0, 'g' }, + { "version", no_argument, 0, 'V' }, + { "quiet", no_argument, 0, 'q' }, + { "verbose", no_argument, 0, 'v' }, + { "verbose-consumer", no_argument, 0, '\0' }, + { "no-kernel", no_argument, 0, '\0' }, + { "pidfile", required_argument, 0, 'p' }, + { "agent-tcp-port", required_argument, 0, '\0' }, + { "config", required_argument, 0, 'f' }, + { "load", required_argument, 0, 'l' }, + { "kmod-probes", required_argument, 0, '\0' }, + { "extra-kmod-probes", required_argument, 0, '\0' }, { NULL, 0, 0, 0 } }; @@ -305,6 +304,9 @@ const char * const config_section_name = "sessiond"; /* Load session thread information to operate. */ struct load_session_thread_data *load_info; +/* Global hash tables */ +struct lttng_ht *agent_apps_ht_by_sock = NULL; + /* * Whether sessiond is ready for commands/health check requests. * NR_LTTNG_SESSIOND_READY must match the number of calls to @@ -582,6 +584,34 @@ static int generate_lock_file_path(char *path, size_t len) return ret; } +/* + * Wait on consumer process termination. + * + * Need to be called with the consumer data lock held or from a context + * ensuring no concurrent access to data (e.g: cleanup). + */ +static void wait_consumer(struct consumer_data *consumer_data) +{ + pid_t ret; + int status; + + if (consumer_data->pid <= 0) { + return; + } + + DBG("Waiting for complete teardown of consumerd (PID: %d)", + consumer_data->pid); + ret = waitpid(consumer_data->pid, &status, 0); + if (ret == -1) { + PERROR("consumerd waitpid pid: %d", consumer_data->pid) + } + if (!WIFEXITED(status)) { + ERR("consumerd termination with error: %d", + WEXITSTATUS(ret)); + } + consumer_data->pid = 0; +} + /* * Cleanup the session daemon's data structures. */ @@ -676,6 +706,13 @@ static void sessiond_cleanup(void) } } + wait_consumer(&kconsumer_data); + wait_consumer(&ustconsumer64_data); + wait_consumer(&ustconsumer32_data); + + DBG("Cleaning up all agent apps"); + agent_app_ht_clean(); + DBG("Closing all UST sockets"); ust_app_clean_list(); buffer_reg_destroy_registries(); @@ -762,6 +799,8 @@ static void sessiond_cleanup_options(void) free(kmod_probes_list); 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", @@ -1126,31 +1165,33 @@ static void *thread_manage_kernel(void *data) } /* Check for data on kernel pipe */ - if (pollfd == kernel_poll_pipe[0] && (revents & LPOLLIN)) { - (void) lttng_read(kernel_poll_pipe[0], - &tmp, 1); - /* - * Ret value is useless here, if this pipe gets any actions an - * update is required anyway. - */ - update_poll_flag = 1; - continue; - } else { - /* - * New CPU detected by the kernel. Adding kernel stream to - * kernel session and updating the kernel consumer - */ - if (revents & LPOLLIN) { + if (revents & LPOLLIN) { + if (pollfd == kernel_poll_pipe[0]) { + (void) lttng_read(kernel_poll_pipe[0], + &tmp, 1); + /* + * Ret value is useless here, if this pipe gets any actions an + * update is required anyway. + */ + update_poll_flag = 1; + continue; + } else { + /* + * New CPU detected by the kernel. Adding kernel stream to + * kernel session and updating the kernel consumer + */ ret = update_kernel_stream(&kconsumer_data, pollfd); if (ret < 0) { continue; } break; - /* - * TODO: We might want to handle the LPOLLERR | LPOLLHUP - * and unregister kernel stream at this point. - */ } + } else if (revents & (LPOLLERR | LPOLLHUP | LPOLLRDHUP)) { + update_poll_flag = 1; + continue; + } else { + ERR("Unexpected poll events %u for sock %d", revents, pollfd); + goto error; } } } @@ -1209,6 +1250,9 @@ static void *thread_manage_consumer(void *data) DBG("[thread] Manage consumer started"); + rcu_register_thread(); + rcu_thread_online(); + health_register(health_sessiond, HEALTH_SESSIOND_TYPE_CONSUMER); health_code_update(); @@ -1277,9 +1321,14 @@ restart: /* Event on the registration socket */ if (pollfd == consumer_data->err_sock) { - if (revents & (LPOLLERR | LPOLLHUP | LPOLLRDHUP)) { + if (revents & LPOLLIN) { + continue; + } else if (revents & (LPOLLERR | LPOLLHUP | LPOLLRDHUP)) { ERR("consumer err socket poll error"); goto error; + } else { + ERR("Unexpected poll events %u for sock %d", revents, pollfd); + goto error; } } } @@ -1409,7 +1458,8 @@ restart_poll: if (pollfd == sock) { /* Event on the consumerd socket */ - if (revents & (LPOLLERR | LPOLLHUP | LPOLLRDHUP)) { + if (revents & (LPOLLERR | LPOLLHUP | LPOLLRDHUP) + && !(revents & LPOLLIN)) { ERR("consumer err socket second poll error"); goto error; } @@ -1427,6 +1477,11 @@ restart_poll: goto exit; } else if (pollfd == consumer_data->metadata_fd) { + if (revents & (LPOLLERR | LPOLLHUP | LPOLLRDHUP) + && !(revents & LPOLLIN)) { + ERR("consumer err metadata socket second poll error"); + goto error; + } /* UST metadata requests */ ret = ust_consumer_metadata_request( &consumer_data->metadata_sock); @@ -1490,7 +1545,6 @@ error: unlink(consumer_data->err_unix_sock_path); unlink(consumer_data->cmd_unix_sock_path); - consumer_data->pid = 0; pthread_mutex_unlock(&consumer_data->lock); /* Cleanup metadata socket mutex. */ @@ -1507,6 +1561,9 @@ error_poll: health_unregister(health_sessiond); DBG("consumer thread cleanup completed"); + rcu_thread_offline(); + rcu_unregister_thread(); + return NULL; } @@ -1592,10 +1649,7 @@ static void *thread_manage_apps(void *data) /* Inspect the apps cmd pipe */ if (pollfd == apps_cmd_pipe[0]) { - if (revents & (LPOLLERR | LPOLLHUP | LPOLLRDHUP)) { - ERR("Apps command pipe error"); - goto error; - } else if (revents & LPOLLIN) { + if (revents & LPOLLIN) { int sock; /* Empty pipe */ @@ -1608,9 +1662,8 @@ static void *thread_manage_apps(void *data) health_code_update(); /* - * We only monitor the error events of the socket. This - * thread does not handle any incoming data from UST - * (POLLIN). + * Since this is a command socket (write then read), + * we only monitor the error events of the socket. */ ret = lttng_poll_add(&events, sock, LPOLLERR | LPOLLHUP | LPOLLRDHUP); @@ -1619,6 +1672,12 @@ static void *thread_manage_apps(void *data) } DBG("Apps with sock %d added to poll set", sock); + } else if (revents & (LPOLLERR | LPOLLHUP | LPOLLRDHUP)) { + ERR("Apps command pipe error"); + goto error; + } else { + ERR("Unknown poll events %u for sock %d", revents, pollfd); + goto error; } } else { /* @@ -1634,6 +1693,9 @@ static void *thread_manage_apps(void *data) /* Socket closed on remote end. */ ust_app_unregister(pollfd); + } else { + ERR("Unexpected poll events %u for sock %d", revents, pollfd); + goto error; } } @@ -1774,7 +1836,16 @@ static void sanitize_wait_queue(struct ust_reg_wait_queue *wait_queue) wait_queue->count--; ust_app_destroy(wait_node->app); free(wait_node); + /* + * Silence warning of use-after-free in + * cds_list_for_each_entry_safe which uses + * __typeof__(*wait_node). + */ + wait_node = NULL; break; + } else { + ERR("Unexpected poll events %u for sock %d", revents, pollfd); + goto error; } } } @@ -1976,7 +2047,7 @@ static void *thread_dispatch_ust_registration(void *data) * Don't care about return value. Let the manage apps threads * handle app unregistration upon socket close. */ - (void) ust_app_register_done(app->sock); + (void) ust_app_register_done(app); /* * Even if the application socket has been closed, send the app @@ -2018,6 +2089,22 @@ error: free(wait_node); } + /* Empty command queue. */ + for (;;) { + /* Dequeue command for registration */ + node = cds_wfcq_dequeue_blocking(&ust_cmd_queue.head, &ust_cmd_queue.tail); + if (node == NULL) { + break; + } + ust_cmd = caa_container_of(node, struct ust_command, node); + ret = close(ust_cmd->sock); + if (ret < 0) { + PERROR("close ust sock exit dispatch %d", ust_cmd->sock); + } + lttng_fd_put(LTTNG_FD_APPS, 1); + free(ust_cmd); + } + error_testpoint: DBG("Dispatch thread dying"); if (err) { @@ -2119,10 +2206,7 @@ static void *thread_registration_apps(void *data) /* Event on the registration socket */ if (pollfd == apps_sock) { - if (revents & (LPOLLERR | LPOLLHUP | LPOLLRDHUP)) { - ERR("Register apps socket poll error"); - goto error; - } else if (revents & LPOLLIN) { + if (revents & LPOLLIN) { sock = lttcomm_accept_unix_sock(apps_sock); if (sock < 0) { goto error; @@ -2150,6 +2234,10 @@ static void *thread_registration_apps(void *data) ust_cmd = zmalloc(sizeof(struct ust_command)); if (ust_cmd == NULL) { PERROR("ust command zmalloc"); + ret = close(sock); + if (ret) { + PERROR("close"); + } goto error; } @@ -2205,6 +2293,12 @@ static void *thread_registration_apps(void *data) * barrier with the exchange in cds_wfcq_enqueue. */ futex_nto1_wake(&ust_cmd_queue.futex); + } else if (revents & (LPOLLERR | LPOLLHUP | LPOLLRDHUP)) { + ERR("Register apps socket poll error"); + goto error; + } else { + ERR("Unexpected poll events %u for sock %d", revents, pollfd); + goto error; } } } @@ -2706,7 +2800,7 @@ static int copy_session_consumer(int domain, struct ltt_session *session) * domain. */ if (session->kernel_session->consumer) { - consumer_destroy_output(session->kernel_session->consumer); + consumer_output_put(session->kernel_session->consumer); } session->kernel_session->consumer = consumer_copy_output(session->consumer); @@ -2720,7 +2814,7 @@ static int copy_session_consumer(int domain, struct ltt_session *session) case LTTNG_DOMAIN_UST: DBG3("Copying tracing session consumer output in UST session"); if (session->ust_session->consumer) { - consumer_destroy_output(session->ust_session->consumer); + consumer_output_put(session->ust_session->consumer); } session->ust_session->consumer = consumer_copy_output(session->consumer); @@ -2840,7 +2934,7 @@ static int create_kernel_session(struct ltt_session *session) session->kernel_session->consumer->dst.trace_path, S_IRWXU | S_IRWXG, session->uid, session->gid); if (ret < 0) { - if (ret != -EEXIST) { + if (errno != EEXIST) { ERR("Trace directory creation error"); goto error; } @@ -2902,6 +2996,8 @@ static int process_client_msg(struct command_ctx *cmd_ctx, int sock, DBG("Processing client command %d", cmd_ctx->lsm->cmd_type); + assert(!rcu_read_ongoing()); + *sock_error = 0; switch (cmd_ctx->lsm->cmd_type) { @@ -3247,9 +3343,74 @@ skip_domain: switch (cmd_ctx->lsm->cmd_type) { case LTTNG_ADD_CONTEXT: { - ret = cmd_add_context(cmd_ctx->session, cmd_ctx->lsm->domain.type, + /* + * An LTTNG_ADD_CONTEXT command might have a supplementary + * payload if the context being added is an application context. + */ + if (cmd_ctx->lsm->u.context.ctx.ctx == + LTTNG_EVENT_CONTEXT_APP_CONTEXT) { + char *provider_name = NULL, *context_name = NULL; + size_t provider_name_len = + cmd_ctx->lsm->u.context.provider_name_len; + size_t context_name_len = + cmd_ctx->lsm->u.context.context_name_len; + + if (provider_name_len == 0 || context_name_len == 0) { + /* + * Application provider and context names MUST + * be provided. + */ + ret = -LTTNG_ERR_INVALID; + goto error; + } + + provider_name = zmalloc(provider_name_len + 1); + if (!provider_name) { + ret = -LTTNG_ERR_NOMEM; + goto error; + } + + context_name = zmalloc(context_name_len + 1); + if (!context_name) { + ret = -LTTNG_ERR_NOMEM; + goto error_add_context; + } + + ret = lttcomm_recv_unix_sock(sock, provider_name, + provider_name_len); + if (ret < 0) { + goto error_add_context; + } + + ret = lttcomm_recv_unix_sock(sock, context_name, + context_name_len); + if (ret < 0) { + goto error_add_context; + } + cmd_ctx->lsm->u.context.ctx.u.app_ctx.provider_name = + provider_name; + cmd_ctx->lsm->u.context.ctx.u.app_ctx.ctx_name = + context_name; + } + + /* + * cmd_add_context assumes ownership of the provider and context + * names. + */ + ret = cmd_add_context(cmd_ctx->session, + cmd_ctx->lsm->domain.type, cmd_ctx->lsm->u.context.channel_name, - &cmd_ctx->lsm->u.context.ctx, kernel_poll_pipe[1]); + &cmd_ctx->lsm->u.context.ctx, + kernel_poll_pipe[1]); + + cmd_ctx->lsm->u.context.ctx.u.app_ctx.provider_name = NULL; + cmd_ctx->lsm->u.context.ctx.u.app_ctx.ctx_name = NULL; +error_add_context: + free(cmd_ctx->lsm->u.context.ctx.u.app_ctx.provider_name); + free(cmd_ctx->lsm->u.context.ctx.u.app_ctx.ctx_name); + if (ret < 0) { + goto error; + } break; } case LTTNG_DISABLE_CHANNEL: @@ -3260,8 +3421,34 @@ skip_domain: } case LTTNG_DISABLE_EVENT: { + + /* + * FIXME: handle filter; for now we just receive the filter's + * bytecode along with the filter expression which are sent by + * liblttng-ctl and discard them. + * + * This fixes an issue where the client may block while sending + * the filter payload and encounter an error because the session + * daemon closes the socket without ever handling this data. + */ + size_t count = cmd_ctx->lsm->u.disable.expression_len + + cmd_ctx->lsm->u.disable.bytecode_len; + + if (count) { + char data[LTTNG_FILTER_MAX_LEN]; + + DBG("Discarding disable event command payload of size %zu", count); + while (count) { + ret = lttcomm_recv_unix_sock(sock, data, + count > sizeof(data) ? sizeof(data) : count); + if (ret < 0) { + goto error; + } + + count -= (size_t) ret; + } + } /* FIXME: passing packed structure to non-packed pointer */ - /* TODO: handle filter */ ret = cmd_disable_event(cmd_ctx->session, cmd_ctx->lsm->domain.type, cmd_ctx->lsm->u.disable.channel_name, &cmd_ctx->lsm->u.disable.event); @@ -3759,7 +3946,35 @@ skip_domain: } case LTTNG_DATA_PENDING: { - ret = cmd_data_pending(cmd_ctx->session); + int pending_ret; + + /* 1 byte to return whether or not data is pending */ + ret = setup_lttng_msg(cmd_ctx, 1); + if (ret < 0) { + goto setup_error; + } + + pending_ret = cmd_data_pending(cmd_ctx->session); + /* + * FIXME + * + * This function may returns 0 or 1 to indicate whether or not + * there is data pending. In case of error, it should return an + * LTTNG_ERR code. However, some code paths may still return + * a nondescript error code, which we handle by returning an + * "unknown" error. + */ + if (pending_ret == 0 || pending_ret == 1) { + ret = LTTNG_OK; + } else if (pending_ret < 0) { + ret = LTTNG_ERR_UNK; + goto setup_error; + } else { + ret = pending_ret; + goto setup_error; + } + + *cmd_ctx->llm->payload = (uint8_t) pending_ret; break; } case LTTNG_SNAPSHOT_ADD_OUTPUT: @@ -3935,6 +4150,7 @@ setup_error: session_unlock_list(); } init_setup_error: + assert(!rcu_read_ongoing()); return ret; } @@ -4050,9 +4266,14 @@ restart: /* Event on the registration socket */ if (pollfd == sock) { - if (revents & (LPOLLERR | LPOLLHUP | LPOLLRDHUP)) { + if (revents & LPOLLIN) { + continue; + } else if (revents & (LPOLLERR | LPOLLHUP | LPOLLRDHUP)) { ERR("Health socket poll error"); goto error; + } else { + ERR("Unexpected poll events %u for sock %d", revents, pollfd); + goto error; } } } @@ -4227,9 +4448,14 @@ static void *thread_manage_clients(void *data) /* Event on the registration socket */ if (pollfd == client_sock) { - if (revents & (LPOLLERR | LPOLLHUP | LPOLLRDHUP)) { + if (revents & LPOLLIN) { + continue; + } else if (revents & (LPOLLERR | LPOLLHUP | LPOLLRDHUP)) { ERR("Client socket poll error"); goto error; + } else { + ERR("Unexpected poll events %u for sock %d", revents, pollfd); + goto error; } } } @@ -4326,9 +4552,10 @@ static void *thread_manage_clients(void *data) health_code_update(); - DBG("Sending response (size: %d, retcode: %s)", + DBG("Sending response (size: %d, retcode: %s (%d))", cmd_ctx->lttng_msg_size, - lttng_strerror(-cmd_ctx->llm->ret_code)); + lttng_strerror(-cmd_ctx->llm->ret_code), + cmd_ctx->llm->ret_code); ret = send_unix_sock(sock, cmd_ctx->llm, cmd_ctx->lttng_msg_size); if (ret < 0) { ERR("Failed to send data back to client"); @@ -4440,6 +4667,11 @@ static void usage(void) fprintf(stderr, " --extra-kmod-probes Specify extra kernel module probes to load\n"); } +static int string_match(const char *str1, const char *str2) +{ + return (str1 && str2) && !strcmp(str1, str2); +} + /* * Take an option from the getopt output and set it in the right variable to be * used later. @@ -4461,36 +4693,25 @@ static int set_option(int opt, const char *arg, const char *optname) goto end; } - switch (opt) { - case 0: - fprintf(stderr, "option %s", optname); - if (arg) { - fprintf(stderr, " with arg %s\n", arg); - } - break; - case 'c': + if (string_match(optname, "client-sock") || opt == 'c') { if (lttng_is_setuid_setgid()) { WARN("Getting '%s' argument from setuid/setgid binary refused for security reasons.", "-c, --client-sock"); } else { snprintf(client_unix_sock_path, PATH_MAX, "%s", arg); } - break; - case 'a': + } else if (string_match(optname, "apps-sock") || opt == 'a') { if (lttng_is_setuid_setgid()) { WARN("Getting '%s' argument from setuid/setgid binary refused for security reasons.", "-a, --apps-sock"); } else { snprintf(apps_unix_sock_path, PATH_MAX, "%s", arg); } - break; - case 'd': + } else if (string_match(optname, "daemonize") || opt == 'd') { opt_daemon = 1; - break; - case 'b': + } else if (string_match(optname, "background") || opt == 'b') { opt_background = 1; - break; - case 'g': + } else if (string_match(optname, "group") || opt == 'g') { if (lttng_is_setuid_setgid()) { WARN("Getting '%s' argument from setuid/setgid binary refused for security reasons.", "-g, --group"); @@ -4510,71 +4731,61 @@ static int set_option(int opt, const char *arg, const char *optname) } tracing_group_name_override = 1; } - break; - case 'h': + } else if (string_match(optname, "help") || opt == 'h') { usage(); exit(EXIT_SUCCESS); - case 'V': + } else if (string_match(optname, "version") || opt == 'V') { fprintf(stdout, "%s\n", VERSION); exit(EXIT_SUCCESS); - case 'S': + } else if (string_match(optname, "sig-parent") || opt == 'S') { opt_sig_parent = 1; - break; - case 'E': + } else if (string_match(optname, "kconsumerd-err-sock")) { if (lttng_is_setuid_setgid()) { WARN("Getting '%s' argument from setuid/setgid binary refused for security reasons.", "--kconsumerd-err-sock"); } else { snprintf(kconsumer_data.err_unix_sock_path, PATH_MAX, "%s", arg); } - break; - case 'C': + } else if (string_match(optname, "kconsumerd-cmd-sock")) { if (lttng_is_setuid_setgid()) { WARN("Getting '%s' argument from setuid/setgid binary refused for security reasons.", "--kconsumerd-cmd-sock"); } else { snprintf(kconsumer_data.cmd_unix_sock_path, PATH_MAX, "%s", arg); } - break; - case 'F': + } else if (string_match(optname, "ustconsumerd64-err-sock")) { if (lttng_is_setuid_setgid()) { WARN("Getting '%s' argument from setuid/setgid binary refused for security reasons.", "--ustconsumerd64-err-sock"); } else { snprintf(ustconsumer64_data.err_unix_sock_path, PATH_MAX, "%s", arg); } - break; - case 'D': + } else if (string_match(optname, "ustconsumerd64-cmd-sock")) { if (lttng_is_setuid_setgid()) { WARN("Getting '%s' argument from setuid/setgid binary refused for security reasons.", "--ustconsumerd64-cmd-sock"); } else { snprintf(ustconsumer64_data.cmd_unix_sock_path, PATH_MAX, "%s", arg); } - break; - case 'H': + } else if (string_match(optname, "ustconsumerd32-err-sock")) { if (lttng_is_setuid_setgid()) { WARN("Getting '%s' argument from setuid/setgid binary refused for security reasons.", "--ustconsumerd32-err-sock"); } else { snprintf(ustconsumer32_data.err_unix_sock_path, PATH_MAX, "%s", arg); } - break; - case 'G': + } else if (string_match(optname, "ustconsumerd32-cmd-sock")) { if (lttng_is_setuid_setgid()) { WARN("Getting '%s' argument from setuid/setgid binary refused for security reasons.", "--ustconsumerd32-cmd-sock"); } else { snprintf(ustconsumer32_data.cmd_unix_sock_path, PATH_MAX, "%s", arg); } - break; - case 'N': + } else if (string_match(optname, "no-kernel")) { opt_no_kernel = 1; - break; - case 'q': + } else if (string_match(optname, "quiet") || opt == 'q') { lttng_opt_quiet = 1; - break; - case 'v': + } else if (string_match(optname, "verbose") || opt == 'v') { /* Verbose level can increase using multiple -v */ if (arg) { /* Value obtained from config file */ @@ -4586,15 +4797,13 @@ static int set_option(int opt, const char *arg, const char *optname) /* Clamp value to [0, 3] */ lttng_opt_verbose = lttng_opt_verbose < 0 ? 0 : (lttng_opt_verbose <= 3 ? lttng_opt_verbose : 3); - break; - case 'Z': + } else if (string_match(optname, "verbose-consumer")) { if (arg) { opt_verbose_consumer = config_parse_value(arg); } else { opt_verbose_consumer += 1; } - break; - case 'u': + } else if (string_match(optname, "consumerd32-path")) { if (lttng_is_setuid_setgid()) { WARN("Getting '%s' argument from setuid/setgid binary refused for security reasons.", "--consumerd32-path"); @@ -4609,8 +4818,7 @@ static int set_option(int opt, const char *arg, const char *optname) } consumerd32_bin_override = 1; } - break; - case 'U': + } else if (string_match(optname, "consumerd32-libdir")) { if (lttng_is_setuid_setgid()) { WARN("Getting '%s' argument from setuid/setgid binary refused for security reasons.", "--consumerd32-libdir"); @@ -4625,8 +4833,7 @@ static int set_option(int opt, const char *arg, const char *optname) } consumerd32_libdir_override = 1; } - break; - case 't': + } else if (string_match(optname, "consumerd64-path")) { if (lttng_is_setuid_setgid()) { WARN("Getting '%s' argument from setuid/setgid binary refused for security reasons.", "--consumerd64-path"); @@ -4641,8 +4848,7 @@ static int set_option(int opt, const char *arg, const char *optname) } consumerd64_bin_override = 1; } - break; - case 'T': + } else if (string_match(optname, "consumerd64-libdir")) { if (lttng_is_setuid_setgid()) { WARN("Getting '%s' argument from setuid/setgid binary refused for security reasons.", "--consumerd64-libdir"); @@ -4657,8 +4863,7 @@ static int set_option(int opt, const char *arg, const char *optname) } consumerd64_libdir_override = 1; } - break; - case 'p': + } else if (string_match(optname, "pidfile") || opt == 'p') { if (lttng_is_setuid_setgid()) { WARN("Getting '%s' argument from setuid/setgid binary refused for security reasons.", "-p, --pidfile"); @@ -4670,9 +4875,7 @@ static int set_option(int opt, const char *arg, const char *optname) ret = -ENOMEM; } } - break; - case 'J': /* Agent TCP port. */ - { + } else if (string_match(optname, "agent-tcp-port")) { if (lttng_is_setuid_setgid()) { WARN("Getting '%s' argument from setuid/setgid binary refused for security reasons.", "--agent-tcp-port"); @@ -4696,9 +4899,7 @@ static int set_option(int opt, const char *arg, const char *optname) agent_tcp_port = (uint32_t) v; DBG3("Agent TCP port set to non default: %u", agent_tcp_port); } - break; - } - case 'l': + } else if (string_match(optname, "load") || opt == 'l') { if (lttng_is_setuid_setgid()) { WARN("Getting '%s' argument from setuid/setgid binary refused for security reasons.", "-l, --load"); @@ -4710,8 +4911,7 @@ static int set_option(int opt, const char *arg, const char *optname) ret = -ENOMEM; } } - break; - case 'P': /* probe modules list */ + } else if (string_match(optname, "kmod-probes")) { if (lttng_is_setuid_setgid()) { WARN("Getting '%s' argument from setuid/setgid binary refused for security reasons.", "--kmod-probes"); @@ -4723,8 +4923,7 @@ static int set_option(int opt, const char *arg, const char *optname) ret = -ENOMEM; } } - break; - case 'e': + } else if (string_match(optname, "extra-kmod-probes")) { if (lttng_is_setuid_setgid()) { WARN("Getting '%s' argument from setuid/setgid binary refused for security reasons.", "--extra-kmod-probes"); @@ -4736,11 +4935,10 @@ static int set_option(int opt, const char *arg, const char *optname) ret = -ENOMEM; } } - break; - case 'f': - /* This is handled in set_options() thus silent break. */ - break; - default: + } else if (string_match(optname, "config") || opt == 'f') { + /* This is handled in set_options() thus silent skip. */ + goto end; + } else { /* Unknown option or other error. * Error is printed by getopt, just return */ ret = -1; @@ -4768,7 +4966,7 @@ end: /* * 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 + * See config_entry_handler_cb comment in common/config/session-config.h for the * return value conventions. */ static int config_entry_handler(const struct config_entry *entry, void *unused) @@ -4875,12 +5073,24 @@ static int set_options(int argc, char **argv) optopt = orig_optopt; optind = orig_optind; while (1) { - c = getopt_long(argc, argv, optstring, long_options, &option_index); + option_index = -1; + /* + * getopt_long() will not set option_index if it encounters a + * short option. + */ + c = getopt_long(argc, argv, optstring, long_options, + &option_index); if (c == -1) { break; } - ret = set_option(c, optarg, long_options[option_index].name); + /* + * Pass NULL as the long option name if popt left the index + * unset. + */ + ret = set_option(c, optarg, + option_index < 0 ? NULL : + long_options[option_index].name); if (ret < 0) { break; } @@ -5365,6 +5575,10 @@ int main(int argc, char **argv) } } + if (run_as_create_worker(argv[0]) < 0) { + goto exit_create_run_as_worker_cleanup; + } + /* * Starting from here, we can create threads. This needs to be after * lttng_daemonize due to RCU. @@ -5630,13 +5844,17 @@ int main(int argc, char **argv) * cleanup() can get called after that point. */ if (ust_app_ht_alloc()) { + ERR("Failed to allocate UST app hash table"); retval = -1; goto exit_init_data; } - /* Initialize agent domain subsystem. */ - if (agent_setup()) { - /* ENOMEM at this point. */ + /* + * Initialize agent app hash table. We allocate the hash table here + * since cleanup() can get called after this point. + */ + if (agent_app_ht_alloc()) { + ERR("Failed to allocate Agent app hash table"); retval = -1; goto exit_init_data; } @@ -5914,6 +6132,10 @@ exit_apps: } exit_reg_apps: + /* + * Join dispatch thread after joining reg_apps_thread to ensure + * we don't leak applications in the queue. + */ ret = pthread_join(dispatch_thread, &status); if (ret) { errno = ret; @@ -5974,11 +6196,16 @@ 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: + if (!retval) { exit(EXIT_SUCCESS); } else {