X-Git-Url: https://git.lttng.org/?p=lttng-tools.git;a=blobdiff_plain;f=ltt-sessiond%2Fltt-sessiond.c;h=f257ddb0904de50d1eb2ab83c7db2f95c4bd6f29;hp=e7b8db7dd84a61b85c445a648666327c28dc778d;hb=5716705821202372fd16168f66f347ba293ef6b4;hpb=826d496db7f18f2ae1f7e0d2f4fc381144ed04a4 diff --git a/ltt-sessiond/ltt-sessiond.c b/ltt-sessiond/ltt-sessiond.c index e7b8db7dd..f257ddb09 100644 --- a/ltt-sessiond/ltt-sessiond.c +++ b/ltt-sessiond/ltt-sessiond.c @@ -39,17 +39,24 @@ #include "liblttsessiondcomm.h" #include "ltt-sessiond.h" +const char default_home_dir[] = DEFAULT_HOME_DIR; +const char default_tracing_group[] = DEFAULT_TRACING_GROUP; +const char default_ust_sock_dir[] = DEFAULT_UST_SOCK_DIR; +const char default_global_apps_pipe[] = DEFAULT_GLOBAL_APPS_PIPE; + /* Static functions */ static int set_signal_handler(void); static int set_socket_perms(void); static void sighandler(int); -static void daemonize(void); static void cleanup(void); +static void copy_common_data(struct lttcomm_lttng_msg *llm, struct lttcomm_session_msg *lsm); static int check_existing_daemon(void); static int notify_apps(const char*); static int connect_app(pid_t); static int init_daemon_socket(void); -static struct lttcomm_lttng_msg *process_client_msg(struct lttcomm_session_msg*); +static int process_client_msg(int sock, struct lttcomm_session_msg*); +static int send_unix_sock(int sock, void *buf, size_t len); +static size_t ust_list_apps(pid_t **pids); static void *thread_manage_clients(void *); static void *thread_manage_apps(void *); @@ -62,8 +69,10 @@ static struct ltt_session *find_session(uuid_t); /* Variables */ const char *progname; const char *opt_tracing_group; +static int opt_sig_parent; static int opt_daemon; static int is_root; /* Set to 1 if the daemon is running as root */ +static pid_t ppid; static char apps_unix_sock_path[PATH_MAX]; /* Global application Unix socket path */ static char client_unix_sock_path[PATH_MAX]; /* Global client Unix socket path */ @@ -72,13 +81,17 @@ static int client_socket; static int apps_socket; static struct ltt_session *current_session; -static int session_count; + +/* Number of element for the list below. */ +static unsigned int session_count; +static unsigned int traceable_app_count; /* Init session's list */ static struct ltt_session_list ltt_session_list = { .head = CDS_LIST_HEAD_INIT(ltt_session_list.head), }; +/* Init ust traceabl application's list */ static struct ltt_traceable_app_list ltt_traceable_app_list = { .head = CDS_LIST_HEAD_INIT(ltt_traceable_app_list.head), }; @@ -94,11 +107,11 @@ static void *thread_manage_apps(void *data) struct ltt_traceable_app *lta; /* TODO: Something more elegant is needed but fine for now */ - struct { + struct { int reg; /* 1:register, 0:unregister */ - pid_t pid; - uid_t uid; - } reg_msg; + pid_t pid; + uid_t uid; + } reg_msg; /* Notify all applications to register */ notify_apps(default_global_apps_pipe); @@ -131,12 +144,17 @@ static void *thread_manage_apps(void *data) lta->pid = reg_msg.pid; lta->uid = reg_msg.uid; cds_list_add(<a->list, <t_traceable_app_list.head); + traceable_app_count++; } else { /* Unregistering */ lta = NULL; cds_list_for_each_entry(lta, <t_traceable_app_list.head, list) { if (lta->pid == reg_msg.pid && lta->uid == reg_msg.uid) { cds_list_del(<a->list); + /* Check to not overflow here */ + if (traceable_app_count != 0) { + traceable_app_count--; + } break; } } @@ -163,13 +181,19 @@ static void *thread_manage_clients(void *data) { int sock, ret; struct lttcomm_session_msg lsm; - struct lttcomm_lttng_msg *llm; ret = lttcomm_listen_unix_sock(client_socket); if (ret < 0) { goto error; } + /* Notify parent pid that we are ready + * to accept command for client side. + */ + if (opt_sig_parent) { + kill(ppid, SIGCHLD); + } + while (1) { /* Blocking call, waiting for transmission */ sock = lttcomm_accept_unix_sock(client_socket); @@ -188,29 +212,14 @@ static void *thread_manage_clients(void *data) } /* This function dispatch the work to the LTTng or UST libs - * and make sure that the reply structure (llm) is filled. - */ - llm = process_client_msg(&lsm); - - /* Having a valid lttcomm_lttng_msg struct, reply is sent back - * to the client directly. + * and then sends back the response to the client. This is needed + * because there might be more then one lttcomm_lttng_msg to + * send out so process_client_msg do both jobs. */ - if (llm != NULL) { - ret = lttcomm_send_unix_sock(sock, llm, - sizeof(struct lttcomm_lttng_msg)); - free(llm); - if (ret < 0) { - continue; - } - } else { - /* The lttcomm_lttng_msg struct was not allocated - * correctly. Fatal error since the daemon is not able - * to respond. However, we still permit client connection. - * - * TODO: We should have a default llm that tells the client - * that the sessiond had a fatal error and thus the client could - * take action to restart ltt-sessiond or inform someone. - */ + ret = process_client_msg(sock, &lsm); + if (ret < 0) { + /* Error detected but still accept command */ + continue; } } @@ -218,6 +227,23 @@ error: return NULL; } +/* + * send_unix_sock + * + * Send data on a unix socket using the liblttsessiondcomm API. + * + * Return lttcomm error code. + */ +static int send_unix_sock(int sock, void *buf, size_t len) +{ + /* Check valid length */ + if (len <= 0) { + return -1; + } + + return lttcomm_send_unix_sock(sock, buf, len); +} + /* * connect_app * @@ -373,75 +399,137 @@ error: * * Return size of the array. */ -static size_t ust_list_apps(pid_t *pids) +static size_t ust_list_apps(pid_t **pids) { size_t size = 0; struct ltt_traceable_app *iter = NULL; + pid_t *p; - cds_list_for_each_entry(iter, <t_traceable_app_list.head, list) { - if (size >= MAX_APPS_PID) { - break; - } + if (traceable_app_count == 0) { + /* No dynamic allocation is done */ + goto end; + } + + p = malloc(sizeof(pid_t) * traceable_app_count); - pids[size] = iter->pid; + /* TODO: Mutex needed to access this list */ + cds_list_for_each_entry(iter, <t_traceable_app_list.head, list) { + p[size] = iter->pid; size++; } + *pids = p; + +end: return size; } +/* + * copy_common_data + * + * Copy common data between lttcomm_lttng_msg and lttcomm_session_msg + */ +static void copy_common_data(struct lttcomm_lttng_msg *llm, struct lttcomm_session_msg *lsm) +{ + llm->cmd_type = lsm->cmd_type; + llm->pid = lsm->pid; + if (!uuid_is_null(lsm->session_id)) { + uuid_copy(llm->session_id, lsm->session_id); + } + strncpy(llm->trace_name, lsm->trace_name, sizeof(llm->trace_name)); +} + /* * process_client_msg * * This takes the lttcomm_session_msg struct and process the command requested - * by the client. It then creates the reply by allocating a lttcomm_lttng_msg - * and fill it with the necessary information. + * by the client. It then creates response(s) and send it back to the + * given socket (sock). * - * It's the caller responsability to free that structure when done with it. - * - * Return pointer to lttcomm_lttng_msg allocated struct. + * Return any error encountered or 0 for success. */ -static struct lttcomm_lttng_msg *process_client_msg(struct lttcomm_session_msg *lsm) +static int process_client_msg(int sock, struct lttcomm_session_msg *lsm) { - struct lttcomm_lttng_msg *llm; - - /* Allocate the reply message structure */ - llm = malloc(sizeof(struct lttcomm_lttng_msg)); - if (llm == NULL) { - perror("malloc"); - goto end; - } + int ret; + struct lttcomm_lttng_msg llm; /* Copy common data to identify the response * on the lttng client side. */ - llm->cmd_type = lsm->cmd_type; - llm->pid = lsm->pid; - if (!uuid_is_null(lsm->session_id)) { - uuid_copy(llm->session_id, lsm->session_id); - } - strncpy(llm->trace_name, lsm->trace_name, sizeof(llm->trace_name)); + copy_common_data(&llm, lsm); /* Default return code. - * In a our world, everything is OK... right? + * In our world, everything is OK... right? ;) */ - llm->ret_code = LTTCOMM_OK; + llm.ret_code = LTTCOMM_OK; /* Process by command type */ switch (lsm->cmd_type) { case UST_LIST_APPS: { - llm->u.list_apps.size = ust_list_apps(llm->u.list_apps.pids); + pid_t *pids; + llm.num_pckt = ust_list_apps(&pids); + if (llm.num_pckt == 0) { + ret = LTTCOMM_NO_APPS; + goto error; + } + + /* Send all packets */ + while (llm.num_pckt != 0) { + llm.u.list_apps.pid = pids[traceable_app_count - llm.num_pckt]; + ret = send_unix_sock(sock, (void*) &llm, sizeof(llm)); + if (ret < 0) { + goto send_error; + } + llm.num_pckt--; + } + /* Allocated array by ust_list_apps() */ + free(pids); + + break; + } + case LTTNG_LIST_SESSIONS: + { + struct ltt_session *iter = NULL; + + llm.num_pckt = session_count; + if (llm.num_pckt == 0) { + ret = LTTCOMM_NO_SESS; + goto error; + } + + cds_list_for_each_entry(iter, <t_session_list.head, list) { + uuid_unparse(iter->uuid, llm.u.list_sessions.uuid); + strncpy(llm.u.list_sessions.name, iter->name, + sizeof(llm.u.list_sessions.name)); + ret = send_unix_sock(sock, (void*) &llm, sizeof(llm)); + if (ret < 0) { + goto send_error; + } + llm.num_pckt--; + } + break; } default: + { /* Undefined command */ - llm->ret_code = LTTCOMM_UND; + ret = LTTCOMM_UND; break; + } } -end: - return llm; + return 0; + +send_error: + return ret; + +error: + /* Notify client of error */ + llm.ret_code = ret; + send_unix_sock(sock, (void*) &llm, sizeof(llm)); + + return -1; } /* @@ -455,7 +543,8 @@ static void usage(void) "\t-a, --apps-sock PATH\t\tSpecify path for apps unix socket.\n" "\t-d, --daemonize\t\tStart as a daemon.\n" "\t-g, --group NAME\t\tSpecify the tracing group name. (default: tracing)\n" - "\t-V, --version\t\tShow version number.\n", + "\t-V, --version\t\tShow version number.\n" + "\t-S, --sig-parent\t\tSend SIGCHLD to parent pid to notify readiness.\n", progname); } @@ -470,6 +559,7 @@ static int parse_args(int argc, char **argv) { "client-sock", 1, 0, 'c' }, { "apps-sock", 1, 0, 'a' }, { "daemonize", 0, 0, 'd' }, + { "sig-parent", 0, 0, 'S' }, { "help", 0, 0, 'h' }, { "group", 1, 0, 'g' }, { "version", 0, 0, 'V' }, @@ -478,7 +568,7 @@ static int parse_args(int argc, char **argv) while (1) { int option_index = 0; - c = getopt_long(argc, argv, "dhV" "a:c:g:s:", long_options, &option_index); + c = getopt_long(argc, argv, "dhVS" "a:c:g:s:", long_options, &option_index); if (c == -1) { break; } @@ -508,6 +598,9 @@ static int parse_args(int argc, char **argv) case 'V': fprintf(stdout, "%s\n", VERSION); exit(EXIT_SUCCESS); + case 'S': + opt_sig_parent = 1; + break; default: /* Unknown option or other error. * Error is printed by getopt, just return */ @@ -595,7 +688,7 @@ static const char *get_home_dir(void) { const char *home_path; - if ((home_path = (const char*) getenv("HOME")) == NULL) { + if ((home_path = (const char *) getenv("HOME")) == NULL) { home_path = default_home_dir; } @@ -632,48 +725,6 @@ end: return ret; } -/* - * daemonize - * - * Daemonize ltt-sessiond. - */ -static void daemonize(void) -{ - pid_t pid, sid; - const char *home_dir = get_home_dir(); - - /* Fork off the parent process */ - if ((pid = fork()) < 0) { - perror("fork"); - exit(EXIT_FAILURE); - } - - /* Parent can now exit */ - if (pid > 0) { - exit(EXIT_SUCCESS); - } - - /* Change the file mode mask */ - umask(0); - - /* Create a new SID for the child process */ - if ((sid = setsid()) < 0) { - perror("setsid"); - exit(EXIT_FAILURE); - } - - /* Change the current working directory */ - if ((chdir(home_dir)) < 0) { - perror("chdir"); - exit(EXIT_FAILURE); - } - - /* Close out the standard file descriptors */ - close(STDIN_FILENO); - close(STDOUT_FILENO); - close(STDERR_FILENO); -} - /* * set_signal_handler * @@ -724,6 +775,7 @@ static void sighandler(int sig) case SIGINT: case SIGTERM: cleanup(); + break; default: break; } @@ -765,7 +817,11 @@ int main(int argc, char **argv) /* Daemonize */ if (opt_daemon) { - daemonize(); + ret = daemon(0, 0); + if (ret < 0) { + perror("daemon"); + goto error; + } } /* Check if daemon is UID = 0 */ @@ -817,6 +873,11 @@ int main(int argc, char **argv) goto error; } + /* Get parent pid if -S, --sig-parent is specified. */ + if (opt_sig_parent) { + ppid = getppid(); + } + while (1) { /* Create thread to manage the client socket */ ret = pthread_create(&threads[0], NULL, thread_manage_clients, (void *) NULL);