return ret;
}
+/*
+ * Set consumer subdirectory using the session name and a generated datetime if
+ * needed. This is appended to the current subdirectory.
+ */
+static int set_consumer_subdir(struct consumer_output *consumer,
+ const char *session_name)
+{
+ int ret = 0;
+ unsigned int have_default_name = 0;
+ char datetime[16], tmp_path[PATH_MAX];
+ time_t rawtime;
+ struct tm *timeinfo;
+
+ assert(consumer);
+ assert(session_name);
+
+ memset(tmp_path, 0, sizeof(tmp_path));
+
+ /* Flag if we have a default session. */
+ if (strncmp(session_name, DEFAULT_SESSION_NAME "-",
+ strlen(DEFAULT_SESSION_NAME) + 1) == 0) {
+ have_default_name = 1;
+ } else {
+ /* Get date and time for session path */
+ time(&rawtime);
+ timeinfo = localtime(&rawtime);
+ strftime(datetime, sizeof(datetime), "%Y%m%d-%H%M%S", timeinfo);
+ }
+
+ if (have_default_name) {
+ ret = snprintf(tmp_path, sizeof(tmp_path),
+ "%s/%s", consumer->subdir, session_name);
+ } else {
+ ret = snprintf(tmp_path, sizeof(tmp_path),
+ "%s/%s-%s/", consumer->subdir, session_name, datetime);
+ }
+ if (ret < 0) {
+ PERROR("snprintf session name date");
+ goto error;
+ }
+
+ strncpy(consumer->subdir, tmp_path, sizeof(consumer->subdir));
+ DBG2("Consumer subdir set to %s", consumer->subdir);
+
+error:
+ return ret;
+}
+
/*
* Copy consumer output from the tracing session to the domain session. The
* function also applies the right modification on a per domain basis for the
goto error;
}
+ ret = set_consumer_subdir(session->consumer, session->name);
+ if (ret < 0) {
+ ret = LTTCOMM_FATAL;
+ goto error;
+ }
+
/* Append correct directory to subdir */
strncat(consumer->subdir, dir_name, sizeof(consumer->subdir));
DBG3("Copy session consumer subdir %s", consumer->subdir);
return i;
}
+/*
+ * Create a session path used by list_lttng_sessions for the case that the
+ * session consumer is on the network.
+ */
+static int build_network_session_path(char *dst, size_t size,
+ struct ltt_session *session)
+{
+ int ret, kdata_port, udata_port;
+ struct lttng_uri *kuri = NULL, *uuri = NULL, *uri = NULL;
+ char tmp_uurl[PATH_MAX], tmp_urls[PATH_MAX];
+
+ assert(session);
+ assert(dst);
+
+ memset(tmp_urls, 0, sizeof(tmp_urls));
+ memset(tmp_uurl, 0, sizeof(tmp_uurl));
+
+ kdata_port = udata_port = DEFAULT_NETWORK_DATA_PORT;
+
+ if (session->kernel_session && session->kernel_session->consumer) {
+ kuri = &session->kernel_session->consumer->dst.net.control;
+ kdata_port = session->kernel_session->consumer->dst.net.data.port;
+ }
+
+ if (session->ust_session && session->ust_session->consumer) {
+ uuri = &session->ust_session->consumer->dst.net.control;
+ udata_port = session->ust_session->consumer->dst.net.data.port;
+ }
+
+ if (uuri == NULL && kuri == NULL) {
+ uri = &session->consumer->dst.net.control;
+ kdata_port = session->consumer->dst.net.data.port;
+ } else if (kuri && uuri) {
+ ret = uri_compare(kuri, uuri);
+ if (ret) {
+ /* Not Equal */
+ uri = kuri;
+ /* Build uuri URL string */
+ ret = uri_to_str_url(uuri, tmp_uurl, sizeof(tmp_uurl));
+ if (ret < 0) {
+ goto error;
+ }
+ } else {
+ uri = kuri;
+ }
+ } else if (kuri && uuri == NULL) {
+ uri = kuri;
+ } else if (uuri && kuri == NULL) {
+ uri = uuri;
+ }
+
+ ret = uri_to_str_url(uri, tmp_urls, sizeof(tmp_urls));
+ if (ret < 0) {
+ goto error;
+ }
+
+ if (strlen(tmp_uurl) > 0) {
+ ret = snprintf(dst, size, "[K]: %s [data: %d] -- [U]: %s [data: %d]",
+ tmp_urls, kdata_port, tmp_uurl, udata_port);
+ } else {
+ ret = snprintf(dst, size, "%s [data: %d]", tmp_urls, kdata_port);
+ }
+
+error:
+ return ret;
+}
+
/*
* Using the session list, filled a lttng_session array to send back to the
* client for session listing.
static void list_lttng_sessions(struct lttng_session *sessions, uid_t uid,
gid_t gid)
{
+ int ret;
unsigned int i = 0;
struct ltt_session *session;
if (!session_access_ok(session, uid, gid)) {
continue;
}
- strncpy(sessions[i].path, session->path, PATH_MAX);
- sessions[i].path[PATH_MAX - 1] = '\0';
+
+ if (session->consumer->type == CONSUMER_DST_LOCAL &&
+ (!session->kernel_session && !session->ust_session)) {
+ ret = snprintf(sessions[i].path, sizeof(session[i].path), "%s",
+ session->consumer->dst.trace_path);
+ } else {
+ ret = build_network_session_path(sessions[i].path,
+ sizeof(session[i].path), session);
+ }
+ if (ret < 0) {
+ PERROR("snprintf session path");
+ continue;
+ }
+
strncpy(sessions[i].name, session->name, NAME_MAX);
sessions[i].name[NAME_MAX - 1] = '\0';
sessions[i].enabled = session->enabled;
* domain adding the default trace directory.
*/
static int add_uri_to_consumer(struct consumer_output *consumer,
- struct lttng_uri *uri, int domain)
+ struct lttng_uri *uri, int domain, const char *session_name)
{
- int ret;
+ int ret = LTTCOMM_OK;
const char *default_trace_dir;
assert(uri);
if (ret < 0) {
ret = LTTCOMM_FATAL;
goto error;
+ } else if (ret == 1) {
+ /*
+ * URI was the same in the consumer so we do not append the subdir
+ * again so to not duplicate output dir.
+ */
+ goto error;
}
- /* On a new subdir, reappend the default trace dir. */
- if (strlen(uri->subdir) != 0) {
- strncat(consumer->subdir, default_trace_dir,
- sizeof(consumer->subdir));
+ if (uri->stype == LTTNG_STREAM_CONTROL && strlen(uri->subdir) == 0) {
+ ret = set_consumer_subdir(consumer, session_name);
+ if (ret < 0) {
+ ret = LTTCOMM_FATAL;
+ goto error;
+ }
+ }
+
+ if (uri->stype == LTTNG_STREAM_CONTROL) {
+ /* On a new subdir, reappend the default trace dir. */
+ strncat(consumer->subdir, default_trace_dir, sizeof(consumer->subdir));
+ DBG3("Append domain trace name to subdir %s", consumer->subdir);
}
break;
}
/*
- * Command LTTNG_CREATE_SESSION processed by the client thread.
+ * Command LTTNG_SET_CONSUMER_URI processed by the client thread.
*/
-static int cmd_create_session_uri(char *name, struct lttng_uri *uris,
- size_t nb_uri, lttng_sock_cred *creds)
+static int cmd_set_consumer_uri(int domain, struct ltt_session *session,
+ size_t nb_uri, struct lttng_uri *uris)
{
- int ret, have_default_name = 0;
- char *path = NULL, datetime[16];
- struct ltt_session *session;
+ int ret, i;
+ struct ltt_kernel_session *ksess = session->kernel_session;
+ struct ltt_ust_session *usess = session->ust_session;
struct consumer_output *consumer = NULL;
- struct lttng_uri *ctrl_uri, *data_uri = NULL;
- time_t rawtime;
- struct tm *timeinfo;
- assert(name);
-
- /* Flag if we have a default session. */
- if (strncmp(name, DEFAULT_SESSION_NAME,
- strlen(DEFAULT_SESSION_NAME)) == 0) {
- have_default_name = 1;
- } else {
- /* Get date and time for session path */
- time(&rawtime);
- timeinfo = localtime(&rawtime);
- strftime(datetime, sizeof(datetime), "%Y%m%d-%H%M%S", timeinfo);
- }
-
- /*
- * Verify if the session already exist
- *
- * XXX: There is no need for the session lock list here since the caller
- * (process_client_msg) is holding it. We might want to change that so a
- * single command does not lock the entire session list.
- */
- session = session_find_by_name(name);
- if (session != NULL) {
- ret = LTTCOMM_EXIST_SESS;
- goto consumer_error;
- }
+ assert(session);
+ assert(uris);
+ assert(nb_uri > 0);
- /* Create default consumer output for the session not yet created. */
- consumer = consumer_create_output(CONSUMER_DST_LOCAL);
- if (consumer == NULL) {
- ret = LTTCOMM_FATAL;
- goto consumer_error;
+ /* Can't enable consumer after session started. */
+ if (session->enabled) {
+ ret = LTTCOMM_TRACE_ALREADY_STARTED;
+ goto error;
}
- /* Add session name and data to the consumer subdir */
- if (have_default_name) {
- ret = snprintf(consumer->subdir, sizeof(consumer->subdir), "/%s",
- name);
- } else {
- ret = snprintf(consumer->subdir, sizeof(consumer->subdir), "/%s-%s",
- name, datetime);
- }
- if (ret < 0) {
- PERROR("snprintf consumer subdir");
+ if (!session->start_consumer) {
+ ret = LTTCOMM_NO_CONSUMER;
goto error;
}
- DBG2("Consumer subdir set to '%s'", consumer->subdir);
/*
- * This means that the lttng_create_session call was called with the _path_
- * argument set to NULL.
+ * This case switch makes sure the domain session has a temporary consumer
+ * so the URL can be set.
*/
- if (uris == NULL) {
+ switch (domain) {
+ case 0:
+ /* Code flow error. A session MUST always have a consumer object */
+ assert(session->consumer);
/*
- * At this point, we'll skip the consumer URI setup and create a
- * session with a NULL path which will flag the session to NOT spawn a
- * consumer.
+ * The URL will be added to the tracing session consumer instead of a
+ * specific domain consumer.
*/
- DBG("Create session %s with NO uri, skipping consumer setup", name);
- goto skip_consumer;
- }
+ consumer = session->consumer;
+ break;
+ case LTTNG_DOMAIN_KERNEL:
+ /* Code flow error if we don't have a kernel session here. */
+ assert(ksess);
- /* TODO: validate URIs */
+ /* Create consumer output if none exists */
+ consumer = ksess->tmp_consumer;
+ if (consumer == NULL) {
+ consumer = consumer_copy_output(ksess->consumer);
+ if (consumer == NULL) {
+ ret = LTTCOMM_FATAL;
+ goto error;
+ }
+ /* Trash the consumer subdir, we are about to set a new one. */
+ memset(consumer->subdir, 0, sizeof(consumer->subdir));
+ ksess->tmp_consumer = consumer;
+ }
- ctrl_uri = &uris[0];
- if (nb_uri > 1) {
- data_uri = &uris[1];
- }
+ break;
+ case LTTNG_DOMAIN_UST:
+ /* Code flow error if we don't have a kernel session here. */
+ assert(usess);
- /* Set subdirectory from the ctrl_uri received. */
- if (strlen(ctrl_uri->subdir) > 0) {
- strncpy(consumer->subdir, ctrl_uri->subdir, sizeof(consumer->subdir));
- DBG2("Consumer subdir copy from ctrl_uri '%s'", consumer->subdir);
+ /* Create consumer output if none exists */
+ consumer = usess->tmp_consumer;
+ if (consumer == NULL) {
+ consumer = consumer_copy_output(usess->consumer);
+ if (consumer == NULL) {
+ ret = LTTCOMM_FATAL;
+ goto error;
+ }
+ /* Trash the consumer subdir, we are about to set a new one. */
+ memset(consumer->subdir, 0, sizeof(consumer->subdir));
+ usess->tmp_consumer = consumer;
+ }
+
+ break;
}
- switch (ctrl_uri->dtype) {
- case LTTNG_DST_IPV4:
- case LTTNG_DST_IPV6:
- /*
- * We MUST have a data_uri set at this point or else there is a code
- * flow error. The caller should check that.
- */
- assert(data_uri);
+ for (i = 0; i < nb_uri; i++) {
+ struct consumer_socket *socket;
+ struct lttng_ht_iter iter;
- /* Set control URI into consumer output object */
- ret = consumer_set_network_uri(consumer, ctrl_uri);
+ ret = add_uri_to_consumer(consumer, &uris[i], domain, session->name);
if (ret < 0) {
- ret = LTTCOMM_FATAL;
goto error;
}
- /* Set data URI into consumer output object */
- ret = consumer_set_network_uri(consumer, data_uri);
- if (ret < 0) {
- ret = LTTCOMM_FATAL;
- goto error;
+ /*
+ * Don't send relayd socket if URI is NOT remote or if the relayd
+ * sockets for the session are already sent.
+ */
+ if (uris[i].dtype == LTTNG_DST_PATH ||
+ consumer->dst.net.relayd_socks_sent) {
+ continue;
}
- /* Empty path since the session is network */
- path = "";
- break;
- case LTTNG_DST_PATH:
- /* Very volatile pointer. Only used for the create session. */
- path = ctrl_uri->dst.path;
- strncpy(consumer->dst.trace_path, path,
- sizeof(consumer->dst.trace_path));
- break;
+ /* Try to send relayd URI to the consumer if exist. */
+ cds_lfht_for_each_entry(consumer->socks->ht, &iter.iter,
+ socket, node.node) {
+
+ /* A socket in the HT should never have a negative fd */
+ assert(socket->fd >= 0);
+
+ pthread_mutex_lock(socket->lock);
+ ret = send_socket_relayd_consumer(domain, session, &uris[i],
+ consumer, socket->fd);
+ pthread_mutex_unlock(socket->lock);
+ if (ret != LTTCOMM_OK) {
+ goto error;
+ }
+ }
}
- consumer->enabled = 1;
+ /* All good! */
+ ret = LTTCOMM_OK;
+
+error:
+ return ret;
+}
+
+
+/*
+ * Command LTTNG_CREATE_SESSION processed by the client thread.
+ */
+static int cmd_create_session_uri(char *name, struct lttng_uri *uris,
+ size_t nb_uri, lttng_sock_cred *creds)
+{
+ int ret;
+ char *path = NULL;
+ struct ltt_session *session;
+
+ assert(name);
+
+ /*
+ * Verify if the session already exist
+ *
+ * XXX: There is no need for the session lock list here since the caller
+ * (process_client_msg) is holding it. We might want to change that so a
+ * single command does not lock the entire session list.
+ */
+ session = session_find_by_name(name);
+ if (session != NULL) {
+ ret = LTTCOMM_EXIST_SESS;
+ goto find_error;
+ }
-skip_consumer:
/* Create tracing session in the registry */
ret = session_create(name, path, LTTNG_SOCK_GET_UID_CRED(creds),
LTTNG_SOCK_GET_GID_CRED(creds));
if (ret != LTTCOMM_OK) {
- goto error;
+ goto session_error;
}
/*
session = session_find_by_name(name);
assert(session);
- /* Assign consumer to session */
- session->consumer = consumer;
+ /* Create default consumer output for the session not yet created. */
+ session->consumer = consumer_create_output(CONSUMER_DST_LOCAL);
+ if (session->consumer == NULL) {
+ ret = LTTCOMM_FATAL;
+ goto consumer_error;
+ }
- /* Set correct path to session */
- if (have_default_name) {
- /* We have the default session so the date-time is already appended */
- ret = snprintf(session->path, sizeof(session->path), "%s/%s",
- path, name);
- } else {
- ret = snprintf(session->path, sizeof(session->path), "%s/%s-%s",
- path, name, datetime);
+ /*
+ * This means that the lttng_create_session call was called with the _path_
+ * argument set to NULL.
+ */
+ if (uris == NULL) {
+ /*
+ * At this point, we'll skip the consumer URI setup and create a
+ * session with a NULL path which will flag the session to NOT spawn a
+ * consumer.
+ */
+ DBG("Create session %s with NO uri, skipping consumer setup", name);
+ goto end;
}
- if (ret < 0) {
- PERROR("snprintf session path");
- goto session_error;
+
+ session->start_consumer = 1;
+
+ ret = cmd_set_consumer_uri(0, session, nb_uri, uris);
+ if (ret != LTTCOMM_OK) {
+ goto consumer_error;
}
+ session->consumer->enabled = 1;
+
+end:
return LTTCOMM_OK;
-session_error:
- session_destroy(session);
-error:
- rcu_read_lock();
- consumer_destroy_output(consumer);
- rcu_read_unlock();
consumer_error:
+ session_destroy(session);
+session_error:
+find_error:
return ret;
}
return ret;
}
-/*
- * Command LTTNG_SET_CONSUMER_URI processed by the client thread.
- */
-static int cmd_set_consumer_uri(int domain, struct ltt_session *session,
- size_t nb_uri, struct lttng_uri *uris)
-{
- int ret, i;
- struct ltt_kernel_session *ksess = session->kernel_session;
- struct ltt_ust_session *usess = session->ust_session;
- struct consumer_output *consumer = NULL;
-
- assert(session);
- assert(uris);
- assert(nb_uri > 0);
-
- /* Can't enable consumer after session started. */
- if (session->enabled) {
- ret = LTTCOMM_TRACE_ALREADY_STARTED;
- goto error;
- }
-
- if (!session->start_consumer) {
- ret = LTTCOMM_NO_CONSUMER;
- goto error;
- }
-
- /*
- * This case switch makes sure the domain session has a temporary consumer
- * so the URL can be set.
- */
- switch (domain) {
- case 0:
- /* Code flow error. A session MUST always have a consumer object */
- assert(session->consumer);
- /*
- * The URL will be added to the tracing session consumer instead of a
- * specific domain consumer.
- */
- consumer = session->consumer;
- break;
- case LTTNG_DOMAIN_KERNEL:
- /* Code flow error if we don't have a kernel session here. */
- assert(ksess);
-
- /* Create consumer output if none exists */
- consumer = ksess->tmp_consumer;
- if (consumer == NULL) {
- consumer = consumer_copy_output(ksess->consumer);
- if (consumer == NULL) {
- ret = LTTCOMM_FATAL;
- goto error;
- }
- ksess->tmp_consumer = consumer;
- }
-
- break;
- case LTTNG_DOMAIN_UST:
- /* Code flow error if we don't have a kernel session here. */
- assert(usess);
-
- /* Create consumer output if none exists */
- consumer = usess->tmp_consumer;
- if (consumer == NULL) {
- consumer = consumer_copy_output(usess->consumer);
- if (consumer == NULL) {
- ret = LTTCOMM_FATAL;
- goto error;
- }
- usess->tmp_consumer = consumer;
- }
-
- break;
- }
-
- for (i = 0; i < nb_uri; i++) {
- struct consumer_socket *socket;
- struct lttng_ht_iter iter;
-
- ret = add_uri_to_consumer(consumer, &uris[i], domain);
- if (ret < 0) {
- goto error;
- }
-
- /*
- * Don't send relayd socket if URI is NOT remote or if the relayd
- * sockets for the session are already sent.
- */
- if (uris[i].dtype == LTTNG_DST_PATH ||
- consumer->dst.net.relayd_socks_sent) {
- continue;
- }
-
- /* Try to send relayd URI to the consumer if exist. */
- cds_lfht_for_each_entry(consumer->socks->ht, &iter.iter,
- socket, node.node) {
-
- /* A socket in the HT should never have a negative fd */
- assert(socket->fd >= 0);
-
- pthread_mutex_lock(socket->lock);
- ret = send_socket_relayd_consumer(domain, session, &uris[i],
- consumer, socket->fd);
- pthread_mutex_unlock(socket->lock);
- if (ret != LTTCOMM_OK) {
- goto error;
- }
- }
- }
-
- /* All good! */
- ret = LTTCOMM_OK;
-
-error:
- return ret;
-}
-
/*
* Command LTTNG_DISABLE_CONSUMER processed by the client thread.
*/
goto error;
}
- /* Append default kernel trace dir to subdir */
- strncat(ksess->consumer->subdir, DEFAULT_KERNEL_TRACE_DIR,
- sizeof(ksess->consumer->subdir));
-
break;
}
+ /* Append default kernel trace dir to subdir */
+ strncat(ksess->consumer->subdir, DEFAULT_KERNEL_TRACE_DIR,
+ sizeof(ksess->consumer->subdir));
+
/*
* @session-lock
* This is race free for now since the session lock is acquired before
goto error;
}
- /* Append default kernel trace dir to subdir */
- strncat(usess->consumer->subdir, DEFAULT_UST_TRACE_DIR,
- sizeof(usess->consumer->subdir));
-
break;
}
+ /* Append default kernel trace dir to subdir */
+ strncat(usess->consumer->subdir, DEFAULT_UST_TRACE_DIR,
+ sizeof(usess->consumer->subdir));
+
/*
* @session-lock
* This is race free for now since the session lock is acquired before
goto error;
}
+ /* Deny register consumer if we already have a spawned consumer. */
+ if (cmd_ctx->lsm->cmd_type == LTTNG_REGISTER_CONSUMER) {
+ pthread_mutex_lock(&kconsumer_data.pid_mutex);
+ if (kconsumer_data.pid > 0) {
+ ret = LTTCOMM_KERN_CONSUMER_FAIL;
+ goto error;
+ }
+ pthread_mutex_unlock(&kconsumer_data.pid_mutex);
+ }
+
/*
* Check for command that don't needs to allocate a returned payload. We do
* this here so we don't have to make the call for no payload at each
}
/* Receive variable len data */
- DBG("Receiving %lu URI(s) from client ...", nb_uri);
+ DBG("Receiving %zu URI(s) from client ...", nb_uri);
ret = lttcomm_recv_unix_sock(sock, uris, len);
if (ret <= 0) {
DBG("No URIs received from client... continuing");
}
/* Receive variable len data */
- DBG("Waiting for %lu URIs from client ...", nb_uri);
+ DBG("Waiting for %zu URIs from client ...", nb_uri);
ret = lttcomm_recv_unix_sock(sock, uris, len);
if (ret <= 0) {
DBG("No URIs received from client... continuing");