PyObject *name = PyString_FromString((*$1)[i].name);
PyObject *path = PyString_FromString((*$1)[i].path);
PyObject *enabled = PyInt_FromSize_t((*$1)[i].enabled);
- PyObject *padding = PyString_FromString((*$1)[i].padding);
PyTuple_SetItem(tmp, 0, name);
PyTuple_SetItem(tmp, 1, path);
PyTuple_SetItem(tmp, 2, enabled);
- PyTuple_SetItem(tmp, 3, padding);
PyList_Append(sessions, tmp);
}
$result = sessions;
char name[NAME_MAX];
char path[PATH_MAX];
uint32_t enabled;
- char padding[LTTNG_SESSION_PADDING1];
+ uint32_t snapshot_mode;
+ unsigned int live_timer_interval;
+ union {
+ char padding[LTTNG_SESSION_PADDING1];
+ void *ptr;
+ } extended;
%extend {
char *__repr__() {
lttng/endpoint.h \
lttng/rotation.h \
lttng/location.h \
- lttng/userspace-probe.h
+ lttng/userspace-probe.h \
+ lttng/session-descriptor.h
lttngactioninclude_HEADERS= \
lttng/action/action.h \
lttng/ref-internal.h \
lttng/location-internal.h \
lttng/userspace-probe-internal.h \
+ lttng/session-internal.h \
+ lttng/session-descriptor-internal.h \
version.h \
version.i
LTTNG_ERR_MKDIR_FAIL_CONSUMER = 145, /* mkdir failure on consumer */
LTTNG_ERR_CHAN_NOT_FOUND = 146, /* Channel not found */
LTTNG_ERR_SNAPSHOT_UNSUPPORTED = 147, /* Session configuration does not allow the use of snapshots */
+ LTTNG_ERR_SESSION_NOT_EXIST = 148, /* The session does not exist on the session daemon */
/* MUST be last element */
LTTNG_ERR_NR, /* Last element */
#include <lttng/session.h>
#include <lttng/snapshot.h>
#include <lttng/endpoint.h>
+#include <lttng/session-descriptor.h>
#include <lttng/action/action.h>
#include <lttng/action/notify.h>
#include <lttng/condition/condition.h>
--- /dev/null
+/*
+ * Copyright (C) 2019 - Jérémie Galarneau <jeremie.galarneau@efficios.com>
+ *
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License, version 2.1 only,
+ * as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef LTTNG_SESSION_DESCRIPTOR_INTERNAL_H
+#define LTTNG_SESSION_DESCRIPTOR_INTERNAL_H
+
+#include <lttng/session-descriptor.h>
+#include <lttng/lttng-error.h>
+#include <common/uri.h>
+#include <common/dynamic-buffer.h>
+#include <common/buffer-view.h>
+#include <stdbool.h>
+
+/* Note that these enums are used as part of the lttnctl protocol. */
+enum lttng_session_descriptor_type {
+ LTTNG_SESSION_DESCRIPTOR_TYPE_UNKNOWN = -1,
+ /*
+ * The output type determines whether this is a no-output, local,
+ * or networked tracing session.
+ */
+ LTTNG_SESSION_DESCRIPTOR_TYPE_REGULAR = 1,
+ LTTNG_SESSION_DESCRIPTOR_TYPE_SNAPSHOT = 2,
+ LTTNG_SESSION_DESCRIPTOR_TYPE_LIVE = 3,
+};
+
+enum lttng_session_descriptor_output_type {
+ LTTNG_SESSION_DESCRIPTOR_OUTPUT_TYPE_NONE = 0,
+ LTTNG_SESSION_DESCRIPTOR_OUTPUT_TYPE_LOCAL = 1,
+ LTTNG_SESSION_DESCRIPTOR_OUTPUT_TYPE_NETWORK = 2,
+};
+
+LTTNG_HIDDEN
+ssize_t lttng_session_descriptor_create_from_buffer(
+ const struct lttng_buffer_view *view,
+ struct lttng_session_descriptor **descriptor);
+
+LTTNG_HIDDEN
+int lttng_session_descriptor_serialize(
+ const struct lttng_session_descriptor *descriptor,
+ struct lttng_dynamic_buffer *buffer);
+
+LTTNG_HIDDEN
+enum lttng_session_descriptor_type
+lttng_session_descriptor_get_type(
+ const struct lttng_session_descriptor *descriptor);
+
+LTTNG_HIDDEN
+enum lttng_session_descriptor_output_type
+lttng_session_descriptor_get_output_type(
+ const struct lttng_session_descriptor *descriptor);
+
+LTTNG_HIDDEN
+void lttng_session_descriptor_get_local_output_uri(
+ const struct lttng_session_descriptor *descriptor,
+ struct lttng_uri *local_uri);
+
+LTTNG_HIDDEN
+void lttng_session_descriptor_get_network_output_uris(
+ const struct lttng_session_descriptor *descriptor,
+ struct lttng_uri *control,
+ struct lttng_uri *data);
+
+LTTNG_HIDDEN
+unsigned long long
+lttng_session_descriptor_live_get_timer_interval(
+ const struct lttng_session_descriptor *descriptor);
+
+LTTNG_HIDDEN
+enum lttng_session_descriptor_status
+lttng_session_descriptor_get_session_name(
+ const struct lttng_session_descriptor *descriptor,
+ const char **name);
+
+LTTNG_HIDDEN
+int lttng_session_descriptor_set_session_name(
+ struct lttng_session_descriptor *descriptor,
+ const char *name);
+
+LTTNG_HIDDEN
+bool lttng_session_descriptor_is_output_destination_initialized(
+ const struct lttng_session_descriptor *descriptor);
+
+LTTNG_HIDDEN
+bool lttng_session_descriptor_has_output_directory(
+ const struct lttng_session_descriptor *descriptor);
+
+LTTNG_HIDDEN
+enum lttng_error_code lttng_session_descriptor_set_default_output(
+ struct lttng_session_descriptor *descriptor,
+ time_t *session_creation_time,
+ const char *absolute_home_path);
+
+LTTNG_HIDDEN
+int lttng_session_descriptor_assign(
+ struct lttng_session_descriptor *dst_descriptor,
+ const struct lttng_session_descriptor *src_descriptor);
+
+#endif /* LTTNG_SESSION_DESCRIPTOR_INTERNAL_H */
--- /dev/null
+/*
+ * Copyright (C) 2019 - Jérémie Galarneau <jeremie.galarneau@efficios.com>
+ *
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License, version 2.1 only,
+ * as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef LTTNG_SESSION_DESCRIPTOR_H
+#define LTTNG_SESSION_DESCRIPTOR_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct lttng_session_descriptor;
+
+/*
+ * Session descriptor API.
+ *
+ * A session descriptor is an object describing the immutable configuration
+ * options of an LTTng tracing session.
+ *
+ * When used with the lttng_create_session_ext() function, a session descriptor
+ * allows the creation of a tracing session of the following types: regular,
+ * snapshot, and live.
+ *
+ * Certain parameters can be omitted at the time of creation of a session
+ * descriptor to use default or auto-generated values selected by the
+ * session daemon. For instance, a session's name can be left unspecified,
+ * in which case one that is guaranteed not to clash with pre-existing
+ * sessions will be automatically be generated by the session daemon.
+ *
+ * Most session descriptors can be created in either "no output", local, or
+ * network output modes. The various output modes supported vary by session
+ * type.
+ *
+ * Regular session creation functions and output modes:
+ * * "no output": lttng_session_descriptor_create()
+ * * local: lttng_session_descriptor_local_create()
+ * * network: lttng_session_descriptor_network_create()
+ *
+ * Snapshot session creation functions and output modes:
+ * * "no output": lttng_session_descriptor_snapshot_create()
+ * * local: lttng_session_descriptor_snapshot_local_create()
+ * * network: lttng_session_descriptor_snapshot_network_create()
+ *
+ * Live session creation functions and output modes:
+ * * "no output": lttng_session_descriptor_live_create()
+ * * network: lttng_session_descriptor_live_network_create()
+ *
+ * Local output functions accept a 'path' parameter that must be an absolute
+ * path to which the user has write access. When a local output is automatically
+ * generated, it adopts the form:
+ * $LTTNG_HOME/DEFAULT_TRACE_DIR_NAME/SESSION_NAME-CREATION_TIME
+ *
+ * Where CREATION_TIME is time of the creation of the session on the session
+ * daemon in the form "yyyymmdd-hhmmss".
+ *
+ * Network output locations can also be auto-genated by leaving the
+ * 'control_url' and 'data_url' output parameters unspecified. In such cases,
+ * the session daemon will create a default output targeting a relay daemon
+ * at net://127.0.0.1, using the default 'control' and 'data' ports.
+ *
+ * The format of the 'control_url' and 'data_url' paramaters is:
+ * NETPROTO://(HOST | IPADDR)[:CTRLPORT[:DATAPORT]][/TRACEPATH]
+ *
+ * NETPROTO: Network protocol, amongst:
+ * * net: TCP over IPv4; the default values of 'CTRLPORT' and 'DATAPORT'
+ * are defined at build time of the lttng toolchain.
+ * * net6: TCP over IPv6: same default ports as the 'net' protocol.
+ * * tcp: Same as the 'net' protocol.
+ * * tcp6: Same as the 'net6' protocol.
+ *
+ * HOST | IPADDR: Hostname or IP address (IPv6 address *must* be enclosed
+ * in brackets; see RFC 2732).
+ *
+ * CTRLPORT: Control port.
+ *
+ * DATAPORT: Data port.
+ *
+ * TRACEPATH: Path of trace files on the remote file system. This path is
+ * relative to the base output directory set on the relay daemon
+ * end.
+ *
+ * The 'data_url' parameter is optional:
+ * * This parameter is meaningless for local tracing.
+ * * If 'control_url' is specified and a network protocol is used, the
+ * default data port, and the 'control_url' host will be used.
+ */
+
+enum lttng_session_descriptor_status {
+ /* Invalid session descriptor parameter. */
+ LTTNG_SESSION_DESCRIPTOR_STATUS_INVALID = -1,
+ LTTNG_SESSION_DESCRIPTOR_STATUS_OK = 0,
+ /* Session descriptor parameter is unset. */
+ LTTNG_SESSION_DESCRIPTOR_STATUS_UNSET = 1,
+};
+
+/*
+ * Create a session descriptor in no-output mode.
+ *
+ * The 'name' parameter can be left NULL to auto-generate a session name.
+ *
+ * Returns an lttng_session_descriptor instance on success, NULL on error.
+ */
+extern struct lttng_session_descriptor *
+lttng_session_descriptor_create(const char *name);
+
+/*
+ * Create a session descriptor with a local output destination.
+ *
+ * The 'name' parameter can be left NULL to auto-generate a session name.
+ *
+ * The 'path' must either be an absolute path or it can be left NULL to
+ * use the default local outout destination.
+ *
+ * Returns an lttng_session_descriptor instance on success, NULL on error.
+ */
+extern struct lttng_session_descriptor *
+lttng_session_descriptor_local_create(const char *name, const char *path);
+
+/*
+ * Create a session descriptor with a remote output destination.
+ *
+ * The 'name' parameter can be left NULL to auto-generate a session name.
+ *
+ * The 'control_url' and 'data_url' must conform to the URL format
+ * described above or can be left NULL to use the default network output.
+ *
+ * Returns an lttng_session_descriptor instance on success, NULL on error.
+ */
+extern struct lttng_session_descriptor *
+lttng_session_descriptor_network_create(const char *name,
+ const char *control_url, const char *data_url);
+
+/*
+ * Create a snapshot session descriptor without a default output.
+ *
+ * The 'name' parameter can be left NULL to auto-generate a session name.
+ *
+ * Returns an lttng_session_descriptor instance on success, NULL on error.
+ */
+extern struct lttng_session_descriptor *
+lttng_session_descriptor_snapshot_create(const char *name);
+
+/*
+ * Create a snapshot session descriptor with a local output destination.
+ *
+ * The 'name' parameter can be left NULL to auto-generate a session name.
+ *
+ * The 'path' must either be an absolute path or it can be left NULL to
+ * use the default local output destination as the default snapshot output.
+ *
+ * Returns an lttng_session_descriptor instance on success, NULL on error.
+ */
+extern struct lttng_session_descriptor *
+lttng_session_descriptor_snapshot_local_create(const char *name,
+ const char *path);
+
+/*
+ * Create a snapshot session descriptor with a remote output destination.
+ *
+ * The 'name' parameter can be left NULL to auto-generate a session name.
+ *
+ * The 'control_url' and 'data_url' must conform to the URL format
+ * described above or can be left NULL to use the default network output as
+ * the default snapshot output.
+ *
+ * Returns an lttng_session_descriptor instance on success, NULL on error.
+ */
+extern struct lttng_session_descriptor *
+lttng_session_descriptor_snapshot_network_create(const char *name,
+ const char *control_url, const char *data_url);
+
+/*
+ * Create a live session descriptor without an output.
+ *
+ * The 'name' parameter can be left NULL to auto-generate a session name.
+ *
+ * The 'live_timer_interval_us' parameter is the live timer's period, specified
+ * in microseconds.
+ *
+ * This parameter can't be 0. There is no default value defined for a live
+ * timer's period.
+ *
+ * Returns an lttng_session_descriptor instance on success, NULL on error.
+ */
+extern struct lttng_session_descriptor *
+lttng_session_descriptor_live_create(
+ const char *name, unsigned long long live_timer_interval_us);
+
+/*
+ * Create a live session descriptor with a remote output destination.
+ *
+ * The 'name' parameter can be left NULL to auto-generate a session name.
+ *
+ * The 'control_url' and 'data_url' must conform to the URL format
+ * described above or can be left NULL to use the default network output.
+ *
+ * The 'live_timer_interval_us' parameter is the live timer's period, specified
+ * in microseconds.
+ *
+ * This parameter can't be 0. There is no default value defined for a live
+ * timer's period.
+ *
+ * Returns an lttng_session_descriptor instance on success, NULL on error.
+ */
+extern struct lttng_session_descriptor *
+lttng_session_descriptor_live_network_create(
+ const char *name,
+ const char *control_url, const char *data_url,
+ unsigned long long live_timer_interval_us);
+
+/*
+ * Get a session descriptor's session name.
+ *
+ * The 'name' parameter is used as an output parameter and will point to
+ * the session descriptor's session name on success
+ * (LTTNG_SESSION_DESCRIPTOR_STATUS_OK). Its content of is left unspecified
+ * for other return codes. The pointer returned through 'name' is only
+ * guaranteed to remain valid until the next method call on the session
+ * descriptor.
+ *
+ * Returns LTTNG_SESSION_DESCRIPTOR_STATUS_OK on success,
+ * LTTNG_SESSION_DESCRIPTOR_STATUS_INVALID if 'descriptor' or 'name' are
+ * NULL, and LTTNG_SESSION_DESCRIPTOR_STATUS_UNSET if the descriptor's
+ * name parameter is unset.
+ */
+extern enum lttng_session_descriptor_status
+lttng_session_descriptor_get_session_name(
+ const struct lttng_session_descriptor *descriptor,
+ const char **name);
+
+/*
+ * Destroy a local lttng_session object.
+ *
+ * This does not destroy the session on the session daemon; it releases
+ * the resources allocated by the descriptor object.
+ */
+extern void lttng_session_descriptor_destroy(
+ struct lttng_session_descriptor *descriptor);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* LTTNG_SESSION_DESCRIPTOR_H */
--- /dev/null
+/*
+ * Copyright (C) 2019 - Jérémie Galarneau <jeremie.galarneau@efficios.com>
+ *
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License, version 2.1 only,
+ * as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef LTTNG_SESSION_INTERNAL_H
+#define LTTNG_SESSION_INTERNAL_H
+
+#include <lttng/constant.h>
+#include <common/macros.h>
+
+struct lttng_session_extended {
+ struct {
+ uint64_t value;
+ uint8_t is_set;
+ } creation_time LTTNG_PACKED;
+} LTTNG_PACKED;
+
+#endif /* LTTNG_SESSION_INTERNAL_H */
extern "C" {
#endif
+struct lttng_session_descriptor;
+
/*
* Basic session information.
*
uint32_t snapshot_mode;
unsigned int live_timer_interval; /* usec */
- char padding[LTTNG_SESSION_PADDING1];
+ union {
+ char padding[LTTNG_SESSION_PADDING1];
+ void *ptr;
+ } extended;
};
+/*
+ * Create a session on the session daemon from a session descriptor.
+ *
+ * See the session descriptor API description in session-descriptor.h
+ *
+ * Note that unspecified session descriptor parameters, such as a session's
+ * name, are updated in the session descriptor if the creation of the session
+ * succeeds. This allows users to query the session's auto-generated name
+ * after its creation. Note that other attributes can be queried using the
+ * session listing API.
+ *
+ * Returns LTTNG_OK on success. See lttng-error.h for the meaning of the other
+ * return codes.
+ */
+extern enum lttng_error_code lttng_create_session_ext(
+ struct lttng_session_descriptor *session_descriptor);
+
/*
* Create a tracing session using a name and an optional URL.
*
/*
* List all the tracing sessions.
*
- * Return the size (number of entries) of the "lttng_session" array. Caller
- * must free sessions. On error, a negative LTTng error code is returned.
+ * Return the number of entries of the "lttng_session" array. The caller
+ * must free the returned sessions array directly using free().
+ *
+ * On error, a negative LTTng error code is returned.
*/
extern int lttng_list_sessions(struct lttng_session **sessions);
+/*
+ * Get the creation time of an lttng_session object on the session daemon.
+ *
+ * This function must only be used with lttng_session objects returned
+ * by lttng_list_sessions() or lttng_session_create().
+ *
+ * The creation time returned is a UNIX timestamp; the number of seconds since
+ * Epoch (1970-01-01 00:00:00 +0000 (UTC)).
+ *
+ * Returns LTTNG_OK on success. See lttng-error.h for the meaning of the other
+ * return codes.
+ */
+extern enum lttng_error_code lttng_session_get_creation_time(
+ const struct lttng_session *session, uint64_t *creation_time);
+
/*
* Set the shared memory path for a session.
*
#include <common/utils.h>
#include <lttng/userspace-probe-internal.h>
#include <lttng/event-internal.h>
+#include <lttng/session-internal.h>
+#include <lttng/session-descriptor-internal.h>
#include "client.h"
#include "lttng-sessiond.h"
}
/* Append correct directory to subdir */
- strncat(consumer->subdir, dir_name,
- sizeof(consumer->subdir) - strlen(consumer->subdir) - 1);
- DBG3("Copy session consumer subdir %s", consumer->subdir);
-
+ ret = lttng_strncpy(consumer->domain_subdir, dir_name,
+ sizeof(consumer->domain_subdir));
+ if (ret) {
+ ret = LTTNG_ERR_UNK;
+ goto error;
+ }
+ DBG3("Copy session consumer subdir %s", consumer->domain_subdir);
ret = LTTNG_OK;
error:
*sock_error = 0;
switch (cmd_ctx->lsm->cmd_type) {
- case LTTNG_CREATE_SESSION:
- case LTTNG_CREATE_SESSION_SNAPSHOT:
- case LTTNG_CREATE_SESSION_LIVE:
+ case LTTNG_CREATE_SESSION_EXT:
case LTTNG_DESTROY_SESSION:
case LTTNG_LIST_SESSIONS:
case LTTNG_LIST_DOMAINS:
/* Commands that DO NOT need a session. */
switch (cmd_ctx->lsm->cmd_type) {
- case LTTNG_CREATE_SESSION:
- case LTTNG_CREATE_SESSION_SNAPSHOT:
- case LTTNG_CREATE_SESSION_LIVE:
+ case LTTNG_CREATE_SESSION_EXT:
case LTTNG_LIST_SESSIONS:
case LTTNG_LIST_TRACEPOINTS:
case LTTNG_LIST_SYSCALLS:
ret = cmd_stop_trace(cmd_ctx->session);
break;
}
- case LTTNG_CREATE_SESSION:
- {
- size_t nb_uri, len;
- struct lttng_uri *uris = NULL;
-
- nb_uri = cmd_ctx->lsm->u.uri.size;
- len = nb_uri * sizeof(struct lttng_uri);
-
- if (nb_uri > 0) {
- uris = zmalloc(len);
- if (uris == NULL) {
- ret = LTTNG_ERR_FATAL;
- goto error;
- }
-
- /* Receive variable len data */
- 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");
- *sock_error = 1;
- ret = LTTNG_ERR_SESSION_FAIL;
- free(uris);
- goto error;
- }
-
- if (nb_uri == 1 && uris[0].dtype != LTTNG_DST_PATH) {
- DBG("Creating session with ONE network URI is a bad call");
- ret = LTTNG_ERR_SESSION_FAIL;
- free(uris);
- goto error;
- }
- }
-
- ret = cmd_create_session_uri(cmd_ctx->lsm->session.name, uris, nb_uri,
- &cmd_ctx->creds, 0);
-
- free(uris);
-
- break;
- }
case LTTNG_DESTROY_SESSION:
{
ret = cmd_destroy_session(cmd_ctx->session,
nr_sessions = lttng_sessions_count(
LTTNG_SOCK_GET_UID_CRED(&cmd_ctx->creds),
LTTNG_SOCK_GET_GID_CRED(&cmd_ctx->creds));
- payload_len = sizeof(struct lttng_session) * nr_sessions;
+
+ payload_len = (sizeof(struct lttng_session) * nr_sessions) +
+ (sizeof(struct lttng_session_extended) * nr_sessions);
sessions_payload = zmalloc(payload_len);
if (!sessions_payload) {
goto setup_error;
}
- cmd_list_lttng_sessions(sessions_payload,
+ cmd_list_lttng_sessions(sessions_payload, nr_sessions,
LTTNG_SOCK_GET_UID_CRED(&cmd_ctx->creds),
LTTNG_SOCK_GET_GID_CRED(&cmd_ctx->creds));
session_unlock_list();
cmd_ctx->lsm->u.snapshot_record.wait);
break;
}
- case LTTNG_CREATE_SESSION_SNAPSHOT:
+ case LTTNG_CREATE_SESSION_EXT:
{
- size_t nb_uri, len;
- struct lttng_uri *uris = NULL;
+ struct lttng_dynamic_buffer payload;
+ struct lttng_session_descriptor *return_descriptor = NULL;
- nb_uri = cmd_ctx->lsm->u.uri.size;
- len = nb_uri * sizeof(struct lttng_uri);
-
- if (nb_uri > 0) {
- uris = zmalloc(len);
- if (uris == NULL) {
- ret = LTTNG_ERR_FATAL;
- goto error;
- }
-
- /* Receive variable len data */
- 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");
- *sock_error = 1;
- ret = LTTNG_ERR_SESSION_FAIL;
- free(uris);
- goto error;
- }
-
- if (nb_uri == 1 && uris[0].dtype != LTTNG_DST_PATH) {
- DBG("Creating session with ONE network URI is a bad call");
- ret = LTTNG_ERR_SESSION_FAIL;
- free(uris);
- goto error;
- }
+ lttng_dynamic_buffer_init(&payload);
+ ret = cmd_create_session(cmd_ctx, sock, &return_descriptor);
+ if (ret != LTTNG_OK) {
+ goto error;
}
- ret = cmd_create_session_snapshot(cmd_ctx->lsm->session.name, uris,
- nb_uri, &cmd_ctx->creds);
- free(uris);
- break;
- }
- case LTTNG_CREATE_SESSION_LIVE:
- {
- size_t nb_uri, len;
- struct lttng_uri *uris = NULL;
-
- nb_uri = cmd_ctx->lsm->u.uri.size;
- len = nb_uri * sizeof(struct lttng_uri);
-
- if (nb_uri > 0) {
- uris = zmalloc(len);
- if (uris == NULL) {
- ret = LTTNG_ERR_FATAL;
- goto error;
- }
-
- /* Receive variable len data */
- 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");
- *sock_error = 1;
- ret = LTTNG_ERR_SESSION_FAIL;
- free(uris);
- goto error;
- }
-
- if (nb_uri == 1 && uris[0].dtype != LTTNG_DST_PATH) {
- DBG("Creating session with ONE network URI is a bad call");
- ret = LTTNG_ERR_SESSION_FAIL;
- free(uris);
- goto error;
- }
+ ret = lttng_session_descriptor_serialize(return_descriptor,
+ &payload);
+ if (ret) {
+ ERR("Failed to serialize session descriptor in reply to \"create session\" command");
+ lttng_session_descriptor_destroy(return_descriptor);
+ ret = LTTNG_ERR_NOMEM;
+ goto error;
}
-
- ret = cmd_create_session_uri(cmd_ctx->lsm->session.name, uris,
- nb_uri, &cmd_ctx->creds, cmd_ctx->lsm->u.session_live.timer_interval);
- free(uris);
+ ret = setup_lttng_msg_no_cmd_header(cmd_ctx, payload.data,
+ payload.size);
+ if (ret) {
+ lttng_session_descriptor_destroy(return_descriptor);
+ ret = LTTNG_ERR_NOMEM;
+ goto error;
+ }
+ lttng_dynamic_buffer_reset(&payload);
+ lttng_session_descriptor_destroy(return_descriptor);
+ ret = LTTNG_OK;
break;
}
case LTTNG_SAVE_SESSION:
#include <lttng/channel-internal.h>
#include <lttng/rotate-internal.h>
#include <lttng/location-internal.h>
+#include <lttng/session-internal.h>
#include <lttng/userspace-probe-internal.h>
+#include <lttng/session-descriptor-internal.h>
#include <common/string-utils/string-utils.h>
#include "channel.h"
* Add URI so the consumer output object. Set the correct path depending on the
* domain adding the default trace directory.
*/
-static int add_uri_to_consumer(struct consumer_output *consumer,
- struct lttng_uri *uri, enum lttng_domain_type domain,
- const char *session_name)
+static enum lttng_error_code add_uri_to_consumer(
+ const struct ltt_session *session,
+ struct consumer_output *consumer,
+ struct lttng_uri *uri, enum lttng_domain_type domain)
{
- int ret = LTTNG_OK;
- const char *default_trace_dir;
+ int ret;
+ enum lttng_error_code ret_code = LTTNG_OK;
assert(uri);
if (consumer == NULL) {
DBG("No consumer detected. Don't add URI. Stopping.");
- ret = LTTNG_ERR_NO_CONSUMER;
+ ret_code = LTTNG_ERR_NO_CONSUMER;
goto error;
}
switch (domain) {
case LTTNG_DOMAIN_KERNEL:
- default_trace_dir = DEFAULT_KERNEL_TRACE_DIR;
+ ret = lttng_strncpy(consumer->domain_subdir,
+ DEFAULT_KERNEL_TRACE_DIR,
+ sizeof(consumer->domain_subdir));
break;
case LTTNG_DOMAIN_UST:
- default_trace_dir = DEFAULT_UST_TRACE_DIR;
+ ret = lttng_strncpy(consumer->domain_subdir,
+ DEFAULT_UST_TRACE_DIR,
+ sizeof(consumer->domain_subdir));
break;
default:
/*
- * This case is possible is we try to add the URI to the global tracing
- * session consumer object which in this case there is no subdir.
+ * This case is possible is we try to add the URI to the global
+ * tracing session consumer object which in this case there is
+ * no subdir.
*/
- default_trace_dir = "";
+ memset(consumer->domain_subdir, 0,
+ sizeof(consumer->domain_subdir));
+ ret = 0;
+ }
+ if (ret) {
+ ERR("Failed to initialize consumer output domain subdirectory");
+ ret_code = LTTNG_ERR_FATAL;
+ goto error;
}
switch (uri->dtype) {
consumer->dst.net.control_isset) ||
(uri->stype == LTTNG_STREAM_DATA &&
consumer->dst.net.data_isset)) {
- ret = LTTNG_ERR_URL_EXIST;
+ ret_code = LTTNG_ERR_URL_EXIST;
goto error;
}
} else {
- memset(&consumer->dst.net, 0, sizeof(consumer->dst.net));
+ memset(&consumer->dst, 0, sizeof(consumer->dst));
}
- consumer->type = CONSUMER_DST_NET;
-
/* Set URI into consumer output object */
- ret = consumer_set_network_uri(consumer, uri);
+ ret = consumer_set_network_uri(session, consumer, uri);
if (ret < 0) {
- ret = -ret;
+ ret_code = -ret;
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.
*/
- ret = LTTNG_OK;
+ ret_code = LTTNG_OK;
goto error;
}
-
- if (uri->stype == LTTNG_STREAM_CONTROL && strlen(uri->subdir) == 0) {
- ret = consumer_set_subdir(consumer, session_name);
- if (ret < 0) {
- ret = LTTNG_ERR_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) - strlen(consumer->subdir) - 1);
- DBG3("Append domain trace name to subdir %s", consumer->subdir);
- }
-
break;
case LTTNG_DST_PATH:
- DBG2("Setting trace directory path from URI to %s", uri->dst.path);
- memset(consumer->dst.session_root_path, 0,
- sizeof(consumer->dst.session_root_path));
- /* Explicit length checks for strcpy and strcat. */
- if (strlen(uri->dst.path) + strlen(default_trace_dir)
- >= sizeof(consumer->dst.session_root_path)) {
- ret = LTTNG_ERR_FATAL;
+ if (*uri->dst.path != '/' || strstr(uri->dst.path, "../")) {
+ ret_code = LTTNG_ERR_INVALID;
goto error;
}
- strcpy(consumer->dst.session_root_path, uri->dst.path);
- /* Append default trace dir */
- strcat(consumer->dst.session_root_path, default_trace_dir);
- /* Flag consumer as local. */
+ DBG2("Setting trace directory path from URI to %s",
+ uri->dst.path);
+ memset(&consumer->dst, 0, sizeof(consumer->dst));
+
+ ret = lttng_strncpy(consumer->dst.session_root_path,
+ uri->dst.path,
+ sizeof(consumer->dst.session_root_path));
consumer->type = CONSUMER_DST_LOCAL;
break;
}
- ret = LTTNG_OK;
-
+ ret_code = LTTNG_OK;
error:
- return ret;
+ return ret_code;
}
/*
struct consumer_socket *socket;
struct lttng_ht_iter iter;
int ret;
- char *path = NULL;
+ char path[LTTNG_PATH_MAX];
if (!output || !output->socks) {
ERR("No consumer output found");
goto end;
}
- path = zmalloc(LTTNG_PATH_MAX * sizeof(char));
- if (!path) {
- ERR("Cannot allocate mkdir path");
- ret = -1;
- goto end;
- }
-
- ret = snprintf(path, LTTNG_PATH_MAX, "%s%s%s",
+ ret = snprintf(path, sizeof(path), "%s/%s%s",
session_get_base_path(session),
- output->chunk_path, output->subdir);
+ output->chunk_path,
+ output->domain_subdir);
if (ret < 0 || ret >= LTTNG_PATH_MAX) {
- ERR("Format path");
+ ERR("Failed to format path new chunk domain path");
ret = -1;
goto end;
}
ret = consumer_mkdir(socket, session->id, output, path, uid, gid);
pthread_mutex_unlock(socket->lock);
if (ret) {
- ERR("Consumer mkdir");
+ ERR("Failed to create directory at \"%s\"", path);
ret = -1;
goto end_unlock;
}
end_unlock:
rcu_read_unlock();
end:
- free(path);
return ret;
}
/* Set the "global" consumer URIs */
for (i = 0; i < nb_uri; i++) {
- ret = add_uri_to_consumer(session->consumer,
- &uris[i], 0, session->name);
+ ret = add_uri_to_consumer(session,
+ session->consumer,
+ &uris[i], LTTNG_DOMAIN_NONE);
if (ret != LTTNG_OK) {
goto error;
}
/* Set UST session URIs */
if (session->ust_session) {
for (i = 0; i < nb_uri; i++) {
- ret = add_uri_to_consumer(
+ ret = add_uri_to_consumer(session,
session->ust_session->consumer,
- &uris[i], LTTNG_DOMAIN_UST,
- session->name);
+ &uris[i], LTTNG_DOMAIN_UST);
if (ret != LTTNG_OK) {
goto error;
}
/* Set kernel session URIs */
if (session->kernel_session) {
for (i = 0; i < nb_uri; i++) {
- ret = add_uri_to_consumer(
+ ret = add_uri_to_consumer(session,
session->kernel_session->consumer,
- &uris[i], LTTNG_DOMAIN_KERNEL,
- session->name);
+ &uris[i], LTTNG_DOMAIN_KERNEL);
if (ret != LTTNG_OK) {
goto error;
}
return ret;
}
-/*
- * Command LTTNG_CREATE_SESSION processed by the client thread.
- */
-int cmd_create_session_uri(char *name, struct lttng_uri *uris,
- size_t nb_uri, lttng_sock_cred *creds, unsigned int live_timer)
+static
+enum lttng_error_code set_session_output_from_descriptor(
+ struct ltt_session *session,
+ const struct lttng_session_descriptor *descriptor)
{
int ret;
- struct ltt_session *session = NULL;
-
- assert(name);
- assert(creds);
-
- /* Check if the session already exists. */
- session_lock_list();
- session = session_find_by_name(name);
- session_unlock_list();
- if (session != NULL) {
- ret = LTTNG_ERR_EXIST_SESS;
+ enum lttng_error_code ret_code = LTTNG_OK;
+ enum lttng_session_descriptor_type session_type =
+ lttng_session_descriptor_get_type(descriptor);
+ enum lttng_session_descriptor_output_type output_type =
+ lttng_session_descriptor_get_output_type(descriptor);
+ struct lttng_uri uris[2] = {};
+ size_t uri_count = 0;
+
+ switch (output_type) {
+ case LTTNG_SESSION_DESCRIPTOR_OUTPUT_TYPE_NONE:
+ goto end;
+ case LTTNG_SESSION_DESCRIPTOR_OUTPUT_TYPE_LOCAL:
+ lttng_session_descriptor_get_local_output_uri(descriptor,
+ &uris[0]);
+ uri_count = 1;
+ break;
+ case LTTNG_SESSION_DESCRIPTOR_OUTPUT_TYPE_NETWORK:
+ lttng_session_descriptor_get_network_output_uris(descriptor,
+ &uris[0], &uris[1]);
+ uri_count = 2;
+ break;
+ default:
+ ret_code = LTTNG_ERR_INVALID;
goto end;
}
- /* Create tracing session in the registry */
- ret = session_create(name, LTTNG_SOCK_GET_UID_CRED(creds),
- LTTNG_SOCK_GET_GID_CRED(creds));
- if (ret != LTTNG_OK) {
+ switch (session_type) {
+ case LTTNG_SESSION_DESCRIPTOR_TYPE_SNAPSHOT:
+ {
+ struct snapshot_output *new_output = NULL;
+
+ new_output = snapshot_output_alloc();
+ if (!new_output) {
+ ret_code = LTTNG_ERR_NOMEM;
+ goto end;
+ }
+
+ ret = snapshot_output_init_with_uri(session,
+ DEFAULT_SNAPSHOT_MAX_SIZE,
+ NULL, uris, uri_count, session->consumer,
+ new_output, &session->snapshot);
+ if (ret < 0) {
+ ret_code = (ret == -ENOMEM) ?
+ LTTNG_ERR_NOMEM : LTTNG_ERR_INVALID;
+ snapshot_output_destroy(new_output);
+ goto end;
+ }
+ snapshot_add_output(&session->snapshot, new_output);
+ break;
+ }
+ case LTTNG_SESSION_DESCRIPTOR_TYPE_REGULAR:
+ case LTTNG_SESSION_DESCRIPTOR_TYPE_LIVE:
+ {
+ ret_code = cmd_set_consumer_uri(session, uri_count, uris);
+ break;
+ }
+ default:
+ ret_code = LTTNG_ERR_INVALID;
goto end;
}
+end:
+ return ret_code;
+}
+
+static
+enum lttng_error_code cmd_create_session_from_descriptor(
+ struct lttng_session_descriptor *descriptor,
+ const lttng_sock_cred *creds,
+ const char *home_path)
+{
+ int ret;
+ enum lttng_error_code ret_code;
+ const char *session_name;
+ struct ltt_session *new_session = NULL;
+ enum lttng_session_descriptor_status descriptor_status;
- /* Get the newly created session pointer back. */
session_lock_list();
- session = session_find_by_name(name);
- session_unlock_list();
- assert(session);
+ if (home_path) {
+ if (*home_path != '/') {
+ ERR("Home path provided by client is not absolute");
+ ret_code = LTTNG_ERR_INVALID;
+ goto end;
+ }
+ }
- session->live_timer = live_timer;
- /* Create default consumer output for the session not yet created. */
- session->consumer = consumer_create_output(CONSUMER_DST_LOCAL);
- if (session->consumer == NULL) {
- ret = LTTNG_ERR_FATAL;
+ descriptor_status = lttng_session_descriptor_get_session_name(
+ descriptor, &session_name);
+ switch (descriptor_status) {
+ case LTTNG_SESSION_DESCRIPTOR_STATUS_OK:
+ break;
+ case LTTNG_SESSION_DESCRIPTOR_STATUS_UNSET:
+ session_name = NULL;
+ break;
+ default:
+ ret_code = LTTNG_ERR_INVALID;
+ goto end;
+ }
+ ret_code = session_create(session_name, creds->uid, creds->gid,
+ &new_session);
+ if (ret_code != LTTNG_OK) {
goto end;
}
- if (uris) {
- ret = cmd_set_consumer_uri(session, nb_uri, uris);
- if (ret != LTTNG_OK) {
+ if (!session_name) {
+ ret = lttng_session_descriptor_set_session_name(descriptor,
+ new_session->name);
+ if (ret) {
+ ret_code = LTTNG_ERR_SESSION_FAIL;
+ goto end;
+ }
+ }
+
+ if (!lttng_session_descriptor_is_output_destination_initialized(
+ descriptor)) {
+ /*
+ * Only include the session's creation time in the output
+ * destination if the name of the session itself was
+ * not auto-generated.
+ */
+ ret_code = lttng_session_descriptor_set_default_output(
+ descriptor,
+ session_name ? &new_session->creation_time : NULL,
+ home_path);
+ if (ret_code != LTTNG_OK) {
goto end;
}
- session->output_traces = 1;
} else {
- session->output_traces = 0;
- DBG2("Session %s created with no output", session->name);
+ new_session->has_user_specified_directory =
+ lttng_session_descriptor_has_output_directory(
+ descriptor);
}
- session->consumer->enabled = 1;
+ switch (lttng_session_descriptor_get_type(descriptor)) {
+ case LTTNG_SESSION_DESCRIPTOR_TYPE_SNAPSHOT:
+ new_session->snapshot_mode = 1;
+ break;
+ case LTTNG_SESSION_DESCRIPTOR_TYPE_LIVE:
+ new_session->live_timer =
+ lttng_session_descriptor_live_get_timer_interval(
+ descriptor);
+ break;
+ default:
+ break;
+ }
- ret = LTTNG_OK;
+ ret_code = set_session_output_from_descriptor(new_session, descriptor);
+ if (ret_code != LTTNG_OK) {
+ goto end;
+ }
+ new_session->consumer->enabled = 1;
+ ret_code = LTTNG_OK;
end:
- if (session) {
- session_lock_list();
- session_put(session);
- session_unlock_list();
+ /* Release reference provided by the session_create function. */
+ session_put(new_session);
+ if (ret_code != LTTNG_OK && new_session) {
+ /* Release the global reference on error. */
+ session_destroy(new_session);
}
- return ret;
+ session_unlock_list();
+ return ret_code;
}
-/*
- * Command LTTNG_CREATE_SESSION_SNAPSHOT processed by the client thread.
- */
-int cmd_create_session_snapshot(char *name, struct lttng_uri *uris,
- size_t nb_uri, lttng_sock_cred *creds)
+enum lttng_error_code cmd_create_session(struct command_ctx *cmd_ctx, int sock,
+ struct lttng_session_descriptor **return_descriptor)
{
int ret;
- struct ltt_session *session = NULL;
- struct snapshot_output *new_output = NULL;
-
- assert(name);
- assert(creds);
-
- /*
- * Create session in no output mode with URIs set to NULL. The uris we've
- * received are for a default snapshot output if one.
- */
- ret = cmd_create_session_uri(name, NULL, 0, creds, 0);
- if (ret != LTTNG_OK) {
- goto end;
+ size_t payload_size;
+ struct lttng_dynamic_buffer payload;
+ struct lttng_buffer_view home_dir_view;
+ struct lttng_buffer_view session_descriptor_view;
+ struct lttng_session_descriptor *session_descriptor = NULL;
+ enum lttng_error_code ret_code;
+
+ lttng_dynamic_buffer_init(&payload);
+ if (cmd_ctx->lsm->u.create_session.home_dir_size >=
+ LTTNG_PATH_MAX) {
+ ret_code = LTTNG_ERR_INVALID;
+ goto error;
}
-
- /* Get the newly created session pointer back. This should NEVER fail. */
- session_lock_list();
- session = session_find_by_name(name);
- session_unlock_list();
- assert(session);
-
- /* Flag session for snapshot mode. */
- session->snapshot_mode = 1;
-
- /* Skip snapshot output creation if no URI is given. */
- if (nb_uri == 0) {
- /* Not an error. */
- goto end;
+ if (cmd_ctx->lsm->u.create_session.session_descriptor_size >
+ LTTNG_SESSION_DESCRIPTOR_MAX_LEN) {
+ ret_code = LTTNG_ERR_INVALID;
+ goto error;
}
- new_output = snapshot_output_alloc();
- if (!new_output) {
- ret = LTTNG_ERR_NOMEM;
- goto error_snapshot_alloc;
+ payload_size = cmd_ctx->lsm->u.create_session.home_dir_size +
+ cmd_ctx->lsm->u.create_session.session_descriptor_size;
+ ret = lttng_dynamic_buffer_set_size(&payload, payload_size);
+ if (ret) {
+ ret_code = LTTNG_ERR_NOMEM;
+ goto error;
}
- ret = snapshot_output_init_with_uri(DEFAULT_SNAPSHOT_MAX_SIZE, NULL,
- uris, nb_uri, session->consumer, new_output, &session->snapshot);
- if (ret < 0) {
- if (ret == -ENOMEM) {
- ret = LTTNG_ERR_NOMEM;
- } else {
- ret = LTTNG_ERR_INVALID;
- }
- goto error_snapshot;
+ ret = lttcomm_recv_unix_sock(sock, payload.data, payload.size);
+ if (ret <= 0) {
+ ERR("Reception of session descriptor failed, aborting.");
+ ret_code = LTTNG_ERR_SESSION_FAIL;
+ goto error;
}
- rcu_read_lock();
- snapshot_add_output(&session->snapshot, new_output);
- rcu_read_unlock();
+ home_dir_view = lttng_buffer_view_from_dynamic_buffer(
+ &payload,
+ 0,
+ cmd_ctx->lsm->u.create_session.home_dir_size);
+ session_descriptor_view = lttng_buffer_view_from_dynamic_buffer(
+ &payload,
+ cmd_ctx->lsm->u.create_session.home_dir_size,
+ cmd_ctx->lsm->u.create_session.session_descriptor_size);
- ret = LTTNG_OK;
- goto end;
+ ret = lttng_session_descriptor_create_from_buffer(
+ &session_descriptor_view, &session_descriptor);
+ if (ret < 0) {
+ ERR("Failed to create session descriptor from payload of \"create session\" command");
+ ret_code = LTTNG_ERR_INVALID;
+ goto error;
+ }
-error_snapshot:
- snapshot_output_destroy(new_output);
-error_snapshot_alloc:
-end:
- if (session) {
- session_lock_list();
- session_put(session);
- session_unlock_list();
+ /*
+ * Sets the descriptor's auto-generated properties (name, output) if
+ * needed.
+ */
+ ret_code = cmd_create_session_from_descriptor(session_descriptor,
+ &cmd_ctx->creds,
+ home_dir_view.size ? home_dir_view.data : NULL);
+ if (ret_code != LTTNG_OK) {
+ goto error;
}
- return ret;
+
+ ret_code = LTTNG_OK;
+ *return_descriptor = session_descriptor;
+ session_descriptor = NULL;
+error:
+ lttng_dynamic_buffer_reset(&payload);
+ lttng_session_descriptor_destroy(session_descriptor);
+ return ret_code;
}
/*
* The session list lock MUST be acquired before calling this function. Use
* session_lock_list() and session_unlock_list().
*/
-void cmd_list_lttng_sessions(struct lttng_session *sessions, uid_t uid,
- gid_t gid)
+void cmd_list_lttng_sessions(struct lttng_session *sessions,
+ size_t session_count, uid_t uid, gid_t gid)
{
int ret;
unsigned int i = 0;
struct ltt_session *session;
struct ltt_session_list *list = session_get_list();
+ struct lttng_session_extended *extended =
+ (typeof(extended)) (&sessions[session_count]);
DBG("Getting all available session for UID %d GID %d",
uid, gid);
sessions[i].enabled = session->active;
sessions[i].snapshot_mode = session->snapshot_mode;
sessions[i].live_timer_interval = session->live_timer;
+ extended[i].creation_time.value = (uint64_t) session->creation_time;
+ extended[i].creation_time.is_set = 1;
i++;
session_put(session);
}
goto error;
}
- ret = snapshot_output_init(output->max_size, output->name,
+ ret = snapshot_output_init(session, output->max_size, output->name,
output->ctrl_url, output->data_url, session->consumer, new_output,
&session->snapshot);
if (ret < 0) {
/* Use temporary output for the session. */
if (*output->ctrl_url != '\0') {
- ret = snapshot_output_init(output->max_size, output->name,
- output->ctrl_url, output->data_url, session->consumer,
+ ret = snapshot_output_init(session, output->max_size,
+ output->name,
+ output->ctrl_url, output->data_url,
+ session->consumer,
&tmp_output, NULL);
if (ret < 0) {
if (ret == -ENOMEM) {
goto end;
}
+ /* Current chunk directory, ex: 20170922-111754-42 */
+ ret = snprintf(session->consumer->chunk_path,
+ sizeof(session->consumer->chunk_path),
+ "%s-%" PRIu64, datetime,
+ session->current_archive_id + 1);
+ if (ret < 0 || ret >= sizeof(session->consumer->chunk_path)) {
+ ERR("Failed to format the new chunk's directory in rotate session command");
+ cmd_ret = LTTNG_ERR_UNK;
+ goto error;
+ }
+
+ /*
+ * The active path for the next rotation/destroy.
+ * Ex: ~/lttng-traces/auto-20170922-111748/20170922-111754-42
+ */
+ ret = snprintf(session->rotation_chunk.active_tracing_path,
+ sizeof(session->rotation_chunk.active_tracing_path),
+ "%s/%s",
+ session_get_base_path(session),
+ session->consumer->chunk_path);
+ if (ret < 0 || ret >= sizeof(session->rotation_chunk.active_tracing_path)) {
+ ERR("Failed to format active tracing path in rotate session command");
+ cmd_ret = LTTNG_ERR_UNK;
+ goto error;
+ }
+
/*
* A rotation has a local step even if the destination is a relay
* daemon; the buffers must be consumed by the consumer daemon.
session->rotation_state = LTTNG_ROTATION_STATE_ONGOING;
if (session->kernel_session) {
- /*
- * The active path for the next rotation/destroy.
- * Ex: ~/lttng-traces/auto-20170922-111748/20170922-111754-42
- */
- ret = snprintf(session->rotation_chunk.active_tracing_path,
- sizeof(session->rotation_chunk.active_tracing_path),
- "%s/%s-%" PRIu64,
- session_get_base_path(session),
- datetime, session->current_archive_id + 1);
- if (ret < 0 || ret == sizeof(session->rotation_chunk.active_tracing_path)) {
- ERR("Failed to format active kernel tracing path in rotate session command");
- cmd_ret = LTTNG_ERR_UNK;
- goto error;
- }
- /*
- * The sub-directory for the consumer
- * Ex: /20170922-111754-42/kernel
- */
- ret = snprintf(session->kernel_session->consumer->chunk_path,
- sizeof(session->kernel_session->consumer->chunk_path),
- "/%s-%" PRIu64, datetime,
- session->current_archive_id + 1);
- if (ret < 0 || ret == sizeof(session->kernel_session->consumer->chunk_path)) {
- ERR("Failed to format the kernel consumer's sub-directory in rotate session command");
+ ret = lttng_strncpy(
+ session->kernel_session->consumer->chunk_path,
+ session->consumer->chunk_path,
+ sizeof(session->kernel_session->consumer->chunk_path));
+ if (ret) {
+ ERR("Failed to copy current chunk directory to kernel session");
cmd_ret = LTTNG_ERR_UNK;
goto error;
}
/*
- * Create the new chunk folder, before the rotation begins so we don't
- * race with the consumer/tracer activity.
+ * Create the new chunk folder, before the rotation begins so we
+ * don't race with the consumer/tracer activity.
*/
ret = domain_mkdir(session->kernel_session->consumer, session,
session->kernel_session->uid,
session->kernel_session->gid);
if (ret) {
- ERR("Failed to create kernel session tracing path at %s",
- session->kernel_session->consumer->chunk_path);
cmd_ret = LTTNG_ERR_CREATE_DIR_FAIL;
goto error;
}
}
}
if (session->ust_session) {
- ret = snprintf(session->rotation_chunk.active_tracing_path,
- PATH_MAX, "%s/%s-%" PRIu64,
- session_get_base_path(session),
- datetime, session->current_archive_id + 1);
- if (ret < 0) {
- ERR("Failed to format active UST tracing path in rotate session command");
- cmd_ret = LTTNG_ERR_UNK;
- goto error;
- }
- ret = snprintf(session->ust_session->consumer->chunk_path,
- PATH_MAX, "/%s-%" PRIu64, datetime,
- session->current_archive_id + 1);
- if (ret < 0) {
- ERR("Failed to format the UST consumer's sub-directory in rotate session command");
+ ret = lttng_strncpy(
+ session->ust_session->consumer->chunk_path,
+ session->consumer->chunk_path,
+ sizeof(session->ust_session->consumer->chunk_path));
+ if (ret) {
+ ERR("Failed to copy current chunk directory to userspace session");
cmd_ret = LTTNG_ERR_UNK;
goto error;
}
- /*
- * Create the new chunk folder, before the rotation begins so we don't
- * race with the consumer/tracer activity.
- */
ret = domain_mkdir(session->ust_session->consumer, session,
session->ust_session->uid,
session->ust_session->gid);
void cmd_init(void);
/* Session commands */
-int cmd_create_session_uri(char *name, struct lttng_uri *uris,
- size_t nb_uri, lttng_sock_cred *creds, unsigned int live_timer);
-int cmd_create_session_snapshot(char *name, struct lttng_uri *uris,
- size_t nb_uri, lttng_sock_cred *creds);
+enum lttng_error_code cmd_create_session(struct command_ctx *cmd_ctx, int sock,
+ struct lttng_session_descriptor **return_descriptor);
int cmd_destroy_session(struct ltt_session *session,
struct notification_thread_handle *notification_thread_handle);
struct ltt_session *session, struct lttng_channel **channels);
ssize_t cmd_list_domains(struct ltt_session *session,
struct lttng_domain **domains);
-void cmd_list_lttng_sessions(struct lttng_session *sessions, uid_t uid,
- gid_t gid);
+void cmd_list_lttng_sessions(struct lttng_session *sessions,
+ size_t session_count, uid_t uid, gid_t gid);
ssize_t cmd_list_tracepoint_fields(enum lttng_domain_type domain,
struct lttng_event_field **fields);
ssize_t cmd_list_tracepoints(enum lttng_domain_type domain,
*
* Should *NOT* be called with RCU read-side lock held.
*/
-struct consumer_output *consumer_copy_output(struct consumer_output *obj)
+struct consumer_output *consumer_copy_output(struct consumer_output *src)
{
int ret;
struct consumer_output *output;
- assert(obj);
+ assert(src);
- output = consumer_create_output(obj->type);
+ output = consumer_create_output(src->type);
if (output == NULL) {
goto end;
}
- output->enabled = obj->enabled;
- output->net_seq_index = obj->net_seq_index;
- memcpy(output->subdir, obj->subdir, sizeof(output->subdir));
- output->snapshot = obj->snapshot;
- output->relay_major_version = obj->relay_major_version;
- output->relay_minor_version = obj->relay_minor_version;
- memcpy(&output->dst, &obj->dst, sizeof(output->dst));
- ret = consumer_copy_sockets(output, obj);
+ output->enabled = src->enabled;
+ output->net_seq_index = src->net_seq_index;
+ memcpy(output->domain_subdir, src->domain_subdir,
+ sizeof(output->domain_subdir));
+ output->snapshot = src->snapshot;
+ output->relay_major_version = src->relay_major_version;
+ output->relay_minor_version = src->relay_minor_version;
+ memcpy(&output->dst, &src->dst, sizeof(output->dst));
+ ret = consumer_copy_sockets(output, src);
if (ret < 0) {
goto error_put;
}
}
/*
- * Set network URI to the consumer output object.
+ * Set network URI to the consumer output.
*
* Return 0 on success. Return 1 if the URI were equal. Else, negative value on
* error.
*/
-int consumer_set_network_uri(struct consumer_output *obj,
+int consumer_set_network_uri(const struct ltt_session *session,
+ struct consumer_output *output,
struct lttng_uri *uri)
{
int ret;
- char tmp_path[PATH_MAX];
- char hostname[HOST_NAME_MAX];
struct lttng_uri *dst_uri = NULL;
/* Code flow error safety net. */
- assert(obj);
+ assert(output);
assert(uri);
switch (uri->stype) {
case LTTNG_STREAM_CONTROL:
- dst_uri = &obj->dst.net.control;
- obj->dst.net.control_isset = 1;
+ dst_uri = &output->dst.net.control;
+ output->dst.net.control_isset = 1;
if (uri->port == 0) {
/* Assign default port. */
uri->port = DEFAULT_NETWORK_CONTROL_PORT;
} else {
- if (obj->dst.net.data_isset && uri->port ==
- obj->dst.net.data.port) {
+ if (output->dst.net.data_isset && uri->port ==
+ output->dst.net.data.port) {
ret = -LTTNG_ERR_INVALID;
goto error;
}
DBG3("Consumer control URI set with port %d", uri->port);
break;
case LTTNG_STREAM_DATA:
- dst_uri = &obj->dst.net.data;
- obj->dst.net.data_isset = 1;
+ dst_uri = &output->dst.net.data;
+ output->dst.net.data_isset = 1;
if (uri->port == 0) {
/* Assign default port. */
uri->port = DEFAULT_NETWORK_DATA_PORT;
} else {
- if (obj->dst.net.control_isset && uri->port ==
- obj->dst.net.control.port) {
+ if (output->dst.net.control_isset && uri->port ==
+ output->dst.net.control.port) {
ret = -LTTNG_ERR_INVALID;
goto error;
}
}
/* URIs were not equal, replacing it. */
- memset(dst_uri, 0, sizeof(struct lttng_uri));
memcpy(dst_uri, uri, sizeof(struct lttng_uri));
- obj->type = CONSUMER_DST_NET;
-
- /* Handle subdir and add hostname in front. */
- if (dst_uri->stype == LTTNG_STREAM_CONTROL) {
- /* Get hostname to append it in the pathname */
- ret = gethostname(hostname, sizeof(hostname));
- if (ret < 0) {
- PERROR("gethostname. Fallback on default localhost");
- strncpy(hostname, "localhost", sizeof(hostname));
- }
- hostname[sizeof(hostname) - 1] = '\0';
+ output->type = CONSUMER_DST_NET;
+ if (dst_uri->stype != LTTNG_STREAM_CONTROL) {
+ /* Only the control uri needs to contain the path. */
+ goto end;
+ }
- /* Setup consumer subdir if none present in the control URI */
- if (strlen(dst_uri->subdir) == 0) {
- ret = snprintf(tmp_path, sizeof(tmp_path), "%s/%s",
- hostname, obj->subdir);
- } else {
- ret = snprintf(tmp_path, sizeof(tmp_path), "%s/%s",
- hostname, dst_uri->subdir);
- }
- if (ret < 0) {
- PERROR("snprintf set consumer uri subdir");
- ret = -LTTNG_ERR_NOMEM;
+ /*
+ * If the user has specified a subdir as part of the control
+ * URL, the session's base output directory is:
+ * /RELAYD_OUTPUT_PATH/HOSTNAME/USER_SPECIFIED_DIR
+ *
+ * Hence, the "base_dir" from which all stream files and
+ * session rotation chunks are created takes the form
+ * /HOSTNAME/USER_SPECIFIED_DIR
+ *
+ * If the user has not specified an output directory as part of
+ * the control URL, the base output directory has the form:
+ * /RELAYD_OUTPUT_PATH/HOSTNAME/SESSION_NAME-CREATION_TIME
+ *
+ * Hence, the "base_dir" from which all stream files and
+ * session rotation chunks are created takes the form
+ * /HOSTNAME/SESSION_NAME-CREATION_TIME
+ *
+ * Note that automatically generated session names already
+ * contain the session's creation time. In that case, the
+ * creation time is omitted to prevent it from being duplicated
+ * in the final directory hierarchy.
+ */
+ if (*uri->subdir) {
+ if (strstr(uri->subdir, "../")) {
+ ERR("Network URI subdirs are not allowed to walk up the path hierarchy");
+ ret = -LTTNG_ERR_INVALID;
goto error;
}
+ ret = snprintf(output->dst.net.base_dir,
+ sizeof(output->dst.net.base_dir),
+ "/%s/%s/", session->hostname, uri->subdir);
+ } else {
+ if (session->has_auto_generated_name) {
+ ret = snprintf(output->dst.net.base_dir,
+ sizeof(output->dst.net.base_dir),
+ "/%s/%s/", session->hostname,
+ session->name);
+ } else {
+ char session_creation_datetime[16];
+ size_t strftime_ret;
+ struct tm *timeinfo;
- if (lttng_strncpy(obj->dst.net.base_dir, tmp_path,
- sizeof(obj->dst.net.base_dir))) {
- ret = -LTTNG_ERR_INVALID;
- goto error;
+ timeinfo = localtime(&session->creation_time);
+ if (!timeinfo) {
+ ret = -LTTNG_ERR_FATAL;
+ goto error;
+ }
+ strftime_ret = strftime(session_creation_datetime,
+ sizeof(session_creation_datetime),
+ "%Y%m%d-%H%M%S", timeinfo);
+ if (strftime_ret == 0) {
+ ERR("Failed to format session creation timestamp while setting network URI");
+ ret = -LTTNG_ERR_FATAL;
+ goto error;
+ }
+ ret = snprintf(output->dst.net.base_dir,
+ sizeof(output->dst.net.base_dir),
+ "/%s/%s-%s/", session->hostname,
+ session->name,
+ session_creation_datetime);
}
- DBG3("Consumer set network uri base_dir path %s", tmp_path);
}
+ if (ret >= sizeof(output->dst.net.base_dir)) {
+ ret = -LTTNG_ERR_INVALID;
+ ERR("Truncation occurred while setting network output base directory");
+ goto error;
+ } else if (ret == -1) {
+ ret = -LTTNG_ERR_INVALID;
+ PERROR("Error occurred while setting network output base directory");
+ goto error;
+ }
+
+ DBG3("Consumer set network uri base_dir path %s",
+ output->dst.net.base_dir);
+end:
return 0;
equal:
return 1;
LTTNG_CONSUMER_SET_CHANNEL_MONITOR_PIPE, pipe);
}
-/*
- * Set consumer subdirectory using the session name and a generated datetime if
- * needed. This is appended to the current subdirectory.
- */
-int consumer_set_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;
- }
-
- if (lttng_strncpy(consumer->subdir, tmp_path,
- sizeof(consumer->subdir))) {
- ret = -EINVAL;
- goto error;
- }
- DBG2("Consumer subdir set to %s", consumer->subdir);
-
-error:
- return ret;
-}
-
/*
* Ask the consumer if the data is pending for the specific session id.
* Returns 1 if data is pending, 0 otherwise, or < 0 on error.
sizeof(msg.u.snapshot_channel.pathname),
"%s/%s/%s-%s-%" PRIu64 "%s",
output->consumer->dst.net.base_dir,
- output->consumer->subdir,
+ output->consumer->domain_subdir,
output->name, output->datetime,
output->nb_snapshot,
session_path);
ERR("Snapshot path exceeds the maximal allowed length of %zu bytes (%i bytes required) with path \"%s/%s/%s-%s-%" PRIu64 "%s\"",
sizeof(msg.u.snapshot_channel.pathname),
ret, output->consumer->dst.net.base_dir,
- output->consumer->subdir,
+ output->consumer->domain_subdir,
output->name, output->datetime,
output->nb_snapshot,
session_path);
*/
int consumer_rotate_channel(struct consumer_socket *socket, uint64_t key,
uid_t uid, gid_t gid, struct consumer_output *output,
- char *domain_path, bool is_metadata_channel,
+ const char *domain_path, bool is_metadata_channel,
uint64_t new_chunk_id)
{
int ret;
sizeof(msg.u.rotate_channel.pathname), "%s%s%s",
output->dst.net.base_dir,
output->chunk_path, domain_path);
- if (ret < 0 || ret == sizeof(msg.u.rotate_channel.pathname)) {
+ if (ret < 0 || ret >= sizeof(msg.u.rotate_channel.pathname)) {
ERR("Failed to format channel path name when asking consumer to rotate channel");
ret = -LTTNG_ERR_INVALID;
goto error;
} else {
msg.u.rotate_channel.relayd_id = (uint64_t) -1ULL;
ret = snprintf(msg.u.rotate_channel.pathname,
- sizeof(msg.u.rotate_channel.pathname), "%s%s%s",
+ sizeof(msg.u.rotate_channel.pathname), "%s/%s%s",
output->dst.session_root_path,
output->chunk_path, domain_path);
- if (ret < 0 || ret == sizeof(msg.u.rotate_channel.pathname)) {
+ if (ret < 0 || ret >= sizeof(msg.u.rotate_channel.pathname)) {
ERR("Failed to format channel path name when asking consumer to rotate channel");
ret = -LTTNG_ERR_INVALID;
goto error;
struct snapshot;
struct snapshot_output;
+struct ltt_session;
enum consumer_dst_type {
CONSUMER_DST_LOCAL,
/*
* Subdirectory path name used for both local and network
- * consumer (/kernel or /ust).
+ * consumer ("/kernel", "/ust", or empty).
*/
- char subdir[LTTNG_PATH_MAX];
+ char domain_subdir[max(sizeof(DEFAULT_KERNEL_TRACE_DIR),
+ sizeof(DEFAULT_UST_TRACE_DIR))];
/*
* Hashtable of consumer_socket index by the file descriptor value. For
- * multiarch consumer support, we can have more than one consumer (ex: 32
- * and 64 bit).
+ * multiarch consumer support, we can have more than one consumer (ex:
+ * 32 and 64 bit).
*/
struct lttng_ht *socks;
struct consumer_output *consumer_copy_output(struct consumer_output *obj);
void consumer_output_get(struct consumer_output *obj);
void consumer_output_put(struct consumer_output *obj);
-int consumer_set_network_uri(struct consumer_output *obj,
+int consumer_set_network_uri(const struct ltt_session *session,
+ struct consumer_output *obj,
struct lttng_uri *uri);
int consumer_send_fds(struct consumer_socket *sock, const int *fds,
size_t nb_fd);
void consumer_output_send_destroy_relayd(struct consumer_output *consumer);
int consumer_create_socket(struct consumer_data *data,
struct consumer_output *output);
-int consumer_set_subdir(struct consumer_output *consumer,
- const char *session_name);
void consumer_init_ask_channel_comm_msg(struct lttcomm_consumer_msg *msg,
uint64_t subbuf_size,
/* Rotation commands. */
int consumer_rotate_channel(struct consumer_socket *socket, uint64_t key,
uid_t uid, gid_t gid, struct consumer_output *output,
- char *domain_path, bool is_metadata_channel, uint64_t new_chunk_id);
+ const char *domain_path, bool is_metadata_channel,
+ uint64_t new_chunk_id);
int consumer_rotate_rename(struct consumer_socket *socket, uint64_t session_id,
const struct consumer_output *output, const char *old_path,
const char *new_path, uid_t uid, gid_t gid);
ret = snprintf(tmp_path, sizeof(tmp_path), "%s%s%s",
consumer->dst.session_root_path,
consumer->chunk_path,
- consumer->subdir);
+ consumer->domain_subdir);
if (ret < 0) {
PERROR("snprintf kernel channel path");
goto error;
sizeof(tmp_path), ret,
consumer->dst.session_root_path,
consumer->chunk_path,
- consumer->subdir);
+ consumer->domain_subdir);
goto error;
}
pathname = lttng_strndup(tmp_path, sizeof(tmp_path));
}
DBG3("Kernel local consumer tracefile path: %s", pathname);
} else {
+ /* Network output. */
ret = snprintf(tmp_path, sizeof(tmp_path), "%s%s",
consumer->dst.net.base_dir,
- consumer->subdir);
+ consumer->domain_subdir);
if (ret < 0) {
PERROR("snprintf kernel metadata path");
goto error;
ERR("Kernel channel path exceeds the maximal allowed length of of %zu bytes (%i bytes required) with path \"%s%s\"",
sizeof(tmp_path), ret,
consumer->dst.net.base_dir,
- consumer->subdir);
+ consumer->domain_subdir);
goto error;
}
pathname = lttng_strndup(tmp_path, sizeof(tmp_path));
chan->key, session->name);
ret = consumer_rotate_channel(socket, chan->key,
ksess->uid, ksess->gid, ksess->consumer,
- ksess->consumer->subdir,
+ ksess->consumer->domain_subdir,
/* is_metadata_channel */ false,
session->current_archive_id);
if (ret < 0) {
*/
ret = consumer_rotate_channel(socket, ksess->metadata->key,
ksess->uid, ksess->gid, ksess->consumer,
- ksess->consumer->subdir,
+ ksess->consumer->domain_subdir,
/* is_metadata_channel */ true,
session->current_archive_id);
if (ret < 0) {
int ret;
char current_full_path[LTTNG_PATH_MAX], new_full_path[LTTNG_PATH_MAX];
- /* Current domain path: <session>/kernel */
if (session->net_handle > 0) {
- ret = snprintf(current_full_path, sizeof(current_full_path), "%s/%s",
- consumer->dst.net.base_dir, consumer->subdir);
+ /*
+ * Current domain path:
+ * HOSTNAME/{SESSION-[TIMESTAMP], USER_DIRECTORY}/DOMAIN
+ */
+ ret = snprintf(current_full_path, sizeof(current_full_path),
+ "%s%s",
+ consumer->dst.net.base_dir,
+ consumer->domain_subdir);
if (ret < 0 || ret >= sizeof(current_full_path)) {
ERR("Failed to initialize current full path while renaming first rotation chunk of session \"%s\"",
session->name);
- ret = -1;
+ ret = -LTTNG_ERR_UNK;
goto error;
}
} else {
- ret = snprintf(current_full_path, sizeof(current_full_path), "%s/%s",
- consumer->dst.session_root_path, consumer->subdir);
+ /*
+ * Current domain path:
+ * SESSION_OUTPUT_PATH/DOMAIN
+ */
+ ret = snprintf(current_full_path, sizeof(current_full_path),
+ "%s/%s",
+ consumer->dst.session_root_path,
+ consumer->domain_subdir);
if (ret < 0 || ret >= sizeof(current_full_path)) {
ERR("Failed to initialize current full path while renaming first rotation chunk of session \"%s\"",
session->name);
- ret = -1;
+ ret = -LTTNG_ERR_UNK;
goto error;
}
}
- /* New domain path: <session>/<start-date>-<end-date>-<rotate-count>/kernel */
+ /*
+ * New domain path:
+ * SESSION_BASE_PATH/<START_TS>_<END_TS>-INDEX/DOMAIN
+ */
ret = snprintf(new_full_path, sizeof(new_full_path), "%s/%s",
- new_path, consumer->subdir);
+ new_path, consumer->domain_subdir);
if (ret < 0 || ret >= sizeof(new_full_path)) {
ERR("Failed to initialize new full path while renaming first rotation chunk of session \"%s\"",
session->name);
- ret = -1;
+ ret = -LTTNG_ERR_UNK;
goto error;
}
- /*
- * Move the per-domain fcurrenter inside the first rotation
- * fcurrenter.
- */
+ /* Move the per-domain inside the first rotation chunk path. */
ret = session_rename_chunk(session, current_full_path, new_full_path);
if (ret < 0) {
ret = -LTTNG_ERR_UNK;
*
* Returns 0 on success, a negative value on error.
*/
-int rename_completed_chunk(struct ltt_session *session, time_t ts)
+int rename_completed_chunk(struct ltt_session *session, time_t end_ts)
{
- struct tm *timeinfo;
- char new_path[LTTNG_PATH_MAX];
- char datetime[21], start_datetime[21];
int ret;
size_t strf_ret;
+ struct tm *timeinfo;
+ char new_path[LTTNG_PATH_MAX];
+ char start_datetime[21], end_datetime[21];
DBG("Renaming completed chunk for session %s", session->name);
- timeinfo = localtime(&ts);
+
+ /* Format chunk start time. */
+ timeinfo = localtime(&session->last_chunk_start_ts);
if (!timeinfo) {
- ERR("Failed to retrieve local time while renaming completed chunk");
+ ERR("Failed to separate local time while renaming completed chunk");
ret = -1;
goto end;
}
-
- strf_ret = strftime(datetime, sizeof(datetime), "%Y%m%dT%H%M%S%z",
- timeinfo);
+ strf_ret = strftime(start_datetime, sizeof(start_datetime),
+ "%Y%m%dT%H%M%S%z", timeinfo);
if (strf_ret == 0) {
ERR("Failed to format timestamp while renaming completed session chunk");
ret = -1;
goto end;
}
- if (session->current_archive_id == 1) {
- char start_time[21];
-
- timeinfo = localtime(&session->last_chunk_start_ts);
- if (!timeinfo) {
- ERR("Failed to retrieve local time while renaming completed chunk");
- ret = -1;
- goto end;
- }
+ /* Format chunk end time. */
+ timeinfo = localtime(&end_ts);
+ if (!timeinfo) {
+ ERR("Failed to parse time while renaming completed chunk");
+ ret = -1;
+ goto end;
+ }
+ strf_ret = strftime(end_datetime, sizeof(end_datetime),
+ "%Y%m%dT%H%M%S%z", timeinfo);
+ if (strf_ret == 0) {
+ ERR("Failed to format timestamp while renaming completed session chunk");
+ ret = -1;
+ goto end;
+ }
- strf_ret = strftime(start_time, sizeof(start_time),
- "%Y%m%dT%H%M%S%z", timeinfo);
- if (strf_ret == 0) {
- ERR("Failed to format timestamp while renaming completed session chunk");
- ret = -1;
- goto end;
- }
+ /* Format completed chunk's path. */
+ ret = snprintf(new_path, sizeof(new_path), "%s/archives/%s-%s-%" PRIu64,
+ session_get_base_path(session),
+ start_datetime, end_datetime,
+ session->current_archive_id);
+ if (ret < 0 || ret >= sizeof(new_path)) {
+ ERR("Failed to format new chunk path while renaming chunk of session \"%s\"",
+ session->name);
+ ret = -1;
+ goto error;
+ }
+ if (session->current_archive_id == 1) {
/*
* On the first rotation, the current_rotate_path is the
* session_root_path, so we need to create the chunk folder
* and move the domain-specific folders inside it.
*/
- ret = snprintf(new_path, sizeof(new_path), "%s/archives/%s-%s-%" PRIu64,
- session->rotation_chunk.current_rotate_path,
- start_time,
- datetime, session->current_archive_id);
- if (ret < 0 || ret >= sizeof(new_path)) {
- ERR("Failed to format new chunk path while renaming session \"%s\"'s first chunk",
- session->name);
- ret = -1;
- goto end;
- }
-
if (session->kernel_session) {
ret = rename_first_chunk(session,
session->kernel_session->consumer,
new_path);
if (ret) {
- ERR("Failed to rename kernel session trace folder to %s", new_path);
+ ERR("Failed to rename kernel session trace folder to \"%s\"", new_path);
/*
* This is not a fatal error for the rotation
* thread, we just need to inform the client
session->ust_session->consumer,
new_path);
if (ret) {
- ERR("Failed to rename userspace session trace folder to %s", new_path);
+ ERR("Failed to rename userspace session trace folder to \"%s\"", new_path);
ret = 0;
goto error;
}
* After the first rotation, all the trace data is already in
* its own chunk folder, we just need to append the suffix.
*/
- /* Recreate the session->rotation_chunk.current_rotate_path */
- timeinfo = localtime(&session->last_chunk_start_ts);
- if (!timeinfo) {
- ERR("Failed to retrieve local time while renaming completed chunk");
- ret = -1;
- goto end;
- }
- strf_ret = strftime(start_datetime, sizeof(start_datetime),
- "%Y%m%dT%H%M%S%z", timeinfo);
- if (!strf_ret) {
- ERR("Failed to format timestamp while renaming completed session chunk");
- ret = -1;
- goto end;
- }
- ret = snprintf(new_path, sizeof(new_path), "%s/archives/%s-%s-%" PRIu64,
- session_get_base_path(session),
- start_datetime,
- datetime, session->current_archive_id);
- if (ret < 0 || ret >= sizeof(new_path)) {
- ERR("Failed to format new chunk path while renaming chunk of session \"%s\"",
- session->name);
- ret = -1;
- goto error;
- }
ret = session_rename_chunk(session,
session->rotation_chunk.current_rotate_path,
new_path);
if (ret) {
- ERR("Failed to rename session trace folder from %s to %s",
+ ERR("Failed to rename session trace folder from \"%s\" to \"%s\"",
session->rotation_chunk.current_rotate_path,
new_path);
ret = 0;
*/
void session_put(struct ltt_session *session)
{
+ if (!session) {
+ return;
+ }
/*
* The session list lock must be held as any session_put()
* may cause the removal of the session from the session_list.
}
/*
- * Create a brand new session and add it to the session list.
+ * Create a new session and add it to the session list.
+ * Session list lock must be held by the caller.
*/
-int session_create(char *name, uid_t uid, gid_t gid)
+enum lttng_error_code session_create(const char *name, uid_t uid, gid_t gid,
+ struct ltt_session **out_session)
{
int ret;
- struct ltt_session *new_session;
+ enum lttng_error_code ret_code;
+ struct ltt_session *new_session = NULL;
- /* Allocate session data structure */
+ ASSERT_LOCKED(ltt_session_list.lock);
+ if (name) {
+ struct ltt_session *clashing_session;
+
+ clashing_session = session_find_by_name(name);
+ if (clashing_session) {
+ session_put(clashing_session);
+ ret_code = LTTNG_ERR_EXIST_SESS;
+ goto error;
+ }
+ }
new_session = zmalloc(sizeof(struct ltt_session));
- if (new_session == NULL) {
- PERROR("zmalloc");
- ret = LTTNG_ERR_FATAL;
- goto error_malloc;
+ if (!new_session) {
+ PERROR("Failed to allocate an ltt_session structure");
+ ret_code = LTTNG_ERR_NOMEM;
+ goto error;
}
urcu_ref_init(&new_session->ref);
+ pthread_mutex_init(&new_session->lock, NULL);
- /* Define session name */
- if (name != NULL) {
- if (snprintf(new_session->name, NAME_MAX, "%s", name) < 0) {
- ret = LTTNG_ERR_FATAL;
- goto error_asprintf;
- }
- } else {
- ERR("No session name given");
- ret = LTTNG_ERR_FATAL;
+ new_session->creation_time = time(NULL);
+ if (new_session->creation_time == (time_t) -1) {
+ PERROR("Failed to sample session creation time");
+ ret_code = LTTNG_ERR_SESSION_FAIL;
goto error;
}
- ret = validate_name(name);
- if (ret < 0) {
- ret = LTTNG_ERR_SESSION_INVALID_CHAR;
+ /* Create default consumer output. */
+ new_session->consumer = consumer_create_output(CONSUMER_DST_LOCAL);
+ if (new_session->consumer == NULL) {
+ ret_code = LTTNG_ERR_NOMEM;
goto error;
}
+ if (name) {
+ ret = lttng_strncpy(new_session->name, name, sizeof(new_session->name));
+ if (ret) {
+ ret_code = LTTNG_ERR_SESSION_INVALID_CHAR;
+ goto error;
+ }
+ ret = validate_name(name);
+ if (ret < 0) {
+ ret_code = LTTNG_ERR_SESSION_INVALID_CHAR;
+ goto error;
+ }
+ } else {
+ int i = 0;
+ bool found_name = false;
+ char datetime[16];
+ struct tm *timeinfo;
+
+ timeinfo = localtime(&new_session->creation_time);
+ if (!timeinfo) {
+ ret_code = LTTNG_ERR_SESSION_FAIL;
+ goto error;
+ }
+ strftime(datetime, sizeof(datetime), "%Y%m%d-%H%M%S", timeinfo);
+ for (i = 0; i < INT_MAX; i++) {
+ struct ltt_session *clashing_session;
+
+ if (i == 0) {
+ ret = snprintf(new_session->name,
+ sizeof(new_session->name),
+ "%s-%s",
+ DEFAULT_SESSION_NAME,
+ datetime);
+ } else {
+ ret = snprintf(new_session->name,
+ sizeof(new_session->name),
+ "%s%d-%s",
+ DEFAULT_SESSION_NAME, i,
+ datetime);
+ }
+ if (ret == -1 || ret >= sizeof(new_session->name)) {
+ /*
+ * Null-terminate in case the name is used
+ * in logging statements.
+ */
+ new_session->name[sizeof(new_session->name) - 1] = '\0';
+ ret_code = LTTNG_ERR_SESSION_FAIL;
+ goto error;
+ }
+
+ clashing_session =
+ session_find_by_name(new_session->name);
+ session_put(clashing_session);
+ if (!clashing_session) {
+ found_name = true;
+ break;
+ }
+ }
+ if (found_name) {
+ DBG("Generated session name \"%s\"", new_session->name);
+ new_session->has_auto_generated_name = true;
+ } else {
+ ERR("Failed to auto-generate a session name");
+ ret_code = LTTNG_ERR_SESSION_FAIL;
+ goto error;
+ }
+ }
+
ret = gethostname(new_session->hostname, sizeof(new_session->hostname));
if (ret < 0) {
if (errno == ENAMETOOLONG) {
new_session->hostname[sizeof(new_session->hostname) - 1] = '\0';
+ ERR("Hostname exceeds the maximal permitted length and has been truncated to %s",
+ new_session->hostname);
} else {
- ret = LTTNG_ERR_FATAL;
+ ret_code = LTTNG_ERR_SESSION_FAIL;
goto error;
}
}
- /* Init kernel session */
- new_session->kernel_session = NULL;
- new_session->ust_session = NULL;
-
- /* Init lock */
- pthread_mutex_init(&new_session->lock, NULL);
-
new_session->uid = uid;
new_session->gid = gid;
ret = snapshot_init(&new_session->snapshot);
if (ret < 0) {
- ret = LTTNG_ERR_NOMEM;
+ ret_code = LTTNG_ERR_NOMEM;
goto error;
}
- new_session->rotation_pending_local = false;
- new_session->rotation_pending_relay = false;
new_session->rotation_state = LTTNG_ROTATION_STATE_NO_ROTATION;
- new_session->rotation_pending_check_timer_enabled = false;
- new_session->rotation_schedule_timer_enabled = false;
-
- /* Add new session to the session list */
- session_lock_list();
+ /* Add new session to the session list. */
new_session->id = add_session_list(new_session);
+
/*
* Add the new session to the ltt_sessions_ht_by_id.
* No ownership is taken by the hash table; it is merely
*/
add_session_ht(new_session);
new_session->published = true;
- session_unlock_list();
/*
- * Consumer is let to NULL since the create_session_uri command will set it
- * up and, if valid, assign it to the session.
+ * Consumer is left to NULL since the create_session_uri command will
+ * set it up and, if valid, assign it to the session.
*/
- DBG("Tracing session %s created with ID %" PRIu64 " by UID %d GID %d",
- name, new_session->id, new_session->uid, new_session->gid);
-
- return LTTNG_OK;
-
+ DBG("Tracing session %s created with ID %" PRIu64 " by uid = %d, gid = %d",
+ new_session->name, new_session->id, new_session->uid,
+ new_session->gid);
+ ret_code = LTTNG_OK;
+end:
+ if (new_session) {
+ (void) session_get(new_session);
+ *out_session = new_session;
+ }
+ return ret_code;
error:
-error_asprintf:
- session_lock_list();
session_put(new_session);
- session_unlock_list();
-
-error_malloc:
- return ret;
+ new_session = NULL;
+ goto end;
}
/*
*/
struct ltt_session {
char name[NAME_MAX];
+ bool has_auto_generated_name;
char hostname[HOST_NAME_MAX]; /* Local hostname. */
+ time_t creation_time;
struct ltt_kernel_session *kernel_session;
struct ltt_ust_session *ust_session;
struct urcu_ref ref;
* copied into those sessions.
*/
struct consumer_output *consumer;
-
+ /*
+ * Indicates whether or not the user has specified an output directory
+ * or if it was configured using the default configuration.
+ */
+ bool has_user_specified_directory;
/* Did at least ONE start command has been triggered?. */
unsigned int has_been_started:1;
/*
};
/* Prototypes */
-int session_create(char *name, uid_t uid, gid_t gid);
-
+enum lttng_error_code session_create(const char *name, uid_t uid, gid_t gid,
+ struct ltt_session **out_session);
void session_lock(struct ltt_session *session);
void session_lock_list(void);
int session_trylock_list(void);
*
* Return 0 on success or else a negative value.
*/
-static int output_init(uint64_t max_size, const char *name,
+static int output_init(const struct ltt_session *session,
+ uint64_t max_size, const char *name,
struct lttng_uri *uris, size_t nb_uri,
struct consumer_output *consumer, struct snapshot_output *output,
struct snapshot *snapshot)
for (i = 0; i < nb_uri; i ++) {
/* Network URIs */
- ret = consumer_set_network_uri(output->consumer, &uris[i]);
+ ret = consumer_set_network_uri(session, output->consumer,
+ &uris[i]);
if (ret < 0) {
goto error;
}
*
* Return 0 on success or else a negative value.
*/
-int snapshot_output_init_with_uri(uint64_t max_size, const char *name,
+int snapshot_output_init_with_uri(const struct ltt_session *session,
+ uint64_t max_size, const char *name,
struct lttng_uri *uris, size_t nb_uri,
struct consumer_output *consumer, struct snapshot_output *output,
struct snapshot *snapshot)
{
- return output_init(max_size, name, uris, nb_uri, consumer, output,
- snapshot);
+ return output_init(session, max_size, name, uris, nb_uri, consumer,
+ output, snapshot);
}
/*
*
* Return 0 on success or else a negative value.
*/
-int snapshot_output_init(uint64_t max_size, const char *name,
+int snapshot_output_init(const struct ltt_session *session,
+ uint64_t max_size, const char *name,
const char *ctrl_url, const char *data_url,
struct consumer_output *consumer, struct snapshot_output *output,
struct snapshot *snapshot)
goto error;
}
- ret = output_init(max_size, name, uris, nb_uri, consumer, output,
- snapshot);
+ ret = output_init(session, max_size, name, uris, nb_uri, consumer,
+ output, snapshot);
error:
free(uris);
#include "consumer.h"
struct consumer_output;
+struct ltt_session;
struct snapshot_output {
uint32_t id;
/* Snapshot output object. */
struct snapshot_output *snapshot_output_alloc(void);
void snapshot_output_destroy(struct snapshot_output *obj);
-int snapshot_output_init(uint64_t max_size, const char *name,
+int snapshot_output_init(const struct ltt_session *session,
+ uint64_t max_size, const char *name,
const char *ctrl_url, const char *data_url,
struct consumer_output *consumer, struct snapshot_output *output,
struct snapshot *snapshot);
-int snapshot_output_init_with_uri(uint64_t max_size, const char *name,
+int snapshot_output_init_with_uri(const struct ltt_session *session,
+ uint64_t max_size, const char *name,
struct lttng_uri *uris, size_t nb_uri,
struct consumer_output *consumer, struct snapshot_output *output,
struct snapshot *snapshot);
/* Create directories if consumer is LOCAL and has a path defined. */
if (usess->consumer->type == CONSUMER_DST_LOCAL &&
usess->consumer->dst.session_root_path[0] != '\0') {
- char *tmp_path;
+ char tmp_path[LTTNG_PATH_MAX];
- tmp_path = zmalloc(LTTNG_PATH_MAX);
- if (!tmp_path) {
- ERR("Alloc tmp_path");
- goto error_unlock;
- }
- ret = snprintf(tmp_path, LTTNG_PATH_MAX, "%s%s%s",
+ ret = snprintf(tmp_path, sizeof(tmp_path), "%s/%s%s",
usess->consumer->dst.session_root_path,
usess->consumer->chunk_path,
- usess->consumer->subdir);
- if (ret >= LTTNG_PATH_MAX) {
- ERR("Local destination path exceeds the maximal allowed length of %i bytes (needs %i bytes) with path = \"%s%s%s\"",
- LTTNG_PATH_MAX, ret,
+ usess->consumer->domain_subdir);
+ if (ret >= sizeof(tmp_path)) {
+ ERR("Local destination path exceeds the maximal allowed length of %zu bytes (needs %i bytes) with path = \"%s%s%s\"",
+ sizeof(tmp_path), ret,
usess->consumer->dst.session_root_path,
usess->consumer->chunk_path,
- usess->consumer->subdir);
- free(tmp_path);
+ usess->consumer->domain_subdir);
goto error_unlock;
}
tmp_path);
ret = run_as_mkdir_recursive(tmp_path, S_IRWXU | S_IRWXG,
ua_sess->euid, ua_sess->egid);
- free(tmp_path);
if (ret < 0) {
if (errno != EEXIST) {
ERR("Trace directory creation error");
ret = snprintf(pathname, sizeof(pathname),
DEFAULT_UST_TRACE_DIR "/" DEFAULT_UST_TRACE_UID_PATH,
reg->uid, reg->bits_per_long);
- if (ret < 0 || ret == sizeof(pathname)) {
+ if (ret < 0 || ret >= sizeof(pathname)) {
PERROR("Failed to format rotation path");
cmd_ret = LTTNG_ERR_INVALID;
goto error;
ret = snprintf(pathname, sizeof(pathname),
DEFAULT_UST_TRACE_DIR "/%s",
ua_sess->path);
- if (ret < 0 || ret == sizeof(pathname)) {
+ if (ret < 0 || ret >= sizeof(pathname)) {
PERROR("Failed to format rotation path");
cmd_ret = LTTNG_ERR_INVALID;
goto error;
/* Get correct path name destination */
if (consumer->type == CONSUMER_DST_LOCAL) {
/* Set application path to the destination path */
- ret = snprintf(pathname, LTTNG_PATH_MAX, "%s%s%s%s",
+ ret = snprintf(pathname, LTTNG_PATH_MAX, "%s/%s%s/%s",
consumer->dst.session_root_path,
consumer->chunk_path,
- consumer->subdir, ua_sess->path);
+ consumer->domain_subdir, ua_sess->path);
if (ret < 0) {
PERROR("snprintf channel path");
goto error;
}
}
} else {
- ret = snprintf(pathname, LTTNG_PATH_MAX, "%s%s%s%s",
+ ret = snprintf(pathname, LTTNG_PATH_MAX, "%s%s/%s%s",
consumer->dst.net.base_dir,
consumer->chunk_path,
- consumer->subdir,
+ consumer->domain_subdir,
ua_sess->path);
if (ret < 0) {
PERROR("snprintf channel path");
const char *session_get_base_path(const struct ltt_session *session)
{
- struct consumer_output *consumer;
-
- if (session->kernel_session) {
- consumer = session->kernel_session->consumer;
- } else if (session->ust_session) {
- consumer = session->ust_session->consumer;
- } else {
- abort();
- }
-
- if (session->net_handle > 0) {
- return consumer->dst.net.base_dir;
- } else {
- return consumer->dst.session_root_path;
- }
+ return session->net_handle > 0 ?
+ session->consumer->dst.net.base_dir :
+ session->consumer->dst.session_root_path;
}
/*
* Copyright (C) 2011 - David Goulet <david.goulet@polymtl.ca>
+ * Copyright (C) 2019 - Jérémie Galarneau <jeremie.galarneau@efficios.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License, version 2 only,
#include <common/uri.h>
#include <common/utils.h>
#include <lttng/snapshot.h>
+#include <lttng/session-descriptor.h>
static char *opt_output_path;
static char *opt_session_name;
OPT_LIVE_TIMER,
};
-static struct mi_writer *writer;
+enum output_type {
+ OUTPUT_NONE,
+ OUTPUT_LOCAL,
+ OUTPUT_NETWORK,
+ OUTPUT_UNSPECIFIED,
+};
+static struct mi_writer *writer;
static struct poptOption long_options[] = {
/* longName, shortName, argInfo, argPtr, value, descrip, argDesc */
{"help", 'h', POPT_ARG_NONE, NULL, OPT_HELP, NULL, NULL},
{0, 0, 0, 0, 0, 0, 0}
};
-/*
- * Please have a look at src/lib/lttng-ctl/lttng-ctl.c for more information on
- * 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);
-
/*
* 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
return ret;
}
-/*
- * For a session name, set the consumer URLs.
- */
-static int set_consumer_url(const char *session_name, const char *ctrl_url,
- const char *data_url)
+static
+struct lttng_session_descriptor *create_session_descriptor(void)
{
int ret;
- struct lttng_handle *handle;
-
- assert(session_name);
-
- /*
- * 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.
- */
- handle = lttng_create_handle(session_name, NULL);
- if (handle == NULL) {
- ret = CMD_FATAL;
- goto error;
- }
-
- ret = lttng_set_consumer_url(handle, ctrl_url, data_url);
- if (ret < 0) {
- goto error;
- }
-
- if (ctrl_url) {
- MSG("Control URL %s set for session %s", ctrl_url, session_name);
- }
-
- if (data_url) {
- MSG("Data URL %s set for session %s", data_url, session_name);
- }
-
-error:
- lttng_destroy_handle(handle);
- return ret;
-}
-
-static int add_snapshot_output(const char *session_name, const char *ctrl_url,
- const char *data_url)
-{
- int ret;
- struct lttng_snapshot_output *output = NULL;
+ ssize_t uri_count;
+ enum output_type output_type;
+ struct lttng_uri *uris = NULL;
+ struct lttng_session_descriptor *descriptor = NULL;
+ const char *uri_str1 = NULL, *uri_str2 = NULL;
+ char local_output_path[LTTNG_PATH_MAX] = {};
+
+ if (opt_no_output) {
+ output_type = OUTPUT_NONE;
+ } else if (opt_output_path) {
+ char *expanded_output_path;
+
+ output_type = OUTPUT_LOCAL;
+ expanded_output_path = utils_expand_path(opt_output_path);
+ if (!expanded_output_path) {
+ ERR("Failed to expand output path.");
+ goto end;
+ }
+ ret = lttng_strncpy(local_output_path, expanded_output_path,
+ sizeof(local_output_path));
+ free(expanded_output_path);
+ if (ret) {
+ ERR("Output path exceeds the maximal supported length (%zu bytes)",
+ sizeof(local_output_path));
+ goto end;
+ }
+ } else if (opt_url || opt_ctrl_url) {
+ uri_str1 = opt_ctrl_url ? opt_ctrl_url : opt_url;
+ uri_str2 = opt_data_url;
- assert(session_name);
+ uri_count = uri_parse_str_urls(uri_str1, uri_str2, &uris);
+ if (uri_count != 1 && uri_count != 2) {
+ ERR("Unrecognized URL format.");
+ goto end;
+ }
- output = lttng_snapshot_output_create();
- if (!output) {
- ret = CMD_FATAL;
- goto error_create;
+ switch (uri_count) {
+ case 1:
+ output_type = OUTPUT_LOCAL;
+ if (uris[0].dtype != LTTNG_DST_PATH) {
+ ERR("Unrecognized URL format.");
+ goto end;
+ }
+ ret = lttng_strncpy(local_output_path, uris[0].dst.path,
+ sizeof(local_output_path));
+ if (ret) {
+ ERR("Output path exceeds the maximal supported length (%zu bytes)",
+ sizeof(local_output_path));
+ }
+ break;
+ case 2:
+ output_type = OUTPUT_NETWORK;
+ break;
+ default:
+ /* Already checked. */
+ abort();
+ }
+ } else {
+ output_type = OUTPUT_UNSPECIFIED;
}
- if (ctrl_url) {
- ret = lttng_snapshot_output_set_ctrl_url(ctrl_url, output);
- if (ret < 0) {
- goto error;
+ if (opt_snapshot) {
+ /* Snapshot session. */
+ switch (output_type) {
+ case OUTPUT_UNSPECIFIED:
+ case OUTPUT_LOCAL:
+ descriptor = lttng_session_descriptor_snapshot_local_create(
+ opt_session_name,
+ output_type == OUTPUT_LOCAL ?
+ local_output_path : NULL);
+ break;
+ case OUTPUT_NONE:
+ descriptor = lttng_session_descriptor_snapshot_create(
+ opt_session_name);
+ break;
+ case OUTPUT_NETWORK:
+ descriptor = lttng_session_descriptor_snapshot_network_create(
+ opt_session_name, uri_str1, uri_str2);
+ break;
+ default:
+ abort();
}
- }
+ } else if (opt_live_timer) {
+ /* Live session. */
+ if (output_type != OUTPUT_UNSPECIFIED &&
+ output_type != OUTPUT_NETWORK) {
+ ERR("Unsupported output type specified for live session.");
+ goto end;
+ }
+ descriptor = lttng_session_descriptor_live_network_create(
+ opt_session_name, uri_str1, uri_str2,
+ opt_live_timer);
- if (data_url) {
- ret = lttng_snapshot_output_set_data_url(data_url, output);
- if (ret < 0) {
- goto error;
+ } else {
+ /* Regular session. */
+ switch (output_type) {
+ case OUTPUT_UNSPECIFIED:
+ case OUTPUT_LOCAL:
+ descriptor = lttng_session_descriptor_local_create(
+ opt_session_name,
+ output_type == OUTPUT_LOCAL ?
+ local_output_path : NULL);
+ break;
+ case OUTPUT_NONE:
+ descriptor = lttng_session_descriptor_create(
+ opt_session_name);
+ break;
+ case OUTPUT_NETWORK:
+ descriptor = lttng_session_descriptor_network_create(
+ opt_session_name, uri_str1, uri_str2);
+ break;
+ default:
+ abort();
}
}
-
- /* This call, if successful, populates the id of the output object. */
- ret = lttng_snapshot_add_output(session_name, output);
- if (ret < 0) {
- goto error;
+ if (!descriptor) {
+ ERR("Failed to initialize session creation command.");
}
-
-error:
- lttng_snapshot_output_destroy(output);
-error_create:
- return ret;
+end:
+ free(uris);
+ return descriptor;
}
/*
*/
static int create_session(void)
{
- int ret;
- char *session_name = NULL, *traces_path = NULL, *alloc_path = NULL;
- char *alloc_url = NULL, *url = NULL, datetime[16];
- 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);
- timeinfo = localtime(&rawtime);
- strftime(datetime, sizeof(datetime), "%Y%m%d-%H%M%S", timeinfo);
-
- /* Auto session name creation */
- if (opt_session_name == NULL) {
- ret = snprintf(session_name_date, sizeof(session_name_date),
- DEFAULT_SESSION_NAME "-%s", datetime);
- if (ret < 0) {
- PERROR("snprintf session name");
- goto error;
- }
- session_name = session_name_date;
- DBG("Auto session name set to %s", session_name_date);
- } else {
+ 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 = LTTNG_ERR_SESSION_FAIL;
+ ret = CMD_ERROR;
goto error;
}
/*
ret = CMD_ERROR;
goto error;
}
- session_name = opt_session_name;
- ret = snprintf(session_name_date, sizeof(session_name_date),
- "%s-%s", session_name, datetime);
- if (ret < 0) {
- PERROR("snprintf session name");
- goto error;
- }
}
- if ((!opt_ctrl_url && opt_data_url) || (opt_ctrl_url && !opt_data_url)) {
- ERR("You need both control and data URL.");
+ if (opt_snapshot && opt_live_timer) {
+ ERR("Snapshot and live modes are mutually exclusive.");
ret = CMD_ERROR;
goto error;
}
- if (opt_output_path != NULL) {
- traces_path = utils_expand_path(opt_output_path);
- if (traces_path == NULL) {
- ret = CMD_ERROR;
- goto error;
- }
-
- /* Create URL string from the local file system path */
- ret = asprintf(&alloc_url, "file://%s", traces_path);
- if (ret < 0) {
- PERROR("asprintf url path");
- ret = CMD_FATAL;
- goto error;
- }
- /* URL to use in the lttng_create_session() call */
- url = alloc_url;
- print_str_url = traces_path;
- } else if (opt_url) { /* Handling URL (-U opt) */
- url = opt_url;
- print_str_url = url;
- } else if (opt_data_url && opt_ctrl_url) {
- /*
- * With both control and data, we'll be setting the consumer URL after
- * session creation thus use no URL.
- */
- url = NULL;
- } else if (!opt_no_output) {
- char *tmp_path;
-
- /* Auto output path */
- 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(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 (ret < 0) {
- PERROR("asprintf trace dir name");
- ret = CMD_FATAL;
- goto error;
- }
-
- url = alloc_url;
- print_str_url = alloc_url + strlen("file://");
- } else {
- /* No output means --no-output or --snapshot mode. */
- url = NULL;
+ 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;
}
- /* Use default live URL if NO url is/are found. */
- if ((opt_live_timer && !opt_url) && (opt_live_timer && !opt_data_url)) {
- /* Override the url */
- free(url);
- url = NULL;
-
- ret = asprintf(&alloc_url, "net://127.0.0.1");
- if (ret < 0) {
- PERROR("asprintf default live URL");
- ret = CMD_FATAL;
- goto error;
- }
- url = alloc_url;
- print_str_url = url;
+ session_descriptor = create_session_descriptor();
+ if (!session_descriptor) {
+ ret = CMD_ERROR;
+ goto error;
}
-
- if (opt_snapshot && opt_live_timer) {
- ERR("Snapshot and live modes are mutually exclusive.");
+ ret_code = lttng_create_session_ext(session_descriptor);
+ if (ret_code != LTTNG_OK) {
+ ERR("%s", lttng_strerror(-ret_code));
ret = CMD_ERROR;
goto error;
}
- if (opt_snapshot) {
- /* No output by default. */
- const char *snapshot_url = NULL;
-
- if (opt_url) {
- snapshot_url = url;
- } else if (!opt_data_url && !opt_ctrl_url) {
- /* This is the session path that we need to use as output. */
- snapshot_url = url;
- }
- ret = lttng_create_session_snapshot(session_name, snapshot_url);
- } else if (opt_live_timer) {
- const char *pathname;
-
- if (opt_relayd_path) {
- pathname = opt_relayd_path;
- } else {
- pathname = INSTALL_BIN_PATH "/lttng-relayd";
- }
- if (!opt_url && !opt_data_url && !check_relayd() &&
- spawn_relayd(pathname, 0) < 0) {
- goto error;
- }
- ret = lttng_create_session_live(session_name, url, opt_live_timer);
- } else {
- ret = _lttng_create_session_ext(session_name, url, datetime);
+ 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) {
- /* Don't set ret so lttng can interpret the sessiond error. */
- switch (-ret) {
- case LTTNG_ERR_EXIST_SESS:
- WARN("Session %s already exists", session_name);
- break;
- default:
+ 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_ctrl_url && opt_data_url) {
- if (opt_snapshot) {
- ret = add_snapshot_output(session_name, opt_ctrl_url,
- opt_data_url);
- } else {
- /* Setting up control URI (-C or/and -D opt) */
- ret = set_consumer_url(session_name, opt_ctrl_url, opt_data_url);
- }
- if (ret < 0) {
- /* Destroy created session because the URL are not valid. */
- lttng_destroy_session(session_name);
- 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;
+ }
}
- }
- 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");
+ "%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(session_name, shm_path);
+ ret = lttng_set_session_shm_path(created_session_name,
+ shm_path);
if (ret < 0) {
- lttng_destroy_session(session_name);
+ lttng_destroy_session(created_session_name);
+ ret = CMD_ERROR;
goto error;
}
}
- MSG("Session %s created.", session_name);
- if (print_str_url && !opt_snapshot) {
- MSG("Traces will be written in %s", print_str_url);
+ 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 set to %u %s", opt_live_timer, USEC_UNIT);
+ MSG("Live timer interval set to %u %s", opt_live_timer,
+ USEC_UNIT);
}
} else if (opt_snapshot) {
- if (print_str_url) {
- MSG("Default snapshot output set to: %s", print_str_url);
+ 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;
}
- MSG("Snapshot mode set. Every channel enabled for that session will "
- "be set to mmap output, and default to overwrite mode.");
+ 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("Session %s set to shm_path: %s.", session_name,
- shm_path);
+ MSG("Shared memory path set to %s", shm_path);
}
/* Mi output */
if (lttng_opt_mi) {
- ret = mi_created_session(session_name);
+ ret = mi_created_session(created_session_name);
if (ret) {
ret = CMD_ERROR;
goto error;
}
/* Init lttng session config */
- ret = config_init(session_name);
+ ret = config_init(created_session_name);
if (ret < 0) {
ret = CMD_ERROR;
goto error;
}
ret = CMD_SUCCESS;
-
error:
- free(alloc_url);
- free(traces_path);
- free(alloc_path);
-
- if (ret < 0) {
- ERR("%s", lttng_strerror(ret));
- }
+ lttng_session_descriptor_destroy(session_descriptor);
+ free(sessions);
return ret;
}
buffer-view.h buffer-view.c \
location.c \
waiter.h waiter.c \
- userspace-probe.c event.c time.c
+ userspace-probe.c event.c time.c \
+ session-descriptor.c
if HAVE_ELF_H
libcommon_la_SOURCES += lttng-elf.h lttng-elf.c
[ ERROR_INDEX(LTTNG_ERR_MKDIR_FAIL_CONSUMER) ] = "mkdir failure on consumer",
[ ERROR_INDEX(LTTNG_ERR_CHAN_NOT_FOUND) ] = "Channel not found",
[ ERROR_INDEX(LTTNG_ERR_SNAPSHOT_UNSUPPORTED) ] = "Session configuration does not allow the use of snapshots",
+ [ ERROR_INDEX(LTTNG_ERR_SESSION_NOT_EXIST) ] = "Tracing session does not exist",
/* Last element */
[ ERROR_INDEX(LTTNG_ERR_NR) ] = "Unknown error code"
--- /dev/null
+/*
+ * Copyright (C) 2019 - Jérémie Galarneau <jeremie.galarneau@efficios.com>
+ *
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License, version 2.1 only,
+ * as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <lttng/session-descriptor-internal.h>
+#include <common/macros.h>
+#include <common/uri.h>
+#include <common/defaults.h>
+#include <common/error.h>
+#include <time.h>
+#include <assert.h>
+#include <stdio.h>
+
+struct lttng_session_descriptor_network_location {
+ struct lttng_uri *control;
+ struct lttng_uri *data;
+};
+
+struct lttng_session_descriptor {
+ enum lttng_session_descriptor_type type;
+ /*
+ * If an output type that is not OUTPUT_TYPE_NONE is specified,
+ * it means that an output of that type must be generated at
+ * session-creation time.
+ */
+ enum lttng_session_descriptor_output_type output_type;
+ char *name;
+ union {
+ struct lttng_session_descriptor_network_location network;
+ struct lttng_uri *local;
+ } output;
+};
+
+struct lttng_session_descriptor_snapshot {
+ struct lttng_session_descriptor base;
+ /*
+ * Assumes at-most one snapshot output is supported. Uses
+ * the output field of the base class.
+ */
+};
+
+struct lttng_session_descriptor_live {
+ struct lttng_session_descriptor base;
+ unsigned long long live_timer_us;
+};
+
+struct lttng_session_descriptor_comm {
+ /* enum lttng_session_descriptor_type */
+ uint8_t type;
+ /* enum lttng_session_descriptor_output_type */
+ uint8_t output_type;
+ /* Includes trailing null. */
+ uint32_t name_len;
+ /* Name follows, followed by URIs */
+ uint8_t uri_count;
+} LTTNG_PACKED;
+
+struct lttng_session_descriptor_live_comm {
+ struct lttng_session_descriptor_comm base;
+ /* Live-specific parameters. */
+ uint64_t live_timer_us;
+} LTTNG_PACKED;
+
+static
+struct lttng_uri *uri_copy(const struct lttng_uri *uri)
+{
+ struct lttng_uri *new_uri = NULL;
+
+ if (!uri) {
+ goto end;
+ }
+
+ new_uri = zmalloc(sizeof(*new_uri));
+ if (!new_uri) {
+ goto end;
+ }
+ memcpy(new_uri, uri, sizeof(*new_uri));
+end:
+ return new_uri;
+}
+
+static
+struct lttng_uri *uri_from_path(const char *path)
+{
+ struct lttng_uri *uris = NULL;
+ ssize_t uri_count;
+ char local_protocol_string[LTTNG_PATH_MAX + sizeof("file://")] =
+ "file://";
+
+ if (strlen(path) >= LTTNG_PATH_MAX) {
+ goto end;
+ }
+
+ if (path[0] != '/') {
+ /* Not an absolute path. */
+ goto end;
+ }
+
+ strncat(local_protocol_string, path, LTTNG_PATH_MAX);
+ uri_count = uri_parse(local_protocol_string, &uris);
+ if (uri_count != 1) {
+ goto error;
+ }
+ if (uris[0].dtype != LTTNG_DST_PATH) {
+ goto error;
+ }
+
+end:
+ return uris;
+error:
+ free(uris);
+ return NULL;
+}
+
+static
+void network_location_fini(
+ struct lttng_session_descriptor_network_location *location)
+{
+ free(location->control);
+ free(location->data);
+}
+
+/* Assumes ownership of control and data. */
+static
+int network_location_set_from_lttng_uris(
+ struct lttng_session_descriptor_network_location *location,
+ struct lttng_uri *control, struct lttng_uri *data)
+{
+ int ret = 0;
+
+ if (!control && !data) {
+ goto end;
+ }
+
+ if (!(control && data)) {
+ /* None or both must be set. */
+ ret = -1;
+ goto end;
+ }
+
+ if (control->stype != LTTNG_STREAM_CONTROL ||
+ data->stype != LTTNG_STREAM_DATA) {
+ ret = -1;
+ goto end;
+ }
+
+ free(location->control);
+ free(location->data);
+ location->control = control;
+ location->data = data;
+ control = NULL;
+ data = NULL;
+end:
+ free(control);
+ free(data);
+ return ret;
+}
+
+static
+int network_location_set_from_uri_strings(
+ struct lttng_session_descriptor_network_location *location,
+ const char *control, const char *data)
+{
+ int ret = 0;
+ ssize_t uri_count;
+ struct lttng_uri *parsed_uris = NULL;
+ struct lttng_uri *control_uri = NULL;
+ struct lttng_uri *data_uri = NULL;
+
+ uri_count = uri_parse_str_urls(control, data, &parsed_uris);
+ if (uri_count != 2 && uri_count != 0) {
+ ret = -1;
+ goto end;
+ }
+
+ /*
+ * uri_parse_str_urls returns a contiguous array of lttng_uris whereas
+ * session descriptors expect individually allocated lttng_uris.
+ */
+ if (uri_count == 2) {
+ control_uri = zmalloc(sizeof(*control_uri));
+ data_uri = zmalloc(sizeof(*data_uri));
+ if (!control_uri || !data_uri) {
+ ret = -1;
+ goto end;
+ }
+ memcpy(control_uri, &parsed_uris[0], sizeof(*control_uri));
+ memcpy(data_uri, &parsed_uris[1], sizeof(*data_uri));
+ }
+
+ /* Ownership of control and data uris is transferred. */
+ ret = network_location_set_from_lttng_uris(
+ location,
+ control_uri,
+ data_uri);
+ control_uri = NULL;
+ data_uri = NULL;
+end:
+ free(parsed_uris);
+ free(control_uri);
+ free(data_uri);
+ return ret;
+}
+
+struct lttng_session_descriptor *
+lttng_session_descriptor_create(const char *name)
+{
+ struct lttng_session_descriptor *descriptor;
+
+ descriptor = zmalloc(sizeof(*descriptor));
+ if (!descriptor) {
+ goto error;
+ }
+
+ descriptor->type = LTTNG_SESSION_DESCRIPTOR_TYPE_REGULAR;
+ descriptor->output_type =
+ LTTNG_SESSION_DESCRIPTOR_OUTPUT_TYPE_NONE;
+ if (lttng_session_descriptor_set_session_name(descriptor, name)) {
+ goto error;
+ }
+ return descriptor;
+error:
+ lttng_session_descriptor_destroy(descriptor);
+ return NULL;
+}
+
+/* Ownership of uri is transferred. */
+static
+struct lttng_session_descriptor *
+_lttng_session_descriptor_local_create(const char *name,
+ struct lttng_uri *uri)
+{
+ struct lttng_session_descriptor *descriptor;
+
+ descriptor = lttng_session_descriptor_create(name);
+ if (!descriptor) {
+ goto error;
+ }
+ descriptor->type = LTTNG_SESSION_DESCRIPTOR_TYPE_REGULAR;
+ descriptor->output_type =
+ LTTNG_SESSION_DESCRIPTOR_OUTPUT_TYPE_LOCAL;
+ if (uri) {
+ if (uri->dtype != LTTNG_DST_PATH) {
+ goto error;
+ }
+ descriptor->output.local = uri;
+ uri = NULL;
+ }
+ return descriptor;
+error:
+ free(uri);
+ lttng_session_descriptor_destroy(descriptor);
+ return NULL;
+}
+
+struct lttng_session_descriptor *
+lttng_session_descriptor_local_create(const char *name, const char *path)
+{
+ struct lttng_uri *uri = NULL;
+ struct lttng_session_descriptor *descriptor;
+
+ if (path) {
+ uri = uri_from_path(path);
+ if (!uri) {
+ goto error;
+ }
+ }
+ descriptor = _lttng_session_descriptor_local_create(name, uri);
+ return descriptor;
+error:
+ return NULL;
+}
+
+/* Assumes the ownership of both uris. */
+static
+struct lttng_session_descriptor *
+_lttng_session_descriptor_network_create(const char *name,
+ struct lttng_uri *control, struct lttng_uri *data)
+{
+ int ret;
+ struct lttng_session_descriptor *descriptor;
+
+ descriptor = lttng_session_descriptor_create(name);
+ if (!descriptor) {
+ goto error;
+ }
+
+ descriptor->type = LTTNG_SESSION_DESCRIPTOR_TYPE_REGULAR;
+ descriptor->output_type = LTTNG_SESSION_DESCRIPTOR_OUTPUT_TYPE_NETWORK;
+ /* Assumes the ownership of both uris. */
+ ret = network_location_set_from_lttng_uris(&descriptor->output.network,
+ control, data);
+ control = NULL;
+ data = NULL;
+ if (ret) {
+ goto error;
+ }
+ return descriptor;
+error:
+ lttng_session_descriptor_destroy(descriptor);
+ free(control);
+ free(data);
+ return NULL;
+}
+
+struct lttng_session_descriptor *
+lttng_session_descriptor_network_create(const char *name,
+ const char *control_url, const char *data_url)
+{
+ int ret;
+ struct lttng_session_descriptor *descriptor;
+
+ descriptor = _lttng_session_descriptor_network_create(name,
+ NULL, NULL);
+ if (!descriptor) {
+ goto error;
+ }
+
+ ret = network_location_set_from_uri_strings(&descriptor->output.network,
+ control_url, data_url);
+ if (ret) {
+ goto error;
+ }
+ return descriptor;
+error:
+ lttng_session_descriptor_destroy(descriptor);
+ return NULL;
+}
+
+static
+struct lttng_session_descriptor_snapshot *
+_lttng_session_descriptor_snapshot_create(const char *name)
+{
+ struct lttng_session_descriptor_snapshot *descriptor;
+
+ descriptor = zmalloc(sizeof(*descriptor));
+ if (!descriptor) {
+ goto error;
+ }
+
+ descriptor->base.type = LTTNG_SESSION_DESCRIPTOR_TYPE_SNAPSHOT;
+ descriptor->base.output_type =
+ LTTNG_SESSION_DESCRIPTOR_OUTPUT_TYPE_NONE;
+ if (lttng_session_descriptor_set_session_name(&descriptor->base,
+ name)) {
+ goto error;
+ }
+ return descriptor;
+error:
+ lttng_session_descriptor_destroy(descriptor ? &descriptor->base : NULL);
+ return NULL;
+}
+
+/* Ownership of control and data is transferred. */
+static
+struct lttng_session_descriptor_snapshot *
+_lttng_session_descriptor_snapshot_network_create(const char *name,
+ struct lttng_uri *control, struct lttng_uri *data)
+{
+ int ret;
+ struct lttng_session_descriptor_snapshot *descriptor;
+
+ descriptor = _lttng_session_descriptor_snapshot_create(name);
+ if (!descriptor) {
+ goto error;
+ }
+
+ descriptor->base.output_type =
+ LTTNG_SESSION_DESCRIPTOR_OUTPUT_TYPE_NETWORK;
+ /* Ownership of control and data is transferred. */
+ ret = network_location_set_from_lttng_uris(
+ &descriptor->base.output.network,
+ control, data);
+ control = NULL;
+ data = NULL;
+ if (ret) {
+ goto error;
+ }
+ return descriptor;
+error:
+ free(control);
+ free(data);
+ lttng_session_descriptor_destroy(descriptor ? &descriptor->base : NULL);
+ return NULL;
+}
+
+struct lttng_session_descriptor *
+lttng_session_descriptor_snapshot_create(const char *name)
+{
+ struct lttng_session_descriptor_snapshot *descriptor;
+
+ descriptor = _lttng_session_descriptor_snapshot_create(name);
+ return descriptor ? &descriptor->base : NULL;
+}
+
+struct lttng_session_descriptor *
+lttng_session_descriptor_snapshot_network_create(const char *name,
+ const char *control_url, const char *data_url)
+{
+ int ret;
+ struct lttng_session_descriptor_snapshot *descriptor;
+
+ descriptor = _lttng_session_descriptor_snapshot_network_create(name,
+ NULL, NULL);
+ if (!descriptor) {
+ goto error;
+ }
+
+ ret = network_location_set_from_uri_strings(
+ &descriptor->base.output.network,
+ control_url, data_url);
+ if (ret) {
+ goto error;
+ }
+ return &descriptor->base;
+error:
+ lttng_session_descriptor_destroy(descriptor ? &descriptor->base : NULL);
+ return NULL;
+}
+
+/* Ownership of uri is transferred. */
+static
+struct lttng_session_descriptor_snapshot *
+_lttng_session_descriptor_snapshot_local_create(const char *name,
+ struct lttng_uri *uri)
+{
+ struct lttng_session_descriptor_snapshot *descriptor;
+
+ descriptor = _lttng_session_descriptor_snapshot_create(name);
+ if (!descriptor) {
+ goto error;
+ }
+ descriptor->base.output_type =
+ LTTNG_SESSION_DESCRIPTOR_OUTPUT_TYPE_LOCAL;
+ if (uri) {
+ if (uri->dtype != LTTNG_DST_PATH) {
+ goto error;
+ }
+ descriptor->base.output.local = uri;
+ uri = NULL;
+ }
+ return descriptor;
+error:
+ free(uri);
+ lttng_session_descriptor_destroy(descriptor ? &descriptor->base : NULL);
+ return NULL;
+}
+
+struct lttng_session_descriptor *
+lttng_session_descriptor_snapshot_local_create(const char *name,
+ const char *path)
+{
+ struct lttng_uri *path_uri = NULL;
+ struct lttng_session_descriptor_snapshot *descriptor;
+
+ if (path) {
+ path_uri = uri_from_path(path);
+ if (!path_uri) {
+ goto error;
+ }
+ }
+ descriptor = _lttng_session_descriptor_snapshot_local_create(name,
+ path_uri);
+ return descriptor ? &descriptor->base : NULL;
+error:
+ return NULL;
+}
+
+static
+struct lttng_session_descriptor_live *
+_lttng_session_descriptor_live_create(const char *name,
+ unsigned long long live_timer_interval_us)
+{
+ struct lttng_session_descriptor_live *descriptor = NULL;
+
+ if (live_timer_interval_us == 0) {
+ goto error;
+ }
+ descriptor = zmalloc(sizeof(*descriptor));
+ if (!descriptor) {
+ goto error;
+ }
+
+ descriptor->base.type = LTTNG_SESSION_DESCRIPTOR_TYPE_LIVE;
+ descriptor->base.output_type =
+ LTTNG_SESSION_DESCRIPTOR_OUTPUT_TYPE_NONE;
+ descriptor->live_timer_us = live_timer_interval_us;
+ if (lttng_session_descriptor_set_session_name(&descriptor->base,
+ name)) {
+ goto error;
+ }
+
+ return descriptor;
+error:
+ lttng_session_descriptor_destroy(descriptor ? &descriptor->base : NULL);
+ return NULL;
+}
+
+/* Ownership of control and data is transferred. */
+static
+struct lttng_session_descriptor_live *
+_lttng_session_descriptor_live_network_create(
+ const char *name,
+ struct lttng_uri *control, struct lttng_uri *data,
+ unsigned long long live_timer_interval_us)
+{
+ int ret;
+ struct lttng_session_descriptor_live *descriptor;
+
+ descriptor = _lttng_session_descriptor_live_create(name,
+ live_timer_interval_us);
+ descriptor->base.output_type =
+ LTTNG_SESSION_DESCRIPTOR_OUTPUT_TYPE_NETWORK;
+
+ /* Ownerwhip of control and data is transferred. */
+ ret = network_location_set_from_lttng_uris(
+ &descriptor->base.output.network,
+ control, data);
+ control = NULL;
+ data = NULL;
+ if (ret) {
+ goto error;
+ }
+ return descriptor;
+error:
+ free(control);
+ free(data);
+ lttng_session_descriptor_destroy(descriptor ? &descriptor->base : NULL);
+ return NULL;
+}
+
+struct lttng_session_descriptor *
+lttng_session_descriptor_live_create(
+ const char *name,
+ unsigned long long live_timer_us)
+{
+ struct lttng_session_descriptor_live *descriptor;
+
+ descriptor = _lttng_session_descriptor_live_create(name, live_timer_us);
+ if (!descriptor) {
+ goto error;
+ }
+
+ return descriptor ? &descriptor->base : NULL;
+error:
+ lttng_session_descriptor_destroy(descriptor ? &descriptor->base : NULL);
+ return NULL;
+}
+
+struct lttng_session_descriptor *
+lttng_session_descriptor_live_network_create(
+ const char *name,
+ const char *control_url, const char *data_url,
+ unsigned long long live_timer_us)
+{
+ int ret;
+ struct lttng_session_descriptor_live *descriptor;
+
+ descriptor = _lttng_session_descriptor_live_network_create(name,
+ NULL, NULL, live_timer_us);
+ if (!descriptor) {
+ goto error;
+ }
+
+ ret = network_location_set_from_uri_strings(
+ &descriptor->base.output.network,
+ control_url, data_url);
+ if (ret) {
+ goto error;
+ }
+ return &descriptor->base;
+error:
+ lttng_session_descriptor_destroy(descriptor ? &descriptor->base : NULL);
+ return NULL;
+}
+
+void lttng_session_descriptor_destroy(
+ struct lttng_session_descriptor *descriptor)
+{
+ if (!descriptor) {
+ return;
+ }
+
+ switch (descriptor->output_type) {
+ case LTTNG_SESSION_DESCRIPTOR_OUTPUT_TYPE_NONE:
+ break;
+ case LTTNG_SESSION_DESCRIPTOR_OUTPUT_TYPE_LOCAL:
+ free(descriptor->output.local);
+ break;
+ case LTTNG_SESSION_DESCRIPTOR_OUTPUT_TYPE_NETWORK:
+ network_location_fini(&descriptor->output.network);
+ break;
+ default:
+ abort();
+ }
+
+ free(descriptor->name);
+ free(descriptor);
+}
+
+LTTNG_HIDDEN
+ssize_t lttng_session_descriptor_create_from_buffer(
+ const struct lttng_buffer_view *payload,
+ struct lttng_session_descriptor **descriptor)
+{
+ int i;
+ ssize_t offset = 0, ret;
+ struct lttng_buffer_view current_view;
+ const char *name = NULL;
+ const struct lttng_session_descriptor_comm *base_header;
+ size_t max_expected_uri_count;
+ uint64_t live_timer_us = 0;
+ struct lttng_uri *uris[2] = {};
+ enum lttng_session_descriptor_type type;
+ enum lttng_session_descriptor_output_type output_type;
+
+ current_view = lttng_buffer_view_from_view(payload, offset,
+ sizeof(*base_header));
+ base_header = (typeof(base_header)) current_view.data;
+ if (!base_header) {
+ ret = -1;
+ goto end;
+ }
+
+ switch (base_header->type) {
+ case LTTNG_SESSION_DESCRIPTOR_TYPE_REGULAR:
+ case LTTNG_SESSION_DESCRIPTOR_TYPE_SNAPSHOT:
+ break;
+ case LTTNG_SESSION_DESCRIPTOR_TYPE_LIVE:
+ {
+ const struct lttng_session_descriptor_live_comm *live_header;
+
+ current_view = lttng_buffer_view_from_view(payload, offset,
+ sizeof(*live_header));
+ live_header = (typeof(live_header)) current_view.data;
+ if (!live_header) {
+ ret = -1;
+ goto end;
+ }
+
+ live_timer_us = live_header->live_timer_us;
+ break;
+ }
+ default:
+ ret = -1;
+ goto end;
+ }
+ /* type has been validated. */
+ type = base_header->type;
+
+ switch (base_header->output_type) {
+ case LTTNG_SESSION_DESCRIPTOR_OUTPUT_TYPE_NONE:
+ max_expected_uri_count = 0;
+ break;
+ case LTTNG_SESSION_DESCRIPTOR_OUTPUT_TYPE_LOCAL:
+ max_expected_uri_count = 1;
+ break;
+ case LTTNG_SESSION_DESCRIPTOR_OUTPUT_TYPE_NETWORK:
+ max_expected_uri_count = 2;
+ break;
+ default:
+ ret = -1;
+ goto end;
+ }
+ /* output_type has been validated. */
+ output_type = base_header->output_type;
+
+ /* Skip after header. */
+ offset += current_view.size;
+ if (!base_header->name_len) {
+ goto skip_name;
+ }
+
+ /* Map the name. */
+ current_view = lttng_buffer_view_from_view(payload, offset,
+ base_header->name_len);
+ name = current_view.data;
+ if (!name) {
+ ret = -1;
+ goto end;
+ }
+
+ if (base_header->name_len == 1 ||
+ name[base_header->name_len - 1] ||
+ strlen(name) != base_header->name_len - 1) {
+ /*
+ * Check that the name is not NULL, is NULL-terminated, and
+ * does not contain a NULL before the last byte.
+ */
+ ret = -1;
+ goto end;
+ }
+
+ /* Skip after the name. */
+ offset += base_header->name_len;
+skip_name:
+ if (base_header->uri_count > max_expected_uri_count) {
+ ret = -1;
+ goto end;
+ }
+
+ for (i = 0; i < base_header->uri_count; i++) {
+ struct lttng_uri *uri;
+
+ /* Map a URI. */
+ current_view = lttng_buffer_view_from_view(payload,
+ offset, sizeof(*uri));
+ uri = (typeof(uri)) current_view.data;
+ if (!uri) {
+ ret = -1;
+ goto end;
+ }
+ uris[i] = zmalloc(sizeof(*uri));
+ if (!uris[i]) {
+ ret = -1;
+ goto end;
+ }
+ memcpy(uris[i], uri, sizeof(*uri));
+ offset += sizeof(*uri);
+ }
+
+ switch (type) {
+ case LTTNG_SESSION_DESCRIPTOR_TYPE_REGULAR:
+ switch (output_type) {
+ case LTTNG_SESSION_DESCRIPTOR_OUTPUT_TYPE_NONE:
+ *descriptor = lttng_session_descriptor_create(name);
+ break;
+ case LTTNG_SESSION_DESCRIPTOR_OUTPUT_TYPE_LOCAL:
+ *descriptor = _lttng_session_descriptor_local_create(
+ name, uris[0]);
+ break;
+ case LTTNG_SESSION_DESCRIPTOR_OUTPUT_TYPE_NETWORK:
+ *descriptor = _lttng_session_descriptor_network_create(
+ name, uris[0], uris[1]);
+ break;
+ default:
+ /* Already checked. */
+ abort();
+ }
+ break;
+ case LTTNG_SESSION_DESCRIPTOR_TYPE_SNAPSHOT:
+ {
+ struct lttng_session_descriptor_snapshot *snapshot;
+ switch (output_type) {
+ case LTTNG_SESSION_DESCRIPTOR_OUTPUT_TYPE_NONE:
+ snapshot = _lttng_session_descriptor_snapshot_create(
+ name);
+ break;
+ case LTTNG_SESSION_DESCRIPTOR_OUTPUT_TYPE_LOCAL:
+ snapshot = _lttng_session_descriptor_snapshot_local_create(
+ name, uris[0]);
+ break;
+ case LTTNG_SESSION_DESCRIPTOR_OUTPUT_TYPE_NETWORK:
+ snapshot = _lttng_session_descriptor_snapshot_network_create(
+ name, uris[0], uris[1]);
+ break;
+ default:
+ /* Already checked. */
+ abort();
+ }
+ *descriptor = snapshot ? &snapshot->base : NULL;
+ break;
+ }
+ case LTTNG_SESSION_DESCRIPTOR_TYPE_LIVE:
+ {
+ struct lttng_session_descriptor_live *live;
+
+ switch (output_type) {
+ case LTTNG_SESSION_DESCRIPTOR_OUTPUT_TYPE_NONE:
+ live = _lttng_session_descriptor_live_create(
+ name, live_timer_us);
+ break;
+ case LTTNG_SESSION_DESCRIPTOR_OUTPUT_TYPE_NETWORK:
+ live = _lttng_session_descriptor_live_network_create(
+ name, uris[0], uris[1],
+ live_timer_us);
+ break;
+ case LTTNG_SESSION_DESCRIPTOR_OUTPUT_TYPE_LOCAL:
+ ret = -1;
+ goto end;
+ default:
+ /* Already checked. */
+ abort();
+ }
+ *descriptor = live ? &live->base : NULL;
+ break;
+ }
+ default:
+ /* Already checked. */
+ abort();
+ }
+ memset(uris, 0, sizeof(uris));
+ if (!*descriptor) {
+ ret = -1;
+ goto end;
+ }
+
+ ret = offset;
+end:
+ free(uris[0]);
+ free(uris[1]);
+ return ret;
+}
+
+LTTNG_HIDDEN
+int lttng_session_descriptor_serialize(
+ const struct lttng_session_descriptor *descriptor,
+ struct lttng_dynamic_buffer *buffer)
+{
+ int ret, i;
+ /* There are, at most, two URIs to serialize. */
+ struct lttng_uri *uris[2] = {};
+ size_t uri_count = 0;
+ /* The live header is a superset of all headers. */
+ struct lttng_session_descriptor_live_comm header = {
+ .base.type = (uint8_t) descriptor->type,
+ .base.output_type = (uint8_t) descriptor->output_type,
+ .base.name_len = descriptor->name ?
+ strlen(descriptor->name) + 1 : 0,
+ };
+ const void *header_ptr = NULL;
+ size_t header_size;
+
+ switch (descriptor->output_type) {
+ case LTTNG_SESSION_DESCRIPTOR_OUTPUT_TYPE_NONE:
+ break;
+ case LTTNG_SESSION_DESCRIPTOR_OUTPUT_TYPE_LOCAL:
+ uris[0] = descriptor->output.local;
+ break;
+ case LTTNG_SESSION_DESCRIPTOR_OUTPUT_TYPE_NETWORK:
+ uris[0] = descriptor->output.network.control;
+ uris[1] = descriptor->output.network.data;
+ break;
+ default:
+ ret = -1;
+ goto end;
+ }
+ uri_count += !!uris[0];
+ uri_count += !!uris[1];
+
+ header.base.uri_count = uri_count;
+ if (descriptor->type == LTTNG_SESSION_DESCRIPTOR_TYPE_LIVE) {
+ const struct lttng_session_descriptor_live *live =
+ container_of(descriptor, typeof(*live),
+ base);
+
+ header.live_timer_us = live->live_timer_us;
+ header_ptr = &header;
+ header_size = sizeof(header);
+ } else {
+ header_ptr = &header.base;
+ header_size = sizeof(header.base);
+ }
+
+ ret = lttng_dynamic_buffer_append(buffer, header_ptr, header_size);
+ if (ret) {
+ goto end;
+ }
+ if (header.base.name_len) {
+ ret = lttng_dynamic_buffer_append(buffer, descriptor->name,
+ header.base.name_len);
+ if (ret) {
+ goto end;
+ }
+ }
+
+ for (i = 0; i < uri_count; i++) {
+ ret = lttng_dynamic_buffer_append(buffer, uris[i],
+ sizeof(struct lttng_uri));
+ if (ret) {
+ goto end;
+ }
+ }
+end:
+ return ret;
+}
+
+LTTNG_HIDDEN
+enum lttng_session_descriptor_type
+lttng_session_descriptor_get_type(
+ const struct lttng_session_descriptor *descriptor)
+{
+ return descriptor->type;
+}
+
+LTTNG_HIDDEN
+enum lttng_session_descriptor_output_type
+lttng_session_descriptor_get_output_type(
+ const struct lttng_session_descriptor *descriptor)
+{
+ return descriptor->output_type;
+}
+
+LTTNG_HIDDEN
+void lttng_session_descriptor_get_local_output_uri(
+ const struct lttng_session_descriptor *descriptor,
+ struct lttng_uri *local_uri)
+{
+ memcpy(local_uri, descriptor->output.local, sizeof(*local_uri));
+}
+
+LTTNG_HIDDEN
+void lttng_session_descriptor_get_network_output_uris(
+ const struct lttng_session_descriptor *descriptor,
+ struct lttng_uri *control,
+ struct lttng_uri *data)
+{
+ memcpy(control, descriptor->output.network.control, sizeof(*control));
+ memcpy(data, descriptor->output.network.data, sizeof(*data));
+}
+
+LTTNG_HIDDEN
+unsigned long long
+lttng_session_descriptor_live_get_timer_interval(
+ const struct lttng_session_descriptor *descriptor)
+{
+ struct lttng_session_descriptor_live *live;
+
+ live = container_of(descriptor, typeof(*live), base);
+ return live->live_timer_us;
+}
+
+enum lttng_session_descriptor_status
+lttng_session_descriptor_get_session_name(
+ const struct lttng_session_descriptor *descriptor,
+ const char **session_name)
+{
+ enum lttng_session_descriptor_status status;
+
+ if (!descriptor || !session_name) {
+ status = LTTNG_SESSION_DESCRIPTOR_STATUS_INVALID;
+ goto end;
+ }
+
+ *session_name = descriptor->name;
+ status = descriptor->name ?
+ LTTNG_SESSION_DESCRIPTOR_STATUS_OK :
+ LTTNG_SESSION_DESCRIPTOR_STATUS_UNSET;
+end:
+ return status;
+}
+
+LTTNG_HIDDEN
+int lttng_session_descriptor_set_session_name(
+ struct lttng_session_descriptor *descriptor,
+ const char *name)
+{
+ int ret = 0;
+ char *new_name;
+
+ if (!name) {
+ goto end;
+ }
+ if (strlen(name) >= LTTNG_NAME_MAX) {
+ ret = -1;
+ goto end;
+ }
+ new_name = strdup(name);
+ if (!new_name) {
+ ret = -1;
+ goto end;
+ }
+ free(descriptor->name);
+ descriptor->name = new_name;
+end:
+ return ret;
+}
+
+LTTNG_HIDDEN
+bool lttng_session_descriptor_is_output_destination_initialized(
+ const struct lttng_session_descriptor *descriptor)
+{
+ switch (descriptor->output_type) {
+ case LTTNG_SESSION_DESCRIPTOR_OUTPUT_TYPE_NONE:
+ return true;
+ case LTTNG_SESSION_DESCRIPTOR_OUTPUT_TYPE_LOCAL:
+ return descriptor->output.local;
+ case LTTNG_SESSION_DESCRIPTOR_OUTPUT_TYPE_NETWORK:
+ return descriptor->output.network.control;
+ default:
+ abort();
+ }
+}
+
+LTTNG_HIDDEN
+bool lttng_session_descriptor_has_output_directory(
+ const struct lttng_session_descriptor *descriptor)
+{
+ switch (descriptor->output_type) {
+ case LTTNG_SESSION_DESCRIPTOR_OUTPUT_TYPE_NONE:
+ break;
+ case LTTNG_SESSION_DESCRIPTOR_OUTPUT_TYPE_LOCAL:
+ if (descriptor->output.local) {
+ return *descriptor->output.local->dst.path;
+ }
+ break;
+ case LTTNG_SESSION_DESCRIPTOR_OUTPUT_TYPE_NETWORK:
+ if (descriptor->output.network.control) {
+ return *descriptor->output.network.control->subdir;
+ }
+ break;
+ default:
+ abort();
+ }
+ return false;
+}
+
+LTTNG_HIDDEN
+enum lttng_error_code lttng_session_descriptor_set_default_output(
+ struct lttng_session_descriptor *descriptor,
+ time_t *session_creation_time,
+ const char *absolute_home_path)
+{
+ enum lttng_error_code ret_code = LTTNG_OK;
+ struct lttng_uri *uris = NULL;
+
+ switch (descriptor->output_type) {
+ case LTTNG_SESSION_DESCRIPTOR_OUTPUT_TYPE_NONE:
+ goto end;
+ case LTTNG_SESSION_DESCRIPTOR_OUTPUT_TYPE_LOCAL:
+ {
+ int ret;
+ ssize_t uri_ret;
+ char local_uri[LTTNG_PATH_MAX];
+ char creation_datetime_suffix[17] = {};
+
+ if (session_creation_time) {
+ size_t strftime_ret;
+ struct tm *timeinfo;
+
+ timeinfo = localtime(session_creation_time);
+ if (!timeinfo) {
+ ret_code = LTTNG_ERR_FATAL;
+ goto end;
+ }
+ strftime_ret = strftime(creation_datetime_suffix,
+ sizeof(creation_datetime_suffix),
+ "-%Y%m%d-%H%M%S", timeinfo);
+ if (strftime_ret == 0) {
+ ERR("Failed to format session creation timestamp while setting default local output destination");
+ ret_code = LTTNG_ERR_FATAL;
+ goto end;
+ }
+ }
+ assert(descriptor->name);
+ ret = snprintf(local_uri, sizeof(local_uri),
+ "file://%s/%s/%s%s",
+ absolute_home_path,
+ DEFAULT_TRACE_DIR_NAME, descriptor->name,
+ creation_datetime_suffix);
+ if (ret >= sizeof(local_uri)) {
+ ERR("Truncation occurred while setting default local output destination");
+ ret_code = LTTNG_ERR_SET_URL;
+ goto end;
+ } else if (ret < 0) {
+ PERROR("Failed to format default local output URI");
+ ret_code = LTTNG_ERR_SET_URL;
+ goto end;
+ }
+
+ uri_ret = uri_parse(local_uri, &uris);
+ if (uri_ret != 1) {
+ ret_code = LTTNG_ERR_SET_URL;
+ goto end;
+ }
+ free(descriptor->output.local);
+ descriptor->output.local = &uris[0];
+ uris = NULL;
+ break;
+ }
+ case LTTNG_SESSION_DESCRIPTOR_OUTPUT_TYPE_NETWORK:
+ {
+ int ret;
+ ssize_t uri_ret;
+ struct lttng_uri *control = NULL, *data = NULL;
+
+ uri_ret = uri_parse_str_urls("net://127.0.0.1", NULL, &uris);
+ if (uri_ret != 2) {
+ ret_code = LTTNG_ERR_SET_URL;
+ goto end;
+ }
+
+ control = uri_copy(&uris[0]);
+ data = uri_copy(&uris[1]);
+ if (!control || !data) {
+ free(control);
+ free(data);
+ ret_code = LTTNG_ERR_SET_URL;
+ goto end;
+ }
+
+ /* Ownership of uris is transferred. */
+ ret = network_location_set_from_lttng_uris(
+ &descriptor->output.network,
+ control, data);
+ if (ret) {
+ abort();
+ ret_code = LTTNG_ERR_SET_URL;
+ goto end;
+ }
+ break;
+ }
+ default:
+ abort();
+ }
+end:
+ free(uris);
+ return ret_code;
+}
+
+/*
+ * Note that only properties that can be populated by the session daemon
+ * (output destination and name) are assigned.
+ */
+LTTNG_HIDDEN
+int lttng_session_descriptor_assign(
+ struct lttng_session_descriptor *dst,
+ const struct lttng_session_descriptor *src)
+{
+ int ret = 0;
+
+ if (dst->type != src->type) {
+ ret = -1;
+ goto end;
+ }
+ if (dst->output_type != src->output_type) {
+ ret = -1;
+ goto end;
+ }
+ ret = lttng_session_descriptor_set_session_name(dst, src->name);
+ if (ret) {
+ goto end;
+ }
+ switch (dst->output_type) {
+ case LTTNG_SESSION_DESCRIPTOR_OUTPUT_TYPE_LOCAL:
+ free(dst->output.local);
+ dst->output.local = uri_copy(src->output.local);
+ if (!dst->output.local) {
+ ret = -1;
+ goto end;
+ }
+ break;
+ case LTTNG_SESSION_DESCRIPTOR_OUTPUT_TYPE_NETWORK:
+ {
+ struct lttng_uri *control_copy = NULL, *data_copy = NULL;
+
+ control_copy = uri_copy(dst->output.network.control);
+ if (!control_copy && dst->output.network.control) {
+ ret = -1;
+ goto end;
+ }
+ data_copy = uri_copy(dst->output.network.data);
+ if (!data_copy && dst->output.network.data) {
+ free(control_copy);
+ ret = -1;
+ goto end;
+ }
+ ret = network_location_set_from_lttng_uris(&dst->output.network,
+ control_copy, data_copy);
+ break;
+ }
+ case LTTNG_SESSION_DESCRIPTOR_OUTPUT_TYPE_NONE:
+ goto end;
+ }
+end:
+ return ret;
+}
LTTNG_ENABLE_EVENT = 6,
/* 7 */
/* Session daemon command */
- LTTNG_CREATE_SESSION = 8,
+ /* 8 */
LTTNG_DESTROY_SESSION = 9,
LTTNG_LIST_CHANNELS = 10,
LTTNG_LIST_DOMAINS = 11,
LTTNG_SNAPSHOT_DEL_OUTPUT = 26,
LTTNG_SNAPSHOT_LIST_OUTPUT = 27,
LTTNG_SNAPSHOT_RECORD = 28,
- LTTNG_CREATE_SESSION_SNAPSHOT = 29,
- LTTNG_CREATE_SESSION_LIVE = 30,
+ /* 29 */
+ /* 30 */
LTTNG_SAVE_SESSION = 31,
LTTNG_TRACK_PID = 32,
LTTNG_UNTRACK_PID = 33,
LTTNG_ROTATION_GET_INFO = 46,
LTTNG_ROTATION_SET_SCHEDULE = 47,
LTTNG_SESSION_LIST_ROTATION_SCHEDULES = 48,
+ LTTNG_CREATE_SESSION_EXT = 49
};
enum lttcomm_relayd_command {
uint8_t set;
uint64_t value;
} LTTNG_PACKED rotation_set_schedule;
+ struct {
+ /*
+ * Includes the null-terminator.
+ * Must be an absolute path.
+ *
+ * Size bounded by LTTNG_PATH_MAX.
+ */
+ uint16_t home_dir_size;
+ uint64_t session_descriptor_size;
+ /* An lttng_session_descriptor follows. */
+ } LTTNG_PACKED create_session;
} u;
} LTTNG_PACKED;
#define LTTNG_FILTER_MAX_LEN 65536
+#define LTTNG_SESSION_DESCRIPTOR_MAX_LEN 65536
/*
* Filter bytecode data. The reloc table is located at the end of the
#include <lttng/channel-internal.h>
#include <lttng/event-internal.h>
#include <lttng/userspace-probe-internal.h>
+#include <lttng/session-internal.h>
+#include <lttng/session-descriptor-internal.h>
#include "filter/filter-ast.h"
#include "filter/filter-parser.h"
return error_get_str(code);
}
+enum lttng_error_code lttng_create_session_ext(
+ struct lttng_session_descriptor *session_descriptor)
+{
+ enum lttng_error_code ret_code;
+ struct lttcomm_session_msg lsm = {
+ .cmd_type = LTTNG_CREATE_SESSION_EXT,
+ };
+ void *reply = NULL;
+ struct lttng_buffer_view reply_view;
+ int reply_ret;
+ bool sessiond_must_generate_ouput;
+ struct lttng_dynamic_buffer payload;
+ int ret;
+ size_t descriptor_size;
+ struct lttng_session_descriptor *descriptor_reply = NULL;
+
+ lttng_dynamic_buffer_init(&payload);
+ if (!session_descriptor) {
+ ret_code = LTTNG_ERR_INVALID;
+ goto end;
+ }
+
+ sessiond_must_generate_ouput =
+ !lttng_session_descriptor_is_output_destination_initialized(
+ session_descriptor);
+ if (sessiond_must_generate_ouput) {
+ const char *home_dir = utils_get_home_dir();
+ size_t home_dir_len = home_dir ? strlen(home_dir) + 1 : 0;
+
+ if (!home_dir || home_dir_len > LTTNG_PATH_MAX) {
+ ret_code = LTTNG_ERR_FATAL;
+ goto end;
+ }
+
+ lsm.u.create_session.home_dir_size = (uint16_t) home_dir_len;
+ ret = lttng_dynamic_buffer_append(&payload, home_dir,
+ home_dir_len);
+ if (ret) {
+ ret_code = LTTNG_ERR_NOMEM;
+ goto end;
+ }
+ }
+
+ descriptor_size = payload.size;
+ ret = lttng_session_descriptor_serialize(session_descriptor,
+ &payload);
+ if (ret) {
+ ret_code = LTTNG_ERR_INVALID;
+ goto end;
+ }
+ descriptor_size = payload.size - descriptor_size;
+ lsm.u.create_session.session_descriptor_size = descriptor_size;
+
+ /* Command returns a session descriptor on success. */
+ reply_ret = lttng_ctl_ask_sessiond_varlen_no_cmd_header(&lsm, payload.data,
+ payload.size, &reply);
+ if (reply_ret < 0) {
+ ret_code = -reply_ret;
+ goto end;
+ } else if (reply_ret == 0) {
+ /* Socket unexpectedly closed by the session daemon. */
+ ret_code = LTTNG_ERR_FATAL;
+ goto end;
+ }
+
+ reply_view = lttng_buffer_view_init(reply, 0, reply_ret);
+ ret = lttng_session_descriptor_create_from_buffer(&reply_view,
+ &descriptor_reply);
+ if (ret < 0) {
+ ret_code = LTTNG_ERR_FATAL;
+ goto end;
+ }
+ ret_code = LTTNG_OK;
+ lttng_session_descriptor_assign(session_descriptor, descriptor_reply);
+end:
+ free(reply);
+ lttng_dynamic_buffer_reset(&payload);
+ lttng_session_descriptor_destroy(descriptor_reply);
+ return ret_code;
+}
+
/*
- * Create a brand new session using name and url for destination.
+ * Create a new session using name and url for destination.
*
* Returns LTTNG_OK on success or a negative error code.
*/
{
int ret;
ssize_t size;
- struct lttcomm_session_msg lsm;
struct lttng_uri *uris = NULL;
+ struct lttng_session_descriptor *descriptor = NULL;
+ enum lttng_error_code ret_code;
- if (name == NULL) {
- return -LTTNG_ERR_INVALID;
+ if (!name) {
+ ret = -LTTNG_ERR_INVALID;
+ goto end;
}
- memset(&lsm, 0, sizeof(lsm));
-
- lsm.cmd_type = LTTNG_CREATE_SESSION;
- lttng_ctl_copy_string(lsm.session.name, name, sizeof(lsm.session.name));
-
- /* There should never be a data URL */
size = uri_parse_str_urls(url, NULL, &uris);
if (size < 0) {
- return -LTTNG_ERR_INVALID;
+ ret = -LTTNG_ERR_INVALID;
+ goto end;
+ }
+ switch (size) {
+ case 0:
+ descriptor = lttng_session_descriptor_create(name);
+ break;
+ case 1:
+ if (uris[0].dtype != LTTNG_DST_PATH) {
+ ret = -LTTNG_ERR_INVALID;
+ goto end;
+ }
+ descriptor = lttng_session_descriptor_local_create(name,
+ uris[0].dst.path);
+ break;
+ case 2:
+ descriptor = lttng_session_descriptor_network_create(name, url,
+ NULL);
+ break;
+ default:
+ ret = -LTTNG_ERR_INVALID;
+ goto end;
+ }
+ if (!descriptor) {
+ ret = -LTTNG_ERR_INVALID;
+ goto end;
}
+ ret_code = lttng_create_session_ext(descriptor);
+ ret = ret_code == LTTNG_OK ? 0 : -ret_code;
+end:
+ lttng_session_descriptor_destroy(descriptor);
+ free(uris);
+ return ret;
+}
- lsm.u.uri.size = size;
+/*
+ * Create a session exclusively used for snapshot.
+ *
+ * Returns LTTNG_OK on success or a negative error code.
+ */
+int lttng_create_session_snapshot(const char *name, const char *snapshot_url)
+{
+ int ret;
+ enum lttng_error_code ret_code;
+ ssize_t size;
+ struct lttng_uri *uris = NULL;
+ struct lttng_session_descriptor *descriptor = NULL;
- ret = lttng_ctl_ask_sessiond_varlen_no_cmd_header(&lsm, uris,
- sizeof(struct lttng_uri) * size, NULL);
+ if (!name) {
+ ret = -LTTNG_ERR_INVALID;
+ goto end;
+ }
+
+ size = uri_parse_str_urls(snapshot_url, NULL, &uris);
+ if (size < 0) {
+ ret = -LTTNG_ERR_INVALID;
+ goto end;
+ }
+ /*
+ * If the user does not specify a custom subdir, use the session name.
+ */
+ if (size > 0 && uris[0].dtype != LTTNG_DST_PATH &&
+ strlen(uris[0].subdir) == 0) {
+ ret = snprintf(uris[0].subdir, sizeof(uris[0].subdir), "%s",
+ name);
+ if (ret < 0) {
+ PERROR("Failed to set session name as network destination sub-directory");
+ ret = -LTTNG_ERR_FATAL;
+ goto end;
+ } else if (ret >= sizeof(uris[0].subdir)) {
+ /* Truncated output. */
+ ret = -LTTNG_ERR_INVALID;
+ goto end;
+ }
+ }
+ switch (size) {
+ case 0:
+ descriptor = lttng_session_descriptor_snapshot_create(name);
+ break;
+ case 1:
+ if (uris[0].dtype != LTTNG_DST_PATH) {
+ ret = -LTTNG_ERR_INVALID;
+ goto end;
+ }
+ descriptor = lttng_session_descriptor_snapshot_local_create(
+ name,
+ uris[0].dst.path);
+ break;
+ case 2:
+ descriptor = lttng_session_descriptor_snapshot_network_create(
+ name,
+ snapshot_url,
+ NULL);
+ break;
+ default:
+ ret = -LTTNG_ERR_INVALID;
+ goto end;
+ }
+ if (!descriptor) {
+ ret = -LTTNG_ERR_INVALID;
+ goto end;
+ }
+ ret_code = lttng_create_session_ext(descriptor);
+ ret = ret_code == LTTNG_OK ? 0 : -ret_code;
+end:
+ lttng_session_descriptor_destroy(descriptor);
free(uris);
return ret;
}
+/*
+ * Create a session exclusively used for live.
+ *
+ * Returns LTTNG_OK on success or a negative error code.
+ */
+int lttng_create_session_live(const char *name, const char *url,
+ unsigned int timer_interval)
+{
+ int ret;
+ enum lttng_error_code ret_code;
+ struct lttng_session_descriptor *descriptor = NULL;
+
+ if (!name) {
+ ret = -LTTNG_ERR_INVALID;
+ goto end;
+ }
+
+ if (url) {
+ descriptor = lttng_session_descriptor_live_network_create(
+ name, url, NULL, timer_interval);
+ } else {
+ descriptor = lttng_session_descriptor_live_create(
+ name, timer_interval);
+ }
+ if (!descriptor) {
+ ret = -LTTNG_ERR_INVALID;
+ goto end;
+ }
+ ret_code = lttng_create_session_ext(descriptor);
+ ret = ret_code == LTTNG_OK ? 0 : -ret_code;
+end:
+ lttng_session_descriptor_destroy(descriptor);
+ return ret;
+}
+
/*
* Destroy session using name.
* Returns size of returned session payload data or a negative error code.
* Returns the number of lttng_session entries in sessions;
* on error, returns a negative value.
*/
-int lttng_list_sessions(struct lttng_session **sessions)
+int lttng_list_sessions(struct lttng_session **out_sessions)
{
int ret;
struct lttcomm_session_msg lsm;
+ const size_t session_size = sizeof(struct lttng_session) +
+ sizeof(struct lttng_session_extended);
+ size_t session_count, i;
+ struct lttng_session_extended *sessions_extended_begin;
+ struct lttng_session *sessions = NULL;
memset(&lsm, 0, sizeof(lsm));
lsm.cmd_type = LTTNG_LIST_SESSIONS;
- ret = lttng_ctl_ask_sessiond(&lsm, (void**) sessions);
- if (ret < 0) {
- return ret;
+ ret = lttng_ctl_ask_sessiond(&lsm, (void**) &sessions);
+ if (ret <= 0) {
+ ret = ret == 0 ? -LTTNG_ERR_FATAL : ret;
+ goto end;
+ }
+ if (!sessions) {
+ ret = -LTTNG_ERR_FATAL;
+ goto end;
+ }
+
+ if (ret % session_size) {
+ ret = -LTTNG_ERR_UNK;
+ free(sessions);
+ *out_sessions = NULL;
+ goto end;
}
+ session_count = (size_t) ret / session_size;
+ sessions_extended_begin = (struct lttng_session_extended *)
+ (&sessions[session_count]);
- return ret / sizeof(struct lttng_session);
+ /* Set extended session info pointers. */
+ for (i = 0; i < session_count; i++) {
+ struct lttng_session *session = &sessions[i];
+ struct lttng_session_extended *extended =
+ &(sessions_extended_begin[i]);
+
+ session->extended.ptr = extended;
+ }
+
+ ret = (int) session_count;
+ *out_sessions = sessions;
+end:
+ return ret;
+}
+
+enum lttng_error_code lttng_session_get_creation_time(
+ const struct lttng_session *session, uint64_t *creation_time)
+{
+ enum lttng_error_code ret = LTTNG_OK;
+ struct lttng_session_extended *extended;
+
+ if (!session || !creation_time || !session->extended.ptr) {
+ ret = LTTNG_ERR_INVALID;
+ goto end;
+ }
+
+ extended = session->extended.ptr;
+ if (!extended->creation_time.is_set) {
+ /* Not created on the session daemon yet. */
+ ret = LTTNG_ERR_SESSION_NOT_EXIST;
+ goto end;
+ }
+ *creation_time = extended->creation_time.value;
+end:
+ return ret;
}
int lttng_set_session_shm_path(const char *session_name,
}
/*
- * This is an extension of create session that is ONLY and SHOULD only be used
- * by the lttng command line program. It exists to avoid using URI parsing in
- * the lttng client.
- *
- * We need the date and time for the trace path subdirectory for the case where
- * the user does NOT define one using either -o or -U. Using the normal
- * lttng_create_session API call, we have no clue on the session daemon side if
- * the URL was generated automatically by the client or define by the user.
- *
- * So this function "wrapper" is hidden from the public API, takes the datetime
- * string and appends it if necessary to the URI subdirectory before sending it
- * to the session daemon.
- *
- * With this extra function, the lttng_create_session call behavior is not
- * changed and the timestamp is appended to the URI on the session daemon side
- * if necessary.
+ * [OBSOLETE]
*/
int _lttng_create_session_ext(const char *name, const char *url,
const char *datetime)
{
- int ret;
- ssize_t size;
- struct lttcomm_session_msg lsm;
- struct lttng_uri *uris = NULL;
-
- if (name == NULL || datetime == NULL) {
- return -LTTNG_ERR_INVALID;
- }
-
- memset(&lsm, 0, sizeof(lsm));
-
- lsm.cmd_type = LTTNG_CREATE_SESSION;
- lttng_ctl_copy_string(lsm.session.name, name, sizeof(lsm.session.name));
-
- /* There should never be a data URL. */
- size = uri_parse_str_urls(url, NULL, &uris);
- if (size < 0) {
- ret = -LTTNG_ERR_INVALID;
- goto error;
- }
-
- lsm.u.uri.size = size;
-
- if (size > 0 && uris[0].dtype != LTTNG_DST_PATH && strlen(uris[0].subdir) == 0) {
- /* Don't append datetime if the name was automatically created. */
- if (strncmp(name, DEFAULT_SESSION_NAME "-",
- strlen(DEFAULT_SESSION_NAME) + 1)) {
- ret = snprintf(uris[0].subdir, sizeof(uris[0].subdir), "%s-%s",
- name, datetime);
- } else {
- ret = snprintf(uris[0].subdir, sizeof(uris[0].subdir), "%s", name);
- }
- if (ret < 0) {
- PERROR("snprintf uri subdir");
- ret = -LTTNG_ERR_FATAL;
- goto error;
- }
- }
-
- ret = lttng_ctl_ask_sessiond_varlen_no_cmd_header(&lsm, uris,
- sizeof(struct lttng_uri) * size, NULL);
-
-error:
- free(uris);
- return ret;
+ return -ENOSYS;
}
/*
return ret;
}
-/*
- * Create a session exclusively used for snapshot.
- *
- * Returns LTTNG_OK on success or a negative error code.
- */
-int lttng_create_session_snapshot(const char *name, const char *snapshot_url)
-{
- int ret;
- ssize_t size;
- struct lttcomm_session_msg lsm;
- struct lttng_uri *uris = NULL;
-
- if (name == NULL) {
- return -LTTNG_ERR_INVALID;
- }
-
- memset(&lsm, 0, sizeof(lsm));
-
- lsm.cmd_type = LTTNG_CREATE_SESSION_SNAPSHOT;
- lttng_ctl_copy_string(lsm.session.name, name, sizeof(lsm.session.name));
-
- size = uri_parse_str_urls(snapshot_url, NULL, &uris);
- if (size < 0) {
- return -LTTNG_ERR_INVALID;
- }
-
- lsm.u.uri.size = size;
-
- /*
- * If the user does not specify a custom subdir, use the session name.
- */
- if (size > 0 && uris[0].dtype != LTTNG_DST_PATH && strlen(uris[0].subdir) == 0) {
- ret = snprintf(uris[0].subdir, sizeof(uris[0].subdir), "%s", name);
- if (ret < 0) {
- PERROR("snprintf uri subdir");
- ret = -LTTNG_ERR_FATAL;
- goto error;
- }
- }
-
- ret = lttng_ctl_ask_sessiond_varlen_no_cmd_header(&lsm, uris,
- sizeof(struct lttng_uri) * size, NULL);
-
-error:
- free(uris);
- return ret;
-}
-
-/*
- * Create a session exclusively used for live.
- *
- * Returns LTTNG_OK on success or a negative error code.
- */
-int lttng_create_session_live(const char *name, const char *url,
- unsigned int timer_interval)
-{
- int ret;
- ssize_t size;
- struct lttcomm_session_msg lsm;
- struct lttng_uri *uris = NULL;
-
- if (name == NULL || timer_interval == 0) {
- return -LTTNG_ERR_INVALID;
- }
-
- memset(&lsm, 0, sizeof(lsm));
-
- lsm.cmd_type = LTTNG_CREATE_SESSION_LIVE;
- lttng_ctl_copy_string(lsm.session.name, name, sizeof(lsm.session.name));
-
- if (url) {
- size = uri_parse_str_urls(url, NULL, &uris);
- if (size <= 0) {
- ret = -LTTNG_ERR_INVALID;
- goto end;
- }
-
- /* file:// is not accepted for live session. */
- if (uris[0].dtype == LTTNG_DST_PATH) {
- ret = -LTTNG_ERR_INVALID;
- goto end;
- }
- } else {
- size = 0;
- }
-
- lsm.u.session_live.nb_uri = size;
- lsm.u.session_live.timer_interval = timer_interval;
-
- ret = lttng_ctl_ask_sessiond_varlen_no_cmd_header(&lsm, uris,
- sizeof(struct lttng_uri) * size, NULL);
-
-end:
- free(uris);
- return ret;
-}
-
/*
* List PIDs in the tracker.
*
lttng_snapshot_record $SESSION_NAME
# Validate test
- validate_trace $EVENT_NAME $TRACE_PATH/$HOSTNAME/snapshot-1*
+ validate_trace $EVENT_NAME $TRACE_PATH/$HOSTNAME/$SESSION_NAME*/snapshot-1*
if [ $? -ne 0 ]; then
return $?
fi
lttng_snapshot_record $SESSION_NAME
# Validate test with the next ID since a del output was done prior.
- validate_trace $EVENT_NAME $TRACE_PATH/$HOSTNAME/snapshot-2*
+ validate_trace $EVENT_NAME $TRACE_PATH/$HOSTNAME/$SESSION_NAME*/snapshot-2*
if [ $? -ne 0 ]; then
return $?
fi
stop_lttng_tracing_ok $SESSION_NAME
destroy_lttng_session_ok $SESSION_NAME
# Validate test
- validate_trace $EVENT_NAME $TRACE_PATH/$HOSTNAME/snapshot-1*
+ validate_trace $EVENT_NAME $TRACE_PATH/$HOSTNAME/$SESSION_NAME*/snapshot-1*
out=$?
return $out
stop_lttng_tracing_ok $SESSION_NAME
destroy_lttng_session_ok $SESSION_NAME
- if ls $TRACE_PATH/$HOSTNAME/$name* &> /dev/null; then
+ if ls $TRACE_PATH/$HOSTNAME/$SESSION_NAME*/$name* &> /dev/null; then
ok 0 "Custom name snapshot exists"
# Validate test
- validate_trace $EVENT_NAME $TRACE_PATH/$HOSTNAME/$name-*
+ validate_trace $EVENT_NAME $TRACE_PATH/$HOSTNAME/$SESSION_NAME*/$name-*
out=$?
else
fail "No custom name snapshot found"
start_lttng_tracing_ok $SESSION_NAME
lttng_snapshot_record $SESSION_NAME
stop_lttng_tracing_ok $SESSION_NAME
- validate_trace $EVENT_NAME $TRACE_PATH/$HOSTNAME/snapshot-1*
+ validate_trace $EVENT_NAME $TRACE_PATH/$HOSTNAME/$SESSION_NAME*/snapshot-1*
if [ $? -ne 0 ]; then
return 1
fi
lttng_snapshot_record $SESSION_NAME
# Validate test
- echo $TRACE_PATH/$HOSTNAME/snapshot-1
- validate_trace $EVENT_NAME $TRACE_PATH/$HOSTNAME/snapshot-1*
+ validate_trace $EVENT_NAME $TRACE_PATH/$HOSTNAME/$SESSION_NAME*/snapshot-1*
if [ $? -ne 0 ]; then
stop_test_apps
return $?
lttng_snapshot_record $SESSION_NAME
# Validate test with the next ID since a del output was done prior.
- validate_trace $EVENT_NAME $TRACE_PATH/$HOSTNAME/snapshot-2*
+ validate_trace $EVENT_NAME $TRACE_PATH/$HOSTNAME/$SESSION_NAME*/snapshot-2*
if [ $? -ne 0 ]; then
stop_test_apps
return $?
stop_lttng_tracing_ok $SESSION_NAME
destroy_lttng_session_ok $SESSION_NAME
# Validate test
- validate_trace $EVENT_NAME $TRACE_PATH/$HOSTNAME/snapshot-1*
+ validate_trace $EVENT_NAME $TRACE_PATH/$HOSTNAME/$SESSION_NAME*/snapshot-1*
out=$?
stop_test_apps
stop_lttng_tracing_ok $SESSION_NAME
destroy_lttng_session_ok $SESSION_NAME
# Validate test
- validate_trace $EVENT_NAME $TRACE_PATH/$HOSTNAME/snapshot-1*
+ validate_trace $EVENT_NAME $TRACE_PATH/$HOSTNAME/$SESSION_NAME*/snapshot-1*
out=$?
stop_test_apps
stop_lttng_tracing_ok $SESSION_NAME
destroy_lttng_session_ok $SESSION_NAME
- if ls $TRACE_PATH/$HOSTNAME/$name* &> /dev/null; then
+ if ls $TRACE_PATH/$HOSTNAME/$SESSION_NAME*/$name* &> /dev/null; then
ok 0 "Custom name snapshot exists"
# Validate test
- validate_trace $EVENT_NAME $TRACE_PATH/$HOSTNAME/$name-*
+ validate_trace $EVENT_NAME $TRACE_PATH/$HOSTNAME/$SESSION_NAME*/$name-*
out=$?
else
fail "No custom name snapshot found"
start_lttng_tracing_ok $SESSION_NAME
lttng_snapshot_record $SESSION_NAME
stop_lttng_tracing_ok $SESSION_NAME
- validate_trace $EVENT_NAME $TRACE_PATH/$HOSTNAME/snapshot-1*
+ validate_trace $EVENT_NAME $TRACE_PATH/$HOSTNAME/$SESSION_NAME*/snapshot-1*
if [ $? -ne 0 ]; then
return 1
fi
static int create_one_session(char *name)
{
int ret;
+ enum lttng_error_code ret_code;
+ struct ltt_session *session = NULL;
- ret = session_create(name, geteuid(), getegid());
- if (ret == LTTNG_OK) {
+ session_lock_list();
+ ret_code = session_create(name, geteuid(), getegid(), &session);
+ session_put(session);
+ if (ret_code == LTTNG_OK) {
/* Validate */
ret = find_session_name(name);
if (ret < 0) {
/* Session not found by name */
printf("session not found after creation\n");
- return -1;
+ ret = -1;
+ goto end;
} else {
/* Success */
- return 0;
+ ret = 0;
+ goto end;
}
} else {
- if (ret == LTTNG_ERR_EXIST_SESS) {
+ if (ret_code == LTTNG_ERR_EXIST_SESS) {
printf("(session already exists) ");
}
- return -1;
+ ret = -1;
+ goto end;
}
-
- return 0;
+ ret = 0;
+end:
+ session_unlock_list();
+ return ret;
}
/*
"Duplicate session creation");
}
-void test_bogus_session_param(void)
+void test_session_name_generation(void)
{
- ok(create_one_session(NULL) < 0,
- "Create session with bogus param: NULL should fail");
+ struct ltt_session *session = NULL;
+ enum lttng_error_code ret_code;
+ const char *expected_session_name_prefix = DEFAULT_SESSION_NAME;
- ok(session_list_count() == 0,
- "Create session with bogus param: session list empty");
+ session_lock_list();
+ ret_code = session_create(NULL, geteuid(), getegid(), &session);
+ ok(ret_code == LTTNG_OK,
+ "Create session with a NULL name (auto-generate a name)");
+ if (!session) {
+ skip(1, "Skipping session name generation tests as session_create() failed.");
+ goto end;
+ }
+ diag("Automatically-generated session name: %s", *session->name ?
+ session->name : "ERROR");
+ ok(*session->name && !strncmp(expected_session_name_prefix, session->name,
+ sizeof(DEFAULT_SESSION_NAME) - 1),
+ "Auto-generated session name starts with %s",
+ DEFAULT_SESSION_NAME);
+end:
+ session_put(session);
+ session_unlock_list();
}
void test_large_session_number(void)
empty_session_list();
- test_bogus_session_param();
+ test_session_name_generation();
test_large_session_number();