lttng rotate command
authorJulien Desfossez <jdesfossez@efficios.com>
Mon, 18 Dec 2017 21:51:41 +0000 (16:51 -0500)
committerJérémie Galarneau <jeremie.galarneau@efficios.com>
Fri, 23 Mar 2018 19:38:20 +0000 (15:38 -0400)
The command line and API interface to the lttng rotate command.

Signed-off-by: Julien Desfossez <jdesfossez@efficios.com>
Signed-off-by: Jérémie Galarneau <jeremie.galarneau@efficios.com>
23 files changed:
include/lttng/lttng-error.h
include/lttng/rotate-internal.h
include/lttng/rotation.h
include/lttng/session.h
src/bin/lttng-sessiond/cmd.c
src/bin/lttng-sessiond/cmd.h
src/bin/lttng-sessiond/consumer.c
src/bin/lttng-sessiond/main.c
src/bin/lttng-sessiond/rotate.c
src/bin/lttng-sessiond/rotation-thread.c
src/bin/lttng-sessiond/session.h
src/bin/lttng/Makefile.am
src/bin/lttng/command.h
src/bin/lttng/commands/rotate.c [new file with mode: 0644]
src/bin/lttng/lttng.c
src/common/error.c
src/common/mi-lttng-3.0.xsd
src/common/mi-lttng.c
src/common/mi-lttng.h
src/common/sessiond-comm/sessiond-comm.h
src/lib/lttng-ctl/Makefile.am
src/lib/lttng-ctl/lttng-ctl.c
src/lib/lttng-ctl/rotate.c [new file with mode: 0644]

index c07bd57b2a88ac50aa0c58e8201d25a876edf54f..57f9de05bd5089b6be7d646d43ec87eae2fc6ad9 100644 (file)
@@ -155,6 +155,7 @@ enum lttng_error_code {
        LTTNG_ERR_ROTATION_SIZE_IS_SET     = 132, /* Rotate size already setup for this session. */
        LTTNG_ERR_ROTATION_MULTIPLE_AFTER_STOP     = 133, /* Already rotated once after a stop. */
        LTTNG_ERR_ROTATION_WRONG_VERSION   = 134, /* Rotate not supported by this kernel tracer version */
+       LTTNG_ERR_NO_SESSION_OUTPUT        = 135, /* Session has no output configured. */
 
        /* MUST be last element */
        LTTNG_ERR_NR,                           /* Last element */
index 908422e190b1c0a79d00220d3eef6459a4e1afe2..265148376fa744e493edcd0bd1a57c235957a089 100644 (file)
 
 #include <limits.h>
 #include <stdint.h>
+#include <stdbool.h>
 
 #include <lttng/constant.h>
 #include <lttng/rotation.h>
 #include <common/macros.h>
 
+/*
+ * Object used as input parameter to the rotate session API for immediate
+ * rotations.
+ * This is opaque to the public library.
+ */
+struct lttng_rotation_immediate_attr {
+       /* Session name to rotate. */
+       char session_name[LTTNG_NAME_MAX];
+       /* For the rotate pending request. */
+       uint64_t rotate_id;
+};
+
+/*
+ * Object returned by the rotate session API.
+ * This is opaque to the public library.
+ */
+struct lttng_rotation_handle {
+       char session_name[LTTNG_NAME_MAX];
+       /*
+        * ID of the rotate command.
+        * This matches the session->rotate_count, so the handle is valid until
+        * the next rotate command. After that, the rotation_get_state command
+        * returns the "expired" state.
+        */
+       uint64_t rotation_id;
+       /*
+        * Where the rotated (readable) trace has been stored when the
+        * rotation is completed.
+        */
+       struct {
+               bool is_set;
+               char path[LTTNG_PATH_MAX];
+       } archive_location;
+};
+
 /*
  * Internal objects between lttng-ctl and the session daemon, the values
- * are then copied to the user's lttng_rotate_session_handle object.
+ * are then copied to the user's lttng_rotation_handle object.
  */
+
 /* For the LTTNG_ROTATE_SESSION command. */
 struct lttng_rotate_session_return {
-       uint64_t rotate_id;
-       /* Represents values defined in enum lttng_rotation_status. */
+       uint64_t rotation_id;
+} LTTNG_PACKED;
+
+/* For the LTTNG_ROTATION_GET_INFO command. */
+struct lttng_rotation_get_info_return {
+       /* Represents values defined in enum lttng_rotation_state. */
        int32_t status;
+       char path[LTTNG_PATH_MAX];
+} LTTNG_PACKED;
+
+/* For the LTTNG_SESSION_GET_CURRENT_OUTPUT command. */
+struct lttng_session_get_current_output_return {
+       char path[LTTNG_PATH_MAX];
 } LTTNG_PACKED;
 
 #endif /* LTTNG_ROTATE_INTERNAL_ABI_H */
index 47ca2571591d2a3d787d3447887d2748a3e782ec..05216fc37629b7f29f7de657e2263112b0a572ab 100644 (file)
@@ -1,5 +1,6 @@
 /*
  * Copyright (C) 2017 - Julien Desfossez <jdesfossez@efficios.com>
+ * Copyright (C) 2018 - 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,
@@ -25,32 +26,130 @@ extern "C" {
 #endif
 
 /*
- * Return codes for lttng_rotate_session_get_output_path.
+ * Return codes for lttng_rotation_handle_get_state()
  */
-enum lttng_rotation_status {
-       /*
-        * After starting a rotation.
-        */
-       LTTNG_ROTATION_STATUS_STARTED = 0,
+enum lttng_rotation_state {
        /*
-        * When the rotation is complete.
+        * Rotation is ongoing, but has not been completed yet.
         */
-       LTTNG_ROTATION_STATUS_COMPLETED = 1,
+       LTTNG_ROTATION_STATE_ONGOING = 0,
        /*
-        * If the handle does not match the last rotate command, we cannot
-        * retrieve the path for the chunk.
+        * Rotation has been completed and the resulting chunk
+        * can now safely be read.
         */
-       LTTNG_ROTATION_STATUS_EXPIRED = 2,
+       LTTNG_ROTATION_STATE_COMPLETED = 1,
        /*
-        * On error.
+        * The rotation has expired.
+        *
+        * The information associated with a given rotation is eventually
+        * purged by the session daemon. In such a case, the attributes of
+        * the rotation, such as its path, may no longer be available.
+        *
+        * Note that this state does not guarantee the the rotation was
+        * completed successfully.
         */
-       LTTNG_ROTATION_STATUS_ERROR = 3,
+       LTTNG_ROTATION_STATE_EXPIRED = 2,
        /*
-        * If no rotation occured during this session.
+        * The rotation could not be completed due to an error.
         */
-       LTTNG_ROTATION_STATUS_NO_ROTATION = 4,
+       LTTNG_ROTATION_STATE_ERROR = 3,
+};
+
+enum lttng_rotation_status {
+       LTTNG_ROTATION_STATUS_OK = 0,
+       /* Information not available. */
+       LTTNG_ROTATION_STATUS_UNAVAILABLE = 1,
+       /* Generic error. */
+       LTTNG_ROTATION_STATUS_ERROR = -1,
+       /* Invalid parameters provided. */
+       LTTNG_ROTATION_STATUS_INVALID = -2,
 };
 
+/*
+ * Input parameter to the lttng_rotate_session command.
+ *
+ * An immediate rotation is performed as soon as possible by the tracers.
+ *
+ * The lttng_rotation_immediate_attr object is opaque to the user. Use the
+ * helper functions below to access it.
+ */
+struct lttng_rotation_immediate_attr;
+
+/*
+ * Handle used to represent a specific rotation.
+ *
+ * This object is opaque to the user. Use the helper functions below to access
+ * it.
+ */
+struct lttng_rotation_handle;
+
+/*
+ * Return a newly allocated immediate session rotation descriptor object or NULL
+ * on error.
+ */
+extern struct lttng_rotation_immediate_attr *
+lttng_rotation_immediate_attr_create(void);
+
+/*
+ * Destroy a given immediate session rotation descriptor object.
+ */
+extern void lttng_rotation_immediate_attr_destroy(
+               struct lttng_rotation_immediate_attr *attr);
+
+/*
+ * Set the name of the session to rotate immediately.
+ *
+ * The session_name parameter is copied to the immediate session rotation
+ * attributes.
+ */
+extern enum lttng_rotation_status lttng_rotation_immediate_attr_set_session_name(
+               struct lttng_rotation_immediate_attr *attr,
+               const char *session_name);
+
+/*
+ * Get the current state of the rotation referenced by the handle.
+ *
+ * This will issue a request to the session daemon on every call. Hence,
+ * the result of this call may change over time.
+ */
+extern enum lttng_rotation_status lttng_rotation_handle_get_state(
+               struct lttng_rotation_handle *rotation_handle,
+               enum lttng_rotation_state *rotation_state);
+
+/*
+ * Get the location of the rotation's resulting archive.
+ *
+ * The rotation must be completed in order for this call to succeed.
+ * The path returned is owned by the rotation handle.
+ *
+ * Note that path will not be set in case of error, or if the session
+ * rotation has expired.
+ *
+ * FIXME: Return an lttng_location object instead of a path.
+ */
+extern enum lttng_rotation_status lttng_rotation_handle_get_completed_archive_location(
+               struct lttng_rotation_handle *rotation_handle,
+               const char **path);
+
+/*
+ * Destroy an lttng_rotate_session handle.
+ */
+extern void lttng_rotation_handle_destroy(
+               struct lttng_rotation_handle *rotation_handle);
+
+/*
+ * Rotate the output folder of the session
+ *
+ * On success, handle is allocated and can be used to monitor the progress
+ * of the rotation with lttng_rotation_get_state(). The handle must be freed
+ * by the caller with lttng_rotation_handle_destroy().
+ *
+ * Return 0 if the rotate action was successfully launched or a negative
+ * LTTng error code on error.
+ */
+extern int lttng_rotate_session(struct lttng_rotation_immediate_attr *attr,
+               struct lttng_rotation_handle **rotation_handle);
+
 #ifdef __cplusplus
 }
 #endif
index 599892d13508d7470f829f6c89da84b18aea6b9c..7211eeec1ca11b7a3e4062148c00a9f7a46b92ad 100644 (file)
@@ -162,6 +162,23 @@ extern int lttng_untrack_pid(struct lttng_handle *handle, int pid);
 extern int lttng_list_tracker_pids(struct lttng_handle *handle,
                int *enabled, int32_t **pids, size_t *nr_pids);
 
+/*
+ * Ask the session daemon where the data for this session is currently being
+ * written to. If rotations occured during a session, this call is useful to
+ * know the location of the last chunk.
+ *
+ * Return 0 and allocate chunk_path if rotations occured for this session, the
+ * caller needs to free chunk_path.
+ * Return 1 if no rotation occured during the session, chunk_path is left
+ * unallocated.
+ *
+ * Return a negative LTTng error code on error (readable with lttng_strerror).
+ *
+ * FIXME: Return an lttng_location object rather than a path.
+ */
+extern int lttng_session_get_current_archive_location(const char *session_name,
+               char **chunk_path);
+
 #ifdef __cplusplus
 }
 #endif
