+++ /dev/null
-/*
- * Copyright (C) 2021 Simon Marchi <simon.marchi@efficios.com>
- *
- * SPDX-License-Identifier: GPL-2.0-only
- *
- */
-
-#include <ctype.h>
-#include <stdio.h>
-#include <string.h>
-
-#include "../command.h"
-#include "../loglevel.h"
-#include "../uprobe.h"
-
-#include "common/argpar/argpar.h"
-#include "common/dynamic-array.h"
-#include "common/mi-lttng.h"
-#include "common/string-utils/string-utils.h"
-#include "common/utils.h"
-#include <lttng/domain-internal.h>
-/* For lttng_event_rule_type_str(). */
-#include <lttng/event-rule/event-rule-internal.h>
-#include <lttng/lttng.h>
-#include "common/filter/filter-ast.h"
-#include "common/filter/filter-ir.h"
-#include "common/dynamic-array.h"
-
-#if (LTTNG_SYMBOL_NAME_LEN == 256)
-#define LTTNG_SYMBOL_NAME_LEN_SCANF_IS_A_BROKEN_API "255"
-#endif
-
-#ifdef LTTNG_EMBED_HELP
-static const char help_msg[] =
-#include <lttng-add-trigger.1.h>
-;
-#endif
-
-enum {
- OPT_HELP,
- OPT_LIST_OPTIONS,
-
- OPT_CONDITION,
- OPT_ACTION,
- OPT_ID,
- OPT_OWNER_UID,
- OPT_RATE_POLICY,
-
- OPT_NAME,
- OPT_FILTER,
- OPT_EXCLUDE_NAME,
- OPT_EVENT_NAME,
- OPT_LOG_LEVEL,
-
- OPT_TYPE,
- OPT_LOCATION,
-
- OPT_MAX_SIZE,
- OPT_DATA_URL,
- OPT_CTRL_URL,
- OPT_URL,
- OPT_PATH,
-
- OPT_CAPTURE,
-};
-
-static const struct argpar_opt_descr event_rule_opt_descrs[] = {
- { OPT_FILTER, 'f', "filter", true },
- { OPT_NAME, 'n', "name", true },
- { OPT_EXCLUDE_NAME, 'x', "exclude-name", true },
- { OPT_LOG_LEVEL, 'l', "log-level", true },
- { OPT_EVENT_NAME, 'E', "event-name", true },
-
- { OPT_TYPE, 't', "type", true },
- { OPT_LOCATION, 'L', "location", true },
-
- /* Capture descriptor */
- { OPT_CAPTURE, '\0', "capture", true },
-
- ARGPAR_OPT_DESCR_SENTINEL
-};
-
-static
-bool has_syscall_prefix(const char *arg)
-{
- bool matches = false;
- const char kernel_syscall_type_opt_prefix[] = "kernel:syscall";
- const size_t kernel_syscall_type_opt_prefix_len =
- sizeof(kernel_syscall_type_opt_prefix) - 1;
- const char syscall_type_opt_prefix[] = "syscall";
- const size_t syscall_type_opt_prefix_len =
- sizeof(syscall_type_opt_prefix) - 1;
-
- if (strncmp(arg, syscall_type_opt_prefix,
- syscall_type_opt_prefix_len) == 0) {
- matches = true;
- } else if (strncmp(arg, kernel_syscall_type_opt_prefix,
- kernel_syscall_type_opt_prefix_len) == 0) {
- matches = true;
- } else {
- matches = false;
- }
-
- return matches;
-}
-
-static
-bool assign_event_rule_type(enum lttng_event_rule_type *dest, const char *arg)
-{
- bool ret;
-
- if (*dest != LTTNG_EVENT_RULE_TYPE_UNKNOWN) {
- ERR("More than one `--type` was specified.");
- goto error;
- }
-
- if (strcmp(arg, "user") == 0 || strcmp(arg, "user:tracepoint") == 0) {
- *dest = LTTNG_EVENT_RULE_TYPE_USER_TRACEPOINT;
- } else if (strcmp(arg, "kernel") == 0 ||
- strcmp(arg, "kernel:tracepoint") == 0) {
- *dest = LTTNG_EVENT_RULE_TYPE_KERNEL_TRACEPOINT;
- } else if (strcmp(arg, "jul") == 0 || strcmp(arg, "jul:logging") == 0) {
- *dest = LTTNG_EVENT_RULE_TYPE_JUL_LOGGING;
- } else if (strcmp(arg, "log4j") == 0 ||
- strcmp(arg, "log4j:logging") == 0) {
- *dest = LTTNG_EVENT_RULE_TYPE_LOG4J_LOGGING;
- } else if (strcmp(arg, "python") == 0 ||
- strcmp(arg, "python:logging") == 0) {
- *dest = LTTNG_EVENT_RULE_TYPE_PYTHON_LOGGING;
- } else if (strcmp(arg, "kprobe") == 0 ||
- strcmp(arg, "kernel:kprobe") == 0) {
- *dest = LTTNG_EVENT_RULE_TYPE_KERNEL_KPROBE;
- } else if (strcmp(arg, "kernel:uprobe") == 0) {
- *dest = LTTNG_EVENT_RULE_TYPE_KERNEL_UPROBE;
- } else if (has_syscall_prefix(arg)) {
- /*
- * Matches the following:
- * - syscall
- * - syscall:entry
- * - syscall:exit
- * - syscall:entry+exit
- * - syscall:*
- * - kernel:syscall
- * - kernel:syscall:entry
- * - kernel:syscall:exit
- * - kernel:syscall:entry+exit
- * - kernel:syscall:*
- *
- * Validation for the right side is left to further usage sites.
- */
- *dest = LTTNG_EVENT_RULE_TYPE_KERNEL_SYSCALL;
- } else {
- ERR("Invalid `--type` value: %s", arg);
- goto error;
- }
-
- ret = true;
- goto end;
-
-error:
- ret = false;
-
-end:
- return ret;
-}
-
-static
-bool assign_string(char **dest, const char *src, const char *opt_name)
-{
- bool ret;
-
- if (*dest) {
- ERR("Duplicate '%s' given.", opt_name);
- goto error;
- }
-
- *dest = strdup(src);
- if (!*dest) {
- PERROR("Failed to allocate string '%s'.", opt_name);
- goto error;
- }
-
- ret = true;
- goto end;
-
-error:
- ret = false;
-
-end:
- return ret;
-}
-
-static bool parse_syscall_emission_site_from_type(const char *str,
- enum lttng_event_rule_kernel_syscall_emission_site *type)
-{
- bool ret = false;
- const char kernel_prefix[] = "kernel:";
- const size_t kernel_prefix_len = sizeof(kernel_prefix) - 1;
-
- /*
- * If the passed string is of the form "kernel:syscall*", move the
- * pointer passed "kernel:".
- */
- if (strncmp(str, kernel_prefix, kernel_prefix_len) == 0) {
- str = &str[kernel_prefix_len];
- }
-
- if (strcmp(str, "syscall") == 0 ||
- strcmp(str, "syscall:entry+exit") == 0) {
- *type = LTTNG_EVENT_RULE_KERNEL_SYSCALL_EMISSION_SITE_ENTRY_EXIT;
- } else if (strcmp(str, "syscall:entry") == 0) {
- *type = LTTNG_EVENT_RULE_KERNEL_SYSCALL_EMISSION_SITE_ENTRY;
- } else if (strcmp(str, "syscall:exit") == 0) {
- *type = LTTNG_EVENT_RULE_KERNEL_SYSCALL_EMISSION_SITE_EXIT;
- } else {
- goto error;
- }
-
- ret = true;
-
-error:
- return ret;
-}
-
-/*
- * Parse `str` as a log level against the passed event rule type.
- *
- * Return the log level in `*log_level`. Return true in `*log_level_only` if
- * the string specifies exactly this log level, false if it specifies at least
- * this log level.
- *
- * Return true if the string was successfully parsed as a log level string.
- */
-static bool parse_log_level_string(const char *str,
- enum lttng_event_rule_type event_rule_type,
- int *log_level,
- bool *log_level_only)
-{
- bool ret;
-
- switch (event_rule_type) {
- case LTTNG_EVENT_RULE_TYPE_USER_TRACEPOINT:
- {
- enum lttng_loglevel log_level_min, log_level_max;
- if (!loglevel_parse_range_string(
- str, &log_level_min, &log_level_max)) {
- goto error;
- }
-
- /* Only support VAL and VAL.. for now. */
- if (log_level_min != log_level_max &&
- log_level_max != LTTNG_LOGLEVEL_EMERG) {
- goto error;
- }
-
- *log_level = (int) log_level_min;
- *log_level_only = log_level_min == log_level_max;
- break;
- }
- case LTTNG_EVENT_RULE_TYPE_LOG4J_LOGGING:
- {
- enum lttng_loglevel_log4j log_level_min, log_level_max;
- if (!loglevel_log4j_parse_range_string(
- str, &log_level_min, &log_level_max)) {
- goto error;
- }
-
- /* Only support VAL and VAL.. for now. */
- if (log_level_min != log_level_max &&
- log_level_max != LTTNG_LOGLEVEL_LOG4J_FATAL) {
- goto error;
- }
-
- *log_level = (int) log_level_min;
- *log_level_only = log_level_min == log_level_max;
- break;
- }
- case LTTNG_EVENT_RULE_TYPE_JUL_LOGGING:
- {
- enum lttng_loglevel_jul log_level_min, log_level_max;
- if (!loglevel_jul_parse_range_string(
- str, &log_level_min, &log_level_max)) {
- goto error;
- }
-
- /* Only support VAL and VAL.. for now. */
- if (log_level_min != log_level_max &&
- log_level_max != LTTNG_LOGLEVEL_JUL_SEVERE) {
- goto error;
- }
-
- *log_level = (int) log_level_min;
- *log_level_only = log_level_min == log_level_max;
- break;
- }
- case LTTNG_EVENT_RULE_TYPE_PYTHON_LOGGING:
- {
- enum lttng_loglevel_python log_level_min, log_level_max;
- if (!loglevel_python_parse_range_string(
- str, &log_level_min, &log_level_max)) {
- goto error;
- }
-
- /* Only support VAL and VAL.. for now. */
- if (log_level_min != log_level_max &&
- log_level_max !=
- LTTNG_LOGLEVEL_PYTHON_CRITICAL) {
- goto error;
- }
-
- *log_level = (int) log_level_min;
- *log_level_only = log_level_min == log_level_max;
- break;
- }
- default:
- /* Invalid domain type. */
- abort();
- }
-
- ret = true;
- goto end;
-
-error:
- ret = false;
-
-end:
- return ret;
-}
-
-static int parse_kernel_probe_opts(const char *source,
- struct lttng_kernel_probe_location **location)
-{
- int ret = 0;
- int match;
- char s_hex[19];
- char name[LTTNG_SYMBOL_NAME_LEN];
- char *symbol_name = NULL;
- uint64_t offset;
-
- /* Check for symbol+offset. */
- match = sscanf(source,
- "%" LTTNG_SYMBOL_NAME_LEN_SCANF_IS_A_BROKEN_API
- "[^'+']+%18s",
- name, s_hex);
- if (match == 2) {
- if (*s_hex == '\0') {
- ERR("Kernel probe symbol offset is missing.");
- goto error;
- }
-
- symbol_name = strndup(name, LTTNG_SYMBOL_NAME_LEN);
- if (!symbol_name) {
- PERROR("Failed to copy kernel probe location symbol name.");
- goto error;
- }
- offset = strtoul(s_hex, NULL, 0);
-
- *location = lttng_kernel_probe_location_symbol_create(
- symbol_name, offset);
- if (!*location) {
- ERR("Failed to create symbol kernel probe location.");
- goto error;
- }
-
- goto end;
- }
-
- /* Check for symbol. */
- if (isalpha(name[0]) || name[0] == '_') {
- match = sscanf(source,
- "%" LTTNG_SYMBOL_NAME_LEN_SCANF_IS_A_BROKEN_API
- "s",
- name);
- if (match == 1) {
- symbol_name = strndup(name, LTTNG_SYMBOL_NAME_LEN);
- if (!symbol_name) {
- ERR("Failed to copy kernel probe location symbol name.");
- goto error;
- }
-
- *location = lttng_kernel_probe_location_symbol_create(
- symbol_name, 0);
- if (!*location) {
- ERR("Failed to create symbol kernel probe location.");
- goto error;
- }
-
- goto end;
- }
- }
-
- /* Check for address. */
- match = sscanf(source, "%18s", s_hex);
- if (match > 0) {
- uint64_t address;
-
- if (*s_hex == '\0') {
- ERR("Invalid kernel probe location address.");
- goto error;
- }
-
- address = strtoul(s_hex, NULL, 0);
- *location = lttng_kernel_probe_location_address_create(address);
- if (!*location) {
- ERR("Failed to create symbol kernel probe location.");
- goto error;
- }
-
- goto end;
- }
-
-error:
- /* No match */
- ret = -1;
- *location = NULL;
-
-end:
- free(symbol_name);
- return ret;
-}
-
-static
-struct lttng_event_expr *ir_op_load_expr_to_event_expr(
- const struct ir_load_expression *load_expr,
- const char *capture_str)
-{
- char *provider_name = NULL;
- struct lttng_event_expr *event_expr = NULL;
- const struct ir_load_expression_op *load_expr_op = load_expr->child;
- const enum ir_load_expression_type load_expr_child_type =
- load_expr_op->type;
-
- switch (load_expr_child_type) {
- case IR_LOAD_EXPRESSION_GET_PAYLOAD_ROOT:
- case IR_LOAD_EXPRESSION_GET_CONTEXT_ROOT:
- {
- const char *field_name;
-
- load_expr_op = load_expr_op->next;
- LTTNG_ASSERT(load_expr_op);
- LTTNG_ASSERT(load_expr_op->type == IR_LOAD_EXPRESSION_GET_SYMBOL);
- field_name = load_expr_op->u.symbol;
- LTTNG_ASSERT(field_name);
-
- event_expr = load_expr_child_type == IR_LOAD_EXPRESSION_GET_PAYLOAD_ROOT ?
- lttng_event_expr_event_payload_field_create(field_name) :
- lttng_event_expr_channel_context_field_create(field_name);
- if (!event_expr) {
- ERR("Failed to create %s event expression: field name = `%s`.",
- load_expr_child_type == IR_LOAD_EXPRESSION_GET_PAYLOAD_ROOT ?
- "payload field" : "channel context",
- field_name);
- goto error;
- }
-
- break;
- }
- case IR_LOAD_EXPRESSION_GET_APP_CONTEXT_ROOT:
- {
- const char *colon;
- const char *type_name;
- const char *field_name;
-
- load_expr_op = load_expr_op->next;
- LTTNG_ASSERT(load_expr_op);
- LTTNG_ASSERT(load_expr_op->type == IR_LOAD_EXPRESSION_GET_SYMBOL);
- field_name = load_expr_op->u.symbol;
- LTTNG_ASSERT(field_name);
-
- /*
- * The field name needs to be of the form PROVIDER:TYPE. We
- * split it here.
- */
- colon = strchr(field_name, ':');
- if (!colon) {
- ERR("Invalid app-specific context field name: missing colon in `%s`.",
- field_name);
- goto error;
- }
-
- type_name = colon + 1;
- if (*type_name == '\0') {
- ERR("Invalid app-specific context field name: missing type name after colon in `%s`.",
- field_name);
- goto error;
- }
-
- provider_name = strndup(field_name, colon - field_name);
- if (!provider_name) {
- PERROR("Failed to allocate field name string");
- goto error;
- }
-
- event_expr = lttng_event_expr_app_specific_context_field_create(
- provider_name, type_name);
- if (!event_expr) {
- ERR("Failed to create app-specific context field event expression: provider name = `%s`, type name = `%s`",
- provider_name, type_name);
- goto error;
- }
-
- break;
- }
- default:
- ERR("%s: unexpected load expr type %d.", __func__,
- load_expr_op->type);
- abort();
- }
-
- load_expr_op = load_expr_op->next;
-
- /* There may be a single array index after that. */
- if (load_expr_op->type == IR_LOAD_EXPRESSION_GET_INDEX) {
- struct lttng_event_expr *index_event_expr;
- const uint64_t index = load_expr_op->u.index;
-
- index_event_expr = lttng_event_expr_array_field_element_create(event_expr, index);
- if (!index_event_expr) {
- ERR("Failed to create array field element event expression.");
- goto error;
- }
-
- event_expr = index_event_expr;
- load_expr_op = load_expr_op->next;
- }
-
- switch (load_expr_op->type) {
- case IR_LOAD_EXPRESSION_LOAD_FIELD:
- /*
- * This is what we expect, IR_LOAD_EXPRESSION_LOAD_FIELD is
- * always found at the end of the chain.
- */
- break;
- case IR_LOAD_EXPRESSION_GET_SYMBOL:
- ERR("While parsing expression `%s`: Capturing subfields is not supported.",
- capture_str);
- goto error;
-
- default:
- ERR("%s: unexpected load expression operator %s.", __func__,
- ir_load_expression_type_str(load_expr_op->type));
- abort();
- }
-
- goto end;
-
-error:
- lttng_event_expr_destroy(event_expr);
- event_expr = NULL;
-
-end:
- free(provider_name);
-
- return event_expr;
-}
-
-static
-struct lttng_event_expr *ir_op_load_to_event_expr(
- const struct ir_op *ir, const char *capture_str)
-{
- struct lttng_event_expr *event_expr = NULL;
-
- LTTNG_ASSERT(ir->op == IR_OP_LOAD);
-
- switch (ir->data_type) {
- case IR_DATA_EXPRESSION:
- {
- const struct ir_load_expression *ir_load_expr =
- ir->u.load.u.expression;
-
- event_expr = ir_op_load_expr_to_event_expr(
- ir_load_expr, capture_str);
- break;
- }
- default:
- ERR("%s: unexpected data type: %s.", __func__,
- ir_data_type_str(ir->data_type));
- abort();
- }
-
- return event_expr;
-}
-
-static
-const char *ir_operator_type_human_str(enum ir_op_type op)
-{
- const char *name;
-
- switch (op) {
- case IR_OP_BINARY:
- name = "Binary";
- break;
- case IR_OP_UNARY:
- name = "Unary";
- break;
- case IR_OP_LOGICAL:
- name = "Logical";
- break;
- default:
- abort();
- }
-
- return name;
-}
-
-static
-struct lttng_event_expr *ir_op_root_to_event_expr(const struct ir_op *ir,
- const char *capture_str)
-{
- struct lttng_event_expr *event_expr = NULL;
-
- LTTNG_ASSERT(ir->op == IR_OP_ROOT);
- ir = ir->u.root.child;
-
- switch (ir->op) {
- case IR_OP_LOAD:
- event_expr = ir_op_load_to_event_expr(ir, capture_str);
- break;
- case IR_OP_BINARY:
- case IR_OP_UNARY:
- case IR_OP_LOGICAL:
- ERR("While parsing expression `%s`: %s operators are not allowed in capture expressions.",
- capture_str,
- ir_operator_type_human_str(ir->op));
- break;
- default:
- ERR("%s: unexpected IR op type: %s.", __func__,
- ir_op_type_str(ir->op));
- abort();
- }
-
- return event_expr;
-}
-
-static
-void destroy_event_expr(void *ptr)
-{
- lttng_event_expr_destroy(ptr);
-}
-
-struct parse_event_rule_res {
- /* Owned by this. */
- struct lttng_event_rule *er;
-
- /* Array of `struct lttng_event_expr *` */
- struct lttng_dynamic_pointer_array capture_descriptors;
-};
-
-static
-struct parse_event_rule_res parse_event_rule(int *argc, const char ***argv)
-{
- enum lttng_event_rule_type event_rule_type =
- LTTNG_EVENT_RULE_TYPE_UNKNOWN;
- struct argpar_state *state;
- struct argpar_item *item = NULL;
- char *error = NULL;
- int consumed_args = -1;
- struct lttng_kernel_probe_location *kernel_probe_location = NULL;
- struct lttng_userspace_probe_location *userspace_probe_location = NULL;
- struct parse_event_rule_res res = { 0 };
- struct lttng_event_expr *event_expr = NULL;
- struct filter_parser_ctx *parser_ctx = NULL;
- struct lttng_log_level_rule *log_level_rule = NULL;
-
- /* Event rule type option */
- char *event_rule_type_str = NULL;
-
- /* Tracepoint and syscall options. */
- char *name = NULL;
- /* Array of strings. */
- struct lttng_dynamic_pointer_array exclude_names;
-
- /* For userspace / kernel probe and function. */
- char *location = NULL;
- char *event_name = NULL;
-
- /* Filter. */
- char *filter = NULL;
-
- /* Log level. */
- char *log_level_str = NULL;
-
- lttng_dynamic_pointer_array_init(&res.capture_descriptors,
- destroy_event_expr);
-
- lttng_dynamic_pointer_array_init(&exclude_names, free);
-
- state = argpar_state_create(*argc, *argv, event_rule_opt_descrs);
- if (!state) {
- ERR("Failed to allocate an argpar state.");
- goto error;
- }
-
- while (true) {
- enum argpar_state_parse_next_status status;
-
- ARGPAR_ITEM_DESTROY_AND_RESET(item);
- status = argpar_state_parse_next(state, &item, &error);
- if (status == ARGPAR_STATE_PARSE_NEXT_STATUS_ERROR) {
- ERR("%s", error);
- goto error;
- } else if (status == ARGPAR_STATE_PARSE_NEXT_STATUS_ERROR_UNKNOWN_OPT) {
- /* Just stop parsing here. */
- break;
- } else if (status == ARGPAR_STATE_PARSE_NEXT_STATUS_END) {
- break;
- }
-
- LTTNG_ASSERT(status == ARGPAR_STATE_PARSE_NEXT_STATUS_OK);
-
- 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_TYPE:
- if (!assign_event_rule_type(&event_rule_type,
- item_opt->arg)) {
- goto error;
- }
-
- /* Save the string for later use. */
- if (!assign_string(&event_rule_type_str,
- item_opt->arg,
- "--type/-t")) {
- goto error;
- }
-
- break;
- case OPT_LOCATION:
- if (!assign_string(&location,
- item_opt->arg,
- "--location/-L")) {
- goto error;
- }
-
- break;
- case OPT_EVENT_NAME:
- if (!assign_string(&event_name,
- item_opt->arg,
- "--event-name/-E")) {
- goto error;
- }
-
- break;
- case OPT_FILTER:
- if (!assign_string(&filter, item_opt->arg,
- "--filter/-f")) {
- goto error;
- }
-
- break;
- case OPT_NAME:
- if (!assign_string(&name, item_opt->arg,
- "--name/-n")) {
- goto error;
- }
-
- break;
- case OPT_EXCLUDE_NAME:
- {
- int ret;
-
- ret = lttng_dynamic_pointer_array_add_pointer(
- &exclude_names,
- strdup(item_opt->arg));
- if (ret != 0) {
- ERR("Failed to add pointer to dynamic pointer array.");
- goto error;
- }
-
- break;
- }
- case OPT_LOG_LEVEL:
- if (!assign_string(&log_level_str,
- item_opt->arg, "--log-level/-l")) {
- goto error;
- }
-
- break;
- case OPT_CAPTURE:
- {
- int ret;
- const char *capture_str = item_opt->arg;
-
- ret = filter_parser_ctx_create_from_filter_expression(
- capture_str, &parser_ctx);
- if (ret) {
- ERR("Failed to parse capture expression `%s`.",
- capture_str);
- goto error;
- }
-
- event_expr = ir_op_root_to_event_expr(
- parser_ctx->ir_root,
- capture_str);
- if (!event_expr) {
- /*
- * ir_op_root_to_event_expr has printed
- * an error message.
- */
- goto error;
- }
-
- ret = lttng_dynamic_pointer_array_add_pointer(
- &res.capture_descriptors,
- event_expr);
- if (ret) {
- goto error;
- }
-
- /*
- * The ownership of event expression was
- * transferred to the dynamic array.
- */
- event_expr = NULL;
-
- break;
- }
- default:
- abort();
- }
- } else {
- const struct argpar_item_non_opt *item_non_opt =
- (const struct argpar_item_non_opt *)
- item;
-
- /* Don't accept non-option arguments. */
- ERR("Unexpected argument '%s'", item_non_opt->arg);
- goto error;
- }
- }
-
- if (event_rule_type == LTTNG_EVENT_RULE_TYPE_UNKNOWN) {
- ERR("Event rule requires a --type.");
- goto error;
- }
-
- /*
- * Option --name is applicable to event rules of type kernel, user, jul,
- * log4j,python and syscall. If --name is omitted, it is implicitly
- * "*".
- */
- switch (event_rule_type) {
- case LTTNG_EVENT_RULE_TYPE_USER_TRACEPOINT:
- case LTTNG_EVENT_RULE_TYPE_KERNEL_TRACEPOINT:
- case LTTNG_EVENT_RULE_TYPE_JUL_LOGGING:
- case LTTNG_EVENT_RULE_TYPE_LOG4J_LOGGING:
- case LTTNG_EVENT_RULE_TYPE_PYTHON_LOGGING:
- case LTTNG_EVENT_RULE_TYPE_KERNEL_SYSCALL:
- if (!name) {
- name = strdup("*");
- }
- break;
-
- default:
- if (name) {
- ERR("Can't use --name with %s event rules.",
- lttng_event_rule_type_str(
- event_rule_type));
- goto error;
- }
-
- if (lttng_dynamic_pointer_array_get_count(&exclude_names) > 0) {
- ERR("Can't use --exclude-name/-x with %s event rules.",
- lttng_event_rule_type_str(
- event_rule_type));
- goto error;
- }
- }
-
- /*
- * Option --location is only applicable to (and mandatory for) event
- * rules of type {k,u}probe and function.
- *
- * Option --event-name is only applicable to event rules of type probe.
- * If omitted, it defaults to the location.
- */
- switch (event_rule_type) {
- case LTTNG_EVENT_RULE_TYPE_KERNEL_KPROBE:
- case LTTNG_EVENT_RULE_TYPE_KERNEL_UPROBE:
- if (!location) {
- ERR("Event rule of type %s requires a --location.",
- lttng_event_rule_type_str(event_rule_type));
- goto error;
- }
-
- if (!event_name) {
- event_name = strdup(location);
- }
-
- break;
-
- default:
- if (location) {
- ERR("Can't use --location with %s event rules.",
- lttng_event_rule_type_str(event_rule_type));
- goto error;
- }
-
- if (event_name) {
- ERR("Can't use --event-name with %s event rules.",
- lttng_event_rule_type_str(
- event_rule_type));
- goto error;
- }
- }
-
- /*
- * Update *argc and *argv so our caller can keep parsing what follows.
- */
- consumed_args = argpar_state_get_ingested_orig_args(state);
- LTTNG_ASSERT(consumed_args >= 0);
- *argc -= consumed_args;
- *argv += consumed_args;
-
- /*
- * Adding a filter to a probe, function or userspace-probe would be
- * denied by the kernel tracer as it's not supported at the moment. We
- * do an early check here to warn the user.
- */
- if (filter) {
- switch (event_rule_type) {
- case LTTNG_EVENT_RULE_TYPE_USER_TRACEPOINT:
- case LTTNG_EVENT_RULE_TYPE_KERNEL_TRACEPOINT:
- case LTTNG_EVENT_RULE_TYPE_JUL_LOGGING:
- case LTTNG_EVENT_RULE_TYPE_LOG4J_LOGGING:
- case LTTNG_EVENT_RULE_TYPE_PYTHON_LOGGING:
- case LTTNG_EVENT_RULE_TYPE_KERNEL_SYSCALL:
- break;
- default:
- ERR("Filter expressions are not supported for %s event rules.",
- lttng_event_rule_type_str(event_rule_type));
- goto error;
- }
- }
-
- /*
- * If --exclude-name/-x was passed, split it into an exclusion list.
- * Exclusions are only supported by
- * LTTNG_EVENT_RULE_TYPE_USER_TRACEPOINT for now.
- */
- if (lttng_dynamic_pointer_array_get_count(&exclude_names) > 0) {
- if (event_rule_type != LTTNG_EVENT_RULE_TYPE_USER_TRACEPOINT) {
- ERR("Event name exclusions are not yet implemented for %s event rules.",
- lttng_event_rule_type_str(event_rule_type));
- goto error;
- }
-
- if (validate_exclusion_list(name, &exclude_names) != 0) {
- /*
- * Assume validate_exclusion_list already prints an
- * error message.
- */
- goto error;
- }
- }
-
- if (log_level_str) {
- switch (event_rule_type) {
- case LTTNG_EVENT_RULE_TYPE_USER_TRACEPOINT:
- case LTTNG_EVENT_RULE_TYPE_JUL_LOGGING:
- case LTTNG_EVENT_RULE_TYPE_LOG4J_LOGGING:
- case LTTNG_EVENT_RULE_TYPE_PYTHON_LOGGING:
- {
- int log_level;
- bool log_level_only;
-
- if (strcmp(log_level_str, "..") == 0) {
- /*
- * ".." is the same as passing no log level
- * option and correspond to the "ANY" case.
- */
- break;
- }
-
- if (!parse_log_level_string(log_level_str, event_rule_type,
- &log_level, &log_level_only)) {
- ERR("Failed to parse log level string `%s`.",
- log_level_str);
- goto error;
- }
-
- if (log_level_only) {
- log_level_rule = lttng_log_level_rule_exactly_create(log_level);
- } else {
- log_level_rule = lttng_log_level_rule_at_least_as_severe_as_create(log_level);
- }
-
- if (log_level_rule == NULL) {
- ERR("Failed to create log level rule object.");
- goto error;
- }
- break;
- }
- default:
- ERR("Log levels are not supported for %s event rules.",
- lttng_event_rule_type_str(event_rule_type));
- goto error;
- }
- }
-
- /* Finally, create the event rule object. */
- switch (event_rule_type) {
- case LTTNG_EVENT_RULE_TYPE_USER_TRACEPOINT:
- {
- enum lttng_event_rule_status event_rule_status;
-
- res.er = lttng_event_rule_user_tracepoint_create();
- if (!res.er) {
- ERR("Failed to create user_tracepoint event rule.");
- goto error;
- }
-
- /* Set pattern. */
- event_rule_status = lttng_event_rule_user_tracepoint_set_name_pattern(
- res.er, name);
- if (event_rule_status != LTTNG_EVENT_RULE_STATUS_OK) {
- ERR("Failed to set user_tracepoint event rule's pattern to '%s'.",
- name);
- goto error;
- }
-
- /* Set filter. */
- if (filter) {
- event_rule_status = lttng_event_rule_user_tracepoint_set_filter(
- res.er, filter);
- if (event_rule_status != LTTNG_EVENT_RULE_STATUS_OK) {
- ERR("Failed to set user_tracepoint event rule's filter to '%s'.",
- filter);
- goto error;
- }
- }
-
- /* Set exclusion list. */
- if (lttng_dynamic_pointer_array_get_count(&exclude_names) > 0) {
- int n;
- int count = lttng_dynamic_pointer_array_get_count(
- &exclude_names);
-
- for (n = 0; n < count; n++) {
- const char *exclude_name =
- lttng_dynamic_pointer_array_get_pointer(
- &exclude_names,
- n);
-
- event_rule_status =
- lttng_event_rule_user_tracepoint_add_name_pattern_exclusion(
- res.er,
- exclude_name);
- if (event_rule_status !=
- LTTNG_EVENT_RULE_STATUS_OK) {
- ERR("Failed to set user_tracepoint exclusion list element '%s'",
- exclude_name);
- goto error;
- }
- }
- }
-
- if (log_level_rule) {
- event_rule_status =
- lttng_event_rule_user_tracepoint_set_log_level_rule(
- res.er, log_level_rule);
-
- if (event_rule_status != LTTNG_EVENT_RULE_STATUS_OK) {
- ERR("Failed to set log level on event fule.");
- goto error;
- }
- }
-
- break;
- }
- case LTTNG_EVENT_RULE_TYPE_KERNEL_TRACEPOINT:
- {
- enum lttng_event_rule_status event_rule_status;
-
- res.er = lttng_event_rule_kernel_tracepoint_create();
- if (!res.er) {
- ERR("Failed to create kernel_tracepoint event rule.");
- goto error;
- }
-
- /* Set pattern. */
- event_rule_status = lttng_event_rule_kernel_tracepoint_set_name_pattern(
- res.er, name);
- if (event_rule_status != LTTNG_EVENT_RULE_STATUS_OK) {
- ERR("Failed to set kernel_tracepoint event rule's pattern to '%s'.",
- name);
- goto error;
- }
-
- /* Set filter. */
- if (filter) {
- event_rule_status = lttng_event_rule_kernel_tracepoint_set_filter(
- res.er, filter);
- if (event_rule_status != LTTNG_EVENT_RULE_STATUS_OK) {
- ERR("Failed to set kernel_tracepoint event rule's filter to '%s'.",
- filter);
- goto error;
- }
- }
- break;
- }
- case LTTNG_EVENT_RULE_TYPE_JUL_LOGGING:
- {
- enum lttng_event_rule_status event_rule_status;
-
- res.er = lttng_event_rule_jul_logging_create();
- if (!res.er) {
- ERR("Failed to create jul_logging event rule.");
- goto error;
- }
-
- /* Set pattern. */
- event_rule_status = lttng_event_rule_jul_logging_set_name_pattern(
- res.er, name);
- if (event_rule_status != LTTNG_EVENT_RULE_STATUS_OK) {
- ERR("Failed to set jul_logging event rule's pattern to '%s'.",
- name);
- goto error;
- }
-
- /* Set filter. */
- if (filter) {
- event_rule_status = lttng_event_rule_jul_logging_set_filter(
- res.er, filter);
- if (event_rule_status != LTTNG_EVENT_RULE_STATUS_OK) {
- ERR("Failed to set jul_logging event rule's filter to '%s'.",
- filter);
- goto error;
- }
- }
-
- if (log_level_rule) {
- event_rule_status =
- lttng_event_rule_jul_logging_set_log_level_rule(
- res.er, log_level_rule);
-
- if (event_rule_status != LTTNG_EVENT_RULE_STATUS_OK) {
- ERR("Failed to set log level on event fule.");
- goto error;
- }
- }
- break;
- }
- case LTTNG_EVENT_RULE_TYPE_LOG4J_LOGGING:
- {
- enum lttng_event_rule_status event_rule_status;
-
- res.er = lttng_event_rule_log4j_logging_create();
- if (!res.er) {
- ERR("Failed to create jul_logging event rule.");
- goto error;
- }
-
- /* Set pattern. */
- event_rule_status = lttng_event_rule_log4j_logging_set_name_pattern(
- res.er, name);
- if (event_rule_status != LTTNG_EVENT_RULE_STATUS_OK) {
- ERR("Failed to set jul_logging event rule's pattern to '%s'.",
- name);
- goto error;
- }
-
- /* Set filter. */
- if (filter) {
- event_rule_status = lttng_event_rule_log4j_logging_set_filter(
- res.er, filter);
- if (event_rule_status != LTTNG_EVENT_RULE_STATUS_OK) {
- ERR("Failed to set jul_logging event rule's filter to '%s'.",
- filter);
- goto error;
- }
- }
-
- if (log_level_rule) {
- event_rule_status =
- lttng_event_rule_log4j_logging_set_log_level_rule(
- res.er, log_level_rule);
-
- if (event_rule_status != LTTNG_EVENT_RULE_STATUS_OK) {
- ERR("Failed to set log level on event fule.");
- goto error;
- }
- }
- break;
- }
- case LTTNG_EVENT_RULE_TYPE_PYTHON_LOGGING:
- {
- enum lttng_event_rule_status event_rule_status;
-
- res.er = lttng_event_rule_python_logging_create();
- if (!res.er) {
- ERR("Failed to create jul_logging event rule.");
- goto error;
- }
-
- /* Set pattern. */
- event_rule_status = lttng_event_rule_python_logging_set_name_pattern(
- res.er, name);
- if (event_rule_status != LTTNG_EVENT_RULE_STATUS_OK) {
- ERR("Failed to set jul_logging event rule's pattern to '%s'.",
- name);
- goto error;
- }
-
- /* Set filter. */
- if (filter) {
- event_rule_status = lttng_event_rule_python_logging_set_filter(
- res.er, filter);
- if (event_rule_status != LTTNG_EVENT_RULE_STATUS_OK) {
- ERR("Failed to set jul_logging event rule's filter to '%s'.",
- filter);
- goto error;
- }
- }
-
- if (log_level_rule) {
- event_rule_status =
- lttng_event_rule_python_logging_set_log_level_rule(
- res.er, log_level_rule);
-
- if (event_rule_status != LTTNG_EVENT_RULE_STATUS_OK) {
- ERR("Failed to set log level on event fule.");
- goto error;
- }
- }
- break;
- }
- case LTTNG_EVENT_RULE_TYPE_KERNEL_KPROBE:
- {
- int ret;
- enum lttng_event_rule_status event_rule_status;
-
- ret = parse_kernel_probe_opts(
- location, &kernel_probe_location);
- if (ret) {
- ERR("Failed to parse kernel probe location.");
- goto error;
- }
-
- LTTNG_ASSERT(kernel_probe_location);
- res.er = lttng_event_rule_kernel_kprobe_create(kernel_probe_location);
- if (!res.er) {
- ERR("Failed to create kprobe event rule.");
- goto error;
- }
-
- event_rule_status =
- lttng_event_rule_kernel_kprobe_set_event_name(
- res.er, event_name);
- if (event_rule_status != LTTNG_EVENT_RULE_STATUS_OK) {
- ERR("Failed to set kprobe event rule's name to '%s'.",
- event_name);
- goto error;
- }
-
- break;
- }
- case LTTNG_EVENT_RULE_TYPE_KERNEL_UPROBE:
- {
- int ret;
- enum lttng_event_rule_status event_rule_status;
-
- ret = parse_userspace_probe_opts(
- location, &userspace_probe_location);
- if (ret) {
- ERR("Failed to parse user space probe location.");
- goto error;
- }
-
- res.er = lttng_event_rule_kernel_uprobe_create(userspace_probe_location);
- if (!res.er) {
- ERR("Failed to create userspace probe event rule.");
- goto error;
- }
-
- event_rule_status =
- lttng_event_rule_kernel_uprobe_set_event_name(
- res.er, event_name);
- if (event_rule_status != LTTNG_EVENT_RULE_STATUS_OK) {
- ERR("Failed to set user space probe event rule's name to '%s'.",
- event_name);
- goto error;
- }
-
- break;
- }
- case LTTNG_EVENT_RULE_TYPE_KERNEL_SYSCALL:
- {
- enum lttng_event_rule_status event_rule_status;
- enum lttng_event_rule_kernel_syscall_emission_site emission_site;
-
- if (!parse_syscall_emission_site_from_type(
- event_rule_type_str, &emission_site)) {
- ERR("Failed to parse syscall type '%s'.", event_rule_type_str);
- goto error;
- }
-
- res.er = lttng_event_rule_kernel_syscall_create(emission_site);
- if (!res.er) {
- ERR("Failed to create syscall event rule.");
- goto error;
- }
-
- event_rule_status = lttng_event_rule_kernel_syscall_set_name_pattern(
- res.er, name);
- if (event_rule_status != LTTNG_EVENT_RULE_STATUS_OK) {
- ERR("Failed to set syscall event rule's pattern to '%s'.",
- name);
- goto error;
- }
-
- if (filter) {
- event_rule_status = lttng_event_rule_kernel_syscall_set_filter(
- res.er, filter);
- if (event_rule_status != LTTNG_EVENT_RULE_STATUS_OK) {
- ERR("Failed to set syscall event rule's filter to '%s'.",
- filter);
- goto error;
- }
- }
-
- break;
- }
- default:
- abort();
- goto error;
- }
-
- goto end;
-
-error:
- lttng_event_rule_destroy(res.er);
- res.er = NULL;
- lttng_dynamic_pointer_array_reset(&res.capture_descriptors);
-
-end:
- if (parser_ctx) {
- filter_parser_ctx_free(parser_ctx);
- }
-
- lttng_event_expr_destroy(event_expr);
- argpar_item_destroy(item);
- free(error);
- argpar_state_destroy(state);
- free(filter);
- free(name);
- lttng_dynamic_pointer_array_reset(&exclude_names);
- free(log_level_str);
- free(location);
- free(event_name);
- free(event_rule_type_str);
-
- lttng_kernel_probe_location_destroy(kernel_probe_location);
- lttng_userspace_probe_location_destroy(userspace_probe_location);
- lttng_log_level_rule_destroy(log_level_rule);
- return res;
-}
-
-static
-struct lttng_condition *handle_condition_event(int *argc, const char ***argv)
-{
- struct parse_event_rule_res res;
- struct lttng_condition *c;
- size_t i;
-
- res = parse_event_rule(argc, argv);
- if (!res.er) {
- c = NULL;
- goto error;
- }
-
- c = lttng_condition_event_rule_matches_create(res.er);
- lttng_event_rule_destroy(res.er);
- res.er = NULL;
- if (!c) {
- goto error;
- }
-
- for (i = 0; i < lttng_dynamic_pointer_array_get_count(&res.capture_descriptors);
- i++) {
- enum lttng_condition_status status;
- struct lttng_event_expr **expr =
- lttng_dynamic_array_get_element(
- &res.capture_descriptors.array, i);
-
- LTTNG_ASSERT(expr);
- LTTNG_ASSERT(*expr);
- status = lttng_condition_event_rule_matches_append_capture_descriptor(
- c, *expr);
- if (status != LTTNG_CONDITION_STATUS_OK) {
- if (status == LTTNG_CONDITION_STATUS_UNSUPPORTED) {
- ERR("The capture feature is unsupported by the event-rule condition type");
- }
-
- goto error;
- }
-
- /* Ownership of event expression moved to `c` */
- *expr = NULL;
- }
-
- goto end;
-
-error:
- lttng_condition_destroy(c);
- c = NULL;
-
-end:
- lttng_dynamic_pointer_array_reset(&res.capture_descriptors);
- lttng_event_rule_destroy(res.er);
- return c;
-}
-
-struct condition_descr {
- const char *name;
- struct lttng_condition *(*handler) (int *argc, const char ***argv);
-};
-
-static const
-struct condition_descr condition_descrs[] = {
- { "event-rule-matches", handle_condition_event },
-};
-
-static
-struct lttng_condition *parse_condition(const char *condition_name, int *argc,
- const char ***argv)
-{
- int i;
- struct lttng_condition *cond;
- const struct condition_descr *descr = NULL;
-
- for (i = 0; i < ARRAY_SIZE(condition_descrs); i++) {
- if (strcmp(condition_name, condition_descrs[i].name) == 0) {
- descr = &condition_descrs[i];
- break;
- }
- }
-
- if (!descr) {
- ERR("Unknown condition name '%s'", condition_name);
- goto error;
- }
-
- cond = descr->handler(argc, argv);
- if (!cond) {
- /* The handler has already printed an error message. */
- goto error;
- }
-
- goto end;
-error:
- cond = NULL;
-end:
- return cond;
-}
-
-static struct lttng_rate_policy *parse_rate_policy(const char *policy_str)
-{
- int ret;
- size_t num_token = 0;
- struct lttng_dynamic_pointer_array tokens;
- struct lttng_rate_policy *policy = NULL;
- enum lttng_rate_policy_type policy_type;
- unsigned long long value;
- char *policy_type_str;
- char *policy_value_str;
-
- LTTNG_ASSERT(policy_str);
- lttng_dynamic_pointer_array_init(&tokens, NULL);
-
- /* Rate policy fields are separated by ':'. */
- ret = strutils_split(policy_str, ':', 1, &tokens);
- if (ret == 0) {
- num_token = lttng_dynamic_pointer_array_get_count(&tokens);
- }
-
- /*
- * Early sanity check that the number of parameter is exactly 2.
- * i.e : type:value
- */
- if (num_token != 2) {
- ERR("Rate policy format is invalid.");
- goto end;
- }
-
- policy_type_str = lttng_dynamic_pointer_array_get_pointer(&tokens, 0);
- policy_value_str = lttng_dynamic_pointer_array_get_pointer(&tokens, 1);
-
- /* Parse the type. */
- if (strcmp(policy_type_str, "once-after") == 0) {
- policy_type = LTTNG_RATE_POLICY_TYPE_ONCE_AFTER_N;
- } else if (strcmp(policy_type_str, "every") == 0) {
- policy_type = LTTNG_RATE_POLICY_TYPE_EVERY_N;
- } else {
- ERR("Rate policy type `%s` unknown.", policy_type_str);
- goto end;
- }
-
- /* Parse the value. */
- if (utils_parse_unsigned_long_long(policy_value_str, &value) != 0) {
- ERR("Failed to parse rate policy value `%s` as an integer.",
- policy_value_str);
- goto end;
- }
-
- if (value == 0) {
- ERR("Rate policy value `%s` must be > 0.", policy_value_str);
- goto end;
- }
-
- switch (policy_type) {
- case LTTNG_RATE_POLICY_TYPE_EVERY_N:
- policy = lttng_rate_policy_every_n_create(value);
- break;
- case LTTNG_RATE_POLICY_TYPE_ONCE_AFTER_N:
- policy = lttng_rate_policy_once_after_n_create(value);
- break;
- default:
- abort();
- }
-
- if (policy == NULL) {
- ERR("Failed to create rate policy `%s`.", policy_str);
- }
-
-end:
- lttng_dynamic_pointer_array_reset(&tokens);
- return policy;
-}
-
-static const struct argpar_opt_descr notify_action_opt_descrs[] = {
- { OPT_RATE_POLICY, '\0', "rate-policy", true },
- ARGPAR_OPT_DESCR_SENTINEL
-};
-
-static
-struct lttng_action *handle_action_notify(int *argc, const char ***argv)
-{
- struct lttng_action *action = NULL;
- struct argpar_state *state = NULL;
- struct argpar_item *item = NULL;
- char *error = NULL;
- struct lttng_rate_policy *policy = NULL;
-
- state = argpar_state_create(*argc, *argv, notify_action_opt_descrs);
- if (!state) {
- ERR("Failed to allocate an argpar state.");
- goto error;
- }
-
- while (true) {
- enum argpar_state_parse_next_status status;
-
- ARGPAR_ITEM_DESTROY_AND_RESET(item);
- status = argpar_state_parse_next(state, &item, &error);
- if (status == ARGPAR_STATE_PARSE_NEXT_STATUS_ERROR) {
- ERR("%s", error);
- goto error;
- } else if (status == ARGPAR_STATE_PARSE_NEXT_STATUS_ERROR_UNKNOWN_OPT) {
- /* Just stop parsing here. */
- break;
- } else if (status == ARGPAR_STATE_PARSE_NEXT_STATUS_END) {
- break;
- }
-
- LTTNG_ASSERT(status == ARGPAR_STATE_PARSE_NEXT_STATUS_OK);
-
- 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_RATE_POLICY:
- {
- policy = parse_rate_policy(item_opt->arg);
- if (!policy) {
- goto error;
- }
- break;
- }
- default:
- abort();
- }
- } else {
- const struct argpar_item_non_opt *item_non_opt;
-
- LTTNG_ASSERT(item->type == ARGPAR_ITEM_TYPE_NON_OPT);
-
- item_non_opt = (const struct argpar_item_non_opt *) item;
-
- switch (item_non_opt->non_opt_index) {
- default:
- ERR("Unexpected argument `%s`.",
- item_non_opt->arg);
- goto error;
- }
- }
- }
-
- *argc -= argpar_state_get_ingested_orig_args(state);
- *argv += argpar_state_get_ingested_orig_args(state);
-
- action = lttng_action_notify_create();
- if (!action) {
- ERR("Failed to create notify action");
- goto error;
- }
-
- if (policy) {
- enum lttng_action_status status;
- status = lttng_action_notify_set_rate_policy(action, policy);
- if (status != LTTNG_ACTION_STATUS_OK) {
- ERR("Failed to set rate policy");
- goto error;
- }
- }
-
- goto end;
-
-error:
- lttng_action_destroy(action);
- action = NULL;
-end:
- free(error);
- lttng_rate_policy_destroy(policy);
- argpar_state_destroy(state);
- argpar_item_destroy(item);
- return action;
-}
-
-/*
- * Generic handler for a kind of action that takes a session name and an
- * optional rate policy.
- */
-
-static struct lttng_action *handle_action_simple_session_with_policy(int *argc,
- const char ***argv,
- struct lttng_action *(*create_action_cb)(void),
- enum lttng_action_status (*set_session_name_cb)(
- struct lttng_action *, const char *),
- enum lttng_action_status (*set_rate_policy_cb)(
- struct lttng_action *,
- const struct lttng_rate_policy *),
- const char *action_name)
-{
- struct lttng_action *action = NULL;
- struct argpar_state *state = NULL;
- struct argpar_item *item = NULL;
- const char *session_name_arg = NULL;
- char *error = NULL;
- enum lttng_action_status action_status;
- struct lttng_rate_policy *policy = NULL;
-
- LTTNG_ASSERT(set_session_name_cb);
- LTTNG_ASSERT(set_rate_policy_cb);
-
- const struct argpar_opt_descr rate_policy_opt_descrs[] = {
- { OPT_RATE_POLICY, '\0', "rate-policy", true },
- ARGPAR_OPT_DESCR_SENTINEL
- };
-
- state = argpar_state_create(*argc, *argv, rate_policy_opt_descrs);
- if (!state) {
- ERR("Failed to allocate an argpar state.");
- goto error;
- }
-
- while (true) {
- enum argpar_state_parse_next_status status;
-
- ARGPAR_ITEM_DESTROY_AND_RESET(item);
- status = argpar_state_parse_next(state, &item, &error);
- if (status == ARGPAR_STATE_PARSE_NEXT_STATUS_ERROR) {
- ERR("%s", error);
- goto error;
- } else if (status ==
- ARGPAR_STATE_PARSE_NEXT_STATUS_ERROR_UNKNOWN_OPT) {
- /* Just stop parsing here. */
- break;
- } else if (status == ARGPAR_STATE_PARSE_NEXT_STATUS_END) {
- break;
- }
-
- LTTNG_ASSERT(status == ARGPAR_STATE_PARSE_NEXT_STATUS_OK);
- 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_RATE_POLICY:
- {
- policy = parse_rate_policy(item_opt->arg);
- if (!policy) {
- goto error;
- }
- break;
- }
- default:
- abort();
- }
- } else {
- const struct argpar_item_non_opt *item_non_opt;
- item_non_opt = (const struct argpar_item_non_opt *) item;
-
- switch (item_non_opt->non_opt_index) {
- case 0:
- session_name_arg = item_non_opt->arg;
- break;
- default:
- ERR("Unexpected argument `%s`.",
- item_non_opt->arg);
- goto error;
- }
- }
- }
-
- *argc -= argpar_state_get_ingested_orig_args(state);
- *argv += argpar_state_get_ingested_orig_args(state);
-
- if (!session_name_arg) {
- ERR("Missing session name.");
- goto error;
- }
-
- action = create_action_cb();
- if (!action) {
- ERR("Failed to allocate %s session action.", action_name);
- goto error;
- }
-
- action_status = set_session_name_cb(action, session_name_arg);
- if (action_status != LTTNG_ACTION_STATUS_OK) {
- ERR("Failed to set action %s session's session name to '%s'.",
- action_name, session_name_arg);
- goto error;
- }
-
- if (policy) {
- action_status = set_rate_policy_cb(action, policy);
- if (action_status != LTTNG_ACTION_STATUS_OK) {
- ERR("Failed to set rate policy");
- goto error;
- }
- }
-
- goto end;
-
-error:
- lttng_action_destroy(action);
- action = NULL;
- argpar_item_destroy(item);
-end:
- lttng_rate_policy_destroy(policy);
- free(error);
- argpar_state_destroy(state);
- return action;
-}
-
-static
-struct lttng_action *handle_action_start_session(int *argc,
- const char ***argv)
-{
- return handle_action_simple_session_with_policy(argc, argv,
- lttng_action_start_session_create,
- lttng_action_start_session_set_session_name,
- lttng_action_start_session_set_rate_policy, "start");
-}
-
-static
-struct lttng_action *handle_action_stop_session(int *argc,
- const char ***argv)
-{
- return handle_action_simple_session_with_policy(argc, argv,
- lttng_action_stop_session_create,
- lttng_action_stop_session_set_session_name,
- lttng_action_stop_session_set_rate_policy, "stop");
-}
-
-static
-struct lttng_action *handle_action_rotate_session(int *argc,
- const char ***argv)
-{
- return handle_action_simple_session_with_policy(argc, argv,
- lttng_action_rotate_session_create,
- lttng_action_rotate_session_set_session_name,
- lttng_action_rotate_session_set_rate_policy,
- "rotate");
-}
-
-static const struct argpar_opt_descr snapshot_action_opt_descrs[] = {
- { OPT_NAME, 'n', "name", true },
- { OPT_MAX_SIZE, 'm', "max-size", true },
- { OPT_CTRL_URL, '\0', "ctrl-url", true },
- { OPT_DATA_URL, '\0', "data-url", true },
- { OPT_URL, '\0', "url", true },
- { OPT_PATH, '\0', "path", true },
- { OPT_RATE_POLICY, '\0', "rate-policy", true },
- ARGPAR_OPT_DESCR_SENTINEL
-};
-
-static
-struct lttng_action *handle_action_snapshot_session(int *argc,
- const char ***argv)
-{
- struct lttng_action *action = NULL;
- struct argpar_state *state = NULL;
- struct argpar_item *item = NULL;
- const char *session_name_arg = NULL;
- char *snapshot_name_arg = NULL;
- char *ctrl_url_arg = NULL;
- char *data_url_arg = NULL;
- char *max_size_arg = NULL;
- char *url_arg = NULL;
- char *path_arg = NULL;
- char *error = NULL;
- enum lttng_action_status action_status;
- struct lttng_snapshot_output *snapshot_output = NULL;
- struct lttng_rate_policy *policy = NULL;
- int ret;
- unsigned int locations_specified = 0;
-
- state = argpar_state_create(*argc, *argv, snapshot_action_opt_descrs);
- if (!state) {
- ERR("Failed to allocate an argpar state.");
- goto error;
- }
-
- while (true) {
- enum argpar_state_parse_next_status status;
-
- ARGPAR_ITEM_DESTROY_AND_RESET(item);
- status = argpar_state_parse_next(state, &item, &error);
- if (status == ARGPAR_STATE_PARSE_NEXT_STATUS_ERROR) {
- ERR("%s", error);
- goto error;
- } else if (status == ARGPAR_STATE_PARSE_NEXT_STATUS_ERROR_UNKNOWN_OPT) {
- /* Just stop parsing here. */
- break;
- } else if (status == ARGPAR_STATE_PARSE_NEXT_STATUS_END) {
- break;
- }
-
- LTTNG_ASSERT(status == ARGPAR_STATE_PARSE_NEXT_STATUS_OK);
-
- 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_NAME:
- if (!assign_string(&snapshot_name_arg, item_opt->arg, "--name/-n")) {
- goto error;
- }
-
- break;
- case OPT_MAX_SIZE:
- if (!assign_string(&max_size_arg, item_opt->arg, "--max-size/-m")) {
- goto error;
- }
-
- break;
- case OPT_CTRL_URL:
- if (!assign_string(&ctrl_url_arg, item_opt->arg, "--ctrl-url")) {
- goto error;
- }
-
- break;
- case OPT_DATA_URL:
- if (!assign_string(&data_url_arg, item_opt->arg, "--data-url")) {
- goto error;
- }
-
- break;
- case OPT_URL:
- if (!assign_string(&url_arg, item_opt->arg, "--url")) {
- goto error;
- }
-
- break;
- case OPT_PATH:
- if (!assign_string(&path_arg, item_opt->arg, "--path")) {
- goto error;
- }
-
- break;
- case OPT_RATE_POLICY:
- {
- policy = parse_rate_policy(item_opt->arg);
- if (!policy) {
- goto error;
- }
- break;
- }
- default:
- abort();
- }
- } else {
- const struct argpar_item_non_opt *item_non_opt;
-
- LTTNG_ASSERT(item->type == ARGPAR_ITEM_TYPE_NON_OPT);
-
- item_non_opt = (const struct argpar_item_non_opt *) item;
-
- switch (item_non_opt->non_opt_index) {
- case 0:
- session_name_arg = item_non_opt->arg;
- break;
- default:
- ERR("Unexpected argument `%s`.",
- item_non_opt->arg);
- goto error;
- }
- }
- }
-
- *argc -= argpar_state_get_ingested_orig_args(state);
- *argv += argpar_state_get_ingested_orig_args(state);
-
- if (!session_name_arg) {
- ERR("Missing session name.");
- goto error;
- }
-
- /* --ctrl-url and --data-url must come in pair. */
- if (ctrl_url_arg && !data_url_arg) {
- ERR("--ctrl-url is specified, but --data-url is missing.");
- goto error;
- }
-
- if (!ctrl_url_arg && data_url_arg) {
- ERR("--data-url is specified, but --ctrl-url is missing.");
- goto error;
- }
-
- locations_specified += !!(ctrl_url_arg || data_url_arg);
- locations_specified += !!url_arg;
- locations_specified += !!path_arg;
-
- /* --ctrl-url/--data-url, --url and --path are mutually exclusive. */
- if (locations_specified > 1) {
- ERR("The --ctrl-url/--data-url, --url, and --path options can't be used together.");
- goto error;
- }
-
- /*
- * Did the user specify an option that implies using a
- * custom/unregistered output?
- */
- if (url_arg || ctrl_url_arg || path_arg) {
- snapshot_output = lttng_snapshot_output_create();
- if (!snapshot_output) {
- ERR("Failed to allocate a snapshot output.");
- goto error;
- }
- }
-
- action = lttng_action_snapshot_session_create();
- if (!action) {
- ERR("Failed to allocate snapshot session action.");
- goto error;
- }
-
- action_status = lttng_action_snapshot_session_set_session_name(
- action, session_name_arg);
- if (action_status != LTTNG_ACTION_STATUS_OK) {
- ERR("Failed to set action snapshot session's session name to '%s'.",
- session_name_arg);
- goto error;
- }
-
- if (snapshot_name_arg) {
- if (!snapshot_output) {
- ERR("Can't provide a snapshot output name without a snapshot output destination.");
- goto error;
- }
-
- ret = lttng_snapshot_output_set_name(
- snapshot_name_arg, snapshot_output);
- if (ret != 0) {
- ERR("Failed to set name of snapshot output.");
- goto error;
- }
- }
-
- if (max_size_arg) {
- uint64_t max_size;
-
- if (!snapshot_output) {
- ERR("Can't provide a snapshot output max size without a snapshot output destination.");
- goto error;
- }
-
- ret = utils_parse_size_suffix(max_size_arg, &max_size);
- if (ret != 0) {
- ERR("Failed to parse `%s` as a size.", max_size_arg);
- goto error;
- }
-
- ret = lttng_snapshot_output_set_size(max_size, snapshot_output);
- if (ret != 0) {
- ERR("Failed to set snapshot output's max size to %" PRIu64 " bytes.",
- max_size);
- goto error;
- }
- }
-
- if (url_arg) {
- int num_uris;
- struct lttng_uri *uris;
-
- if (!strstr(url_arg, "://")) {
- ERR("Failed to parse '%s' as an URL.", url_arg);
- goto error;
- }
-
- num_uris = uri_parse_str_urls(url_arg, NULL, &uris);
- if (num_uris < 1) {
- ERR("Failed to parse '%s' as an URL.", url_arg);
- goto error;
- }
-
- if (uris[0].dtype == LTTNG_DST_PATH) {
- ret = lttng_snapshot_output_set_local_path(
- uris[0].dst.path, snapshot_output);
- free(uris);
- if (ret != 0) {
- ERR("Failed to assign '%s' as a local destination.",
- url_arg);
- goto error;
- }
- } else {
- ret = lttng_snapshot_output_set_network_url(
- url_arg, snapshot_output);
- free(uris);
- if (ret != 0) {
- ERR("Failed to assign '%s' as a network URL.",
- url_arg);
- goto error;
- }
- }
- }
-
- if (path_arg) {
- ret = lttng_snapshot_output_set_local_path(
- path_arg, snapshot_output);
- if (ret != 0) {
- ERR("Failed to parse '%s' as a local path.", path_arg);
- goto error;
- }
- }
-
- if (ctrl_url_arg) {
- /*
- * Two argument form, network output with separate control and
- * data URLs.
- */
- ret = lttng_snapshot_output_set_network_urls(
- ctrl_url_arg, data_url_arg, snapshot_output);
- if (ret != 0) {
- ERR("Failed to parse `%s` and `%s` as control and data URLs.",
- ctrl_url_arg, data_url_arg);
- goto error;
- }
- }
-
- if (snapshot_output) {
- action_status = lttng_action_snapshot_session_set_output(
- action, snapshot_output);
- if (action_status != LTTNG_ACTION_STATUS_OK) {
- ERR("Failed to set snapshot session action's output.");
- goto error;
- }
-
- /* Ownership of `snapshot_output` has been transferred to the action. */
- snapshot_output = NULL;
- }
-
- if (policy) {
- enum lttng_action_status status;
- status = lttng_action_snapshot_session_set_rate_policy(
- action, policy);
- if (status != LTTNG_ACTION_STATUS_OK) {
- ERR("Failed to set rate policy");
- goto error;
- }
- }
-
- goto end;
-
-error:
- lttng_action_destroy(action);
- action = NULL;
- free(error);
-end:
- free(snapshot_name_arg);
- free(path_arg);
- free(url_arg);
- free(ctrl_url_arg);
- free(data_url_arg);
- free(snapshot_output);
- free(max_size_arg);
- lttng_rate_policy_destroy(policy);
- argpar_state_destroy(state);
- argpar_item_destroy(item);
- return action;
-}
-
-struct action_descr {
- const char *name;
- struct lttng_action *(*handler) (int *argc, const char ***argv);
-};
-
-static const
-struct action_descr action_descrs[] = {
- { "notify", handle_action_notify },
- { "start-session", handle_action_start_session },
- { "stop-session", handle_action_stop_session },
- { "rotate-session", handle_action_rotate_session },
- { "snapshot-session", handle_action_snapshot_session },
-};
-
-static
-struct lttng_action *parse_action(const char *action_name, int *argc, const char ***argv)
-{
- int i;
- struct lttng_action *action;
- const struct action_descr *descr = NULL;
-
- for (i = 0; i < ARRAY_SIZE(action_descrs); i++) {
- if (strcmp(action_name, action_descrs[i].name) == 0) {
- descr = &action_descrs[i];
- break;
- }
- }
-
- if (!descr) {
- ERR("Unknown action name: %s", action_name);
- goto error;
- }
-
- action = descr->handler(argc, argv);
- if (!action) {
- /* The handler has already printed an error message. */
- goto error;
- }
-
- goto end;
-error:
- action = NULL;
-end:
- return action;
-}
-
-static const
-struct argpar_opt_descr add_trigger_options[] = {
- { OPT_HELP, 'h', "help", false },
- { OPT_LIST_OPTIONS, '\0', "list-options", false },
- { OPT_CONDITION, '\0', "condition", true },
- { OPT_ACTION, '\0', "action", true },
- { OPT_NAME, '\0', "name", true },
- { OPT_OWNER_UID, '\0', "owner-uid", true },
- ARGPAR_OPT_DESCR_SENTINEL,
-};
-
-static
-void lttng_actions_destructor(void *p)
-{
- struct lttng_action *action = p;
-
- lttng_action_destroy(action);
-}
-
-int cmd_add_trigger(int argc, const char **argv)
-{
- int ret;
- int my_argc = argc - 1;
- const char **my_argv = argv + 1;
- struct lttng_condition *condition = NULL;
- struct lttng_dynamic_pointer_array actions;
- struct argpar_state *argpar_state = NULL;
- struct argpar_item *argpar_item = NULL;
- struct lttng_action *action_list = NULL;
- struct lttng_action *action = NULL;
- struct lttng_trigger *trigger = NULL;
- char *error = NULL;
- char *name = NULL;
- int i;
- char *owner_uid = NULL;
- enum lttng_error_code ret_code;
- struct mi_writer *mi_writer = NULL;
-
- lttng_dynamic_pointer_array_init(&actions, lttng_actions_destructor);
-
- if (lttng_opt_mi) {
- mi_writer = mi_lttng_writer_create(
- fileno(stdout), lttng_opt_mi);
- if (!mi_writer) {
- ret = CMD_ERROR;
- goto error;
- }
-
- /* Open command element. */
- ret = mi_lttng_writer_command_open(mi_writer,
- mi_lttng_element_command_add_trigger);
- if (ret) {
- ret = CMD_ERROR;
- goto error;
- }
-
- /* Open output element. */
- ret = mi_lttng_writer_open_element(
- mi_writer, mi_lttng_element_command_output);
- if (ret) {
- ret = CMD_ERROR;
- goto error;
- }
- }
-
- while (true) {
- enum argpar_state_parse_next_status status;
- const struct argpar_item_opt *item_opt;
- int ingested_args;
-
- argpar_state_destroy(argpar_state);
- argpar_state = argpar_state_create(my_argc, my_argv,
- add_trigger_options);
- if (!argpar_state) {
- ERR("Failed to create argpar state.");
- goto error;
- }
-
- ARGPAR_ITEM_DESTROY_AND_RESET(argpar_item);
- status = argpar_state_parse_next(argpar_state, &argpar_item, &error);
- if (status == ARGPAR_STATE_PARSE_NEXT_STATUS_ERROR) {
- ERR("%s", error);
- goto error;
- } else if (status == ARGPAR_STATE_PARSE_NEXT_STATUS_ERROR_UNKNOWN_OPT) {
- ERR("%s", error);
- goto error;
- } else if (status == ARGPAR_STATE_PARSE_NEXT_STATUS_END) {
- break;
- }
-
- LTTNG_ASSERT(status == ARGPAR_STATE_PARSE_NEXT_STATUS_OK);
-
- if (argpar_item->type == ARGPAR_ITEM_TYPE_NON_OPT) {
- const struct argpar_item_non_opt *item_non_opt =
- (const struct argpar_item_non_opt *)
- argpar_item;
-
- ERR("Unexpected argument `%s`.", item_non_opt->arg);
- goto error;
- }
-
- item_opt = (const struct argpar_item_opt *) argpar_item;
-
- ingested_args = argpar_state_get_ingested_orig_args(
- argpar_state);
-
- my_argc -= ingested_args;
- my_argv += ingested_args;
-
- switch (item_opt->descr->id) {
- case OPT_HELP:
- SHOW_HELP();
- ret = 0;
- goto end;
- case OPT_LIST_OPTIONS:
- list_cmd_options_argpar(stdout, add_trigger_options);
- ret = 0;
- goto end;
- case OPT_CONDITION:
- {
- if (condition) {
- ERR("A --condition was already given.");
- goto error;
- }
-
- condition = parse_condition(item_opt->arg, &my_argc, &my_argv);
- if (!condition) {
- /*
- * An error message was already printed by
- * parse_condition.
- */
- goto error;
- }
-
- break;
- }
- case OPT_ACTION:
- {
- action = parse_action(item_opt->arg, &my_argc, &my_argv);
- if (!action) {
- /*
- * An error message was already printed by
- * parse_condition.
- */
- goto error;
- }
-
- ret = lttng_dynamic_pointer_array_add_pointer(
- &actions, action);
- if (ret) {
- ERR("Failed to add pointer to pointer array.");
- goto error;
- }
-
- /* Ownership of the action was transferred to the list. */
- action = NULL;
-
- break;
- }
- case OPT_NAME:
- {
- if (!assign_string(&name, item_opt->arg, "--name")) {
- goto error;
- }
-
- break;
- }
- case OPT_OWNER_UID:
- {
- if (!assign_string(&owner_uid, item_opt->arg,
- "--owner-uid")) {
- goto error;
- }
-
- break;
- }
- default:
- abort();
- }
- }
-
- if (!condition) {
- ERR("Missing --condition.");
- goto error;
- }
-
- if (lttng_dynamic_pointer_array_get_count(&actions) == 0) {
- ERR("Need at least one --action.");
- goto error;
- }
-
- action_list = lttng_action_list_create();
- if (!action_list) {
- goto error;
- }
-
- for (i = 0; i < lttng_dynamic_pointer_array_get_count(&actions); i++) {
- enum lttng_action_status status;
-
- action = lttng_dynamic_pointer_array_steal_pointer(&actions, i);
-
- status = lttng_action_list_add_action(action_list, action);
- if (status != LTTNG_ACTION_STATUS_OK) {
- goto error;
- }
-
- /*
- * The `lttng_action_list_add_action()` takes a reference to
- * the action. We can destroy ours.
- */
- lttng_action_destroy(action);
- action = NULL;
- }
-
- trigger = lttng_trigger_create(condition, action_list);
- if (!trigger) {
- goto error;
- }
-
- if (owner_uid) {
- enum lttng_trigger_status trigger_status;
- char *end;
- long long uid;
-
- errno = 0;
- uid = strtol(owner_uid, &end, 10);
- if (end == owner_uid || *end != '\0' || errno != 0) {
- ERR("Failed to parse `%s` as a user id.", owner_uid);
- goto error;
- }
-
- trigger_status = lttng_trigger_set_owner_uid(trigger, uid);
- if (trigger_status != LTTNG_TRIGGER_STATUS_OK) {
- ERR("Failed to set trigger's user identity.");
- goto error;
- }
- }
-
- if (name) {
- ret_code = lttng_register_trigger_with_name(trigger, name);
- } else {
- ret_code = lttng_register_trigger_with_automatic_name(trigger);
- }
-
- if (ret_code != LTTNG_OK) {
- ERR("Failed to register trigger: %s.",
- lttng_strerror(-ret_code));
- goto error;
- }
-
- if (lttng_opt_mi) {
- ret_code = lttng_trigger_mi_serialize(trigger, mi_writer, NULL);
- if (ret_code != LTTNG_OK) {
- goto error;
- }
- } else {
- const char *returned_trigger_name;
- const enum lttng_trigger_status trigger_status =
- lttng_trigger_get_name(trigger,
- &returned_trigger_name);
-
- if (trigger_status != LTTNG_TRIGGER_STATUS_OK) {
- WARN("Failed to retrieve the added trigger's name.");
- } else {
- MSG("Added trigger `%s`.", returned_trigger_name);
- }
- }
-
- ret = 0;
-
- goto end;
-
-error:
- ret = 1;
-
-end:
- /* Mi closing. */
- if (lttng_opt_mi && mi_writer) {
- int mi_ret;
-
- /* Close output element. */
- mi_ret = mi_lttng_writer_close_element(mi_writer);
- if (mi_ret) {
- ret = 1;
- goto cleanup;
- }
-
- mi_ret = mi_lttng_writer_write_element_bool(mi_writer,
- mi_lttng_element_command_success, ret ? 0 : 1);
- if (mi_ret) {
- ret = 1;
- goto cleanup;
- }
-
- /* Command element close. */
- mi_ret = mi_lttng_writer_command_close(mi_writer);
- if (mi_ret) {
- ret = 1;
- goto cleanup;
- }
- }
-
-cleanup:
- argpar_state_destroy(argpar_state);
- argpar_item_destroy(argpar_item);
- lttng_dynamic_pointer_array_reset(&actions);
- lttng_condition_destroy(condition);
- lttng_action_destroy(action_list);
- lttng_action_destroy(action);
- lttng_trigger_destroy(trigger);
- free(error);
- free(name);
- free(owner_uid);
- if (mi_writer && mi_lttng_writer_destroy(mi_writer)) {
- /* Preserve original error code. */
- ret = ret ? ret : CMD_ERROR;
- }
-
- return ret;
-}