X-Git-Url: https://git.lttng.org/?p=lttng-tools.git;a=blobdiff_plain;f=ltt-sessiond%2Fltt-sessiond.c;h=6df78d8e3c40cb88d11301d66be4878aabd77fcf;hp=08d1555a8a45f39148c638236d864ff6a863e6b8;hb=df0da1392bb6c77fff7fc65be518dce7de457ed7;hpb=fac6795d6e2c60e79bdc7dab42da94d2025a57d3 diff --git a/ltt-sessiond/ltt-sessiond.c b/ltt-sessiond/ltt-sessiond.c index 08d1555a8..6df78d8e3 100644 --- a/ltt-sessiond/ltt-sessiond.c +++ b/ltt-sessiond/ltt-sessiond.c @@ -1,4 +1,5 @@ -/* Copyright (C) 2011 - David Goulet +/* + * Copyright (C) 2011 - David Goulet * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -13,7 +14,6 @@ * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - * */ #define _GNU_SOURCE @@ -35,35 +35,54 @@ #include /* URCU list library (-lurcu) */ #include /* UST control lib (-lust) */ +#include #include "liblttsessiondcomm.h" #include "ltt-sessiond.h" +#include "lttngerr.h" + +/* Const values */ +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 sighandler(int sig); 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 notify_apps(const char* name); +static int connect_app(pid_t pid); 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 int setup_data_buffer(char **buf, size_t size, struct lttcomm_lttng_msg *llm); -static void *thread_manage_clients(void *); -static void *thread_manage_apps(void *); +/* Command function */ +static void get_list_apps(pid_t *pids); +static void get_list_sessions(struct lttng_session *lt); -static int create_session(const char*, uuid_t *); -static void destroy_session(uuid_t); +static void *thread_manage_clients(void *data); +static void *thread_manage_apps(void *data); -static struct ltt_session *find_session(uuid_t); +static int create_session(char *name, uuid_t *session_id); +static int destroy_session(uuid_t *uuid); + +static struct ltt_session *find_session_by_uuid(uuid_t session_id); +static struct ltt_session *find_session_by_name(char *name); /* Variables */ const char *progname; const char *opt_tracing_group; +static int opt_sig_parent; static int opt_daemon; +int opt_verbose; +int opt_quiet; 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 +91,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 +117,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 +154,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 +191,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); @@ -183,34 +217,19 @@ static void *thread_manage_clients(void *data) * request of the client. */ ret = lttcomm_recv_unix_sock(sock, &lsm, sizeof(lsm)); - if (ret < 0) { + if (ret <= 0) { continue; } /* 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 +237,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 * @@ -230,7 +266,7 @@ static int connect_app(pid_t pid) sock = ustctl_connect_pid(pid); if (sock < 0) { - fprintf(stderr, "Fail connecting to the PID %d\n", pid); + ERR("Fail connecting to the PID %d\n", pid); } return sock; @@ -267,13 +303,14 @@ error: } /* - * find_session + * find_session_by_uuid * * Return a ltt_session structure ptr that matches the uuid. */ -static struct ltt_session *find_session(uuid_t session_id) +static struct ltt_session *find_session_by_uuid(uuid_t session_id) { - struct ltt_session *iter = NULL; + int found = 0; + struct ltt_session *iter; /* Sanity check for NULL session_id */ if (uuid_is_null(session_id)) { @@ -281,12 +318,41 @@ static struct ltt_session *find_session(uuid_t session_id) } cds_list_for_each_entry(iter, <t_session_list.head, list) { - if (uuid_compare(iter->uuid, session_id)) { + if (uuid_compare(iter->uuid, session_id) == 0) { + found = 1; break; } } end: + if (!found) { + iter = NULL; + } + return iter; +} + +/* + * find_session_by_name + * + * Return a ltt_session structure ptr that matches name. + * If no session found, NULL is returned. + */ +static struct ltt_session *find_session_by_name(char *name) +{ + int found = 0; + struct ltt_session *iter; + + cds_list_for_each_entry(iter, <t_session_list.head, list) { + if (strncmp(iter->name, name, strlen(iter->name)) == 0) { + found = 1; + break; + } + } + + if (!found) { + iter = NULL; + } + return iter; } @@ -295,30 +361,35 @@ end: * * Delete session from the global session list * and free the memory. + * + * Return -1 if no session is found. + * On success, return 1; */ -static void destroy_session(uuid_t session_id) +static int destroy_session(uuid_t *uuid) { - struct ltt_session *iter = NULL; + int found = -1; + struct ltt_session *iter; cds_list_for_each_entry(iter, <t_session_list.head, list) { - if (uuid_compare(iter->uuid, session_id)) { + if (uuid_compare(iter->uuid, *uuid) == 0) { cds_list_del(&iter->list); + free(iter); + session_count--; + found = 1; break; } } - if (iter) { - free(iter); - session_count--; - } + return found; } /* * create_session * - * Create a brand new session, + * Create a brand new session and add it to the + * global session list. */ -static int create_session(const char *name, uuid_t *session_id) +static int create_session(char *name, uuid_t *session_id) { struct ltt_session *new_session; @@ -335,7 +406,7 @@ static int create_session(const char *name, uuid_t *session_id) } } else { /* Generate session name based on the session count */ - if (asprintf(&new_session->name, "%s%d", "auto", session_count) < 0) { + if (asprintf(&new_session->name, "%s%d", "lttng-", session_count) < 0) { goto error; } } @@ -366,82 +437,233 @@ error: } /* - * ust_list_apps + * get_list_apps * * List traceable user-space application and fill an * array of pids. - * - * Return size of the array. */ -static size_t ust_list_apps(pid_t *pids) +static void get_list_apps(pid_t *pids) { - size_t size = 0; - struct ltt_traceable_app *iter = NULL; + int i = 0; + struct ltt_traceable_app *iter; + /* TODO: Mutex needed to access this list */ cds_list_for_each_entry(iter, <t_traceable_app_list.head, list) { - if (size >= MAX_APPS_PID) { - break; - } + pids[i] = iter->pid; + i++; + } +} + +/* + * get_list_sessions + * + * List sessions and fill the data buffer. + */ +static void get_list_sessions(struct lttng_session *lt) +{ + int i = 0; + struct ltt_session *iter; + struct lttng_session lsess; + + /* Iterate over session list and append data after + * the control struct in the buffer. + */ + cds_list_for_each_entry(iter, <t_session_list.head, list) { + /* Copy name and uuid */ + uuid_unparse(iter->uuid, lsess.uuid); + strncpy(lsess.name, iter->name, sizeof(lsess.name)); + lsess.name[sizeof(lsess.name) - 1] = '\0'; + memcpy(<[i], &lsess, sizeof(lsess)); + i++; + /* Reset struct for next pass */ + memset(&lsess, 0, sizeof(lsess)); + } +} + +/* + * 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; - pids[size] = iter->pid; - size++; + /* Manage uuid */ + if (!uuid_is_null(lsm->session_id)) { + uuid_copy(llm->session_id, lsm->session_id); } - return size; + strncpy(llm->trace_name, lsm->trace_name, strlen(llm->trace_name)); + llm->trace_name[strlen(llm->trace_name) - 1] = '\0'; } /* - * process_client_msg + * setup_data_buffer * - * 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. + * Setup the outgoing data buffer for the response + * data allocating the right amount of memory. * - * It's the caller responsability to free that structure when done with it. - * - * Return pointer to lttcomm_lttng_msg allocated struct. + * Return total size of the buffer pointed by buf. */ -static struct lttcomm_lttng_msg *process_client_msg(struct lttcomm_session_msg *lsm) +static int setup_data_buffer(char **buf, size_t s_data, struct lttcomm_lttng_msg *llm) { - struct lttcomm_lttng_msg *llm; + int ret = 0; + size_t buf_size; - /* Allocate the reply message structure */ - llm = malloc(sizeof(struct lttcomm_lttng_msg)); - if (llm == NULL) { + buf_size = sizeof(struct lttcomm_lttng_msg) + s_data; + *buf = malloc(buf_size); + if (*buf == NULL) { perror("malloc"); - goto end; + ret = -1; + goto error; } + /* Setup lttcomm_lttng_msg data and copy + * it to the newly allocated buffer. + */ + llm->size_payload = s_data; + memcpy(*buf, llm, sizeof(struct lttcomm_lttng_msg)); + + return buf_size; + +error: + return ret; +} + +/* + * process_client_msg + * + * This takes the lttcomm_session_msg struct and process the command requested + * by the client. It then creates response(s) and send it back to the + * given socket (sock). + * + * Return any error encountered or 0 for success. + */ +static int process_client_msg(int sock, struct lttcomm_session_msg *lsm) +{ + int ret; + int buf_size; + char *send_buf = NULL; + 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 LTTNG_CREATE_SESSION: + { + ret = create_session(lsm->session_name, &llm.session_id); + if (ret < 0) { + goto end; + } + + buf_size = setup_data_buffer(&send_buf, 0, &llm); + if (buf_size < 0) { + ret = LTTCOMM_FATAL; + goto end; + } + + break; + } + case LTTNG_DESTROY_SESSION: + { + ret = destroy_session(&lsm->session_id); + if (ret < 0) { + ret = LTTCOMM_NO_SESS; + } else { + ret = LTTCOMM_OK; + } + + /* No auxiliary data so only send the llm struct. */ + goto end; + } + case UST_CREATE_TRACE: + { + int sock; + sock = connect_app(lsm->pid); + + ret = ustctl_create_trace(sock, "auto"); + if (ret < 0) { + ret = LTTCOMM_CREATE_FAIL; + } else { + ret = LTTCOMM_OK; + } + + goto end; + } case UST_LIST_APPS: { - llm->u.list_apps.size = ust_list_apps(llm->u.list_apps.pids); + /* Stop right now if no apps */ + if (traceable_app_count == 0) { + ret = LTTCOMM_NO_APPS; + goto end; + } + + /* Setup data buffer and details for transmission */ + buf_size = setup_data_buffer(&send_buf, + sizeof(pid_t) * traceable_app_count, &llm); + if (buf_size < 0) { + ret = LTTCOMM_FATAL; + goto end; + } + + get_list_apps((pid_t *)(send_buf + sizeof(struct lttcomm_lttng_msg))); + + break; + } + case LTTNG_LIST_SESSIONS: + { + /* Stop right now if no session */ + if (session_count == 0) { + ret = LTTCOMM_NO_SESS; + goto end; + } + + /* Setup data buffer and details for transmission */ + buf_size = setup_data_buffer(&send_buf, + (sizeof(struct lttng_session) * session_count), &llm); + if (buf_size < 0) { + ret = LTTCOMM_FATAL; + goto end; + } + + get_list_sessions((struct lttng_session *)(send_buf + sizeof(struct lttcomm_lttng_msg))); + break; } default: + { /* Undefined command */ - llm->ret_code = LTTCOMM_UND; - break; + ret = LTTCOMM_UND; + goto end; + } + } + + ret = send_unix_sock(sock, send_buf, buf_size); + + if (send_buf != NULL) { + free(send_buf); } + return ret; + end: - return llm; + /* Notify client of error */ + llm.ret_code = ret; + llm.size_payload = 0; + send_unix_sock(sock, (void*) &llm, sizeof(llm)); + + return ret; } /* @@ -455,7 +677,9 @@ 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" + "\t-q, --quiet\t\tNo output at all.\n", progname); } @@ -470,15 +694,17 @@ 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' }, + { "quiet", 0, 0, 'q' }, { NULL, 0, 0, 0 } }; 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, "dhqVS" "a:c:g:s:", long_options, &option_index); if (c == -1) { break; } @@ -508,6 +734,12 @@ 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; + case 'q': + opt_quiet = 1; + break; default: /* Unknown option or other error. * Error is printed by getopt, just return */ @@ -595,7 +827,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; } @@ -618,7 +850,7 @@ static int set_socket_perms(void) (grp = getgrnam(default_tracing_group)); if (grp == NULL) { - fprintf(stderr, "Missing tracing group. Aborting execution.\n"); + ERR("Missing tracing group. Aborting execution.\n"); ret = -1; goto end; } @@ -632,48 +864,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 * @@ -721,9 +911,11 @@ static void sighandler(int sig) { switch (sig) { case SIGPIPE: + return; case SIGINT: case SIGTERM: cleanup(); + break; default: break; } @@ -739,8 +931,8 @@ static void sighandler(int sig) static void cleanup() { /* */ - fprintf(stdout, "\n\n%c[%d;%dm*** assert failed *** ==> %c[%dm", 27,1,31,27,0); - fprintf(stdout, "%c[%d;%dm Matthew, BEET driven development works!%c[%dm\n",27,1,33,27,0); + MSG("\n\n%c[%d;%dm*** assert failed *** ==> %c[%dm", 27,1,31,27,0); + MSG("%c[%d;%dm Matthew, BEET driven development works!%c[%dm\n",27,1,33,27,0); /* */ unlink(client_unix_sock_path); @@ -765,7 +957,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 */ @@ -799,7 +995,7 @@ int main(int argc, char **argv) * socket needed by the daemon are present, this test fails */ if ((ret = check_existing_daemon()) == 0) { - fprintf(stderr, "Already running daemon.\n"); + ERR("Already running daemon.\n"); goto error; } @@ -817,6 +1013,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);