SoW-2019-0002: Dynamic Snapshot
[lttng-tools.git] / src / bin / lttng-sessiond / cmd.c
index 1dec61ea17b6ba7f74e122e37a7df99afa2e07c6..f4c7390ef784d52d9371d982e78a68dab966e358 100644 (file)
@@ -1,19 +1,9 @@
 /*
- * Copyright (C) 2012 David Goulet <dgoulet@efficios.com>
- * Copyright (C) 2016 Jérémie Galarneau <jeremie.galarneau@efficios.com>
+ * Copyright (C) 2012 David Goulet <dgoulet@efficios.com>
+ * Copyright (C) 2016 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, as
- * published by the Free Software Foundation.
+ * SPDX-License-Identifier: GPL-2.0-only
  *
- * 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 <lttng/location-internal.h>
 #include <lttng/trigger/trigger-internal.h>
 #include <lttng/condition/condition.h>
+#include <lttng/condition/condition-internal.h>
+#include <lttng/condition/event-rule.h>
+#include <lttng/condition/event-rule-internal.h>
+#include <lttng/event-rule/event-rule.h>
+#include <lttng/event-rule/event-rule-internal.h>
+#include <lttng/event-rule/uprobe-internal.h>
+#include <lttng/event-rule/tracepoint.h>
 #include <lttng/action/action.h>
 #include <lttng/channel.h>
 #include <lttng/channel-internal.h>
@@ -998,6 +995,8 @@ static enum lttng_error_code create_connect_relayd(struct lttng_uri *uri,
 
        /* Create socket for control stream. */
        if (uri->stype == LTTNG_STREAM_CONTROL) {
+               uint64_t result_flags;
+
                DBG3("Creating relayd stream socket from URI");
 
                /* Check relayd version */
@@ -1012,6 +1011,16 @@ static enum lttng_error_code create_connect_relayd(struct lttng_uri *uri,
                }
                consumer->relay_major_version = rsock->major;
                consumer->relay_minor_version = rsock->minor;
+               ret = relayd_get_configuration(rsock, 0,
+                               &result_flags);
+               if (ret < 0) {
+                       ERR("Unable to get relayd configuration");
+                       status = LTTNG_ERR_RELAYD_CONNECT_FAIL;
+                       goto close_sock;
+               }
+               if (result_flags & LTTCOMM_RELAYD_CONFIGURATION_FLAG_CLEAR_ALLOWED) {
+                       consumer->relay_allows_clear = true;
+               }
        } else if (uri->stype == LTTNG_STREAM_DATA) {
                DBG3("Creating relayd data socket from URI");
        } else {
@@ -1185,6 +1194,7 @@ int cmd_setup_relayd(struct ltt_session *session)
 
        DBG("Setting relayd for session %s", session->name);
 
+       rcu_read_lock();
        if (session->current_trace_chunk) {
                enum lttng_trace_chunk_status status = lttng_trace_chunk_get_id(
                                session->current_trace_chunk, &current_chunk_id.value);
@@ -1198,8 +1208,6 @@ int cmd_setup_relayd(struct ltt_session *session)
                }
        }
 
-       rcu_read_lock();
-
        if (usess && usess->consumer && usess->consumer->type == CONSUMER_DST_NET
                        && usess->consumer->enabled) {
                /* For each consumer socket, send relayd sockets */
@@ -1225,6 +1233,8 @@ int cmd_setup_relayd(struct ltt_session *session)
                        usess->consumer->relay_major_version;
                session->consumer->relay_minor_version =
                        usess->consumer->relay_minor_version;
+               session->consumer->relay_allows_clear =
+                       usess->consumer->relay_allows_clear;
        }
 
        if (ksess && ksess->consumer && ksess->consumer->type == CONSUMER_DST_NET
@@ -1251,6 +1261,8 @@ int cmd_setup_relayd(struct ltt_session *session)
                        ksess->consumer->relay_major_version;
                session->consumer->relay_minor_version =
                        ksess->consumer->relay_minor_version;
+               session->consumer->relay_allows_clear =
+                       ksess->consumer->relay_allows_clear;
        }
 
 error:
@@ -1261,7 +1273,7 @@ error:
 /*
  * Start a kernel session by opening all necessary streams.
  */
-static int start_kernel_session(struct ltt_kernel_session *ksess)
+int start_kernel_session(struct ltt_kernel_session *ksess)
 {
        int ret;
        struct ltt_kernel_channel *kchan;
@@ -1323,6 +1335,53 @@ error:
        return ret;
 }
 
