lttng: Add remove-trigger command
authorSimon Marchi <simon.marchi@efficios.com>
Mon, 20 Jan 2020 21:39:56 +0000 (16:39 -0500)
committerJérémie Galarneau <jeremie.galarneau@efficios.com>
Wed, 24 Feb 2021 20:54:36 +0000 (15:54 -0500)
Signed-off-by: Simon Marchi <simon.marchi@efficios.com>
Signed-off-by: Jérémie Galarneau <jeremie.galarneau@efficios.com>
Change-Id: I323ddc181c9214dcf4ae66e23a382451f6582fff
Depends-on: lttng-ust: I5a800fc92e588c2a6a0e26282b0ad5f31c044479

13 files changed:
doc/man/Makefile.am
doc/man/lttng-remove-trigger.1.txt [new file with mode: 0644]
include/lttng/trigger/trigger-internal.h
include/lttng/trigger/trigger.h
src/bin/lttng/Makefile.am
src/bin/lttng/command.h
src/bin/lttng/commands/remove_trigger.c [new file with mode: 0644]
src/bin/lttng/lttng.c
src/common/trigger.c
src/lib/lttng-ctl/lttng-ctl.c
tests/regression/Makefile.am
tests/regression/tools/trigger/Makefile.am
tests/regression/tools/trigger/test_remove_trigger_cli [new file with mode: 0755]

index 769dca4703acab8ed35a69aa62f71f1c9a8d9573..5ae6ffbe30da3d4755deed80d5ccfb9e591414f1 100644 (file)
@@ -38,6 +38,7 @@ MAN1_NAMES = \
        lttng-disable-rotation \
        lttng-clear \
        lttng-add-trigger \
+       lttng-remove-trigger \
        lttng-list-triggers
 
 MAN3_NAMES =
diff --git a/doc/man/lttng-remove-trigger.1.txt b/doc/man/lttng-remove-trigger.1.txt
new file mode 100644 (file)
index 0000000..645ef15
--- /dev/null
@@ -0,0 +1,38 @@
+lttng-remove-trigger(1)
+========================
+:revdate: 20 January 2020
+
+
+NAME
+----
+lttng-remove-trigger - Remove LTTng triggers
+
+
+SYNOPSIS
+--------
+
+[verse]
+*lttng* ['linkgenoptions:(GENERAL OPTIONS)'] *remove-trigger* 'ID'
+
+
+DESCRIPTION
+-----------
+
+The `lttng remove-trigger` command removes the trigger with the given
+'ID'.
+
+
+OPTIONS
+-------
+
+include::common-cmd-help-options.txt[]
+
+
+include::common-cmd-footer.txt[]
+
+
+SEE ALSO
+--------
+man:lttng-add-trigger(1),
+man:lttng-list-trigger(1),
+man:lttng(1)
index 20989bd99e700c0c547de38ea18e9060e8da972e..21c269befd14b78b26c2aaa3496ed6600d43cf1a 100644 (file)
@@ -84,7 +84,7 @@ int lttng_trigger_serialize(const struct lttng_trigger *trigger,
                struct lttng_payload *payload);
 
 LTTNG_HIDDEN
