lttng-disable-rotation \
lttng-clear \
lttng-add-trigger \
+ lttng-remove-trigger \
lttng-list-triggers
MAN3_NAMES =
--- /dev/null
+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)
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(
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 */
*
* 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.
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
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[]);
--- /dev/null
+/*
+ * 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;
+}
{ "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},
#include <inttypes.h>
LTTNG_HIDDEN
-bool lttng_trigger_validate(struct lttng_trigger *trigger)
+bool lttng_trigger_validate(const struct lttng_trigger *trigger)
{
bool valid;
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;
+}
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,
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
* "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;
}
}
- if (!lttng_trigger_validate(trigger)) {
+ if (!lttng_trigger_validate(copy)) {
ret = -LTTNG_ERR_INVALID_TRIGGER;
goto end;
}
*/
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;
ret = 0;
end:
+ lttng_trigger_destroy(copy);
lttng_payload_reset(&message);
lttng_payload_reset(&reply);
return ret;
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
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 \
--- /dev/null
+#!/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}"