X-Git-Url: https://git.lttng.org/?p=lttng-tools.git;a=blobdiff_plain;f=ltt-sessiond%2Fltt-sessiond.c;h=45f79a70980a4506b5dfc34f57f0cf17622cce7c;hp=050c67397345eb0fa97a04239342959364926d90;hb=c01bdd9d853345f49985ed448198bf1a8ac27e79;hpb=53094c051fe98f0d7288e463b2304e0139324f8c diff --git a/ltt-sessiond/ltt-sessiond.c b/ltt-sessiond/ltt-sessiond.c index 050c67397..45f79a709 100644 --- a/ltt-sessiond/ltt-sessiond.c +++ b/ltt-sessiond/ltt-sessiond.c @@ -35,10 +35,13 @@ #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; @@ -47,29 +50,42 @@ 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 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 find_app_by_pid(pid_t pid); static int init_daemon_socket(void); 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 add_traceable_app(struct ltt_traceable_app *lta); +static void del_traceable_app(struct ltt_traceable_app *lta); +static void add_session_list(struct ltt_session *ls); +static void del_session_list(struct ltt_session *ls); -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; @@ -95,6 +111,9 @@ static struct ltt_traceable_app_list ltt_traceable_app_list = { .head = CDS_LIST_HEAD_INIT(ltt_traceable_app_list.head), }; +/* List mutex */ +pthread_mutex_t ltt_traceable_app_list_mutex; + /* * thread_manage_apps * @@ -142,26 +161,16 @@ static void *thread_manage_apps(void *data) lta = malloc(sizeof(struct ltt_traceable_app)); lta->pid = reg_msg.pid; lta->uid = reg_msg.uid; - cds_list_add(<a->list, <t_traceable_app_list.head); - traceable_app_count++; + add_traceable_app(lta); } 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--; - } + del_traceable_app(lta); + free(lta); break; } } - - /* If an item was found, free it from memory */ - if (lta) { - free(lta); - } } } @@ -206,7 +215,7 @@ 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; } @@ -226,6 +235,62 @@ error: return NULL; } +/* + * add_traceable_app + * + * Add a traceable application structure to the global + * list protected by a mutex. + */ +static void add_traceable_app(struct ltt_traceable_app *lta) +{ + pthread_mutex_lock(<t_traceable_app_list_mutex); + cds_list_add(<a->list, <t_traceable_app_list.head); + traceable_app_count++; + pthread_mutex_unlock(<t_traceable_app_list_mutex); +} + +/* + * del_traceable_app + * + * Delete a traceable application structure from the + * global list protected by a mutex. + */ +static void del_traceable_app(struct ltt_traceable_app *lta) +{ + pthread_mutex_lock(<t_traceable_app_list_mutex); + cds_list_del(<a->list); + /* Sanity check */ + if (traceable_app_count != 0) { + traceable_app_count--; + } + pthread_mutex_unlock(<t_traceable_app_list_mutex); +} + +/* + * add_session_list + * + * Add a ltt_session structure to the global list. + */ +static void add_session_list(struct ltt_session *ls) +{ + cds_list_add(&ls->list, <t_session_list.head); + session_count++; +} + +/* + * del_session_list + * + * Delete a ltt_session structure to the global list. + */ +static void del_session_list(struct ltt_session *ls) +{ + cds_list_del(&ls->list); + /* Sanity check */ + if (session_count != 0) { + session_count--; + } +} + /* * send_unix_sock * @@ -248,14 +313,22 @@ static int send_unix_sock(int sock, void *buf, size_t len) * * Return a socket connected to the libust communication socket * of the application identified by the pid. + * + * If the pid is not found in the traceable list, + * return -1 to indicate error. */ static int connect_app(pid_t pid) { - int sock; + int sock, ret; + + ret = find_app_by_pid(pid); + if (ret == 0) { + return -1; + } 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; @@ -292,13 +365,37 @@ error: } /* - * find_session + * find_app_by_pid + * + * Iterate over the traceable apps list. + * On success, return 1, else return 0 + */ +static int find_app_by_pid(pid_t pid) +{ + struct ltt_traceable_app *iter; + + pthread_mutex_lock(<t_traceable_app_list_mutex); + cds_list_for_each_entry(iter, <t_traceable_app_list.head, list) { + if (iter->pid == pid) { + pthread_mutex_unlock(<t_traceable_app_list_mutex); + /* Found */ + return 1; + } + } + pthread_mutex_unlock(<t_traceable_app_list_mutex); + + return 0; +} + +/* + * 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)) { @@ -306,12 +403,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; } @@ -320,30 +446,34 @@ 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)) { - cds_list_del(&iter->list); + if (uuid_compare(iter->uuid, *uuid) == 0) { + del_session_list(iter); + free(iter); + 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; @@ -360,7 +490,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; } } @@ -380,9 +510,7 @@ static int create_session(const char *name, uuid_t *session_id) CDS_INIT_LIST_HEAD(&new_session->lttng_traces); /* Add new session to the global session list */ - cds_list_add(&new_session->list, <t_session_list.head); - - session_count++; + add_session_list(new_session); return 0; @@ -391,36 +519,96 @@ error: } /* - * ust_list_apps + * ust_create_trace * - * List traceable user-space application and fill an - * array of pids. - * - * Return size of the array. + * Create an userspace trace using pid. + * This trace is then appended to the current session + * ust trace list. */ -static size_t ust_list_apps(pid_t **pids) +static int ust_create_trace(pid_t pid) { - size_t size = 0; - struct ltt_traceable_app *iter = NULL; - pid_t *p; + int sock, ret; + struct ltt_ust_trace *trace; - if (traceable_app_count == 0) { - /* No dynamic allocation is done */ - goto end; + trace = malloc(sizeof(struct ltt_ust_trace)); + if (trace == NULL) { + perror("malloc"); + ret = -1; + goto error; } - p = malloc(sizeof(pid_t) * traceable_app_count); + /* Init */ + trace->pid = pid; + trace->shmid = 0; + + /* Connect to app using ustctl API */ + sock = connect_app(pid); + if (sock < 0) { + ret = LTTCOMM_NO_TRACEABLE; + goto error; + } - /* TODO: Mutex needed to access this list */ + ret = ustctl_create_trace(sock, "auto"); + if (ret < 0) { + ret = LTTCOMM_CREATE_FAIL; + goto error; + } + + /* Check if current session is valid */ + if (current_session) { + cds_list_add(&trace->list, ¤t_session->ust_traces); + } + +error: + return ret; +} + +/* + * get_list_apps + * + * List traceable user-space application and fill an + * array of pids. + */ +static void get_list_apps(pid_t *pids) +{ + int i = 0; + struct ltt_traceable_app *iter; + + /* Protected by a mutex here because the threads manage_client + * and manage_apps can access this list. + */ + pthread_mutex_lock(<t_traceable_app_list_mutex); cds_list_for_each_entry(iter, <t_traceable_app_list.head, list) { - p[size] = iter->pid; - size++; + pids[i] = iter->pid; + i++; } + pthread_mutex_unlock(<t_traceable_app_list_mutex); +} - *pids = p; +/* + * 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; -end: - return size; + /* 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)); + } } /* @@ -432,10 +620,47 @@ static void copy_common_data(struct lttcomm_lttng_msg *llm, struct lttcomm_sessi { llm->cmd_type = lsm->cmd_type; llm->pid = lsm->pid; + + /* Manage uuid */ 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)); + + strncpy(llm->trace_name, lsm->trace_name, strlen(llm->trace_name)); + llm->trace_name[strlen(llm->trace_name) - 1] = '\0'; +} + +/* + * setup_data_buffer + * + * Setup the outgoing data buffer for the response + * data allocating the right amount of memory. + * + * Return total size of the buffer pointed by buf. + */ +static int setup_data_buffer(char **buf, size_t s_data, struct lttcomm_lttng_msg *llm) +{ + int ret = 0; + size_t buf_size; + + buf_size = sizeof(struct lttcomm_lttng_msg) + s_data; + *buf = malloc(buf_size); + if (*buf == NULL) { + perror("malloc"); + 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; } /* @@ -450,6 +675,8 @@ static void copy_common_data(struct lttcomm_lttng_msg *llm, struct lttcomm_sessi 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 @@ -457,6 +684,19 @@ static int process_client_msg(int sock, struct lttcomm_session_msg *lsm) */ copy_common_data(&llm, lsm); + /* Check command that needs a session */ + if (lsm->cmd_type != LTTNG_CREATE_SESSION && + lsm->cmd_type != LTTNG_LIST_SESSIONS && + lsm->cmd_type != UST_LIST_APPS) + { + current_session = find_session_by_uuid(lsm->session_id); + if (current_session == NULL) { + ret = LTTCOMM_SELECT_SESS; + goto end; + } + } + + /* Default return code. * In our world, everything is OK... right? ;) */ @@ -464,26 +704,81 @@ static int process_client_msg(int sock, struct lttcomm_session_msg *lsm) /* 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: + { + ret = ust_create_trace(lsm->pid); + if (ret < 0) { + ret = LTTCOMM_CREATE_FAIL; + goto end; + } + + /* No auxiliary data so only send the llm struct. */ + goto end; + } case UST_LIST_APPS: { - pid_t *pids; - llm.num_pckt = ust_list_apps(&pids); - if (llm.num_pckt == 0) { + /* Stop right now if no apps */ + if (traceable_app_count == 0) { ret = LTTCOMM_NO_APPS; - goto error; + goto end; } - /* 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--; + /* 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; } - /* Allocated array by ust_list_apps() */ - free(pids); + + 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; } @@ -491,21 +786,25 @@ static int process_client_msg(int sock, struct lttcomm_session_msg *lsm) { /* Undefined command */ ret = LTTCOMM_UND; - break; + goto end; } } - return 0; + ret = send_unix_sock(sock, send_buf, buf_size); + + if (send_buf != NULL) { + free(send_buf); + } -send_error: return ret; -error: +end: /* Notify client of error */ llm.ret_code = ret; + llm.size_payload = 0; send_unix_sock(sock, (void*) &llm, sizeof(llm)); - return -1; + return ret; } /* @@ -520,7 +819,8 @@ static void usage(void) "\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-S, --sig-parent\t\tSend SIGCHLD to parent pid to notify readiness.\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); } @@ -539,12 +839,13 @@ static int parse_args(int argc, char **argv) { "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, "dhVS" "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; } @@ -577,6 +878,9 @@ static int parse_args(int argc, char **argv) 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 */ @@ -687,7 +991,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; } @@ -748,6 +1052,7 @@ static void sighandler(int sig) { switch (sig) { case SIGPIPE: + return; case SIGINT: case SIGTERM: cleanup(); @@ -767,8 +1072,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); @@ -831,7 +1136,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; }