struct lttng_session_descriptor *dst_descriptor,
const struct lttng_session_descriptor *src_descriptor);
+LTTNG_HIDDEN
+int lttng_session_descriptor_get_base_path(struct lttng_session_descriptor *dst,
+ const char **base_path);
+
#endif /* LTTNG_SESSION_DESCRIPTOR_INTERNAL_H */
#include "utils.h"
int cmd_create_session_2_11(const struct lttng_buffer_view *payload,
- char *session_name, char *hostname,
+ char *session_name, char *hostname, char *base_path,
uint32_t *live_timer, bool *snapshot,
uint64_t *id_sessiond, lttng_uuid sessiond_uuid,
bool *has_current_chunk, uint64_t *current_chunk_id,
{
int ret;
struct lttcomm_relayd_create_session_2_11 header;
- size_t header_len, received_names_size;
+ size_t header_len, received_names_size, offset;
struct lttng_buffer_view session_name_view;
struct lttng_buffer_view hostname_view;
+ struct lttng_buffer_view base_path_view;
header_len = sizeof(header);
header.session_name_len = be32toh(header.session_name_len);
header.hostname_len = be32toh(header.hostname_len);
+ header.base_path_len = be32toh(header.base_path_len);
header.live_timer = be32toh(header.live_timer);
header.current_chunk_id.value = be64toh(header.current_chunk_id.value);
header.current_chunk_id.is_set = !!header.current_chunk_id.is_set;
lttng_uuid_copy(sessiond_uuid, header.sessiond_uuid);
- received_names_size = header.session_name_len + header.hostname_len;
+ received_names_size = header.session_name_len + header.hostname_len +
+ header.base_path_len;
if (payload->size < header_len + received_names_size) {
ERR("Unexpected payload size in \"cmd_create_session_2_11\": expected >= %zu bytes, got %zu bytes",
header_len + received_names_size, payload->size);
ERR("Length of hostname (%" PRIu32 " bytes) received in create_session command exceeds maximum length (%d bytes)", header.hostname_len, LTTNG_HOST_NAME_MAX);
goto error;
}
+ if (header.base_path_len > LTTNG_PATH_MAX) {
+ ret = -ENAMETOOLONG;
+ ERR("Length of base_path (%" PRIu32 " bytes) received in create_session command exceeds maximum length (%d bytes)", header.base_path_len, PATH_MAX);
+ goto error;
+ }
- session_name_view = lttng_buffer_view_from_view(payload, header_len,
+ offset = header_len;
+ session_name_view = lttng_buffer_view_from_view(payload, offset,
header.session_name_len);
+ offset += header.session_name_len;
hostname_view = lttng_buffer_view_from_view(payload,
- header_len + header.session_name_len, header.hostname_len);
+ offset, header.hostname_len);
+ offset += header.hostname_len;
+ base_path_view = lttng_buffer_view_from_view(payload,
+ offset, header.base_path_len);
/* Validate that names are NULL terminated. */
if (session_name_view.data[session_name_view.size - 1] != '\0') {
goto error;
}
+ if (base_path_view.size != 0 &&
+ base_path_view.data[base_path_view.size - 1] != '\0') {
+ ERR("cmd_create_session_2_11 base_path is invalid (not NULL terminated)");
+ ret = -1;
+ goto error;
+ }
+
/*
* Length and null-termination check are already performed.
- * LTTNG_NAME_MAX and LTTNG_HOST_NAME_MAX max size are expected.
+ * LTTNG_NAME_MAX, LTTNG_HOST_NAME_MAX, and LTTNG_PATH_MAX max sizes are expected.
*/
strcpy(session_name, session_name_view.data);
strcpy(hostname, hostname_view.data);
+ strcpy(base_path, base_path_view.size ? base_path_view.data : "");
*live_timer = header.live_timer;
*snapshot = !!header.snapshot;
#include <common/compat/uuid.h>
int cmd_create_session_2_11(const struct lttng_buffer_view *payload,
- char *session_name, char *hostname,
+ char *session_name, char *hostname, char *base_path,
uint32_t *live_timer, bool *snapshot,
uint64_t *id_sessiond, lttng_uuid sessiond_uuid,
bool *has_current_chunk, uint64_t *current_chunk_id,
uint32_t live_timer = 0;
bool snapshot = false;
/* Left nil for peers < 2.11. */
+ char base_path[LTTNG_PATH_MAX] = {};
lttng_uuid sessiond_uuid = {};
LTTNG_OPTIONAL(uint64_t) id_sessiond = {};
LTTNG_OPTIONAL(uint64_t) current_chunk_id = {};
/* From 2.11 to ... */
ret = cmd_create_session_2_11(payload, session_name, hostname,
- &live_timer, &snapshot, &id_sessiond_value,
+ base_path, &live_timer, &snapshot, &id_sessiond_value,
sessiond_uuid, &has_current_chunk,
¤t_chunk_id_value, &creation_time_value);
if (lttng_uuid_is_nil(sessiond_uuid)) {
goto send_reply;
}
- session = session_create(session_name, hostname, live_timer,
+ session = session_create(session_name, hostname, base_path, live_timer,
snapshot, sessiond_uuid,
id_sessiond.is_set ? &id_sessiond.value : NULL,
current_chunk_id.is_set ? ¤t_chunk_id.value : NULL,
struct lttng_directory_handle *handle)
{
int ret;
- /* hostname/session_name */
+ /*
+ * session_directory:
+ *
+ * if base_path is NULL
+ * hostname/session_name
+ * else
+ * hostname/base_path
+ */
char *session_directory = NULL;
/*
* base path + session_directory
* e.g. /home/user/lttng-traces/hostname/session_name
*/
char *full_session_path = NULL;
- char creation_time_str[16];
- struct tm *timeinfo;
- assert(session->creation_time.is_set);
- timeinfo = localtime(&session->creation_time.value);
- if (!timeinfo) {
- ret = -1;
- goto end;
- }
- strftime(creation_time_str, sizeof(creation_time_str), "%Y%m%d-%H%M%S",
- timeinfo);
+ /*
+ * If base path is set, it overrides the session name for the
+ * session relative base path. No timestamp is appended if the
+ * base path is overridden.
+ */
+ if (session->base_path[0] == '\0') {
+ char creation_time_str[16];
+ struct tm *timeinfo;
- pthread_mutex_lock(&session->lock);
- ret = asprintf(&session_directory, "%s/%s-%s", session->hostname,
- session->session_name, creation_time_str);
- pthread_mutex_unlock(&session->lock);
+ assert(session->creation_time.is_set);
+ timeinfo = localtime(&session->creation_time.value);
+ if (!timeinfo) {
+ ret = -1;
+ goto end;
+ }
+ strftime(creation_time_str, sizeof(creation_time_str), "%Y%m%d-%H%M%S",
+ timeinfo);
+
+ pthread_mutex_lock(&session->lock);
+ ret = asprintf(&session_directory, "%s/%s-%s", session->hostname,
+ session->session_name, creation_time_str);
+ pthread_mutex_unlock(&session->lock);
+ } else {
+ pthread_mutex_lock(&session->lock);
+ ret = asprintf(&session_directory, "%s/%s", session->hostname,
+ session->base_path);
+ pthread_mutex_unlock(&session->lock);
+ }
if (ret < 0) {
PERROR("Failed to format session directory name");
goto end;
* Return allocated session or else NULL.
*/
struct relay_session *session_create(const char *session_name,
- const char *hostname,
+ const char *hostname, const char *base_path,
uint32_t live_timer,
bool snapshot,
const lttng_uuid sessiond_uuid,
WARN("Hostname exceeds maximal allowed length");
goto error;
}
+ if (lttng_strncpy(session->base_path, base_path,
+ sizeof(session->base_path))) {
+ WARN("Base path exceeds maximal allowed length");
+ goto error;
+ }
+
session->ctf_traces_ht = lttng_ht_new(0, LTTNG_HT_TYPE_STRING);
if (!session->ctf_traces_ht) {
goto error;
LTTNG_OPTIONAL(time_t) creation_time;
char session_name[LTTNG_NAME_MAX];
char hostname[LTTNG_HOST_NAME_MAX];
+ char base_path[LTTNG_PATH_MAX];
uint32_t live_timer;
/* Session in snapshot mode. */
};
struct relay_session *session_create(const char *session_name,
- const char *hostname,
+ const char *hostname, const char *base_path,
uint32_t live_timer,
bool snapshot,
const lttng_uuid sessiond_uuid,
struct consumer_output *consumer,
struct consumer_socket *consumer_sock,
const char *session_name, const char *hostname,
- int session_live_timer,
+ const char *base_path, int session_live_timer,
const uint64_t *current_chunk_id,
time_t session_creation_time)
{
/* Send relayd socket to consumer. */
ret = consumer_send_relayd_socket(consumer_sock, rsock, consumer,
relayd_uri->stype, session_id,
- session_name, hostname, session_live_timer,
- current_chunk_id, session_creation_time);
+ session_name, hostname, base_path,
+ session_live_timer, current_chunk_id,
+ session_creation_time);
if (ret < 0) {
status = LTTNG_ERR_ENABLE_CONSUMER_FAIL;
goto close_sock;
enum lttng_domain_type domain,
unsigned int session_id, struct consumer_output *consumer,
struct consumer_socket *sock, const char *session_name,
- const char *hostname, int session_live_timer,
+ const char *hostname, const char *base_path, int session_live_timer,
const uint64_t *current_chunk_id, time_t session_creation_time)
{
enum lttng_error_code status = LTTNG_OK;
if (!sock->control_sock_sent) {
status = send_consumer_relayd_socket(session_id,
&consumer->dst.net.control, consumer, sock,
- session_name, hostname, session_live_timer,
+ session_name, hostname, base_path, session_live_timer,
current_chunk_id, session_creation_time);
if (status != LTTNG_OK) {
goto error;
if (!sock->data_sock_sent) {
status = send_consumer_relayd_socket(session_id,
&consumer->dst.net.data, consumer, sock,
- session_name, hostname, session_live_timer,
+ session_name, hostname, base_path, session_live_timer,
current_chunk_id, session_creation_time);
if (status != LTTNG_OK) {
goto error;
ret = send_consumer_relayd_sockets(LTTNG_DOMAIN_UST, session->id,
usess->consumer, socket,
session->name, session->hostname,
+ session->base_path,
session->live_timer,
current_chunk_id.is_set ? ¤t_chunk_id.value : NULL,
session->creation_time);
ret = send_consumer_relayd_sockets(LTTNG_DOMAIN_KERNEL, session->id,
ksess->consumer, socket,
session->name, session->hostname,
+ session->base_path,
session->live_timer,
current_chunk_id.is_set ? ¤t_chunk_id.value : NULL,
session->creation_time);
const char *session_name;
struct ltt_session *new_session = NULL;
enum lttng_session_descriptor_status descriptor_status;
+ const char *base_path;
session_lock_list();
if (home_path) {
ret_code = LTTNG_ERR_INVALID;
goto end;
}
+ ret = lttng_session_descriptor_get_base_path(descriptor, &base_path);
+ if (ret) {
+ ret_code = LTTNG_ERR_INVALID;
+ goto end;
+ }
ret_code = session_create(session_name, creds->uid, creds->gid,
- &new_session);
+ base_path, &new_session);
if (ret_code != LTTNG_OK) {
goto end;
}
struct lttng_ht_iter iter;
struct consumer_socket *socket;
LTTNG_OPTIONAL(uint64_t) current_chunk_id = {};
+ const char *base_path;
assert(output);
assert(session);
goto error;
}
+ /*
+ * The snapshot record URI base path overrides the session
+ * base path.
+ */
+ if (output->dst.net.control.subdir[0] != '\0') {
+ base_path = output->dst.net.control.subdir;
+ } else {
+ base_path = session->base_path;
+ }
+
/*
* For each consumer socket, create and send the relayd object of the
* snapshot output.
status = send_consumer_relayd_sockets(0, session->id,
output, socket,
session->name, session->hostname,
+ base_path,
session->live_timer,
current_chunk_id.is_set ? ¤t_chunk_id.value : NULL,
session->creation_time);
struct lttcomm_relayd_sock *rsock, struct consumer_output *consumer,
enum lttng_stream_type type, uint64_t session_id,
const char *session_name, const char *hostname,
- int session_live_timer, const uint64_t *current_chunk_id,
- time_t session_creation_time)
+ const char *base_path, int session_live_timer,
+ const uint64_t *current_chunk_id, time_t session_creation_time)
{
int ret;
struct lttcomm_consumer_msg msg;
if (type == LTTNG_STREAM_CONTROL) {
ret = relayd_create_session(rsock,
&msg.u.relayd_sock.relayd_session_id,
- session_name, hostname, session_live_timer,
+ session_name, hostname, base_path,
+ session_live_timer,
consumer->snapshot, session_id,
sessiond_uuid, current_chunk_id,
session_creation_time);
struct lttcomm_relayd_sock *rsock, struct consumer_output *consumer,
enum lttng_stream_type type, uint64_t session_id,
const char *session_name, const char *hostname,
- int session_live_timer, const uint64_t *current_chunk_id,
- time_t session_creation_time);
+ const char *base_path, int session_live_timer,
+ const uint64_t *current_chunk_id, time_t session_creation_time);
int consumer_send_channel_monitor_pipe(struct consumer_socket *consumer_sock,
int pipe);
int consumer_send_destroy_relayd(struct consumer_socket *sock,
}
lttng_dynamic_array_reset(&session->destroy_notifiers);
free(session->last_archived_chunk_name);
+ free(session->base_path);
free(session);
if (session_published) {
/*
* Session list lock must be held by the caller.
*/
enum lttng_error_code session_create(const char *name, uid_t uid, gid_t gid,
- struct ltt_session **out_session)
+ const char *base_path, struct ltt_session **out_session)
{
int ret;
enum lttng_error_code ret_code;
}
}
+ if (base_path) {
+ new_session->base_path = strdup(base_path);
+ if (!new_session->base_path) {
+ ERR("Failed to allocate base path of session \"%s\"",
+ name);
+ ret_code = LTTNG_ERR_SESSION_FAIL;
+ goto error;
+ }
+ }
+
new_session->uid = uid;
new_session->gid = gid;
char *last_archived_chunk_name;
LTTNG_OPTIONAL(uint64_t) last_archived_chunk_id;
struct lttng_dynamic_array destroy_notifiers;
+ /* Session base path override. Set non-null. */
+ char *base_path;
};
/* Prototypes */
enum lttng_error_code session_create(const char *name, uid_t uid, gid_t gid,
- struct ltt_session **out_session);
+ const char *base_path, struct ltt_session **out_session);
void session_lock(struct ltt_session *session);
void session_lock_list(void);
int session_trylock_list(void);
}
/*
- * Starting from 2.11, RELAYD_CREATE_SESSION payload (session_name & hostname)
- * have no length restriction on the sender side.
+ * Starting from 2.11, RELAYD_CREATE_SESSION payload (session_name,
+ * hostname, and base_path) have no length restriction on the sender side.
* Length for both payloads is stored in the msg struct. A new dynamic size
* payload size is introduced.
*/
static int relayd_create_session_2_11(struct lttcomm_relayd_sock *rsock,
const char *session_name, const char *hostname,
- int session_live_timer, unsigned int snapshot,
- uint64_t sessiond_session_id, const lttng_uuid sessiond_uuid,
- const uint64_t *current_chunk_id,
+ const char *base_path, int session_live_timer,
+ unsigned int snapshot, uint64_t sessiond_session_id,
+ const lttng_uuid sessiond_uuid, const uint64_t *current_chunk_id,
time_t creation_time)
{
int ret;
struct lttcomm_relayd_create_session_2_11 *msg = NULL;
size_t session_name_len;
size_t hostname_len;
+ size_t base_path_len;
size_t msg_length;
+ char *dst;
/* The two names are sent with a '\0' delimiter between them. */
session_name_len = strlen(session_name) + 1;
hostname_len = strlen(hostname) + 1;
+ base_path_len = base_path ? strlen(base_path) + 1 : 0;
- msg_length = sizeof(*msg) + session_name_len + hostname_len;
+ msg_length = sizeof(*msg) + session_name_len + hostname_len + base_path_len;
msg = zmalloc(msg_length);
if (!msg) {
PERROR("zmalloc create_session_2_11 command message");
assert(hostname_len <= UINT32_MAX);
msg->hostname_len = htobe32(hostname_len);
- if (lttng_strncpy(msg->names, session_name, session_name_len)) {
+ assert(base_path_len <= UINT32_MAX);
+ msg->base_path_len = htobe32(base_path_len);
+
+ dst = msg->names;
+ if (lttng_strncpy(dst, session_name, session_name_len)) {
+ ret = -1;
+ goto error;
+ }
+ dst += session_name_len;
+ if (lttng_strncpy(dst, hostname, hostname_len)) {
ret = -1;
goto error;
}
- if (lttng_strncpy(msg->names + session_name_len, hostname, hostname_len)) {
+ dst += hostname_len;
+ if (base_path && lttng_strncpy(dst, base_path, base_path_len)) {
ret = -1;
goto error;
}
int relayd_create_session(struct lttcomm_relayd_sock *rsock,
uint64_t *relayd_session_id,
const char *session_name, const char *hostname,
- int session_live_timer,
+ const char *base_path, int session_live_timer,
unsigned int snapshot, uint64_t sessiond_session_id,
const lttng_uuid sessiond_uuid,
const uint64_t *current_chunk_id,
} else {
/* From 2.11 to ... */
ret = relayd_create_session_2_11(rsock, session_name,
- hostname, session_live_timer, snapshot,
+ hostname, base_path, session_live_timer, snapshot,
sessiond_session_id, sessiond_uuid,
current_chunk_id, creation_time);
}
int relayd_create_session(struct lttcomm_relayd_sock *rsock,
uint64_t *relayd_session_id,
const char *session_name, const char *hostname,
- int session_live_timer,
+ const char *base_path, int session_live_timer,
unsigned int snapshot, uint64_t sessiond_session_id,
const lttng_uuid sessiond_uuid,
const uint64_t *current_chunk_id,
end:
return ret;
}
+
+LTTNG_HIDDEN
+int lttng_session_descriptor_get_base_path(struct lttng_session_descriptor *dst,
+ const char **_base_path)
+{
+ switch (dst->output_type) {
+ case LTTNG_SESSION_DESCRIPTOR_OUTPUT_TYPE_NETWORK:
+ {
+ *_base_path = dst->output.network.control->subdir[0] ?
+ dst->output.network.control->subdir : NULL;
+ break;
+ }
+ case LTTNG_SESSION_DESCRIPTOR_OUTPUT_TYPE_LOCAL:
+ case LTTNG_SESSION_DESCRIPTOR_OUTPUT_TYPE_NONE:
+ *_base_path = NULL;
+ break;
+ }
+ return 0;
+}
struct lttcomm_relayd_create_session_2_11 {
uint32_t session_name_len;
uint32_t hostname_len;
+ /* Optional, set to 0 to indicate it is not user-specified. */
+ uint32_t base_path_len;
uint32_t live_timer;
uint8_t snapshot;
/* Sessiond instance UUID */
/* Session creation time, in seconds since UNIX Epoch. */
uint64_t creation_time;
LTTNG_OPTIONAL_COMM(uint64_t) LTTNG_PACKED current_chunk_id;
- /* Contains the session_name and hostname */
+ /* Contains the session_name, hostname, base_path. */
char names[];
} LTTNG_PACKED;
struct ltt_session *session = NULL;
session_lock_list();
- ret_code = session_create(name, geteuid(), getegid(), &session);
+ ret_code = session_create(name, geteuid(), getegid(), NULL, &session);
session_put(session);
if (ret_code == LTTNG_OK) {
/* Validate */
const char *expected_session_name_prefix = DEFAULT_SESSION_NAME;
session_lock_list();
- ret_code = session_create(NULL, geteuid(), getegid(), &session);
+ ret_code = session_create(NULL, geteuid(), getegid(), NULL, &session);
ok(ret_code == LTTNG_OK,
"Create session with a NULL name (auto-generate a name)");
if (!session) {