From b61776fb63d4bb14df77c0b5a15de28beed7ddfc Mon Sep 17 00:00:00 2001 From: Simon Marchi Date: Mon, 20 Jan 2020 16:39:56 -0500 Subject: [PATCH] lttng: Add remove-trigger command MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit Signed-off-by: Simon Marchi Signed-off-by: Jérémie Galarneau Change-Id: I323ddc181c9214dcf4ae66e23a382451f6582fff Depends-on: lttng-ust: I5a800fc92e588c2a6a0e26282b0ad5f31c044479 --- doc/man/Makefile.am | 1 + doc/man/lttng-remove-trigger.1.txt | 38 ++++ include/lttng/trigger/trigger-internal.h | 5 +- include/lttng/trigger/trigger.h | 2 +- src/bin/lttng/Makefile.am | 1 + src/bin/lttng/command.h | 1 + src/bin/lttng/commands/remove_trigger.c | 191 ++++++++++++++++++ src/bin/lttng/lttng.c | 1 + src/common/trigger.c | 33 ++- src/lib/lttng-ctl/lttng-ctl.c | 23 ++- tests/regression/Makefile.am | 3 +- tests/regression/tools/trigger/Makefile.am | 6 +- .../tools/trigger/test_remove_trigger_cli | 116 +++++++++++ 13 files changed, 407 insertions(+), 14 deletions(-) create mode 100644 doc/man/lttng-remove-trigger.1.txt create mode 100644 src/bin/lttng/commands/remove_trigger.c create mode 100755 tests/regression/tools/trigger/test_remove_trigger_cli diff --git a/doc/man/Makefile.am b/doc/man/Makefile.am index 769dca470..5ae6ffbe3 100644 --- a/doc/man/Makefile.am +++ b/doc/man/Makefile.am @@ -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 index 000000000..645ef152f --- /dev/null +++ b/doc/man/lttng-remove-trigger.1.txt @@ -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) diff --git a/include/lttng/trigger/trigger-internal.h b/include/lttng/trigger/trigger-internal.h index 20989bd99..21c269bef 100644 --- a/include/lttng/trigger/trigger-internal.h +++ b/include/lttng/trigger/trigger-internal.h @@ -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 */ diff --git a/include/lttng/trigger/trigger.h b/include/lttng/trigger/trigger.h index 2a7d4e36b..5fef53fd4 100644 --- a/include/lttng/trigger/trigger.h +++ b/include/lttng/trigger/trigger.h @@ -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. diff --git a/src/bin/lttng/Makefile.am b/src/bin/lttng/Makefile.am index 7a305d49a..50ab92988 100644 --- a/src/bin/lttng/Makefile.am +++ b/src/bin/lttng/Makefile.am @@ -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 diff --git a/src/bin/lttng/command.h b/src/bin/lttng/command.h index 8a318c6f7..bf0045210 100644 --- a/src/bin/lttng/command.h +++ b/src/bin/lttng/command.h @@ -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 index 000000000..1fabc70ec --- /dev/null +++ b/src/bin/lttng/commands/remove_trigger.c @@ -0,0 +1,191 @@ +/* + * Copyright (C) 2021 Simon Marchi + * + * SPDX-License-Identifier: GPL-2.0-only + * + */ + +#include "../command.h" +#include "common/argpar/argpar.h" +#include +#include + +#ifdef LTTNG_EMBED_HELP +static const char help_msg[] = +#include +; +#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; +} diff --git a/src/bin/lttng/lttng.c b/src/bin/lttng/lttng.c index e5642e24c..437a9cc4c 100644 --- a/src/bin/lttng/lttng.c +++ b/src/bin/lttng/lttng.c @@ -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}, diff --git a/src/common/trigger.c b/src/common/trigger.c index 55ab99729..04b3e7f11 100644 --- a/src/common/trigger.c +++ b/src/common/trigger.c @@ -23,7 +23,7 @@ #include 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(©_buffer); + + ret = lttng_trigger_serialize(trigger, ©_buffer); + if (ret < 0) { + goto end; + } + + { + struct lttng_payload_view view = + lttng_payload_view_from_payload( + ©_buffer, 0, -1); + ret = lttng_trigger_create_from_payload( + &view, ©); + if (ret < 0) { + copy = NULL; + goto end; + } + } + +end: + lttng_payload_reset(©_buffer); + return copy; +} diff --git a/src/lib/lttng-ctl/lttng-ctl.c b/src/lib/lttng-ctl/lttng-ctl.c index 5b774e1d6..5529b3364 100644 --- a/src/lib/lttng-ctl/lttng-ctl.c +++ b/src/lib/lttng-ctl/lttng-ctl.c @@ -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; diff --git a/tests/regression/Makefile.am b/tests/regression/Makefile.am index cc5541956..2ec92262c 100644 --- a/tests/regression/Makefile.am +++ b/tests/regression/Makefile.am @@ -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 diff --git a/tests/regression/tools/trigger/Makefile.am b/tests/regression/tools/trigger/Makefile.am index dcd15b4d1..dcc5d98b0 100644 --- a/tests/regression/tools/trigger/Makefile.am +++ b/tests/regression/tools/trigger/Makefile.am @@ -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 index 000000000..168227a4a --- /dev/null +++ b/tests/regression/tools/trigger/test_remove_trigger_cli @@ -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}" -- 2.34.1