index a2af4c38aa40a9a040ecb5e911408367d9ef2213..5377ad8ee7ea44fced57db158ae85d9d8ddec044 100644 (file)
@@ -4367,13 +4367,13 @@ int cmd_rotate_session(struct ltt_session *session,
 
        if (!session->has_been_started) {
                ret = -LTTNG_ERR_START_SESSION_ONCE;
-               goto error;
+               goto end;
        }
 
        if (session->live_timer || session->snapshot_mode ||
                        !session->output_traces) {
                ret = -LTTNG_ERR_ROTATION_NOT_AVAILABLE;
-               goto error;
+               goto end;
        }
 
        /*
@@ -4383,13 +4383,13 @@ int cmd_rotate_session(struct ltt_session *session,
                        (session->consumer->relay_major_version == 2 &&
                        session->consumer->relay_minor_version < 11)) {
                ret = -LTTNG_ERR_ROTATION_NOT_AVAILABLE;
-               goto error;
+               goto end;
        }
 
        if (session->rotate_pending || session->rotate_pending_relay) {
                ret = -LTTNG_ERR_ROTATION_PENDING;
                DBG("Rotate already in progress");
-               goto error;
+               goto end;
        }
 
        /*
@@ -4400,7 +4400,7 @@ int cmd_rotate_session(struct ltt_session *session,
                DBG("Session \"%s\" was already rotated after stop, refusing rotation",
                                session->name);
                ret = -LTTNG_ERR_ROTATION_MULTIPLE_AFTER_STOP;
-               goto error;
+               goto end;
        }
 
        /* Special case for the first rotation. */
@@ -4422,7 +4422,7 @@ int cmd_rotate_session(struct ltt_session *session,
                if (ret) {
                        ERR("Failed to copy session base path to current rotation chunk path");
                        ret = -LTTNG_ERR_UNK;
-                       goto error;
+                       goto end;
                }
        } else {
                /*
@@ -4435,14 +4435,14 @@ int cmd_rotate_session(struct ltt_session *session,
                if (ret) {
                        ERR("Failed to copy the active tracing path to the current rotate path");
                        ret = -LTTNG_ERR_UNK;
-                       goto error;
+                       goto end;
                }
        }
        DBG("Current rotate path %s", session->rotation_chunk.current_rotate_path);
 
        session->rotate_count++;
        session->rotate_pending = true;
-       session->rotation_status = LTTNG_ROTATION_STATUS_STARTED;
+       session->rotation_state = LTTNG_ROTATION_STATE_ONGOING;
 
        /*
         * Create the path name for the next chunk.
@@ -4450,7 +4450,7 @@ int cmd_rotate_session(struct ltt_session *session,
        now = time(NULL);
        if (now == (time_t) -1) {
                ret = -LTTNG_ERR_ROTATION_NOT_AVAILABLE;
-               goto error;
+               goto end;
        }
        session->last_chunk_start_ts = session->current_chunk_start_ts;
        session->current_chunk_start_ts = now;
@@ -4459,14 +4459,14 @@ int cmd_rotate_session(struct ltt_session *session,
        if (!timeinfo) {
                PERROR("Failed to sample local time in rotate session command");
                ret = -LTTNG_ERR_UNK;
-               goto error;
+               goto end;
        }
        strf_ret = strftime(datetime, sizeof(datetime), "%Y%m%d-%H%M%S",
                        timeinfo);
        if (!strf_ret) {
                ERR("Failed to format local time timestamp in rotate session command");
                ret = -LTTNG_ERR_UNK;
-               goto error;
+               goto end;
        }
        if (session->kernel_session) {
                /*
@@ -4481,7 +4481,7 @@ int cmd_rotate_session(struct ltt_session *session,
                if (ret < 0 || ret == sizeof(session->rotation_chunk.active_tracing_path)) {
                        ERR("Failed to format active kernel tracing path in rotate session command");
                        ret = -LTTNG_ERR_UNK;
-                       goto error;
+                       goto end;
                }
                /*
                 * The sub-directory for the consumer
@@ -4494,7 +4494,7 @@ int cmd_rotate_session(struct ltt_session *session,
                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_ERR_UNK;
-                       goto error;
+                       goto end;
                }
                /*
                 * Create the new chunk folder, before the rotation begins so we don't
@@ -4505,12 +4505,14 @@ int cmd_rotate_session(struct ltt_session *session,
                                session->kernel_session->gid);
                if (ret) {
                        ERR("Failed to create kernel session tracing path at %s",
-                                       session->kernel_session->chunk_path);
-                       goto error;
+                                       session->kernel_session->consumer->chunk_path);
+                       ret = -LTTNG_ERR_CREATE_DIR_FAIL;
+                       goto end;
                }
                ret = kernel_rotate_session(session);
                if (ret != LTTNG_OK) {
-                       goto error;
+                       ret = -ret;
+                       goto end;
                }
        }
        if (session->ust_session) {
@@ -4521,7 +4523,7 @@ int cmd_rotate_session(struct ltt_session *session,
                if (ret < 0) {
                        ERR("Failed to format active UST tracing path in rotate session command");
                        ret = -LTTNG_ERR_UNK;
-                       goto error;
+                       goto end;
                }
                ret = snprintf(session->ust_session->consumer->chunk_path,
                                PATH_MAX, "/%s-%" PRIu64, datetime,
@@ -4529,7 +4531,7 @@ int cmd_rotate_session(struct ltt_session *session,
                if (ret < 0) {
                        ERR("Failed to format the UST consumer's sub-directory in rotate session command");
                        ret = -LTTNG_ERR_UNK;
-                       goto error;
+                       goto end;
                }
                /*
                 * Create the new chunk folder, before the rotation begins so we don't
@@ -4540,7 +4542,8 @@ int cmd_rotate_session(struct ltt_session *session,
                                session->ust_session->gid);
                ret = ust_app_rotate_session(session, &ust_active);
                if (ret != LTTNG_OK) {
-                       goto error;
+                       ret = -LTTNG_ERR_CREATE_DIR_FAIL;
+                       goto end;
                }
                /*
                 * Handle the case where we did not start a rotation on any channel.
@@ -4555,7 +4558,7 @@ int cmd_rotate_session(struct ltt_session *session,
                                goto end;
                        }
                        session->rotate_pending = false;
-                       session->rotation_status = LTTNG_ROTATION_STATUS_COMPLETED;
+                       session->rotation_state = LTTNG_ROTATION_STATE_COMPLETED;
                }
        }
 
@@ -4564,86 +4567,67 @@ int cmd_rotate_session(struct ltt_session *session,
        }
 
        if (rotate_return) {
-               (*rotate_return)->rotate_id = session->rotate_count;
-               (*rotate_return)->status = LTTNG_ROTATION_STATUS_STARTED;
+               rotate_return->rotation_id = session->rotate_count;
        }
 
-
        DBG("Cmd rotate session %s, rotate_id %" PRIu64 " completed", session->name,
                        session->rotate_count);
        ret = LTTNG_OK;
 
-       goto end;
-
-error:
-       if (rotate_return) {
-               (*rotate_return)->status = LTTNG_ROTATION_STATUS_ERROR;
-       }
 end:
        return ret;
 }
 
 /*
- * Command LTTNG_ROTATE_PENDING from the lttng-ctl library.
+ * Command LTTNG_ROTATION_GET_INFO from the lttng-ctl library.
  *
  * Check if the session has finished its rotation.
  *
  * Return 0 on success or else a LTTNG_ERR code.
  */
-int cmd_rotate_pending(struct ltt_session *session,
-               struct lttng_rotate_pending_return **pending_return,
-               uint64_t rotate_id)
+int cmd_rotate_get_info(struct ltt_session *session,
+               struct lttng_rotation_get_info_return *info_return,
+               uint64_t rotation_id)
 {
        int ret;
 
        assert(session);
 
-       DBG("Cmd rotate pending session %s, rotate_id %" PRIu64, session->name,
+       DBG("Cmd rotate_get_info session %s, rotation id %" PRIu64, session->name,
                        session->rotate_count);
 
-       *pending_return = zmalloc(sizeof(struct lttng_rotate_pending_return));
-       if (!*pending_return) {
-               ret = -ENOMEM;
-               goto end;
-       }
-
-       if (session->rotate_count != rotate_id) {
-               (*pending_return)->status = LTTNG_ROTATION_STATUS_EXPIRED;
+       if (session->rotate_count != rotation_id) {
+               info_return->status = (int32_t) LTTNG_ROTATION_STATE_EXPIRED;
                ret = LTTNG_OK;
                goto end;
        }
 
-       if (session->rotation_status == LTTNG_ROTATION_STATUS_ERROR) {
-               DBG("An error occurred during rotation");
-               (*pending_return)->status = LTTNG_ROTATION_STATUS_ERROR;
-       /* Rotate with a relay */
-       } else if (session->rotate_pending_relay) {
-               DBG("Session %s, rotate_id %" PRIu64 " still pending",
-                               session->name, session->rotate_count);
-               (*pending_return)->status = LTTNG_ROTATION_STATUS_STARTED;
-       } else if (session->rotate_pending) {
-               DBG("Session %s, rotate_id %" PRIu64 " still pending",
-                               session->name, session->rotate_count);
-               (*pending_return)->status = LTTNG_ROTATION_STATUS_STARTED;
-       } else {
-               DBG("Session %s, rotate_id %" PRIu64 " finished",
-                               session->name, session->rotate_count);
-               (*pending_return)->status = LTTNG_ROTATION_STATUS_COMPLETED;
-               ret = lttng_strncpy((*pending_return)->output_path,
+       switch (session->rotation_state) {
+       case LTTNG_ROTATION_STATE_ONGOING:
+               DBG("Reporting that rotation id %" PRIu64 " of session %s is still pending",
+                               rotation_id, session->name);
+               break;
+       case LTTNG_ROTATION_STATE_COMPLETED:
+               ret = lttng_strncpy(info_return->path,
                                session->rotation_chunk.current_rotate_path,
-                               sizeof((*pending_return)->output_path));
+                               sizeof(info_return->path));
                if (ret) {
-                       ERR("Failed to copy active tracing path to rotate pending command reply");
-                       (*pending_return)->status = LTTNG_ROTATION_STATUS_ERROR;
-                       ret = -1;
+                       ERR("Failed to copy active tracing path to rotate_get_info reply");
+                       info_return->status = LTTNG_ROTATION_STATUS_ERROR;
+                       ret = -LTTNG_ERR_UNK;
                        goto end;
                }
+               break;
+       case LTTNG_ROTATION_STATE_ERROR:
+               DBG("Reporting that an error occurred during rotation %" PRIu64 " of session %s",
+                               rotation_id, session->name);
+               break;
+       default:
+               abort();
        }
 
+       info_return->status = (int32_t) session->rotation_state;
        ret = LTTNG_OK;
-
-       goto end;
-
 end:
        return ret;
 }
@@ -4656,33 +4640,46 @@ end:
  *
  * Return LTTNG_OK on success or else a LTTNG_ERR code.
  */
-int cmd_rotate_get_current_path(struct ltt_session *session,
-               struct lttng_rotate_get_current_path **get_return)
+int cmd_session_get_current_output(struct ltt_session *session,
+               struct lttng_session_get_current_output_return *output_return)
 {
        int ret;
+       const char *path;
 
-       *get_return = zmalloc(sizeof(struct lttng_rotate_get_current_path));
-       if (!*get_return) {
-               ret = -ENOMEM;
-               goto end;
+       if (!session->snapshot_mode) {
+               if (session->rotate_count == 0) {
+                       if (session->kernel_session) {
+                               path = session_get_base_path(session);
+                       } else if (session->ust_session) {
+                               path = session_get_base_path(session);
+                       } else {
+                               abort();
+                       }
+                       assert(path);
+               } else {
+                       path = session->rotation_chunk.active_tracing_path;
+               }
+       } else {
+               /*
+                * A snapshot session does not have a "current" trace archive
+                * location.
+                */
+               path = "";
        }
 
-       if (session->rotate_count == 0) {
-               (*get_return)->status = LTTNG_ROTATION_STATUS_NO_ROTATION;
-       } else {
-               (*get_return)->status = session->rotation_status;
-               ret = lttng_strncpy((*get_return)->output_path,
-                               session->rotation_chunk.current_rotate_path,
-                               sizeof((*get_return)->output_path));
-               if (ret) {
-                       ERR("Failed to copy trace output path to rotate get current path command reply");
-                       ret = -1;
-                       goto end;
-               }
+       DBG("Cmd get current output for session %s, returning %s",
+                       session->name, path);
+
+       ret = lttng_strncpy(output_return->path,
+                       path,
+                       sizeof(output_return->path));
+       if (ret) {
+               ERR("Failed to copy trace output path to session get current output command reply");
+               ret = -LTTNG_ERR_UNK;
+               goto end;
        }
 
        ret = LTTNG_OK;
-
 end:
        return ret;
 }
index 685c2f3b023adad37379446152de807d86d21782..49e9992ccc8f09cb4b05e5514a9f341310e5910e 100644 (file)
@@ -120,5 +120,10 @@ int cmd_unregister_trigger(struct command_ctx *cmd_ctx, int sock,
 
 int cmd_rotate_session(struct ltt_session *session,
                struct lttng_rotate_session_return *rotate_return);
+int cmd_rotate_get_info(struct ltt_session *session,
+               struct lttng_rotation_get_info_return *info_return,
+               uint64_t rotate_id);
+int cmd_session_get_current_output(struct ltt_session *session,
+               struct lttng_session_get_current_output_return *output_return);
 
 #endif /* CMD_H */
index f89bb1df290fbc8d5f6682e1f1089448974ca40e..5906cdca5901358fd339cf24f6de366eb99d7369 100644 (file)
@@ -1752,7 +1752,7 @@ int consumer_rotate_pending_relay(struct consumer_socket *socket,
 
        assert(socket);
 
-       DBG("Consumer rotate pending on relay for session %" PRIu64 ", chunk id % " PRIu64,
+       DBG("Consumer rotate pending on relay for session %" PRIu64 ", chunk id %" PRIu64,
                        session_id, chunk_id);
        assert(output->type == CONSUMER_DST_NET);
 
index 1d9ca91c5fc3b751d061fbcb3f543fcd52626f6b..226433ead4057a3b1751de9d60e8c6e7aa3f0e09 100644 (file)
@@ -2964,8 +2964,8 @@ static int process_client_msg(struct command_ctx *cmd_ctx, int sock,
        case LTTNG_REGISTER_TRIGGER:
        case LTTNG_UNREGISTER_TRIGGER:
        case LTTNG_ROTATE_SESSION:
-       case LTTNG_ROTATE_PENDING:
-       case LTTNG_ROTATE_GET_CURRENT_PATH:
+       case LTTNG_ROTATION_GET_INFO:
+       case LTTNG_SESSION_GET_CURRENT_OUTPUT:
                need_domain = 0;
                break;
        default:
@@ -3009,7 +3009,7 @@ static int process_client_msg(struct command_ctx *cmd_ctx, int sock,
        case LTTNG_LIST_TRACKER_PIDS:
        case LTTNG_DATA_PENDING:
        case LTTNG_ROTATE_SESSION:
-       case LTTNG_ROTATE_PENDING:
+       case LTTNG_ROTATION_GET_INFO:
                break;
        default:
                /* Setup lttng message with no payload */
@@ -4104,6 +4104,7 @@ error_add_context:
 
                DBG("Client rotate session \"%s\"", cmd_ctx->session->name);
 
+               memset(&rotate_return, 0, sizeof(rotate_return));
                if (cmd_ctx->session->kernel_session && !check_rotate_compatible()) {
                        DBG("Kernel tracer version is not compatible with the rotation feature");
                        ret = LTTNG_ERR_ROTATION_WRONG_VERSION;
@@ -4126,20 +4127,20 @@ error_add_context:
                ret = LTTNG_OK;
                break;
        }
-       case LTTNG_ROTATE_PENDING:
+       case LTTNG_ROTATION_GET_INFO:
        {
-               struct lttng_rotate_pending_return *pending_return = NULL;
+               struct lttng_rotation_get_info_return get_info_return;
 
-               ret = cmd_rotate_pending(cmd_ctx->session, &pending_return,
-                               cmd_ctx->lsm->u.rotate_pending.rotate_id);
+               memset(&get_info_return, 0, sizeof(get_info_return));
+               ret = cmd_rotate_get_info(cmd_ctx->session, &get_info_return,
+                               cmd_ctx->lsm->u.get_rotation_info.rotation_id);
                if (ret < 0) {
                        ret = -ret;
                        goto error;
                }
 
-               ret = setup_lttng_msg_no_cmd_header(cmd_ctx, pending_return,
-                               sizeof(struct lttng_rotate_session_handle));
-               free(pending_return);
+               ret = setup_lttng_msg_no_cmd_header(cmd_ctx, &get_info_return,
+                               sizeof(get_info_return));
                if (ret < 0) {
                        ret = -ret;
                        goto error;
@@ -4148,19 +4149,20 @@ error_add_context:
                ret = LTTNG_OK;
                break;
        }
-       case LTTNG_ROTATE_GET_CURRENT_PATH:
+       case LTTNG_SESSION_GET_CURRENT_OUTPUT:
        {
-               struct lttng_rotate_get_current_path *get_return = NULL;
+               struct lttng_session_get_current_output_return output_return;
 
-               ret = cmd_rotate_get_current_path(cmd_ctx->session, &get_return);
+               memset(&output_return, 0, sizeof(output_return));
+               ret = cmd_session_get_current_output(cmd_ctx->session,
+                               &output_return);
                if (ret < 0) {
                        ret = -ret;
                        goto error;
                }
 
-               ret = setup_lttng_msg_no_cmd_header(cmd_ctx, get_return,
-                               sizeof(struct lttng_rotate_get_current_path));
-               free(get_return);
+               ret = setup_lttng_msg_no_cmd_header(cmd_ctx, &output_return,
+                               sizeof(output_return));
                if (ret < 0) {
                        ret = -ret;
                        goto error;
index 3ca80ce6a8a16ad970b6a9c99ddf2a3543201b2d..237723d3da8c7bc3e4f8963fcf73e829310bdd72 100644 (file)
@@ -348,7 +348,7 @@ int rename_complete_chunk(struct ltt_session *session, time_t ts)
        goto end;
 
 error:
-       session->rotation_status = LTTNG_ROTATION_STATUS_ERROR;
+       session->rotation_state = LTTNG_ROTATION_STATE_ERROR;
 end:
        return ret;
 }
index 21f20b40341023d78aa6533971bd77aa97e6c375..9e599e48999c90808f4861414c13f49286861925 100644 (file)
@@ -356,7 +356,7 @@ int handle_channel_rotation_pipe(int fd, uint32_t revents,
                time_t now = time(NULL);
 
                if (now == (time_t) -1) {
-                       session->rotation_status = LTTNG_ROTATION_STATUS_ERROR;
+                       session->rotation_state = LTTNG_ROTATION_STATE_ERROR;
                        ret = LTTNG_ERR_UNK;
                        goto end_unlock_session;
                }
@@ -367,7 +367,7 @@ int handle_channel_rotation_pipe(int fd, uint32_t revents,
                        goto end_unlock_session;
                }
                session->rotate_pending = false;
-               session->rotation_status = LTTNG_ROTATION_STATUS_COMPLETED;
+               session->rotation_state = LTTNG_ROTATION_STATE_COMPLETED;
                session->last_chunk_start_ts = session->current_chunk_start_ts;
                if (session->rotate_pending_relay) {
                        ret = sessiond_timer_rotate_pending_start(
index 2e22885e801c092d23feee3825d2ac222a4befab..3c9bc182489cdcb8537e7c5d9af31fe6c59d4233 100644 (file)
@@ -132,8 +132,8 @@ struct ltt_session {
         * True until the relay has finished the rotation of all the streams.
         */
        bool rotate_pending_relay;
-       /* Current status of a rotation. */
-       enum lttng_rotation_status rotation_status;
+       /* Current state of a rotation. */
+       enum lttng_rotation_state rotation_state;
        /*
         * Number of channels waiting for a rotation.
         * When this number reaches 0, we can handle the rename of the chunk
index 1a6977eb5fb38e4b6aebd40ba60f4575e79d7935..b56ba2be83d5a2551667390f8db9c2fbb82d132c 100644 (file)
@@ -23,6 +23,7 @@ lttng_SOURCES = command.h conf.c conf.h commands/start.c \
                                commands/metadata.c \
                                commands/regenerate.c \
                                commands/help.c \
+                               commands/rotate.c \
                                utils.c utils.h lttng.c
 
 lttng_LDADD = $(top_builddir)/src/lib/lttng-ctl/liblttng-ctl.la \
index bda6ef937d3b4c4ce0498fce49b771e52ddec45c..32d54d22446613d27da68383ee99694271475a8d 100644 (file)
@@ -83,6 +83,7 @@ DECL_COMMAND(track);
 DECL_COMMAND(untrack);
 DECL_COMMAND(metadata);
 DECL_COMMAND(regenerate);
+DECL_COMMAND(rotate);
 
 extern int cmd_help(int argc, const char **argv,
                const struct cmd_struct commands[]);
diff --git a/src/bin/lttng/commands/rotate.c b/src/bin/lttng/commands/rotate.c
new file mode 100644 (file)
index 0000000..f8cba79
--- /dev/null
@@ -0,0 +1,337 @@
+/*
+ * Copyright (C) 2017 - Julien Desfossez <jdesfossez@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,
+ * as published by the Free Software Foundation.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#define _LGPL_SOURCE
+#include <popt.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <inttypes.h>
+#include <ctype.h>
+#include <assert.h>
+
+#include <common/sessiond-comm/sessiond-comm.h>
+#include <common/mi-lttng.h>
+
+#include "../command.h"
+#include <lttng/rotation.h>
+
+static char *opt_session_name;
+static int opt_no_wait;
+static struct mi_writer *writer;
+
+enum {
+       OPT_HELP = 1,
+       OPT_LIST_OPTIONS,
+};
+
+static struct poptOption long_options[] = {
+       /* longName, shortName, argInfo, argPtr, value, descrip, argDesc */
+       {"help",      'h', POPT_ARG_NONE, 0, OPT_HELP, 0, 0},
+       {"list-options", 0, POPT_ARG_NONE, NULL, OPT_LIST_OPTIONS, NULL, NULL},
+       {"no-wait",   'n', POPT_ARG_VAL, &opt_no_wait, 1, 0, 0},
+       {0, 0, 0, 0, 0, 0, 0}
+};
+
+static int mi_output_rotate(const char *status, const char *path,
+               const char *session_name)
+{
+       int ret;
+
+       if (!lttng_opt_mi) {
+               ret = 0;
+               goto end;
+       }
+
+       ret = mi_lttng_writer_open_element(writer,
+                       mi_lttng_element_rotation);
+       if (ret) {
+               goto end;
+       }
+
+       ret = mi_lttng_writer_write_element_string(writer,
+                       mi_lttng_element_session_name, session_name);
+       if (ret) {
+               goto end;
+       }
+
+       ret = mi_lttng_writer_write_element_string(writer,
+                       mi_lttng_element_rotate_status, status);
+       if (ret) {
+               goto end;
+       }
+       if (path) {
+               ret = mi_lttng_writer_write_element_string(writer,
+                               config_element_path, path);
+               if (ret) {
+                       goto end;
+               }
+       }
+       /* Close rotation element */
+       ret = mi_lttng_writer_close_element(writer);
+       if (ret) {
+               goto end;
+       }
+
+end:
+       return ret;
+}
+
+static int rotate_tracing(char *session_name)
+{
+       int ret;
+       struct lttng_rotation_immediate_attr *attr = NULL;
+       struct lttng_rotation_handle *handle = NULL;
+       enum lttng_rotation_status rotation_status;
+       enum lttng_rotation_state rotation_state = LTTNG_ROTATION_STATE_ONGOING;
+
+       DBG("Rotating the output files of session %s", session_name);
+
+       attr = lttng_rotation_immediate_attr_create();
+       if (!attr) {
+               goto error;
+       }
+
+       ret = lttng_rotation_immediate_attr_set_session_name(attr, session_name);
+       if (ret < 0) {
+               ERR("Session name exceeds the maximal allowed length");
+               goto error;
+       }
+
+       ret = lttng_rotate_session(attr, &handle);
+       if (ret < 0) {
+               switch (-ret) {
+               case LTTNG_ERR_SESSION_NOT_STARTED:
+                       WARN("Tracing session %s not started yet", session_name);
+                       break;
+               default:
+                       ERR("%s", lttng_strerror(ret));
+                       break;
+               }
+               goto error;
+       }
+
+       if (!opt_no_wait) {
+               _MSG("Waiting for rotation to complete");
+               ret = fflush(stdout);
+               if (ret) {
+                       PERROR("fflush");
+                       goto error;
+               }
+
+               do {
+                       rotation_status = lttng_rotation_handle_get_state(handle,
+                                       &rotation_state);
+                       if (rotation_status != LTTNG_ROTATION_STATUS_OK) {
+                               ERR("Failed to query the state of the rotation");
+                               goto error;
+                       }
+
+                       /*
+                        * Data sleep time before retrying (in usec). Don't
+                        * sleep if the call returned value indicates
+                        * availability.
+                        */
+                       if (rotation_state == LTTNG_ROTATION_STATE_ONGOING) {
+                               ret = usleep(DEFAULT_DATA_AVAILABILITY_WAIT_TIME);
+                               if (ret) {
+                                       PERROR("usleep");
+                                       goto error;
+                               }
+                               _MSG(".");
+
+                               ret = fflush(stdout);
+                               if (ret) {
+                                       PERROR("fflush");
+                                       goto error;
+                               }
+                       }
+               } while (rotation_state == LTTNG_ROTATION_STATE_ONGOING);
+               MSG("");
+       }
+
+       switch (rotation_state) {
+       case LTTNG_ROTATION_STATE_COMPLETED:
+       {
+               const char *path;
+
+               rotation_status = lttng_rotation_handle_get_completed_archive_location(
+                               handle, &path);
+               if (rotation_status != LTTNG_ROTATION_STATUS_OK) {
+                       ERR("Failed to retrieve the rotation's completed chunk archive location");
+                       goto error;
+               }
+               MSG("Trace chunk archive for session %s is now readable at %s",
+                               session_name, path);
+               ret = mi_output_rotate("completed", path, session_name);
+               if (ret) {
+                       goto error;
+               }
+               ret = CMD_SUCCESS;
+               goto end;
+       }
+       case LTTNG_ROTATION_STATE_EXPIRED:
+               MSG("Session %s rotated, but handle expired", session_name);
+               ret = mi_output_rotate("expired", NULL, session_name);
+               if (ret) {
+                       goto error;
+               }
+               ret = CMD_SUCCESS;
+               goto end;
+       default:
+               ERR("Unexpected rotation state received, aborting...");
+               goto error;
+       }
+
+error:
+       ret = CMD_ERROR;
+end:
+       lttng_rotation_handle_destroy(handle);
+       lttng_rotation_immediate_attr_destroy(attr);
+       return ret;
+}
+
+/*
+ *  cmd_rotate
+ *
+ *  The 'rotate <options>' first level command
+ */
+int cmd_rotate(int argc, const char **argv)
+{
+       int opt, ret = CMD_SUCCESS, command_ret = CMD_SUCCESS, success = 1;
+       int popt_ret;
+       static poptContext pc;
+       char *session_name = NULL;
+       bool free_session_name = false;
+
+       pc = poptGetContext(NULL, argc, argv, long_options, 0);
+       popt_ret = poptReadDefaultConfig(pc, 0);
+       if (popt_ret) {
+               ret = CMD_ERROR;
+               ERR("poptReadDefaultConfig");
+               goto end;
+       }
+
+       while ((opt = poptGetNextOpt(pc)) != -1) {
+               switch (opt) {
+               case OPT_HELP:
+                       SHOW_HELP();
+                       goto end;
+               case OPT_LIST_OPTIONS:
+                       list_cmd_options(stdout, long_options);
+                       goto end;
+               default:
+                       ret = CMD_UNDEFINED;
+                       goto end;
+               }
+       }
+
+       opt_session_name = (char*) poptGetArg(pc);
+
+       if (!opt_session_name) {
+               session_name = get_session_name();
+               if (!session_name) {
+                       goto end;
+               }
+               free_session_name = true;
+       } else {
+               session_name = opt_session_name;
+       }
+
+       /* Mi check */
+       if (lttng_opt_mi) {
+               writer = mi_lttng_writer_create(fileno(stdout), lttng_opt_mi);
+               if (!writer) {
+                       ret = -LTTNG_ERR_NOMEM;
+                       goto end;
+               }
+
+               /* Open rotate command */
+               ret = mi_lttng_writer_command_open(writer,
+                               mi_lttng_element_command_rotate);
+               if (ret) {
+                       ret = CMD_ERROR;
+                       goto end;
+               }
+
+               /* Open output element */
+               ret = mi_lttng_writer_open_element(writer,
+                               mi_lttng_element_command_output);
+               if (ret) {
+                       goto end;
+               }
+
+               /* Open rotations element */
+               ret = mi_lttng_writer_open_element(writer,
+                               mi_lttng_element_rotations);
+               if (ret) {
+                       goto end;
+               }
+
+       }
+
+       command_ret = rotate_tracing(session_name);
+       if (command_ret) {
+               success = 0;
+       }
+
+       /* Mi closing */
+       if (lttng_opt_mi) {
+               /* Close  rotations element */
+               ret = mi_lttng_writer_close_element(writer);
+               if (ret) {
+                       goto end;
+               }
+               /* Close  output element */
+               ret = mi_lttng_writer_close_element(writer);
+               if (ret) {
+                       goto end;
+               }
+               /* Success ? */
+               ret = mi_lttng_writer_write_element_bool(writer,
+                               mi_lttng_element_command_success, success);
+               if (ret) {
+                       ret = CMD_ERROR;
+                       goto end;
+               }
+
+               /* Command element close */
+               ret = mi_lttng_writer_command_close(writer);
+               if (ret) {
+                       ret = CMD_ERROR;
+                       goto end;
+               }
+       }
+
+end:
+       /* Mi clean-up */
+       if (writer && mi_lttng_writer_destroy(writer)) {
+               /* Preserve original error code */
+               ret = ret ? ret : -LTTNG_ERR_MI_IO_FAIL;
+       }
+
+       /* Overwrite ret if an error occurred with start_tracing */
+       ret = command_ret ? command_ret : ret;
+       poptFreeContext(pc);
+       if (free_session_name) {
+               free(session_name);
+       }
+       return ret;
+}
index bf2128ca35896dbbc998ecadf125e7eb4774ed6d..c0f5a05ca7cabba6f181bdd0ed75c0fe60567ac4 100644 (file)
@@ -85,6 +85,7 @@ static struct cmd_struct commands[] =  {
        { "load", cmd_load},
        { "metadata", cmd_metadata},
        { "regenerate", cmd_regenerate},
+       { "rotate", cmd_rotate},
        { "save", cmd_save},
        { "set-session", cmd_set_session},
        { "snapshot", cmd_snapshot},
index c859eeca5ebe13dffa630ee117db7ee8ab3d78cf..1e161c9bd70ad30830ac74b37bb468aaeb1df13f 100644 (file)
@@ -196,6 +196,7 @@ static const char *error_string_array[] = {
        [ ERROR_INDEX(LTTNG_ERR_ROTATION_SIZE_IS_SET) ] = "Automatic rotation schedule with a size threshold condition already set for this session",
        [ ERROR_INDEX(LTTNG_ERR_ROTATION_MULTIPLE_AFTER_STOP) ] = "Session was already rotated once since it became inactive",
        [ ERROR_INDEX(LTTNG_ERR_ROTATION_WRONG_VERSION) ] = "Rotation feature is not supported by this kernel tracer version",
+       [ ERROR_INDEX(LTTNG_ERR_NO_SESSION_OUTPUT) ] = "Session has no output",
 
        /* Last element */
        [ ERROR_INDEX(LTTNG_ERR_NR) ] = "Unknown error code"
index ae00ee80eec146d6a3891d425aa7050165998994..f800758aa0d922e34d13c77ce5f1859570911cb9 100644 (file)
@@ -580,6 +580,7 @@ THE SOFTWARE.
                        <xs:element name="targets" type="tns:targets_type" minOccurs="0" />
                        <xs:element name="metadata_action" type="tns:metadata_cmd_type" minOccurs="0" />
                        <xs:element name="regenerate_action" type="tns:regenerate_cmd_type" minOccurs="0" />
+                       <xs:element name="rotations" type="tns:rotations_type" minOccurs="0" />
                </xs:choice>
        </xs:complexType>
 
@@ -606,6 +607,7 @@ THE SOFTWARE.
                        <xs:enumeration value="untrack" />
                        <xs:enumeration value="metadata" />
                        <xs:enumeration value="regenerate" />
+                       <xs:enumeration value="rotate" />
                </xs:restriction>
        </xs:simpleType>
 
index f0244d9fdd46d012dee437f335b495a6a8b188cf..21cf78693b8ac44b2934c2876731bb7a7cdbffd7 100644 (file)
@@ -74,6 +74,7 @@ const char * const mi_lttng_element_command_success = "success";
 const char * const mi_lttng_element_command_track = "track";
 const char * const mi_lttng_element_command_untrack = "untrack";
 const char * const mi_lttng_element_command_version = "version";
+const char * const mi_lttng_element_command_rotate = "rotate";
 
 /* Strings related to version command */
 const char * const mi_lttng_element_version = "version";
@@ -179,6 +180,13 @@ const char * const mi_lttng_element_snapshots = "snapshots";
 /* String related to track/untrack command */
 const char * const mi_lttng_element_track_untrack_all_wildcard = "*";
 
+LTTNG_HIDDEN const char * const mi_lttng_element_session_name = "session_name";
+
+/* String related to rotate command */
+LTTNG_HIDDEN const char * const mi_lttng_element_rotation = "rotation";
+LTTNG_HIDDEN const char * const mi_lttng_element_rotations = "rotations";
+LTTNG_HIDDEN const char * const mi_lttng_element_rotate_status = "status";
+
 /* Deprecated symbols preserved for ABI compatibility. */
 const char * const mi_lttng_context_type_perf_counter;
 const char * const mi_lttng_context_type_perf_cpu_counter;
index e7cf8af92ff37b840e01ebbcddbfc60c484510ac..b74d30086e07b4e84076f25939b50f35aaf0c05e 100644 (file)
@@ -80,6 +80,7 @@ extern const char * const mi_lttng_element_command_success;
 extern const char * const mi_lttng_element_command_track;
 extern const char * const mi_lttng_element_command_untrack;
 extern const char * const mi_lttng_element_command_version;
+extern const char * const mi_lttng_element_command_rotate;
 
 /* Strings related to version command */
 extern const char * const mi_lttng_element_version;
@@ -185,6 +186,13 @@ extern const char * const mi_lttng_element_snapshots;
 /* String related to track/untrack command */
 const char * const mi_lttng_element_track_untrack_all_wildcard;
 
+LTTNG_HIDDEN const char * const mi_lttng_element_session_name;
+
+/* String related to rotate command */
+LTTNG_HIDDEN const char * const mi_lttng_element_rotation;
+LTTNG_HIDDEN const char * const mi_lttng_element_rotations;
+LTTNG_HIDDEN const char * const mi_lttng_element_rotate_status;
+
 /* Utility string function  */
 const char *mi_lttng_loglevel_string(int value, enum lttng_domain_type domain);
 const char *mi_lttng_logleveltype_string(enum lttng_loglevel_type value);
index 4eed95dec50779bb860a2143cca1a3af09445068..5b7cc089ec4d9ec5ccf857bc8f67fd5fab2b7698 100644 (file)
@@ -102,7 +102,8 @@ enum lttcomm_sessiond_command {
        LTTNG_REGISTER_TRIGGER              = 43,
        LTTNG_UNREGISTER_TRIGGER            = 44,
        LTTNG_ROTATE_SESSION                = 45,
-       LTTNG_ROTATE_PENDING                = 46,
+       LTTNG_ROTATION_GET_INFO             = 46,
+       LTTNG_SESSION_GET_CURRENT_OUTPUT    = 48,
 };
 
 enum lttcomm_relayd_command {
@@ -333,8 +334,8 @@ struct lttcomm_session_msg {
                        uint32_t length;
                } LTTNG_PACKED trigger;
                struct {
-                       uint64_t rotate_id;
-               } LTTNG_PACKED rotate_pending;
+                       uint64_t rotation_id;
+               } LTTNG_PACKED get_rotation_info;
        } u;
 } LTTNG_PACKED;
 
index 03c073c9d74261dc5d363e8a562737cc8c82d04f..bc340d20fcbb14b6872f3724eba736c118d3dd9e 100644 (file)
@@ -6,7 +6,7 @@ lib_LTLIBRARIES = liblttng-ctl.la
 
 liblttng_ctl_la_SOURCES = lttng-ctl.c snapshot.c lttng-ctl-helper.h \
                lttng-ctl-health.c save.c load.c deprecated-symbols.c \
-               channel.c
+               channel.c rotate.c
 
 liblttng_ctl_la_LDFLAGS = \
                $(LT_NO_UNDEFINED)
index 3db9b89b440d12796ce7565423cac04d2f7db2ad..0468b6746f51cdf20e33821cc6cb3d3de9acda9d 100644 (file)
@@ -2756,6 +2756,50 @@ end:
        return ret;
 }
 
+int lttng_session_get_current_archive_location(const char *session_name,
+               char **chunk_path)
+{
+       struct lttcomm_session_msg lsm;
+       struct lttng_session_get_current_output_return *output_return = NULL;
+       int ret;
+       size_t path_len;
+
+       memset(&lsm, 0, sizeof(lsm));
+       lsm.cmd_type = LTTNG_SESSION_GET_CURRENT_OUTPUT;
+       ret = lttng_strncpy(lsm.session.name, session_name,
+                       sizeof(lsm.session.name));
+       if (ret) {
+               ret = -LTTNG_ERR_INVALID;
+               goto end;
+       }
+
+       ret = lttng_ctl_ask_sessiond(&lsm, (void **) &output_return);
+       if (ret < 0) {
+               ret = -1;
+               goto end;
+       }
+
+       path_len = lttng_strnlen(output_return->path,
+                       sizeof(output_return->path));
+       if (path_len == 0 || path_len == sizeof(output_return->path)) {
+               ret = -LTTNG_ERR_NO_SESSION_OUTPUT;
+               goto end;
+       }
+
+       *chunk_path = zmalloc(path_len + 1);
+       if (!*chunk_path) {
+               ret = -1;
+               goto end;
+       }
+       memcpy(*chunk_path, output_return->path, path_len);
+
+       ret = 0;
+
+end:
+       free(output_return);
+       return ret;
+}
+
 /*
  * lib constructor.
  */
diff --git a/src/lib/lttng-ctl/rotate.c b/src/lib/lttng-ctl/rotate.c
new file mode 100644 (file)
index 0000000..4132159
--- /dev/null
@@ -0,0 +1,253 @@
+/*
+ * Copyright (C) 2017 - Julien Desfossez <jdesfossez@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
+ */
+
+#define _LGPL_SOURCE
+#include <assert.h>
+#include <string.h>
+
+#include <lttng/lttng-error.h>
+#include <lttng/rotation.h>
+#include <lttng/rotate-internal.h>
+#include <common/sessiond-comm/sessiond-comm.h>
+#include <common/macros.h>
+
+#include "lttng-ctl-helper.h"
+
+struct lttng_rotation_immediate_attr *lttng_rotation_immediate_attr_create(void)
+{
+       return zmalloc(sizeof(struct lttng_rotation_immediate_attr));
+}
+
+void lttng_rotation_immediate_attr_destroy(
+               struct lttng_rotation_immediate_attr *attr)
+{
+       free(attr);
+}
+
+enum lttng_rotation_status lttng_rotation_immediate_attr_set_session_name(
+               struct lttng_rotation_immediate_attr *attr,
+               const char *session_name)
+{
+       enum lttng_rotation_status status = LTTNG_ROTATION_STATUS_OK;
+       int ret;
+
+       if (!attr || !session_name) {
+               status = LTTNG_ROTATION_STATUS_INVALID;
+               goto error;
+       }
+
+       ret = lttng_strncpy(attr->session_name, session_name,
+                       sizeof(attr->session_name));
+       if (ret) {
+               status = LTTNG_ROTATION_STATUS_INVALID;
+               goto error;
+       }
+
+error:
+       return status;
+}
+
+static
+enum lttng_rotation_status ask_rotation_info(
+               struct lttng_rotation_handle *rotation_handle,
+               struct lttng_rotation_get_info_return **info)
+{
+       /* lsm.get_rotation_state.rotation_id */
+       struct lttcomm_session_msg lsm;
+       enum lttng_rotation_status status = LTTNG_ROTATION_STATUS_OK;
+       int ret;
+
+       if (!rotation_handle || !info) {
+               status = LTTNG_ROTATION_STATUS_INVALID;
+               goto end;
+       }
+
+       memset(&lsm, 0, sizeof(lsm));
+       lsm.cmd_type = LTTNG_ROTATION_GET_INFO;
+       lsm.u.get_rotation_info.rotation_id = rotation_handle->rotation_id;
+
+       ret = lttng_strncpy(lsm.session.name, rotation_handle->session_name,
+                       sizeof(lsm.session.name));
+       if (ret) {
+               status = LTTNG_ROTATION_STATUS_INVALID;
+               goto end;
+       }
+
+       ret = lttng_ctl_ask_sessiond(&lsm, (void **) info);
+       if (ret < 0) {
+               status = LTTNG_ROTATION_STATUS_ERROR;
+               goto end;
+       }
+end:
+       return status;
+
+}
+
+enum lttng_rotation_status lttng_rotation_handle_get_state(
+               struct lttng_rotation_handle *rotation_handle,
+               enum lttng_rotation_state *state)
+{
+       enum lttng_rotation_status status = LTTNG_ROTATION_STATUS_OK;
+       struct lttng_rotation_get_info_return *info = NULL;
+       int ret;
+
+       if (!rotation_handle || !state) {
+               status = LTTNG_ROTATION_STATUS_INVALID;
+               goto end;
+       }
+
+       status = ask_rotation_info(rotation_handle, &info);
+       if (status != LTTNG_ROTATION_STATUS_OK) {
+               goto end;
+       }
+
+       *state = (enum lttng_rotation_state) info->status;
+       if (rotation_handle->archive_location.is_set ||
+                       *state != LTTNG_ROTATION_STATE_COMPLETED) {
+               /*
+                * The path is only provided by the sessiond once
+                * the session rotation is completed, but not expired.
+                */
+               goto end;
+       }
+
+       /*
+        * Cache the location since the rotation may expire before the user
+        * has a chance to query it.
+        */
+       ret = lttng_strncpy(rotation_handle->archive_location.path,
+                       info->path,
+                       sizeof(rotation_handle->archive_location.path));
+       if (ret) {
+               status = LTTNG_ROTATION_STATUS_ERROR;
+               goto end;
+       }
+       rotation_handle->archive_location.is_set = true;
+end:
+       free(info);
+       return status;
+}
+
+enum lttng_rotation_status lttng_rotation_handle_get_completed_archive_location(
+               struct lttng_rotation_handle *rotation_handle,
+               const char **path)
+{
+       int ret;
+       enum lttng_rotation_status status = LTTNG_ROTATION_STATUS_OK;
+       struct lttng_rotation_get_info_return *info = NULL;
+
+       if (!rotation_handle || !path) {
+               status = LTTNG_ROTATION_STATUS_INVALID;
+               goto end;
+       }
+
+       /* Use the cached location we got from a previous query. */
+       if (rotation_handle->archive_location.is_set) {
+               *path = rotation_handle->archive_location.path;
+               goto end;
+       }
+
+       status = ask_rotation_info(rotation_handle, &info);
+       if (status != LTTNG_ROTATION_STATUS_OK) {
+               goto end;
+       }
+
+       if ((enum lttng_rotation_state) info->status !=
+                       LTTNG_ROTATION_STATE_COMPLETED) {
+               status = LTTNG_ROTATION_STATUS_UNAVAILABLE;
+               goto end;
+       }
+
+       ret = lttng_strncpy(rotation_handle->archive_location.path,
+                       info->path,
+                       sizeof(rotation_handle->archive_location.path));
+       if (ret) {
+               status = LTTNG_ROTATION_STATUS_ERROR;
+               goto end;
+       }
+       rotation_handle->archive_location.is_set = true;
+end:
+       free(info);
+       return status;
+}
+
+void lttng_rotation_handle_destroy(
+               struct lttng_rotation_handle *rotation_handle)
+{
+       free(rotation_handle);
+}
+
+static
+int init_rotation_handle(struct lttng_rotation_handle *rotation_handle,
+               struct lttng_rotate_session_return *rotate_return,
+               struct lttng_rotation_immediate_attr *attr)
+{
+       int ret;
+
+       ret = lttng_strncpy(rotation_handle->session_name, attr->session_name,
+                       sizeof(rotation_handle->session_name));
+       if (ret) {
+               goto end;
+       }
+
+       rotation_handle->rotation_id = rotate_return->rotation_id;
+end:
+       return ret;
+}
+
+/*
+ * Rotate the output folder of the session.
+ *
+ * Return 0 on success else a negative LTTng error code.
+ */
+int lttng_rotate_session(struct lttng_rotation_immediate_attr *attr,
+               struct lttng_rotation_handle **rotation_handle)
+{
+       struct lttcomm_session_msg lsm;
+       struct lttng_rotate_session_return *rotate_return = NULL;
+       int ret;
+
+       if (!attr) {
+               ret = -LTTNG_ERR_INVALID;
+               goto end;
+       }
+
+       memset(&lsm, 0, sizeof(lsm));
+       lsm.cmd_type = LTTNG_ROTATE_SESSION;
+       lttng_ctl_copy_string(lsm.session.name, attr->session_name,
+                       sizeof(lsm.session.name));
+
+       ret = lttng_ctl_ask_sessiond(&lsm, (void **) &rotate_return);
+       if (ret < 0) {
+               *rotation_handle = NULL;
+               goto end;
+       }
+
+       *rotation_handle = zmalloc(sizeof(struct lttng_rotation_handle));
+       if (!*rotation_handle) {
+               ret = -LTTNG_ERR_NOMEM;
+               goto end;
+       }
+
+       init_rotation_handle(*rotation_handle, rotate_return, attr);
+
+       ret = 0;
+
+end:
+       free(rotate_return);
+       return ret;
+}
This page took 0.048651 seconds and 4 git commands to generate.