/* * set_session */ static int set_session(void) { int ret = CMD_SUCCESS; int count, i; unsigned int session_found = 0; struct lttng_session *sessions; if (opt_session_name && strlen(opt_session_name) > NAME_MAX) { ERR("Session name too long. Length must be lower or equal to %d", NAME_MAX); ret = CMD_ERROR; goto end; } count = lttng_list_sessions(&sessions); if (count < 0) { ret = CMD_ERROR; ERR("%s", lttng_strerror(count)); goto end; } for (i = 0; i < count; i++) { if (strncmp(sessions[i].name, opt_session_name, NAME_MAX) == 0) { session_found = 1; break; } } if (!session_found) { ERR("Session '%s' not found", opt_session_name); ret = CMD_ERROR; goto error; } ret = config_init(opt_session_name); if (ret < 0) { ERR("Unable to set session name"); ret = CMD_ERROR; goto error; } MSG("Session set to %s", opt_session_name); if (lttng_opt_mi) { ret = mi_print(opt_session_name); if (ret) { ret = CMD_ERROR; goto error; } } ret = CMD_SUCCESS; error: free(sessions); end: return ret; }
/* * List available tracing session. List only basic information. * * If session_name is NULL, all sessions are listed. */ static int list_sessions(const char *session_name) { int ret, count, i; unsigned int session_found = 0; struct lttng_session *sessions; count = lttng_list_sessions(&sessions); DBG("Session count %d", count); if (count < 0) { ret = count; goto error; } else if (count == 0) { MSG("Currently no available tracing session"); goto end; } if (session_name == NULL) { MSG("Available tracing sessions:"); } for (i = 0; i < count; i++) { if (session_name != NULL) { if (strncmp(sessions[i].name, session_name, NAME_MAX) == 0) { session_found = 1; MSG("Tracing session %s:%s", session_name, active_string(sessions[i].enabled)); MSG("%sTrace path: %s\n", indent4, sessions[i].path); break; } continue; } MSG(" %d) %s (%s)%s", i + 1, sessions[i].name, sessions[i].path, active_string(sessions[i].enabled)); if (session_found) { break; } } free(sessions); if (!session_found && session_name != NULL) { ERR("Session '%s' not found", session_name); ret = CMD_ERROR; goto error; } if (session_name == NULL) { MSG("\nUse lttng list <session_name> for more details"); } end: return CMD_SUCCESS; error: return ret; }
/* * Retrieve the created session and mi output it based on provided argument * This is currently a summary of what was pretty printed and is subject to * enhancements. */ static int mi_created_session(const char *session_name) { int ret, i, count, found; struct lttng_session *sessions; /* session_name should not be null */ assert(session_name); assert(writer); count = lttng_list_sessions(&sessions); if (count < 0) { ret = count; ERR("%s", lttng_strerror(ret)); goto error; } if (count == 0) { ERR("Error session creation failed: session %s not found", session_name); ret = -LTTNG_ERR_SESS_NOT_FOUND; goto end; } found = 0; for (i = 0; i < count; i++) { if (strncmp(sessions[i].name, session_name, NAME_MAX) == 0) { found = 1; ret = mi_lttng_session(writer, &sessions[i], 0); if (ret) { goto error; } break; } } if (!found) { ret = -LTTNG_ERR_SESS_NOT_FOUND; } else { ret = CMD_SUCCESS; } error: free(sessions); end: return ret; }
/* * Exec viewer if found and use session name path. */ static int view_trace(void) { int ret; char *session_name, *trace_path = NULL; struct lttng_session *sessions = NULL; /* * Safety net. If lttng is suid at some point for *any* useless reasons, * this prevent any bad execution of binaries. */ if (getuid() != 0) { if (getuid() != geteuid()) { ERR("UID does not match effective UID."); ret = CMD_ERROR; goto error; } else if (getgid() != getegid()) { ERR("GID does not match effective GID."); ret = CMD_ERROR; goto error; } } /* User define trace path override the session name */ if (opt_trace_path) { session_name = NULL; } else if(opt_session_name == NULL) { session_name = get_session_name(); if (session_name == NULL) { ret = CMD_ERROR; goto error; } } else { session_name = opt_session_name; } DBG("Viewing trace for session %s", session_name); if (session_name) { int i, count, found = 0; /* Getting all sessions */ count = lttng_list_sessions(&sessions); if (count < 0) { ERR("Unable to list sessions. Session name %s not found.", session_name); MSG("Is there a session daemon running?"); ret = CMD_ERROR; goto free_error; } /* Find our session listed by the session daemon */ for (i = 0; i < count; i++) { if (strncmp(sessions[i].name, session_name, NAME_MAX) == 0) { found = 1; break; } } if (!found) { MSG("Session name %s not found", session_name); ret = CMD_ERROR; goto free_sessions; } session_live_mode = sessions[i].live_timer_interval; DBG("Session live mode set to %d", session_live_mode); if (sessions[i].enabled && !session_live_mode) { WARN("Session %s is running. Please stop it before reading it.", session_name); ret = CMD_ERROR; goto free_sessions; } /* If the timer interval is set we are in live mode. */ if (session_live_mode) { trace_path = build_live_path(session_name); if (!trace_path) { ret = CMD_ERROR; goto free_sessions; } } else { /* Get file system session path. */ trace_path = sessions[i].path; } } else { trace_path = opt_trace_path; } MSG("Trace directory: %s\n", trace_path); ret = spawn_viewer(trace_path); if (ret < 0) { /* Don't set ret so lttng can interpret the sessiond error. */ goto free_sessions; } free_sessions: if (session_live_mode) { free(trace_path); } free(sessions); free_error: if (opt_session_name == NULL) { free(session_name); } error: return ret; }
/* * The 'destroy <options>' first level command */ int cmd_destroy(int argc, const char **argv) { int opt; int ret = CMD_SUCCESS , i, command_ret = CMD_SUCCESS, success = 1; static poptContext pc; char *session_name = NULL; const char *leftover = NULL; struct lttng_session *sessions; int count; int found; pc = poptGetContext(NULL, argc, argv, long_options, 0); poptReadDefaultConfig(pc, 0); while ((opt = poptGetNextOpt(pc)) != -1) { switch (opt) { case OPT_HELP: SHOW_HELP(); break; case OPT_LIST_OPTIONS: list_cmd_options(stdout, long_options); break; default: ret = CMD_UNDEFINED; break; } goto end; } /* Mi preparation */ if (lttng_opt_mi) { writer = mi_lttng_writer_create(fileno(stdout), lttng_opt_mi); if (!writer) { ret = -LTTNG_ERR_NOMEM; goto end; } /* Open command element */ ret = mi_lttng_writer_command_open(writer, mi_lttng_element_command_destroy); if (ret) { ret = CMD_ERROR; goto end; } /* Open output element */ ret = mi_lttng_writer_open_element(writer, mi_lttng_element_command_output); if (ret) { ret = CMD_ERROR; goto end; } /* For validation and semantic purpose we open a sessions element */ ret = mi_lttng_sessions_open(writer); if (ret) { ret = CMD_ERROR; goto end; } } /* Recuperate all sessions for further operation */ count = lttng_list_sessions(&sessions); if (count < 0) { ERR("%s", lttng_strerror(count)); command_ret = CMD_ERROR; success = 0; goto mi_closing; } /* Ignore session name in case all sessions are to be destroyed */ if (opt_destroy_all) { command_ret = destroy_all_sessions(sessions, count); if (command_ret) { success = 0; } } else { opt_session_name = (char *) poptGetArg(pc); if (!opt_session_name) { /* No session name specified, lookup default */ session_name = get_session_name(); if (session_name == NULL) { command_ret = CMD_ERROR; success = 0; goto mi_closing; } } else { session_name = opt_session_name; } /* Find the corresponding lttng_session struct */ found = 0; for (i = 0; i < count; i++) { if (strncmp(sessions[i].name, session_name, NAME_MAX) == 0) { found = 1; command_ret = destroy_session(&sessions[i]); if (command_ret) { success = 0; } } } if (!found) { ERR("Session name %s not found", session_name); command_ret = LTTNG_ERR_SESS_NOT_FOUND; success = 0; goto mi_closing; } } leftover = poptGetArg(pc); if (leftover) { ERR("Unknown argument: %s", leftover); ret = CMD_ERROR; success = 0; goto mi_closing; } mi_closing: /* Mi closing */ if (lttng_opt_mi) { /* Close sessions and output element element */ ret = mi_lttng_close_multi_element(writer, 2); if (ret) { ret = CMD_ERROR; goto end; } /* Success ? */ ret = mi_lttng_writer_write_element_bool(writer, mi_lttng_element_command_success, success); if (ret) { ret = CMD_ERROR; goto end; } /* Command element close */ ret = mi_lttng_writer_command_close(writer); if (ret) { ret = CMD_ERROR; goto end; } } end: /* Mi clean-up */ if (writer && mi_lttng_writer_destroy(writer)) { /* Preserve original error code */ ret = ret ? ret : -LTTNG_ERR_MI_IO_FAIL; } if (opt_session_name == NULL) { free(session_name); } /* Overwrite ret if an error occurred during destroy_session/all */ ret = command_ret ? command_ret : ret; poptFreeContext(pc); return ret; }
/* * List available tracing session. List only basic information. * * If session_name is NULL, all sessions are listed. */ static int list_sessions(const char *session_name) { int ret = CMD_SUCCESS; int count, i; unsigned int session_found = 0; struct lttng_session *sessions; count = lttng_list_sessions(&sessions); DBG("Session count %d", count); if (count < 0) { ret = CMD_ERROR; ERR("%s", lttng_strerror(count)); goto end; } if (lttng_opt_mi) { /* Mi */ if (session_name == NULL) { /* List all session */ ret = mi_list_sessions(sessions, count); } else { /* Note : this return an open session element */ ret = mi_list_session(session_name, sessions, count); } if (ret) { ret = CMD_ERROR; goto error; } } else { /* Pretty print */ if (count == 0) { MSG("Currently no available tracing session"); goto end; } if (session_name == NULL) { MSG("Available tracing sessions:"); } for (i = 0; i < count; i++) { if (session_name != NULL) { if (strncmp(sessions[i].name, session_name, NAME_MAX) == 0) { session_found = 1; MSG("Tracing session %s: [%s%s]", session_name, active_string(sessions[i].enabled), snapshot_string(sessions[i].snapshot_mode)); MSG("%sTrace path: %s\n", indent4, sessions[i].path); break; } } else { MSG(" %d) %s (%s) [%s%s]", i + 1, sessions[i].name, sessions[i].path, active_string(sessions[i].enabled), snapshot_string(sessions[i].snapshot_mode)); MSG("%sTrace path: %s", indent4, sessions[i].path); if (sessions[i].live_timer_interval != 0) { MSG("%sLive timer interval (usec): %u", indent4, sessions[i].live_timer_interval); } MSG(""); } } if (!session_found && session_name != NULL) { ERR("Session '%s' not found", session_name); ret = CMD_ERROR; goto error; } if (session_name == NULL) { MSG("\nUse lttng list <session_name> for more details"); } } error: free(sessions); end: return ret; }
/* * Create a tracing session. * If no name is specified, a default name is generated. * * Returns one of the CMD_* result constants. */ static int create_session(void) { int ret, i; char shm_path[LTTNG_PATH_MAX] = {}; struct lttng_session_descriptor *session_descriptor = NULL; enum lttng_session_descriptor_status descriptor_status; enum lttng_error_code ret_code; struct lttng_session *sessions = NULL; const struct lttng_session *created_session = NULL; const char *created_session_name; /* Validate options. */ if (opt_session_name) { if (strlen(opt_session_name) > NAME_MAX) { ERR("Session name too long. Length must be lower or equal to %d", NAME_MAX); ret = CMD_ERROR; goto error; } /* * Check if the session name begins with "auto-" or is exactly "auto". * Both are reserved for the default session name. See bug #449 to * understand why we need to check both here. */ if ((strncmp(opt_session_name, DEFAULT_SESSION_NAME "-", strlen(DEFAULT_SESSION_NAME) + 1) == 0) || (strncmp(opt_session_name, DEFAULT_SESSION_NAME, strlen(DEFAULT_SESSION_NAME)) == 0 && strlen(opt_session_name) == strlen(DEFAULT_SESSION_NAME))) { ERR("%s is a reserved keyword for default session(s)", DEFAULT_SESSION_NAME); ret = CMD_ERROR; goto error; } } if (opt_snapshot && opt_live_timer) { ERR("Snapshot and live modes are mutually exclusive."); ret = CMD_ERROR; goto error; } if ((!opt_ctrl_url && opt_data_url) || (opt_ctrl_url && !opt_data_url)) { ERR("Both control and data URLs must be specified."); ret = CMD_ERROR; goto error; } session_descriptor = create_session_descriptor(); if (!session_descriptor) { ret = CMD_ERROR; goto error; } ret_code = lttng_create_session_ext(session_descriptor); if (ret_code != LTTNG_OK) { ERR("%s", lttng_strerror(-ret_code)); ret = CMD_ERROR; goto error; } descriptor_status = lttng_session_descriptor_get_session_name( session_descriptor, &created_session_name); if (descriptor_status != LTTNG_SESSION_DESCRIPTOR_STATUS_OK) { ERR("Failed to obtain created session name"); ret = CMD_ERROR; goto error; } ret = lttng_list_sessions(&sessions); if (ret < 0) { ERR("Failed to fetch properties of created session: %s", lttng_strerror(ret)); ret = CMD_ERROR; goto error; } for (i = 0; i < ret; i++) { if (!strcmp(created_session_name, sessions[i].name)) { created_session = &sessions[i]; break; } } if (!created_session) { ERR("Failed to fetch properties of created session"); ret = CMD_ERROR; goto error; } if (opt_shm_path) { char datetime_suffix[17] = {}; /* * An auto-generated session name already includes the creation * timestamp. */ if (opt_session_name) { uint64_t creation_time; struct tm *timeinfo; time_t creation_time_t; size_t strftime_ret; ret_code = lttng_session_get_creation_time( created_session, &creation_time); if (ret_code != LTTNG_OK) { ERR("%s", lttng_strerror(-ret_code)); ret = CMD_ERROR; goto error; } creation_time_t = (time_t) creation_time; timeinfo = localtime(&creation_time_t); if (!timeinfo) { PERROR("Failed to interpret session creation time"); ret = CMD_ERROR; goto error; } strftime_ret = strftime(datetime_suffix, sizeof(datetime_suffix), "-%Y%m%d-%H%M%S", timeinfo); if (strftime_ret == 0) { ERR("Failed to format session creation time."); ret = CMD_ERROR; goto error; } } ret = snprintf(shm_path, sizeof(shm_path), "%s/%s%s", opt_shm_path, created_session_name, datetime_suffix); if (ret < 0 || ret >= sizeof(shm_path)) { ERR("Failed to format the shared memory path."); ret = CMD_ERROR; goto error; } ret = lttng_set_session_shm_path(created_session_name, shm_path); if (ret < 0) { lttng_destroy_session(created_session_name); ret = CMD_ERROR; goto error; } } if (opt_snapshot) { MSG("Snapshot session %s created.", created_session_name); } else if (opt_live_timer) { MSG("Live session %s created.", created_session_name); } else { MSG("Session %s created.", created_session_name); } if (*created_session->path && !opt_snapshot) { MSG("Traces will be output to %s", created_session->path); if (opt_live_timer) { MSG("Live timer interval set to %u %s", opt_live_timer, USEC_UNIT); } } else if (opt_snapshot) { struct lttng_snapshot_output_list *list; struct lttng_snapshot_output *iter; char snapshot_url[LTTNG_PATH_MAX] = {}; ret = lttng_snapshot_list_output(created_session_name, &list); if (ret < 0) { ERR("Failed to list snapshot outputs."); ret = CMD_ERROR; goto error; } while ((iter = lttng_snapshot_output_list_get_next(list))) { const char *url = NULL; url = lttng_snapshot_output_get_ctrl_url( iter); ret = lttng_strncpy(snapshot_url, url, sizeof(snapshot_url)); if (ret) { snapshot_url[0] = '\0'; ERR("Failed to retrieve snapshot output destination"); } break; } lttng_snapshot_output_list_destroy(list); if (*snapshot_url) { MSG("Default snapshot output set to %s", snapshot_url); } MSG("Every channel enabled for this session will be set to mmap output and default to overwrite mode."); } if (opt_shm_path) { MSG("Shared memory path set to %s", shm_path); } /* Mi output */ if (lttng_opt_mi) { ret = mi_created_session(created_session_name); if (ret) { ret = CMD_ERROR; goto error; } } /* Init lttng session config */ ret = config_init(created_session_name); if (ret < 0) { ret = CMD_ERROR; goto error; } ret = CMD_SUCCESS; error: lttng_session_descriptor_destroy(session_descriptor); free(sessions); return ret; }