+int stop_kernel_session(struct ltt_kernel_session *ksess)
+{
+       struct ltt_kernel_channel *kchan;
+       bool error_occurred = false;
+       int ret;
+
+       if (!ksess || !ksess->active) {
+               return LTTNG_OK;
+       }
+       DBG("Stopping kernel tracing");
+
+       ret = kernel_stop_session(ksess);
+       if (ret < 0) {
+               ret = LTTNG_ERR_KERN_STOP_FAIL;
+               goto error;
+       }
+
+       kernel_wait_quiescent();
+
+       /* Flush metadata after stopping (if exists) */
+       if (ksess->metadata_stream_fd >= 0) {
+               ret = kernel_metadata_flush_buffer(ksess->metadata_stream_fd);
+               if (ret < 0) {
+                       ERR("Kernel metadata flush failed");
+                       error_occurred = true;
+               }
+       }
+
+       /* Flush all buffers after stopping */
+       cds_list_for_each_entry(kchan, &ksess->channel_list.head, list) {
+               ret = kernel_flush_buffer(kchan);
+               if (ret < 0) {
+                       ERR("Kernel flush buffer error");
+                       error_occurred = true;
+               }
+       }
+
+       ksess->active = 0;
+       if (error_occurred) {
+               ret = LTTNG_ERR_UNK;
+       } else {
+               ret = LTTNG_OK;
+       }
+error:
+       return ret;
+}
+
 /*
  * Command LTTNG_DISABLE_CHANNEL processed by the client thread.
  */
@@ -1380,12 +1439,14 @@ error:
 }
 
 /*
- * Command LTTNG_TRACK_PID processed by the client thread.
+ * Command LTTNG_TRACK_ID processed by the client thread.
  *
  * Called with session lock held.
  */
