#include <sys/types.h>
#include <time.h>
#include <unistd.h>
+#include <signal.h>
#include <common/mi-lttng.h>
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;
{"no-consumer", 0, POPT_ARG_VAL, &opt_no_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}
};
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, " --shm-path PATH Path where shared memory holding buffers\n");
+ fprintf(ofp, " should be created. Useful when used with pramfs\n");
+ fprintf(ofp, " to extract trace data after crash.\n");
fprintf(ofp, "\n");
fprintf(ofp, "Extended Options:\n");
fprintf(ofp, "\n");
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);
*/
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);
}
}
+ 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);
MSG("Snapshot mode set. Every channel enabled for that session will "
"be set in overwrite mode and mmap output.");
}
+ if (opt_shm_path) {
+ MSG("Session %s set to shm_path: %s.", session_name,
+ shm_path);
+ }
/* Mi output */
if (lttng_opt_mi) {
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");
+ recv_child_signal = 0;
+ pid = fork();
+ if (pid == 0) {
+ /*
+ * Spawn session daemon and tell
+ * it to signal us when ready.
+ */
+ execlp(pathname, "lttng-sessiond", "--sig-parent", "--quiet", 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) {
+ sessiond_pid = pid;
+ /*
+ * Wait for lttng-sessiond to start. We need to use a flag to check if
+ * the signal has been sent to us, because the child can be scheduled
+ * before the parent, and thus send the signal before this check. In
+ * the signal handler, we set the recv_child_signal flag, so anytime we
+ * check it after the fork is fine. Note that sleep() is interrupted
+ * before the 1 second delay as soon as the signal is received, so it
+ * will not cause visible delay for the user.
+ */
+ while (!recv_child_signal) {
+ sleep(1);
+ }
+ /*
+ * The signal handler will nullify sessiond_pid on SIGCHLD
+ */
+ if (!sessiond_pid) {
+ exit(EXIT_FAILURE);
+ }
+ 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);
+ if (ret < 0) {
+ ERR("Problem occurred when starting %s", pathname);
+ }
+end:
+ return ret;
+}
+
/*
* The 'create <options>' first level command
*
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;
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);