X-Git-Url: https://git.lttng.org/?p=lttng-tools.git;a=blobdiff_plain;f=src%2Fbin%2Flttng%2Fcommands%2Fcreate.c;h=0ae2b10968456adc54d4df7f4985458268c4e8f7;hp=4145e14d85e88e15b5d1b025d38881dfa61e856c;hb=8d5841ea483139d3ab2f2b4dd39263dad63832b1;hpb=acc0921507a42345aa6b032231180c7c6999f55a diff --git a/src/bin/lttng/commands/create.c b/src/bin/lttng/commands/create.c index 4145e14d8..0ae2b1096 100644 --- a/src/bin/lttng/commands/create.c +++ b/src/bin/lttng/commands/create.c @@ -15,7 +15,7 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ -#define _GNU_SOURCE +#define _LGPL_SOURCE #include #include #include @@ -26,6 +26,8 @@ #include #include #include +#include +#include #include @@ -43,11 +45,11 @@ static char *opt_session_name; static char *opt_url; static char *opt_ctrl_url; static char *opt_data_url; +static char *opt_shm_path; static int opt_no_consumer; static int opt_no_output; static int opt_snapshot; static unsigned int opt_live_timer; -static int opt_disable_consumer; enum { OPT_HELP = 1, @@ -67,9 +69,9 @@ static struct poptOption long_options[] = { {"data-url", 'D', POPT_ARG_STRING, &opt_data_url, 0, 0, 0}, {"no-output", 0, POPT_ARG_VAL, &opt_no_output, 1, 0, 0}, {"no-consumer", 0, POPT_ARG_VAL, &opt_no_consumer, 1, 0, 0}, - {"disable-consumer", 0, POPT_ARG_VAL, &opt_disable_consumer, 1, 0, 0}, {"snapshot", 0, POPT_ARG_VAL, &opt_snapshot, 1, 0, 0}, {"live", 0, POPT_ARG_INT | POPT_ARGFLAG_OPTIONAL, 0, OPT_LIVE_TIMER, 0, 0}, + {"shm-path", 0, POPT_ARG_STRING, &opt_shm_path, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0} }; @@ -78,85 +80,12 @@ static struct poptOption long_options[] = { * why this declaration exists and used ONLY in for this command. */ extern int _lttng_create_session_ext(const char *name, const char *url, - const char *datetime, int live_timer); + const char *datetime); /* - * usage - */ -static void usage(FILE *ofp) -{ - fprintf(ofp, "usage: lttng create [NAME] [OPTIONS] \n"); - fprintf(ofp, "\n"); - fprintf(ofp, "Without a given NAME, the default is 'auto--'\n"); - fprintf(ofp, "\n"); - fprintf(ofp, "Options:\n"); - fprintf(ofp, " -h, --help Show this help\n"); - fprintf(ofp, " --list-options Simple listing of options\n"); - fprintf(ofp, " -o, --output PATH Specify output path for traces\n"); - fprintf(ofp, " --no-output Traces will not be outputted\n"); - fprintf(ofp, " --snapshot Set the session in snapshot mode.\n"); - fprintf(ofp, " Created in no-output mode and uses the URL,\n"); - fprintf(ofp, " if one, as the default snapshot output.\n"); - fprintf(ofp, " Every channel will be set in overwrite mode\n"); - fprintf(ofp, " and with mmap output (splice not supported).\n"); - fprintf(ofp, " --live [USEC] Set the session in live-reading mode.\n"); - fprintf(ofp, " The delay parameter in micro-seconds is the\n"); - fprintf(ofp, " maximum time the user can wait for the data\n"); - fprintf(ofp, " to be flushed. Can be set with a network\n"); - fprintf(ofp, " URL (-U or -C/-D) and must have a relayd listening.\n"); - fprintf(ofp, " By default, %u is used for the timer and the\n", - DEFAULT_LTTNG_LIVE_TIMER); - fprintf(ofp, " network URL is set to net://127.0.0.1.\n"); - fprintf(ofp, "\n"); - fprintf(ofp, "Extended Options:\n"); - fprintf(ofp, "\n"); - fprintf(ofp, "Using these options, each API call can be controlled individually.\n"); - fprintf(ofp, "\n"); - fprintf(ofp, " -U, --set-url=URL Set URL destination of the trace data.\n"); - fprintf(ofp, " It is persistent for the session lifetime.\n"); - fprintf(ofp, " This will set both data and control URL.\n"); - fprintf(ofp, " You can change it with the enable-consumer cmd\n"); - fprintf(ofp, " -C, --ctrl-url=URL Set control path URL. (Must use -D also)\n"); - fprintf(ofp, " -D, --data-url=URL Set data path URL. (Must use -C also)\n"); - fprintf(ofp, "\n"); - fprintf(ofp, "Please refer to the man page (lttng(1)) for more information on network\n"); - fprintf(ofp, "streaming mechanisms and explanation of the control and data port\n"); - fprintf(ofp, "You must have a running remote lttng-relayd for network streaming\n"); - fprintf(ofp, "\n"); - fprintf(ofp, "URL format is has followed:\n"); - fprintf(ofp, "\n"); - fprintf(ofp, " proto://[HOST|IP][:PORT1[:PORT2]][/TRACE_PATH]\n"); - fprintf(ofp, "\n"); - fprintf(ofp, " Supported protocols are (proto):\n"); - fprintf(ofp, " > file://...\n"); - fprintf(ofp, " Local filesystem full path.\n"); - fprintf(ofp, "\n"); - fprintf(ofp, " > net[6]://...\n"); - fprintf(ofp, " This will use the default network transport layer which is\n"); - fprintf(ofp, " TCP for both control (PORT1) and data port (PORT2).\n"); - fprintf(ofp, " The default ports are respectively 5342 and 5343.\n"); - fprintf(ofp, "\n"); - fprintf(ofp, " > tcp[6]://...\n"); - fprintf(ofp, " Can only be used with -C and -D together\n"); - fprintf(ofp, "\n"); - fprintf(ofp, "NOTE: IPv6 address MUST be enclosed in brackets '[]' (rfc2732)\n"); - fprintf(ofp, "\n"); - fprintf(ofp, "Examples:\n"); - fprintf(ofp, " # lttng create -U net://192.168.1.42\n"); - fprintf(ofp, " Uses TCP and default ports for the given destination.\n"); - fprintf(ofp, " # lttng create -U net6://[fe80::f66d:4ff:fe53:d220]\n"); - fprintf(ofp, " Uses TCP, default ports and IPv6.\n"); - fprintf(ofp, " # lttng create s1 -U net://myhost.com:3229\n"); - fprintf(ofp, " Set the consumer to the remote HOST on port 3229 for control.\n"); - fprintf(ofp, "\n"); -} - -/* - * Retrieve the created session and - * mi output it of the created session based on provided argument + * 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. - * str_url is a placement string for output url (snapshot or regular trace) */ static int mi_created_session(const char *session_name) { @@ -212,18 +141,15 @@ static int set_consumer_url(const char *session_name, const char *ctrl_url, { int ret; struct lttng_handle *handle; - struct lttng_domain dom; assert(session_name); /* - * Set handle with the session name and the domain set to 0. This means to - * the session daemon that the next action applies on the tracing session - * rather then the domain specific session. + * Set handle with the session_name, but no domain. This implies that + * the actions taken with this handle apply on the tracing session + * rather then the domain-specific session. */ - memset(&dom, 0, sizeof(dom)); - - handle = lttng_create_handle(session_name, &dom); + handle = lttng_create_handle(session_name, NULL); if (handle == NULL) { ret = CMD_FATAL; goto error; @@ -301,6 +227,7 @@ static int create_session(void) char session_name_date[NAME_MAX + 17], *print_str_url = NULL; time_t rawtime; struct tm *timeinfo; + char shm_path[PATH_MAX] = ""; /* Get date and time for automatic session name/path */ time(&rawtime); @@ -381,16 +308,22 @@ static int create_session(void) */ url = NULL; } else if (!opt_no_output) { + char *tmp_path; + /* Auto output path */ - alloc_path = utils_get_home_dir(); - if (alloc_path == NULL) { + tmp_path = utils_get_home_dir(); + if (tmp_path == NULL) { ERR("HOME path not found.\n \ Please specify an output path using -o, --output PATH"); ret = CMD_FATAL; goto error; } - alloc_path = strdup(alloc_path); - + alloc_path = strdup(tmp_path); + if (!alloc_path) { + PERROR("allocating alloc_path"); + ret = CMD_FATAL; + goto error; + } ret = asprintf(&alloc_url, "file://%s/" DEFAULT_TRACE_DIR_NAME "/%s", alloc_path, session_name_date); @@ -450,7 +383,7 @@ static int create_session(void) } ret = lttng_create_session_live(session_name, url, opt_live_timer); } else { - ret = _lttng_create_session_ext(session_name, url, datetime, -1); + ret = _lttng_create_session_ext(session_name, url, datetime); } if (ret < 0) { /* Don't set ret so lttng can interpret the sessiond error. */ @@ -479,6 +412,21 @@ static int create_session(void) } } + if (opt_shm_path) { + ret = snprintf(shm_path, sizeof(shm_path), + "%s/%s", opt_shm_path, session_name_date); + if (ret < 0) { + PERROR("snprintf shm_path"); + goto error; + } + + ret = lttng_set_session_shm_path(session_name, shm_path); + if (ret < 0) { + lttng_destroy_session(session_name); + goto error; + } + } + MSG("Session %s created.", session_name); if (print_str_url && !opt_snapshot) { MSG("Traces will be written in %s", print_str_url); @@ -491,7 +439,11 @@ static int create_session(void) MSG("Default snapshot output set to: %s", print_str_url); } MSG("Snapshot mode set. Every channel enabled for that session will " - "be set in overwrite mode and mmap output."); + "be set to mmap output, and default to overwrite mode."); + } + if (opt_shm_path) { + MSG("Session %s set to shm_path: %s.", session_name, + shm_path); } /* Mi output */ @@ -523,6 +475,137 @@ error: return ret; } +/* + * spawn_sessiond + * + * Spawn a session daemon by forking and execv. + */ +static int spawn_sessiond(char *pathname) +{ + int ret = 0; + pid_t pid; + + MSG("Spawning a session daemon"); + pid = fork(); + if (pid == 0) { + /* + * Spawn session daemon in daemon mode. + */ + execlp(pathname, "lttng-sessiond", + "--daemonize", NULL); + /* execlp only returns if error happened */ + if (errno == ENOENT) { + ERR("No session daemon found. Use --sessiond-path."); + } else { + PERROR("execlp"); + } + kill(getppid(), SIGTERM); /* wake parent */ + exit(EXIT_FAILURE); + } else if (pid > 0) { + /* + * In daemon mode (--daemonize), sessiond only exits when + * it's ready to accept commands. + */ + for (;;) { + int status; + pid_t wait_pid_ret = waitpid(pid, &status, 0); + + if (wait_pid_ret < 0) { + if (errno == EINTR) { + continue; + } + PERROR("waitpid"); + ret = -errno; + goto end; + } + + if (WIFSIGNALED(status)) { + ERR("Session daemon was killed by signal %d", + WTERMSIG(status)); + ret = -1; + goto end; + } else if (WIFEXITED(status)) { + DBG("Session daemon terminated normally (exit status: %d)", + WEXITSTATUS(status)); + + if (WEXITSTATUS(status) != 0) { + ERR("Session daemon terminated with an error (exit status: %d)", + WEXITSTATUS(status)); + ret = -1; + goto end; + } + break; + } + } + + goto end; + } else { + PERROR("fork"); + ret = -1; + goto end; + } + +end: + return ret; +} + +/* + * launch_sessiond + * + * Check if the session daemon is available using + * the liblttngctl API for the check. If not, try to + * spawn a daemon. + */ +static int launch_sessiond(void) +{ + int ret; + char *pathname = NULL; + + ret = lttng_session_daemon_alive(); + if (ret) { + /* Sessiond is alive, not an error */ + ret = 0; + goto end; + } + + /* Try command line option path */ + pathname = opt_sessiond_path; + + /* Try LTTNG_SESSIOND_PATH env variable */ + if (pathname == NULL) { + pathname = getenv(DEFAULT_SESSIOND_PATH_ENV); + } + + /* Try with configured path */ + if (pathname == NULL) { + if (CONFIG_SESSIOND_BIN[0] != '\0') { + pathname = CONFIG_SESSIOND_BIN; + } + } + + /* Try the default path */ + if (pathname == NULL) { + pathname = INSTALL_BIN_PATH "/lttng-sessiond"; + } + + DBG("Session daemon binary path: %s", pathname); + + /* Check existence and permissions */ + ret = access(pathname, F_OK | X_OK); + if (ret < 0) { + ERR("No such file or access denied: %s", pathname); + goto end; + } + + ret = spawn_sessiond(pathname); +end: + if (ret) { + ERR("Problem occurred while launching session daemon (%s)", + pathname); + } + return ret; +} + /* * The 'create ' first level command * @@ -540,7 +623,7 @@ int cmd_create(int argc, const char **argv) while ((opt = poptGetNextOpt(pc)) != -1) { switch (opt) { case OPT_HELP: - usage(stdout); + SHOW_HELP(); goto end; case OPT_LIST_OPTIONS: list_cmd_options(stdout, long_options); @@ -570,12 +653,16 @@ int cmd_create(int argc, const char **argv) ret = CMD_ERROR; goto end; } + if (v == 0) { + ERR("Live timer interval must be greater than zero"); + ret = CMD_ERROR; + goto end; + } opt_live_timer = (uint32_t) v; DBG("Session live timer interval set to %d", opt_live_timer); break; } default: - usage(stderr); ret = CMD_UNDEFINED; goto end; } @@ -587,13 +674,15 @@ int cmd_create(int argc, const char **argv) goto end; } - if (opt_disable_consumer) { - MSG("The option --disable-consumer is obsolete."); - ret = CMD_WARNING; - goto end; + /* Spawn a session daemon if needed */ + if (!opt_no_sessiond) { + ret = launch_sessiond(); + if (ret) { + ret = CMD_ERROR; + goto end; + } } - /* MI initialization */ if (lttng_opt_mi) { writer = mi_lttng_writer_create(fileno(stdout), lttng_opt_mi);