-int cmd_track_pid(struct ltt_session *session, enum lttng_domain_type domain,
-               int pid)
+int cmd_track_id(struct ltt_session *session,
+               enum lttng_tracker_type tracker_type,
+               enum lttng_domain_type domain,
+               const struct lttng_tracker_id *id)
 {
        int ret;
 
@@ -1398,7 +1459,7 @@ int cmd_track_pid(struct ltt_session *session, enum lttng_domain_type domain,
 
                ksess = session->kernel_session;
 
-               ret = kernel_track_pid(ksess, pid);
+               ret = kernel_track_id(tracker_type, ksess, id);
                if (ret != LTTNG_OK) {
                        goto error;
                }
@@ -1412,7 +1473,7 @@ int cmd_track_pid(struct ltt_session *session, enum lttng_domain_type domain,
 
                usess = session->ust_session;
 
-               ret = trace_ust_track_pid(usess, pid);
+               ret = trace_ust_track_id(tracker_type, usess, id);
                if (ret != LTTNG_OK) {
                        goto error;
                }
@@ -1431,12 +1492,14 @@ error:
 }
 
 /*
- * Command LTTNG_UNTRACK_PID processed by the client thread.
+ * Command LTTNG_UNTRACK_ID processed by the client thread.
  *
  * Called with session lock held.
  */
-int cmd_untrack_pid(struct ltt_session *session, enum lttng_domain_type domain,
-               int pid)
+int cmd_untrack_id(struct ltt_session *session,
+               enum lttng_tracker_type tracker_type,
+               enum lttng_domain_type domain,
+               const struct lttng_tracker_id *id)
 {
        int ret;
 
@@ -1449,7 +1512,7 @@ int cmd_untrack_pid(struct ltt_session *session, enum lttng_domain_type domain,
 
                ksess = session->kernel_session;
 
-               ret = kernel_untrack_pid(ksess, pid);
+               ret = kernel_untrack_id(tracker_type, ksess, id);
                if (ret != LTTNG_OK) {
                        goto error;
                }
@@ -1463,7 +1526,7 @@ int cmd_untrack_pid(struct ltt_session *session, enum lttng_domain_type domain,
 
                usess = session->ust_session;
 
-               ret = trace_ust_untrack_pid(usess, pid);
+               ret = trace_ust_untrack_id(tracker_type, usess, id);
                if (ret != LTTNG_OK) {
                        goto error;
                }
@@ -2511,15 +2574,16 @@ ssize_t cmd_list_syscalls(struct lttng_event **events)
 }
 
 /*
- * Command LTTNG_LIST_TRACKER_PIDS processed by the client thread.
+ * Command LTTNG_LIST_TRACKER_IDS processed by the client thread.
  *
  * Called with session lock held.
  */
-ssize_t cmd_list_tracker_pids(struct ltt_session *session,
-               enum lttng_domain_type domain, int32_t **pids)
+int cmd_list_tracker_ids(enum lttng_tracker_type tracker_type,
+               struct ltt_session *session,
+               enum lttng_domain_type domain,
+               struct lttng_tracker_ids **ids)
 {
-       int ret;
-       ssize_t nr_pids = 0;
+       int ret = LTTNG_OK;
 
        switch (domain) {
        case LTTNG_DOMAIN_KERNEL:
@@ -2527,9 +2591,9 @@ ssize_t cmd_list_tracker_pids(struct ltt_session *session,
                struct ltt_kernel_session *ksess;
 
                ksess = session->kernel_session;
-               nr_pids = kernel_list_tracker_pids(ksess, pids);
-               if (nr_pids < 0) {
-                       ret = LTTNG_ERR_KERN_LIST_FAIL;
+               ret = kernel_list_tracker_ids(tracker_type, ksess, ids);
+               if (ret != LTTNG_OK) {
+                       ret = -LTTNG_ERR_KERN_LIST_FAIL;
                        goto error;
                }
                break;
@@ -2539,9 +2603,9 @@ ssize_t cmd_list_tracker_pids(struct ltt_session *session,
                struct ltt_ust_session *usess;
 
                usess = session->ust_session;
-               nr_pids = trace_ust_list_tracker_pids(usess, pids);
-               if (nr_pids < 0) {
-                       ret = LTTNG_ERR_UST_LIST_FAIL;
+               ret = trace_ust_list_tracker_ids(tracker_type, usess, ids);
+               if (ret != LTTNG_OK) {
+                       ret = -LTTNG_ERR_UST_LIST_FAIL;
                        goto error;
                }
                break;
@@ -2550,15 +2614,13 @@ ssize_t cmd_list_tracker_pids(struct ltt_session *session,
        case LTTNG_DOMAIN_JUL:
        case LTTNG_DOMAIN_PYTHON:
        default:
-               ret = LTTNG_ERR_UND;
+               ret = -LTTNG_ERR_UND;
                goto error;
        }
 
-       return nr_pids;
-
 error:
        /* Return negative value to differentiate return code */
-       return -ret;
+       return ret;
 }
 
 /*
@@ -2572,6 +2634,10 @@ int cmd_start_trace(struct ltt_session *session)
        unsigned long nb_chan = 0;
        struct ltt_kernel_session *ksession;
        struct ltt_ust_session *usess;
+       const bool session_rotated_after_last_stop =
+                       session->rotated_after_last_stop;
+       const bool session_cleared_after_last_stop =
+                       session->cleared_after_last_stop;
 
        assert(session);
 
@@ -2582,6 +2648,23 @@ int cmd_start_trace(struct ltt_session *session)
        /* Is the session already started? */
        if (session->active) {
                ret = LTTNG_ERR_TRACE_ALREADY_STARTED;
+               /* Perform nothing */
+               goto end;
+       }
+
+       if (session->rotation_state == LTTNG_ROTATION_STATE_ONGOING &&
+                       !session->current_trace_chunk) {
+               /*
+                * A rotation was launched while the session was stopped and
+                * it has not been completed yet. It is not possible to start
+                * the session since starting the session here would require a
+                * rotation from "NULL" to a new trace chunk. That rotation
+                * would overlap with the ongoing rotation, which is not
+                * supported.
+                */
+               WARN("Refusing to start session \"%s\" as a rotation launched after the last \"stop\" is still ongoing",
+                               session->name);
+               ret = LTTNG_ERR_ROTATION_PENDING;
                goto error;
        }
 
@@ -2600,21 +2683,47 @@ int cmd_start_trace(struct ltt_session *session)
                goto error;
        }
 
+       session->active = 1;
+       session->rotated_after_last_stop = false;
+       session->cleared_after_last_stop = false;
        if (session->output_traces && !session->current_trace_chunk) {
-               struct lttng_trace_chunk *trace_chunk;
+               if (!session->has_been_started) {
+                       struct lttng_trace_chunk *trace_chunk;
 
-               trace_chunk = session_create_new_trace_chunk(
-                               session, NULL, NULL, NULL);
-               if (!trace_chunk) {
-                       ret = LTTNG_ERR_CREATE_DIR_FAIL;
-                       goto error;
-               }
-               assert(!session->current_trace_chunk);
-               ret = session_set_trace_chunk(session, trace_chunk, NULL);
-               lttng_trace_chunk_put(trace_chunk);
-               if (ret) {
-                       ret = LTTNG_ERR_CREATE_TRACE_CHUNK_FAIL_CONSUMER;
-                       goto error;
+                       DBG("Creating initial trace chunk of session \"%s\"",
+                                       session->name);
+                       trace_chunk = session_create_new_trace_chunk(
+                                       session, NULL, NULL, NULL);
+                       if (!trace_chunk) {
+                               ret = LTTNG_ERR_CREATE_DIR_FAIL;
+                               goto error;
+                       }
+                       assert(!session->current_trace_chunk);
+                       ret = session_set_trace_chunk(session, trace_chunk,
+                                       NULL);
+                       lttng_trace_chunk_put(trace_chunk);
+                       if (ret) {
+                               ret = LTTNG_ERR_CREATE_TRACE_CHUNK_FAIL_CONSUMER;
+                               goto error;
+                       }
+               } else {
+                       DBG("Rotating session \"%s\" from its current \"NULL\" trace chunk to a new chunk",
+                                       session->name);
+                       /*
+                        * Rotate existing streams into the new chunk.
+                        * This is a "quiet" rotation has no client has
+                        * explicitly requested this operation.
+                        *
+                        * There is also no need to wait for the rotation
+                        * to complete as it will happen immediately. No data
+                        * was produced as the session was stopped, so the
+                        * rotation should happen on reception of the command.
+                        */
+                       ret = cmd_rotate_session(session, NULL, true,
+                                       LTTNG_TRACE_CHUNK_COMMAND_TYPE_NO_OPERATION);
+                       if (ret != LTTNG_OK) {
+                               goto error;
+                       }
                }
        }
 
@@ -2637,10 +2746,6 @@ int cmd_start_trace(struct ltt_session *session)
                }
        }
 
-       /* Flag this after a successful start. */
-       session->has_been_started = 1;
-       session->active = 1;
-
        /*
         * Clear the flag that indicates that a rotation was done while the
         * session was stopped.
@@ -2661,6 +2766,18 @@ int cmd_start_trace(struct ltt_session *session)
        ret = LTTNG_OK;
 
 error:
+       if (ret == LTTNG_OK) {
+               /* Flag this after a successful start. */
+               session->has_been_started |= 1;
+       } else {
+               session->active = 0;
+               /* Restore initial state on error. */
+               session->rotated_after_last_stop =
+                               session_rotated_after_last_stop;
+               session->cleared_after_last_stop =
+                               session_cleared_after_last_stop;
+       }
+end:
        return ret;
 }
 
@@ -2670,14 +2787,12 @@ error:
 int cmd_stop_trace(struct ltt_session *session)
 {
        int ret;
-       struct ltt_kernel_channel *kchan;
        struct ltt_kernel_session *ksession;
        struct ltt_ust_session *usess;
-       bool error_occurred = false;
 
        assert(session);
 
-       DBG("Begin stop session %s (id %" PRIu64 ")", session->name, session->id);
+       DBG("Begin stop session \"%s\" (id %" PRIu64 ")", session->name, session->id);
        /* Short cut */
        ksession = session->kernel_session;
        usess = session->ust_session;
@@ -2688,39 +2803,9 @@ int cmd_stop_trace(struct ltt_session *session)
                goto error;
        }
 
-       /* Kernel tracer */
-       if (ksession && ksession->active) {
-               DBG("Stop kernel tracing");
-
-               ret = kernel_stop_session(ksession);
-               if (ret < 0) {
-                       ret = LTTNG_ERR_KERN_STOP_FAIL;
-                       goto error;
-               }
-
-               kernel_wait_quiescent();
-
-               /* Flush metadata after stopping (if exists) */
-               if (ksession->metadata_stream_fd >= 0) {
-                       ret = kernel_metadata_flush_buffer(ksession->metadata_stream_fd);
-                       if (ret < 0) {
-                               ERR("Kernel metadata flush failed");
-                               error_occurred = true;
-                       }
-               }
-
-               /* Flush all buffers after stopping */
-               cds_list_for_each_entry(kchan, &ksession->channel_list.head, list) {
-                       ret = kernel_flush_buffer(kchan);
-                       if (ret < 0) {
-                               ERR("Kernel flush buffer error");
-                               error_occurred = true;
-                       }
-               }
-
-               ksession->active = 0;
-               DBG("Kernel session stopped %s (id %" PRIu64 ")", session->name,
-                               session->id);
+       ret = stop_kernel_session(ksession);
+       if (ret != LTTNG_OK) {
+               goto error;
        }
 
        if (usess && usess->active) {
@@ -2731,33 +2816,26 @@ int cmd_stop_trace(struct ltt_session *session)
                }
        }
 
+       DBG("Completed stop session \"%s\" (id %" PRIu64 ")", session->name,
+                       session->id);
        /* Flag inactive after a successful stop. */
        session->active = 0;
-       ret = !error_occurred ? LTTNG_OK : LTTNG_ERR_UNK;
+       ret = LTTNG_OK;
 
 error:
        return ret;
 }
 
 /*
- * Command LTTNG_SET_CONSUMER_URI processed by the client thread.
+ * Set the base_path of the session only if subdir of a control uris is set.
+ * Return LTTNG_OK on success, otherwise LTTNG_ERR_*.
  */
-int cmd_set_consumer_uri(struct ltt_session *session, size_t nb_uri,
+static int set_session_base_path_from_uris(struct ltt_session *session,
+               size_t nb_uri,
                struct lttng_uri *uris)
 {
-       int ret, i;
-       struct ltt_kernel_session *ksess = session->kernel_session;
-       struct ltt_ust_session *usess = session->ust_session;
-
-       assert(session);
-       assert(uris);
-       assert(nb_uri > 0);
-
-       /* Can't set consumer URI if the session is active. */
-       if (session->active) {
-               ret = LTTNG_ERR_TRACE_ALREADY_STARTED;
-               goto error;
-       }
+       int ret;
+       size_t i;
 
        for (i = 0; i < nb_uri; i++) {
                if (uris[i].stype != LTTNG_STREAM_CONTROL ||
@@ -2774,11 +2852,47 @@ int cmd_set_consumer_uri(struct ltt_session *session, size_t nb_uri,
                /* Set session base_path */
                session->base_path = strdup(uris[i].subdir);
                if (!session->base_path) {
-                       PERROR("Copying base path: %s", uris[i].subdir);
+                       PERROR("Failed to copy base path \"%s\" to session \"%s\"",
+                                       uris[i].subdir, session->name);
+                       ret = LTTNG_ERR_NOMEM;
                        goto error;
                }
-               DBG2("Setting base path for session %" PRIu64 ": %s",
-                               session->id, session->base_path);
+               DBG2("Setting base path \"%s\" for session \"%s\"",
+                               session->base_path, session->name);
+       }
+       ret = LTTNG_OK;
+error:
+       return ret;
+}
+
+/*
+ * Command LTTNG_SET_CONSUMER_URI processed by the client thread.
+ */
+int cmd_set_consumer_uri(struct ltt_session *session, size_t nb_uri,
+               struct lttng_uri *uris)
+{
+       int ret, i;
+       struct ltt_kernel_session *ksess = session->kernel_session;
+       struct ltt_ust_session *usess = session->ust_session;
+
+       assert(session);
+       assert(uris);
+       assert(nb_uri > 0);
+
+       /* Can't set consumer URI if the session is active. */
+       if (session->active) {
+               ret = LTTNG_ERR_TRACE_ALREADY_STARTED;
+               goto error;
+       }
+
+       /*
+        * Set the session base path if any. This is done inside
+        * cmd_set_consumer_uri to preserve backward compatibility of the
+        * previous session creation api vs the session descriptor api.
+        */
+       ret = set_session_base_path_from_uris(session, nb_uri, uris);
+       if (ret != LTTNG_OK) {
+               goto error;
        }
 
        /* Set the "global" consumer URIs */
@@ -3216,14 +3330,13 @@ int cmd_destroy_session(struct ltt_session *session,
                session->rotate_size = 0;
        }
 
-       if (session->most_recent_chunk_id.is_set &&
-                       session->most_recent_chunk_id.value != 0 &&
-                       session->current_trace_chunk && session->output_traces) {
+       if (session->rotated && session->current_trace_chunk && session->output_traces) {
                /*
                 * Perform a last rotation on destruction if rotations have
                 * occurred during the session's lifetime.
                 */
-               ret = cmd_rotate_session(session, NULL, false);
+               ret = cmd_rotate_session(session, NULL, false,
+                       LTTNG_TRACE_CHUNK_COMMAND_TYPE_MOVE_TO_COMPLETED);
                if (ret != LTTNG_OK) {
                        ERR("Failed to perform an implicit rotation as part of the destruction of session \"%s\": %s",
                                        session->name, lttng_strerror(-ret));
@@ -3242,7 +3355,8 @@ int cmd_destroy_session(struct ltt_session *session,
                 * emitted and no renaming of the current trace chunk takes
                 * place.
                 */
-               ret = cmd_rotate_session(session, NULL, true);
+               ret = cmd_rotate_session(session, NULL, true,
+                       LTTNG_TRACE_CHUNK_COMMAND_TYPE_NO_OPERATION);
                if (ret != LTTNG_OK) {
                        ERR("Failed to perform a quiet rotation as part of the destruction of session \"%s\": %s",
                                        session->name, lttng_strerror(-ret));
@@ -4176,8 +4290,94 @@ end:
        return ret;
 }
 
+/* TODO: is this the best place to perform this? (code wise) */
+/*
+ * Set sock to -1 if reception of more information is not necessary e.g on
+ * unregister. TODO find a better way.
+ *
+ * On success LTTNG_OK. On error, returns lttng_error code.
+ * */
+static enum lttng_error_code prepare_trigger_object(struct lttng_trigger *trigger, int sock)
+{
+       enum lttng_error_code ret;
+       /* Internal object of the trigger might have to "generate" and
+        * "populate" internal field e.g filter bytecode
+        */
+       struct lttng_condition *condition = NULL;
+       condition = lttng_trigger_get_condition(trigger);
+       if (!condition) {
+               ret = LTTNG_ERR_INVALID_TRIGGER;
+               goto end;
+       }
+
+       switch (lttng_condition_get_type(condition)) {
+       case LTTNG_CONDITION_TYPE_EVENT_RULE_HIT:
+       {
+               struct lttng_event_rule *event_rule;
+               const struct lttng_credentials *credential = lttng_trigger_get_credentials(trigger);
+               lttng_condition_event_rule_get_rule_no_const(
+                               condition, &event_rule);
+               ret = lttng_event_rule_populate(event_rule, credential->uid, credential->gid);
+               if (ret != LTTNG_OK) {
+                       goto end;
+               }
+
+               switch (lttng_event_rule_get_type(event_rule)) {
+               case LTTNG_EVENT_RULE_TYPE_UPROBE:
+               {
+                       int fd;
+                       struct lttng_userspace_probe_location *location = lttng_event_rule_uprobe_get_location_no_const(event_rule);
+
+                       if (sock < 0) {
+                               /* Nothing to receive */
+                               break;
+                       }
+                       /*
+                        * Receive the file descriptor to the target binary from
+                        * the client.
+                        */
+                       DBG("Receiving userspace probe target FD from client ...");
+                       ret = lttcomm_recv_fds_unix_sock(sock, &fd, 1);
+                       if (ret <= 0) {
+                               DBG("Nothing recv() from client userspace probe fd... continuing");
+                               ret = LTTNG_ERR_PROBE_LOCATION_INVAL;
+                               goto end;
+                       }
+
+                       /*
+                        * Set the file descriptor received from the client
+                        * through the unix socket in the probe location.
+                        */
+                       ret = lttng_userspace_probe_location_set_binary_fd(
+                                       location, fd);
+                       if (ret) {
+                               ret = LTTNG_ERR_PROBE_LOCATION_INVAL;
+                               goto end;
+                       }
+
+                       break;
+               }
+               default:
+                       /* Nothing to do */
+                       break;
+               }
+               ret = LTTNG_OK;
+               break;
+       }
+       default:
+       {
+               ret = LTTNG_OK;
+               break;
+       }
+       }
+end:
+       return ret;
+}
+
+/* Caller must call lttng_destroy_trigger on the returned trigger object */
 int cmd_register_trigger(struct command_ctx *cmd_ctx, int sock,
-               struct notification_thread_handle *notification_thread)
+               struct notification_thread_handle *notification_thread,
+               struct lttng_trigger **return_trigger)
 {
        int ret;
        size_t trigger_len;
@@ -4211,9 +4411,95 @@ int cmd_register_trigger(struct command_ctx *cmd_ctx, int sock,
                goto end;
        }
 
+       /* Set the trigger credential */
+       lttng_trigger_set_credentials(trigger, cmd_ctx->creds.uid, cmd_ctx->creds.gid);
+
+       /* Prepare internal trigger object if needed on reception.
+        * Handles also special treatment for certain internal object of the
+        * trigger (e.g uprobe event rule binary fd.
+        */
+       ret = prepare_trigger_object(trigger, sock);
+       if (ret != LTTNG_OK) {
+               goto end;
+       }
+
+       /*
+        * Since we return the trigger object, take a reference to it
+        * Caller is responsible for calling lttng_destroy_trigger on it.
+        * This thread does not OWN the trigger.
+        */
+       lttng_trigger_get(trigger);
+
+       /* Inform the notification thread */
        ret = notification_thread_command_register_trigger(notification_thread,
                        trigger);
-       /* Ownership of trigger was transferred. */
+       if (ret != LTTNG_OK) {
+               goto end;
+       }
+
+       /* Synchronize tracers, only if needed */
+       /* TODO: maybe extract somewhere else */
+       {
+               struct lttng_condition *condition = NULL;
+               condition = lttng_trigger_get_condition(trigger);
+               if (!condition) {
+                       ret = LTTNG_ERR_INVALID_TRIGGER;
+                       goto end;
+               }
+
+               if (lttng_condition_get_type(condition) == LTTNG_CONDITION_TYPE_EVENT_RULE_HIT) {
+                       const struct lttng_event_rule *rule = NULL;
+                       (void) lttng_condition_event_rule_get_rule(condition, &rule);
+                       if (!rule) {
+                               ret = LTTNG_ERR_INVALID_TRIGGER;
+                               goto end;
+                       }
+                       if (lttng_event_rule_get_domain_type(rule) == LTTNG_DOMAIN_KERNEL) {
+                               /* TODO: get the token value from the
+                                * notification thread and only perform an
+                                * enable and a disable.... This is NOT
+                                * OPTIMIZED AT ALL
+                                */
+                               kernel_update_tokens();
+                       } else {
+                               /* TODO: get the token value from the
+                                * notification thread and only perform an
+                                * enable and a disable.... This is NOT
+                                * OPTIMIZED AT ALL
+                                */
+                               ust_app_global_update_all_tokens();
+                               /* Agent handling */
+                               if (lttng_event_rule_is_agent(rule)) {
+                                       struct agent *agt;
+                                       const char *pattern;
+                                       enum lttng_domain_type domain_type;
+                                       domain_type = lttng_event_rule_get_domain_type(
+                                                       rule);
+                                       (void) lttng_event_rule_tracepoint_get_pattern(
+                                                       rule, &pattern);
+                                       agt = trigger_find_agent(domain_type);
+                                       if (!agt) {
+                                               agt = agent_create(domain_type);
+                                               if (!agt) {
+                                                       ret = LTTNG_ERR_NOMEM;
+                                                       goto end;
+                                               }
+                                               agent_add(agt, trigger_agents_ht_by_domain);
+                                       }
+
+                                       ret = trigger_agent_enable(
+                                                       trigger, agt);
+                                       if (ret != LTTNG_OK) {
+                                               goto end;
+                                       }
+                               }
+                       }
+               }
+       }
+
+       /* Return an image of the updated object to the client */
+       *return_trigger = trigger;
+       /* Ownership of trigger was transferred to caller. */
        trigger = NULL;
 end:
        lttng_trigger_destroy(trigger);
@@ -4256,14 +4542,110 @@ int cmd_unregister_trigger(struct command_ctx *cmd_ctx, int sock,
                goto end;
        }
 
+       lttng_trigger_set_credentials(trigger, cmd_ctx->creds.uid, cmd_ctx->creds.gid);
+
+       /* TODO: forgotting this bited me for agent since the filter is
+        * genereted on this side. Wonder if we could find a way to detect when
+        * do it or not.
+        */
+
+       /* Prepare internal trigger object if needed on reception.
+        * Handles also special treatment for certain internal object of the
+        * trigger (e.g uprobe event rule binary fd.
+        */
+       ret = prepare_trigger_object(trigger, -1);
+       if (ret != LTTNG_OK) {
+               goto end;
+       }
+
        ret = notification_thread_command_unregister_trigger(notification_thread,
                        trigger);
+
+       /* Synchronize tracers, only if needed */
+       /* TODO: maybe extract somewhere else */
+       {
+               struct lttng_condition *condition = NULL;
+               condition = lttng_trigger_get_condition(trigger);
+               if (!condition) {
+                       ret = LTTNG_ERR_INVALID_TRIGGER;
+                       goto end;
+               }
+
+               if (lttng_condition_get_type(condition) == LTTNG_CONDITION_TYPE_EVENT_RULE_HIT) {
+                       const struct lttng_event_rule *rule = NULL;
+                       (void) lttng_condition_event_rule_get_rule(condition, &rule);
+                       if (!rule) {
+                               ret = LTTNG_ERR_INVALID_TRIGGER;
+                               goto end;
+                       }
+                       if (lttng_event_rule_get_domain_type(rule) == LTTNG_DOMAIN_KERNEL) {
+                               /* TODO: get the token value from the
+                                * notification thread and only perform an
+                                * enable and a disable.... This is NOT
+                                * OPTIMIZED AT ALL
+                                */
+                               kernel_update_tokens();
+                       } else {
+                               /* TODO: get the token value from the
+                                * notification thread and only perform an
+                                * enable and a disable.... This is NOT
+                                * OPTIMIZED AT ALL
+                                */
+                               ust_app_global_update_all_tokens();
+                               if (lttng_event_rule_is_agent(rule)) {
+                                       struct agent *agt;
+                                       const char *pattern;
+                                       enum lttng_domain_type domain_type;
+
+                                       domain_type = lttng_event_rule_get_domain_type(
+                                                       rule);
+                                       (void) lttng_event_rule_tracepoint_get_pattern(
+                                                       rule, &pattern);
+
+                                       agt = trigger_find_agent(domain_type);
+                                       if (!agt) {
+                                               ret = LTTNG_ERR_UST_EVENT_NOT_FOUND;
+                                               goto end;
+                                       }
+                                       ret = trigger_agent_disable(
+                                                       trigger, agt);
+                                       if (ret != LTTNG_OK) {
+                                               goto end;
+                                       }
+                               }
+                       }
+               }
+       }
+
 end:
        lttng_trigger_destroy(trigger);
        lttng_dynamic_buffer_reset(&trigger_buffer);
        return ret;
 }
 
+int cmd_list_triggers(struct command_ctx *cmd_ctx, int sock,
+               struct notification_thread_handle *notification_thread,
+               struct lttng_triggers **return_triggers)
+{
+       int ret = 0;
+       enum lttng_error_code ret_code;
+       struct lttng_triggers *triggers = NULL;
+
+       /* Get list of token trigger from the notification thread here */
+       ret_code = notification_thread_command_list_triggers(notification_thread_handle, cmd_ctx->creds.uid, cmd_ctx->creds.gid, &triggers);
+       if (ret_code != LTTNG_OK) {
+               ret = ret_code;
+               goto end;
+       }
+
+       /* Return a "view" of the current triggers */
+       *return_triggers = triggers;
+       triggers = NULL;
+       ret = LTTNG_OK;
+end:
+       lttng_triggers_destroy(triggers);
+       return ret;
+}
 /*
  * Send relayd sockets from snapshot output to consumer. Ignore request if the
  * snapshot output is *not* set with a remote destination.
@@ -4467,7 +4849,7 @@ int64_t get_session_nb_packets_per_stream(const struct ltt_session *session,
                }
                cur_nb_packets++;
        }
-       if (!cur_nb_packets) {
+       if (!cur_nb_packets && size_left != max_size) {
                /* Not enough room to grab one packet of each stream, error. */
                return -1;
        }
@@ -4580,7 +4962,7 @@ enum lttng_error_code snapshot_record(struct ltt_session *session,
                        snapshot_output->max_size);
        if (nb_packets_per_stream < 0) {
                ret_code = LTTNG_ERR_MAX_SIZE_INVALID;
-               goto error;
+               goto error_close_trace_chunk;
        }
 
        if (session->kernel_session) {
@@ -4588,7 +4970,7 @@ enum lttng_error_code snapshot_record(struct ltt_session *session,
                                snapshot_kernel_consumer_output, session,
                                wait, nb_packets_per_stream);
                if (ret_code != LTTNG_OK) {
-                       goto error;
+                       goto error_close_trace_chunk;
                }
        }
 
@@ -4597,12 +4979,19 @@ enum lttng_error_code snapshot_record(struct ltt_session *session,
                                snapshot_ust_consumer_output, session,
                                wait, nb_packets_per_stream);
                if (ret_code != LTTNG_OK) {
-                       goto error;
+                       goto error_close_trace_chunk;
                }
        }
 
-       if (session_close_trace_chunk(
-                           session, session->current_trace_chunk, NULL, NULL)) {
+error_close_trace_chunk:
+       if (session_set_trace_chunk(session, NULL, &snapshot_trace_chunk)) {
+               ERR("Failed to release the current trace chunk of session \"%s\"",
+                               session->name);
+               ret_code = LTTNG_ERR_UNK;
+       }
+
+       if (session_close_trace_chunk(session, snapshot_trace_chunk,
+                       LTTNG_TRACE_CHUNK_COMMAND_TYPE_NO_OPERATION, NULL)) {
                /*
                 * Don't goto end; make sure the chunk is closed for the session
                 * to allow future snapshots.
@@ -4611,11 +5000,6 @@ enum lttng_error_code snapshot_record(struct ltt_session *session,
                                session->name);
                ret_code = LTTNG_ERR_CLOSE_TRACE_CHUNK_FAIL_CONSUMER;
        }
-       if (session_set_trace_chunk(session, NULL, NULL)) {
-               ERR("Failed to release the current trace chunk of session \"%s\"",
-                               session->name);
-               ret_code = LTTNG_ERR_UNK;
-       }
 error:
        if (original_ust_consumer_output) {
                session->ust_session->consumer = original_ust_consumer_output;
@@ -4796,7 +5180,8 @@ int cmd_set_session_shm_path(struct ltt_session *session,
  */
 int cmd_rotate_session(struct ltt_session *session,
                struct lttng_rotate_session_return *rotate_return,
-               bool quiet_rotation)
+               bool quiet_rotation,
+               enum lttng_trace_chunk_command_type command)
 {
        int ret;
        uint64_t ongoing_rotation_chunk_id;
@@ -4834,6 +5219,12 @@ int cmd_rotate_session(struct ltt_session *session,
                goto end;
        }
 
+       /* Unsupported feature in lttng-modules before 2.8 (lack of sequence number). */
+       if (session->kernel_session && !kernel_supports_ring_buffer_packet_sequence_number()) {
+               cmd_ret = LTTNG_ERR_ROTATION_NOT_AVAILABLE_KERNEL;
+               goto end;
+       }
+
        if (session->rotation_state == LTTNG_ROTATION_STATE_ONGOING) {
                DBG("Refusing to launch a rotation; a rotation is already in progress for session %s",
                                session->name);
@@ -4852,7 +5243,16 @@ int cmd_rotate_session(struct ltt_session *session,
                goto end;
        }
 
-       session->rotation_state = LTTNG_ROTATION_STATE_ONGOING;
+       /*
+        * After a stop followed by a clear, disallow following rotations a they would
+        * generate empty chunks.
+        */
+       if (session->cleared_after_last_stop) {
+               DBG("Session \"%s\" was already cleared after stop, refusing rotation",
+                               session->name);
+               cmd_ret = LTTNG_ERR_ROTATION_AFTER_STOP_CLEAR;
+               goto end;
+       }
 
        if (session->active) {
                new_trace_chunk = session_create_new_trace_chunk(session, NULL,
@@ -4877,11 +5277,6 @@ int cmd_rotate_session(struct ltt_session *session,
                goto error;
        }
 
-       assert(chunk_being_archived);
-       chunk_status = lttng_trace_chunk_get_id(chunk_being_archived,
-                       &ongoing_rotation_chunk_id);
-       assert(chunk_status == LTTNG_TRACE_CHUNK_STATUS_OK);
-
        if (session->kernel_session) {
                cmd_ret = kernel_rotate_session(session);
                if (cmd_ret != LTTNG_OK) {
@@ -4897,12 +5292,28 @@ int cmd_rotate_session(struct ltt_session *session,
                }
        }
 
+       if (!session->active) {
+               session->rotated_after_last_stop = true;
+       }
+
+       if (!chunk_being_archived) {
+               DBG("Rotating session \"%s\" from a \"NULL\" trace chunk to a new trace chunk, skipping completion check",
+                               session->name);
+               if (failed_to_rotate) {
+                       cmd_ret = rotation_fail_code;
+                       goto error;
+               }
+               cmd_ret = LTTNG_OK;
+               goto end;
+       }
+
+       session->rotation_state = LTTNG_ROTATION_STATE_ONGOING;
+       chunk_status = lttng_trace_chunk_get_id(chunk_being_archived,
+                       &ongoing_rotation_chunk_id);
+       assert(chunk_status == LTTNG_TRACE_CHUNK_STATUS_OK);
+
        ret = session_close_trace_chunk(session, chunk_being_archived,
-                       quiet_rotation ?
-                                       NULL :
-                                       &((enum lttng_trace_chunk_command_type){
-                                                       LTTNG_TRACE_CHUNK_COMMAND_TYPE_MOVE_TO_COMPLETED}),
-                       session->last_chunk_path);
+               command, session->last_chunk_path);
        if (ret) {
                cmd_ret = LTTNG_ERR_CLOSE_TRACE_CHUNK_FAIL_CONSUMER;
                goto error;
@@ -4921,10 +5332,6 @@ int cmd_rotate_session(struct ltt_session *session,
                goto error;
        }
 
-       if (!session->active) {
-               session->rotated_after_last_stop = true;
-       }
-
        if (rotate_return) {
                rotate_return->rotation_id = ongoing_rotation_chunk_id;
        }
This page took 0.038106 seconds and 5 git commands to generate.