-bool lttng_trigger_validate(struct lttng_trigger *trigger);
+bool lttng_trigger_validate(const struct lttng_trigger *trigger);
 
 LTTNG_HIDDEN
 int lttng_trigger_assign_name(
@@ -193,4 +193,7 @@ enum lttng_error_code lttng_trigger_generate_bytecode(
                struct lttng_trigger *trigger,
                const struct lttng_credentials *creds);
 
+LTTNG_HIDDEN
+struct lttng_trigger *lttng_trigger_copy(const struct lttng_trigger *trigger);
+
 #endif /* LTTNG_TRIGGER_INTERNAL_H */
index 2a7d4e36bf1b1c26f94b2666f159259f89b60763..5fef53fd415f15e69b859f48e9e1ce947f291fb9 100644 (file)
@@ -190,7 +190,7 @@ extern int lttng_register_trigger(struct lttng_trigger *trigger);
  *
  * Return 0 on success, a negative LTTng error code on error.
  */
-extern int lttng_unregister_trigger(struct lttng_trigger *trigger);
+extern int lttng_unregister_trigger(const struct lttng_trigger *trigger);
 
 /*
  * List triggers for the current user.
index 7a305d49ae8cd07950e94455a508bf6a6e9dcadc..50ab92988db3d88b957bc3aba9af6181d12d73ec 100644 (file)
@@ -32,6 +32,7 @@ lttng_SOURCES = command.h conf.c conf.h commands/start.c \
                                loglevel.c loglevel.h \
                                commands/add_trigger.c \
                                commands/list_triggers.c \
+                               commands/remove_trigger.c \
                                utils.c utils.h lttng.c \
                                uprobe.c uprobe.h
 
index 8a318c6f7529e7fd7830565cf2856ef73cc9070d..bf004521003787acb910b9d29ea3a1b519c9af9a 100644 (file)
@@ -79,6 +79,7 @@ DECL_COMMAND(disable_rotation);
 DECL_COMMAND(clear);
 DECL_COMMAND(add_trigger);
 DECL_COMMAND(list_triggers);
+DECL_COMMAND(remove_trigger);
 
 extern int cmd_help(int argc, const char **argv,
                const struct cmd_struct commands[]);
diff --git a/src/bin/lttng/commands/remove_trigger.c b/src/bin/lttng/commands/remove_trigger.c
new file mode 100644 (file)
index 0000000..1fabc70
--- /dev/null
@@ -0,0 +1,191 @@
+/*
+ * Copyright (C) 2021 Simon Marchi <simon.marchi@efficios.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0-only
+ *
+ */
+
+#include "../command.h"
+#include "common/argpar/argpar.h"
+#include <lttng/lttng.h>
+#include <stdio.h>
+
+#ifdef LTTNG_EMBED_HELP
+static const char help_msg[] =
+#include <lttng-remove-trigger.1.h>
+;
+#endif
+
+enum {
+       OPT_HELP,
+       OPT_LIST_OPTIONS,
+       OPT_USER_ID,
+};
+
+static const
+struct argpar_opt_descr remove_trigger_options[] = {
+       { OPT_HELP, 'h', "help", false },
+       { OPT_LIST_OPTIONS, '\0', "list-options", false },
+       { OPT_USER_ID, '\0', "user-id", true },
+       ARGPAR_OPT_DESCR_SENTINEL,
+};
+
+static
+bool assign_string(char **dest, const char *src, const char *opt_name)
+{
+       bool ret;
+
+       if (*dest) {
+               ERR("Duplicate option '%s' given.", opt_name);
+               goto error;
+       }
+
+       *dest = strdup(src);
+       if (!*dest) {
+               ERR("Failed to allocate '%s' string.", opt_name);
+               goto error;
+       }
+
+       ret = true;
+       goto end;
+
+error:
+       ret = false;
+
+end:
+       return ret;
+}
+
+int cmd_remove_trigger(int argc, const char **argv)
+{
+       int ret;
+       struct argpar_parse_ret argpar_parse_ret = {};
+       const char *id = NULL;
+       int i;
+       struct lttng_triggers *triggers = NULL;
+       unsigned int triggers_count;
+       enum lttng_trigger_status trigger_status;
+       const struct lttng_trigger *trigger_to_remove = NULL;
+       char *user_id = NULL;
+       long long uid;
+
+       argpar_parse_ret = argpar_parse(argc - 1, argv + 1,
+               remove_trigger_options, true);
+       if (!argpar_parse_ret.items) {
+               ERR("%s", argpar_parse_ret.error);
+               goto error;
+       }
+
+       for (i = 0; i < argpar_parse_ret.items->n_items; i++) {
+               const struct argpar_item *item =
+                               argpar_parse_ret.items->items[i];
+
+               if (item->type == ARGPAR_ITEM_TYPE_OPT) {
+                       const struct argpar_item_opt *item_opt =
+                                       (const struct argpar_item_opt *) item;
+
+                       switch (item_opt->descr->id) {
+                       case OPT_HELP:
+                               SHOW_HELP();
+                               ret = 0;
+                               goto end;
+                       case OPT_LIST_OPTIONS:
+                               list_cmd_options_argpar(stdout,
+                                       remove_trigger_options);
+                               ret = 0;
+                               goto end;
+                       case OPT_USER_ID:
+                       {
+                               if (!assign_string(&user_id, item_opt->arg,
+                                               "--user-id")) {
+                                       goto error;
+                               }
+                               break;
+                       }
+                       default:
+                               abort();
+                       }
+               } else {
+                       const struct argpar_item_non_opt *item_non_opt =
+                                       (const struct argpar_item_non_opt *) item;
+
+                       if (id) {
+                               ERR("Unexpected argument '%s'", item_non_opt->arg);
+                               goto error;
+                       }
+
+                       id = item_non_opt->arg;
+               }
+       }
+
+       if (!id) {
+               ERR("Missing `id` argument.");
+               goto error;
+       }
+
+       if (user_id) {
+               char *end;
+
+               errno = 0;
+               uid = strtol(user_id, &end, 10);
+               if (end == user_id || *end != '\0' || errno != 0) {
+                       ERR("Failed to parse `%s` as an integer.", user_id);
+               }
+       } else {
+               uid = geteuid();
+       }
+
+       ret = lttng_list_triggers(&triggers);
+       if (ret != LTTNG_OK) {
+               ERR("Failed to get the list of triggers.");
+               goto error;
+       }
+
+       trigger_status = lttng_triggers_get_count(triggers, &triggers_count);
+       assert(trigger_status == LTTNG_TRIGGER_STATUS_OK);
+
+       for (i = 0; i < triggers_count; i++) {
+               const struct lttng_trigger *trigger;
+               const char *trigger_name;
+               uid_t trigger_uid;
+
+               trigger = lttng_triggers_get_at_index(triggers, i);
+               trigger_status = lttng_trigger_get_name(trigger, &trigger_name);
+               assert(trigger_status == LTTNG_TRIGGER_STATUS_OK);
+
+               trigger_status = lttng_trigger_get_owner_uid(
+                               trigger, &trigger_uid);
+               assert(trigger_status == LTTNG_TRIGGER_STATUS_OK);
+
+               if (trigger_uid == uid && strcmp(trigger_name, id) == 0) {
+                       trigger_to_remove = trigger;
+                       break;
+               }
+       }
+
+       if (!trigger_to_remove) {
+               ERR("Couldn't find trigger with id `%s`.", id);
+               goto error;
+       }
+
+       ret = lttng_unregister_trigger(trigger_to_remove);
+       if (ret != 0) {
+               ERR("Failed to unregister trigger `%s`.", id);
+               goto error;
+       }
+
+       MSG("Removed trigger `%s`.", id);
+
+       ret = 0;
+       goto end;
+
+error:
+       ret = 1;
+
+end:
+       argpar_parse_ret_fini(&argpar_parse_ret);
+       lttng_triggers_destroy(triggers);
+       free(user_id);
+
+       return ret;
+}
index e5642e24cd5796242cba82d796bd975f43087250..437a9cc4c2e00367ec5d10f2d0061ae18f4d5c49 100644 (file)
@@ -79,6 +79,7 @@ static struct cmd_struct commands[] =  {
        { "load", cmd_load},
        { "metadata", cmd_metadata},
        { "regenerate", cmd_regenerate},
+       { "remove-trigger", cmd_remove_trigger},
        { "rotate", cmd_rotate},
        { "enable-rotation", cmd_enable_rotation},
        { "disable-rotation", cmd_disable_rotation},
index 55ab99729c338259d72476e1a8074d12b9e5f43f..04b3e7f116bc7ba667c96b8570c1621e2a09930e 100644 (file)
@@ -23,7 +23,7 @@
 #include <inttypes.h>
 
 LTTNG_HIDDEN
-bool lttng_trigger_validate(struct lttng_trigger *trigger)
+bool lttng_trigger_validate(const struct lttng_trigger *trigger)
 {
        bool valid;
 
@@ -971,3 +971,34 @@ enum lttng_error_code lttng_trigger_generate_bytecode(
 end:
        return ret;
 }
+
+LTTNG_HIDDEN
+struct lttng_trigger *lttng_trigger_copy(const struct lttng_trigger *trigger)
+{
+       int ret;
+       struct lttng_payload copy_buffer;
+       struct lttng_trigger *copy = NULL;
+
+       lttng_payload_init(&copy_buffer);
+
+       ret = lttng_trigger_serialize(trigger, &copy_buffer);
+       if (ret < 0) {
+               goto end;
+       }
+
+       {
+               struct lttng_payload_view view =
+                               lttng_payload_view_from_payload(
+                                               &copy_buffer, 0, -1);
+               ret = lttng_trigger_create_from_payload(
+                               &view, &copy);
+               if (ret < 0) {
+                       copy = NULL;
+                       goto end;
+               }
+       }
+
+end:
+       lttng_payload_reset(&copy_buffer);
+       return copy;
+}
index 5b774e1d6bcbc1e9df4c01efc0e98634e1172e72..5529b3364f12027c8b143fbdcba8a4e7304dad70 100644 (file)
@@ -3201,13 +3201,14 @@ end:
        return ret;
 }
 
-int lttng_unregister_trigger(struct lttng_trigger *trigger)
+int lttng_unregister_trigger(const struct lttng_trigger *trigger)
 {
        int ret;
        struct lttcomm_session_msg lsm;
        struct lttcomm_session_msg *message_lsm;
        struct lttng_payload message;
        struct lttng_payload reply;
+       struct lttng_trigger *copy = NULL;
        const struct lttng_credentials user_creds = {
                .uid = LTTNG_OPTIONAL_INIT_VALUE(geteuid()),
                .gid = LTTNG_OPTIONAL_INIT_UNSET,
@@ -3221,9 +3222,15 @@ int lttng_unregister_trigger(struct lttng_trigger *trigger)
                goto end;
        }
 
-       if (!trigger->creds.uid.is_set) {
-               /* Use the client's credentials as the trigger credentials. */
-               lttng_trigger_set_credentials(trigger, &user_creds);
+       copy = lttng_trigger_copy(trigger);
+       if (!copy) {
+               ret = -LTTNG_ERR_UNK;
+               goto end;
+       }
+
+       if (!copy->creds.uid.is_set) {
+               /* Use the client credentials as the trigger credentials */
+               lttng_trigger_set_credentials(copy, &user_creds);
        } else {
                /*
                 * Validate that either the current trigger credentials and the
@@ -3236,8 +3243,7 @@ int lttng_unregister_trigger(struct lttng_trigger *trigger)
                 * "safety" checks.
                 */
                const struct lttng_credentials *trigger_creds =
-                               lttng_trigger_get_credentials(trigger);
-
+                               lttng_trigger_get_credentials(copy);
                if (!lttng_credentials_is_equal_uid(trigger_creds, &user_creds)) {
                        if (lttng_credentials_get_uid(&user_creds) != 0) {
                                ret = -LTTNG_ERR_EPERM;
@@ -3246,7 +3252,7 @@ int lttng_unregister_trigger(struct lttng_trigger *trigger)
                }
        }
 
-       if (!lttng_trigger_validate(trigger)) {
+       if (!lttng_trigger_validate(copy)) {
                ret = -LTTNG_ERR_INVALID_TRIGGER;
                goto end;
        }
@@ -3266,7 +3272,7 @@ int lttng_unregister_trigger(struct lttng_trigger *trigger)
        */
        message_lsm = (struct lttcomm_session_msg *) message.buffer.data;
 
-       ret = lttng_trigger_serialize(trigger, &message);
+       ret = lttng_trigger_serialize(copy, &message);
        if (ret < 0) {
                ret = -LTTNG_ERR_UNK;
                goto end;
@@ -3294,6 +3300,7 @@ int lttng_unregister_trigger(struct lttng_trigger *trigger)
 
        ret = 0;
 end:
+       lttng_trigger_destroy(copy);
        lttng_payload_reset(&message);
        lttng_payload_reset(&reply);
        return ret;
index cc554195667519125af0f902f19af83061f56e55..2ec92262ce11b7d911f341f149659fe5054aec46 100644 (file)
@@ -41,7 +41,8 @@ TESTS = tools/filtering/test_invalid_filter \
        tools/clear/test_kernel \
        tools/tracker/test_event_tracker \
        tools/trigger/test_add_trigger_cli \
-       tools/trigger/test_list_triggers_cli
+       tools/trigger/test_list_triggers_cli \
+       tools/trigger/test_remove_trigger_cli
 
 if HAVE_LIBLTTNG_UST_CTL
 SUBDIRS += ust
index dcd15b4d1505d1c288178f68017af61326e6fadf..dcc5d98b0f9621de84665a61e39551821eae45a6 100644 (file)
@@ -1,7 +1,9 @@
 noinst_SCRIPTS = test_add_trigger_cli \
-       test_list_triggers_cli
+       test_list_triggers_cli \
+       test_remove_trigger_cli
 EXTRA_DIST = test_add_trigger_cli \
-       test_list_triggers_cli
+       test_list_triggers_cli \
+       test_remove_trigger_cli
 
 all-local:
        @if [ x"$(srcdir)" != x"$(builddir)" ]; then \
diff --git a/tests/regression/tools/trigger/test_remove_trigger_cli b/tests/regression/tools/trigger/test_remove_trigger_cli
new file mode 100755 (executable)
index 0000000..168227a
--- /dev/null
@@ -0,0 +1,116 @@
+#!/bin/bash
+#
+# Copyright (C) - 2020 EfficiOS, inc
+#
+# This library is free software; you can redistribute it and/or modify it under
+# the terms of the GNU Lesser General Public License as published by the Free
+# Software Foundation; version 2.1 of the License.
+#
+# 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
+
+# Test the `lttng remove-trigger` command line interface.
+
+CURDIR="$(dirname "$0")"
+TESTDIR="$CURDIR/../../.."
+
+# shellcheck source=../../../utils/utils.sh
+source "$TESTDIR/utils/utils.sh"
+
+plan_tests 17
+
+FULL_LTTNG_BIN="${TESTDIR}/../src/bin/lttng/${LTTNG_BIN}"
+
+tmp_stdout=$(mktemp -t test_list_triggers_cli_stdout.XXXXXX)
+tmp_stderr=$(mktemp -t test_list_triggers_cli_stderr.XXXXXX)
+tmp_expected_stdout=$(mktemp -t test_list_triggers_cli_expected_stdout.XXXXXX)
+
+uid=$(id --user)
+gid=$(id --group)
+
+function add_trigger ()
+{
+       "${FULL_LTTNG_BIN}" add-trigger "$@"
+       ok $? "add trigger \`$*\`: exit code is 0"
+}
+
+function list_triggers ()
+{
+       local test_name="$1"
+       local expected_stdout_file="$2"
+
+       "${FULL_LTTNG_BIN}" list-triggers > "${tmp_stdout}" 2> "${tmp_stderr}"
+       ok $? "${test_name}: exit code is 0"
+
+       diff -u "${expected_stdout_file}" "${tmp_stdout}"
+       ok $? "${test_name}: expected stdout"
+
+       diff -u /dev/null "${tmp_stderr}"
+       ok $? "${test_name}: expected stderr"
+}
+
+function remove_trigger ()
+{
+       local id="$1"
+       local test_name="remove trigger ${id}"
+
+       "${FULL_LTTNG_BIN}" remove-trigger "${id}" > "${tmp_stdout}" 2> "${tmp_stderr}"
+       ok $? "${test_name}: exit code is 0"
+
+       diff -u <(echo "Removed trigger \`${id}\`.") "${tmp_stdout}"
+       ok $? "${test_name}: expected stdout"
+
+       diff -u /dev/null "${tmp_stderr}"
+       ok $? "${test_name}: expected stderr"
+}
+
+# shellcheck disable=SC2119
+start_lttng_sessiond_notap
+
+# Add a few triggers
+add_trigger --condition on-event -u -a --action notify
+add_trigger --id ABC --condition on-event aaa -u --filter 'p == 2' --action notify
+
+cat > "${tmp_expected_stdout}" <<- EOF
+- id: ABC
+  user id: ${uid}
+  condition: event rule hit
+    rule: aaa (type: tracepoint, domain: ust, filter: p == 2)
+  actions:
+    notify
+- id: T0
+  user id: ${uid}
+  condition: event rule hit
+    rule: * (type: tracepoint, domain: ust)
+  actions:
+    notify
+EOF
+list_triggers "two triggers left" "${tmp_expected_stdout}"
+
+remove_trigger "ABC"
+
+cat > "${tmp_expected_stdout}" <<- EOF
+- id: T0
+  user id: ${uid}
+  condition: event rule hit
+    rule: * (type: tracepoint, domain: ust)
+  actions:
+    notify
+EOF
+list_triggers "one trigger left" "${tmp_expected_stdout}"
+
+remove_trigger "T0"
+
+list_triggers "no triggers left" "/dev/null"
+
+# Cleanup
+stop_lttng_sessiond_notap
+rm -f "${tmp_stdout}"
+rm -f "${tmp_stderr}"
+rm -f "${tmp_expected_stdout}"
This page took 0.037105 seconds and 4 git commands to generate.