instrumented_app_SOURCES = instrumented-app.c
instrumented_app_LDADD = libtracepoint-trigger-example.a $(UST_LIBS) $(DL_LIBS)
-notification_client_SOURCES = notification-client.c
+notification_client_SOURCES = notification-client.cpp
notification_client_LDADD = $(LIBLTTNG_CTL)
endif
+++ /dev/null
-/*
- * Copyright (C) 2020 Jérémie Galarneau <jeremie.galarneau@efficios.com>
- *
- * SPDX-License-Identifier: MIT
- *
- */
-
-#include <lttng/lttng.h>
-
-#include <inttypes.h>
-#include <stdbool.h>
-#include <stddef.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/time.h>
-#include <time.h>
-
-#include <common/macros.h>
-
-static int print_capture(const struct lttng_condition *condition,
- const struct lttng_event_field_value *capture,
- unsigned int indent_level);
-static int print_array(const struct lttng_condition *condition,
- const struct lttng_event_field_value *array,
- unsigned int indent_level);
-
-static void indent(unsigned int indentation_level)
-{
- unsigned int i;
- for (i = 0; i < indentation_level; i++) {
- printf(" ");
- }
-}
-
-static void print_one_event_expr(const struct lttng_event_expr *event_expr)
-{
- enum lttng_event_expr_type type;
-
- type = lttng_event_expr_get_type(event_expr);
-
- switch (type) {
- case LTTNG_EVENT_EXPR_TYPE_EVENT_PAYLOAD_FIELD:
- {
- const char *name;
-
- name = lttng_event_expr_event_payload_field_get_name(
- event_expr);
- printf("%s", name);
-
- break;
- }
-
- case LTTNG_EVENT_EXPR_TYPE_CHANNEL_CONTEXT_FIELD:
- {
- const char *name;
-
- name = lttng_event_expr_channel_context_field_get_name(
- event_expr);
- printf("$ctx.%s", name);
-
- break;
- }
-
- case LTTNG_EVENT_EXPR_TYPE_APP_SPECIFIC_CONTEXT_FIELD:
- {
- const char *provider_name;
- const char *type_name;
-
- provider_name = lttng_event_expr_app_specific_context_field_get_provider_name(
- event_expr);
- type_name = lttng_event_expr_app_specific_context_field_get_type_name(
- event_expr);
-
- printf("$app.%s:%s", provider_name, type_name);
-
- break;
- }
-
- case LTTNG_EVENT_EXPR_TYPE_ARRAY_FIELD_ELEMENT:
- {
- unsigned int index;
- const struct lttng_event_expr *parent_expr;
- enum lttng_event_expr_status status;
-
- parent_expr = lttng_event_expr_array_field_element_get_parent_expr(
- event_expr);
- LTTNG_ASSERT(parent_expr != NULL);
-
- print_one_event_expr(parent_expr);
-
- status = lttng_event_expr_array_field_element_get_index(
- event_expr, &index);
- LTTNG_ASSERT(status == LTTNG_EVENT_EXPR_STATUS_OK);
-
- printf("[%u]", index);
-
- break;
- }
-
- default:
- abort();
- }
-}
-
-static bool action_group_contains_notify(
- const struct lttng_action *action_group)
-{
- unsigned int i, count;
- enum lttng_action_status status =
- lttng_action_list_get_count(action_group, &count);
-
- if (status != LTTNG_ACTION_STATUS_OK) {
- printf("Failed to get action count from action group\n");
- exit(1);
- }
-
- for (i = 0; i < count; i++) {
- const struct lttng_action *action =
- lttng_action_list_get_at_index(action_group, i);
- const enum lttng_action_type action_type =
- lttng_action_get_type(action);
-
- if (action_type == LTTNG_ACTION_TYPE_NOTIFY) {
- return true;
- }
- }
- return false;
-}
-
-static int print_capture(const struct lttng_condition *condition,
- const struct lttng_event_field_value *capture,
- unsigned int indent_level)
-{
- int ret = 0;
- enum lttng_event_field_value_status event_field_status;
- uint64_t u_val;
- int64_t s_val;
- double d_val;
- const char *string_val = NULL;
-
- switch (lttng_event_field_value_get_type(capture)) {
- case LTTNG_EVENT_FIELD_VALUE_TYPE_UNSIGNED_INT:
- {
- event_field_status =
- lttng_event_field_value_unsigned_int_get_value(
- capture, &u_val);
- if (event_field_status != LTTNG_EVENT_FIELD_VALUE_STATUS_OK) {
- ret = 1;
- goto end;
- }
-
- printf("[Unsigned int] %" PRIu64, u_val);
- break;
- }
- case LTTNG_EVENT_FIELD_VALUE_TYPE_SIGNED_INT:
- {
- event_field_status =
- lttng_event_field_value_signed_int_get_value(
- capture, &s_val);
- if (event_field_status != LTTNG_EVENT_FIELD_VALUE_STATUS_OK) {
- ret = 1;
- goto end;
- }
-
- printf("[Signed int] %" PRId64, s_val);
- break;
- }
- case LTTNG_EVENT_FIELD_VALUE_TYPE_UNSIGNED_ENUM:
- {
- event_field_status =
- lttng_event_field_value_unsigned_int_get_value(
- capture, &u_val);
- if (event_field_status != LTTNG_EVENT_FIELD_VALUE_STATUS_OK) {
- ret = 1;
- goto end;
- }
-
- printf("[Unsigned enum] %" PRIu64, u_val);
- break;
- }
- case LTTNG_EVENT_FIELD_VALUE_TYPE_SIGNED_ENUM:
- {
- event_field_status =
- lttng_event_field_value_signed_int_get_value(
- capture, &s_val);
- if (event_field_status != LTTNG_EVENT_FIELD_VALUE_STATUS_OK) {
- ret = 1;
- goto end;
- }
-
- printf("[Signed enum] %" PRId64, s_val);
- break;
- }
- case LTTNG_EVENT_FIELD_VALUE_TYPE_REAL:
- {
- event_field_status = lttng_event_field_value_real_get_value(
- capture, &d_val);
- if (event_field_status != LTTNG_EVENT_FIELD_VALUE_STATUS_OK) {
- ret = 1;
- goto end;
- }
-
- printf("[Real] %lf", d_val);
- break;
- }
- case LTTNG_EVENT_FIELD_VALUE_TYPE_STRING:
- {
- event_field_status = lttng_event_field_value_string_get_value(
- capture, &string_val);
- if (event_field_status != LTTNG_EVENT_FIELD_VALUE_STATUS_OK) {
- ret = 1;
- goto end;
- }
-
- printf("[String] %s", string_val);
- break;
- }
- case LTTNG_EVENT_FIELD_VALUE_TYPE_ARRAY:
- printf("[Array] [\n");
- print_array(condition, capture, indent_level);
- indent(indent_level);
- printf("]\n");
- break;
- case LTTNG_EVENT_FIELD_VALUE_TYPE_UNKNOWN:
- case LTTNG_EVENT_FIELD_VALUE_TYPE_INVALID:
- default:
- ret = 1;
- break;
- }
-
-end:
- return ret;
-}
-
-static void print_unavailabe(void)
-{
- printf("Capture unavailable");
-}
-
-static int print_array(const struct lttng_condition *condition,
- const struct lttng_event_field_value *array,
- unsigned int indent_level)
-{
- int ret = 0;
- enum lttng_event_field_value_status event_field_status;
- unsigned int captured_field_count;
-
- event_field_status = lttng_event_field_value_array_get_length(
- array, &captured_field_count);
- if (event_field_status != LTTNG_EVENT_FIELD_VALUE_STATUS_OK) {
- ret = 1;
- goto end;
- }
-
- for (unsigned int i = 0; i < captured_field_count; i++) {
- const struct lttng_event_field_value *captured_field = NULL;
- const struct lttng_event_expr *expr =
- lttng_condition_event_rule_matches_get_capture_descriptor_at_index(
- condition, i);
- LTTNG_ASSERT(expr);
-
- indent(indent_level + 1);
-
- printf("Field: ");
- print_one_event_expr(expr);
- printf(" Value: ");
-
- event_field_status =
- lttng_event_field_value_array_get_element_at_index(
- array, i, &captured_field);
- if (event_field_status != LTTNG_EVENT_FIELD_VALUE_STATUS_OK) {
- if (event_field_status ==
- LTTNG_EVENT_FIELD_VALUE_STATUS_UNAVAILABLE) {
- print_unavailabe();
- } else {
- ret = 1;
- goto end;
- }
- } else {
- print_capture(condition, captured_field,
- indent_level + 1);
- }
-
- if (i + 1 < captured_field_count) {
- printf(",");
- } else {
- printf(".");
- }
- printf("\n");
- }
-
-end:
- return ret;
-}
-
-static int print_captures(struct lttng_notification *notification)
-{
- int ret = 0;
- const struct lttng_evaluation *evaluation =
- lttng_notification_get_evaluation(notification);
- const struct lttng_condition *condition =
- lttng_notification_get_condition(notification);
-
- /* Status */
- enum lttng_condition_status condition_status;
- enum lttng_evaluation_event_rule_matches_status evaluation_status;
-
- const struct lttng_event_field_value *captured_field_array = NULL;
- unsigned int expected_capture_field_count;
-
- LTTNG_ASSERT(lttng_evaluation_get_type(evaluation) ==
- LTTNG_CONDITION_TYPE_EVENT_RULE_MATCHES);
-
- condition_status =
- lttng_condition_event_rule_matches_get_capture_descriptor_count(
- condition,
- &expected_capture_field_count);
- if (condition_status != LTTNG_CONDITION_STATUS_OK) {
- ret = 1;
- goto end;
- }
-
- if (expected_capture_field_count == 0) {
- ret = 0;
- goto end;
- }
-
- evaluation_status =
- lttng_evaluation_event_rule_matches_get_captured_values(
- evaluation, &captured_field_array);
- if (evaluation_status != LTTNG_EVALUATION_EVENT_RULE_MATCHES_STATUS_OK) {
- ret = 1;
- goto end;
- }
-
- printf("Captured field values:\n");
- print_array(condition, captured_field_array, 1);
-end:
- return ret;
-}
-
-static int print_notification(struct lttng_notification *notification)
-{
- int ret = 0;
- const struct lttng_evaluation *evaluation =
- lttng_notification_get_evaluation(notification);
- const enum lttng_condition_type type =
- lttng_evaluation_get_type(evaluation);
-
- switch (type) {
- case LTTNG_CONDITION_TYPE_SESSION_CONSUMED_SIZE:
- printf("Received consumed size notification\n");
- break;
- case LTTNG_CONDITION_TYPE_BUFFER_USAGE_LOW:
- case LTTNG_CONDITION_TYPE_BUFFER_USAGE_HIGH:
- printf("Received buffer usage notification\n");
- break;
- case LTTNG_CONDITION_TYPE_SESSION_ROTATION_ONGOING:
- printf("Received session rotation ongoing notification\n");
- break;
- case LTTNG_CONDITION_TYPE_SESSION_ROTATION_COMPLETED:
- printf("Received session rotation completed notification\n");
- break;
- case LTTNG_CONDITION_TYPE_EVENT_RULE_MATCHES:
- {
- const char *trigger_name;
- enum lttng_trigger_status trigger_status;
- char time_str[64];
- struct timeval tv;
- time_t the_time;
- const struct lttng_trigger *trigger = NULL;
-
- gettimeofday(&tv, NULL);
- the_time = tv.tv_sec;
-
- strftime(time_str, sizeof(time_str), "[%m-%d-%Y] %T",
- localtime(&the_time));
- printf("%s.%ld - ", time_str, tv.tv_usec);
-
- trigger = lttng_notification_get_trigger(notification);
- if (!trigger) {
- fprintf(stderr, "Failed to retrieve notification's trigger");
- goto end;
- }
-
- trigger_status = lttng_trigger_get_name(trigger, &trigger_name);
- if (trigger_status != LTTNG_TRIGGER_STATUS_OK) {
- fprintf(stderr, "Failed to retrieve trigger's name");
- goto end;
- }
-
- printf("Received notification of event rule matches trigger \"%s\"\n",
- trigger_name);
- ret = print_captures(notification);
- break;
- }
- default:
- fprintf(stderr, "Unknown notification type (%d)\n", type);
- }
-
-end:
- return ret;
-}
-
-int main(int argc, char **argv)
-{
- int ret;
- struct lttng_triggers *triggers = NULL;
- unsigned int count, i, j, subcription_count = 0, trigger_count;
- enum lttng_trigger_status trigger_status;
- struct lttng_notification_channel *notification_channel = NULL;
-
- if (argc < 2) {
- fprintf(stderr, "Missing trigger name(s)\n");
- fprintf(stderr, "Usage: notification-client TRIGGER_NAME ...");
- ret = -1;
- goto end;
- }
-
- trigger_count = argc - 1;
-
- notification_channel = lttng_notification_channel_create(
- lttng_session_daemon_notification_endpoint);
- if (!notification_channel) {
- fprintf(stderr, "Failed to create notification channel\n");
- ret = -1;
- goto end;
- }
-
- ret = lttng_list_triggers(&triggers);
- if (ret != LTTNG_OK) {
- fprintf(stderr, "Failed to list triggers\n");
- goto end;
- }
-
- trigger_status = lttng_triggers_get_count(triggers, &count);
- if (trigger_status != LTTNG_TRIGGER_STATUS_OK) {
- fprintf(stderr, "Failed to get trigger count\n");
- ret = -1;
- goto end;
- }
-
- for (i = 0; i < count; i++) {
- const struct lttng_trigger *trigger =
- lttng_triggers_get_at_index(triggers, i);
- const struct lttng_condition *condition =
- lttng_trigger_get_const_condition(trigger);
- const struct lttng_action *action =
- lttng_trigger_get_const_action(trigger);
- const enum lttng_action_type action_type =
- lttng_action_get_type(action);
- enum lttng_notification_channel_status channel_status;
- const char *trigger_name = NULL;
- bool subscribe = false;
-
- lttng_trigger_get_name(trigger, &trigger_name);
- for (j = 0; j < trigger_count; j++) {
- if (!strcmp(trigger_name, argv[j + 1])) {
- subscribe = true;
- break;
- }
- }
-
- if (!subscribe) {
- continue;
- }
-
- if (!((action_type == LTTNG_ACTION_TYPE_LIST &&
- action_group_contains_notify(action)) ||
- action_type == LTTNG_ACTION_TYPE_NOTIFY)) {
- printf("The action of trigger \"%s\" is not \"notify\", skipping.\n",
- trigger_name);
- continue;
- }
-
- channel_status = lttng_notification_channel_subscribe(
- notification_channel, condition);
- if (channel_status ==
- LTTNG_NOTIFICATION_CHANNEL_STATUS_ALREADY_SUBSCRIBED) {
- continue;
- }
- if (channel_status) {
- fprintf(stderr, "Failed to subscribe to notifications of trigger \"%s\"\n",
- trigger_name);
- ret = -1;
- goto end;
- }
-
- printf("Subscribed to notifications of trigger \"%s\"\n",
- trigger_name);
- subcription_count++;
- }
-
- if (subcription_count == 0) {
- printf("No matching trigger with a notify action found.\n");
- ret = 0;
- goto end;
- }
-
- for (;;) {
- struct lttng_notification *notification;
- enum lttng_notification_channel_status channel_status;
-
- channel_status =
- lttng_notification_channel_get_next_notification(
- notification_channel,
- ¬ification);
- switch (channel_status) {
- case LTTNG_NOTIFICATION_CHANNEL_STATUS_NOTIFICATIONS_DROPPED:
- printf("Dropped notification\n");
- break;
- case LTTNG_NOTIFICATION_CHANNEL_STATUS_INTERRUPTED:
- ret = 0;
- goto end;
- case LTTNG_NOTIFICATION_CHANNEL_STATUS_OK:
- break;
- case LTTNG_NOTIFICATION_CHANNEL_STATUS_CLOSED:
- printf("Notification channel was closed by peer.\n");
- break;
- default:
- fprintf(stderr, "A communication error occurred on the notification channel.\n");
- ret = -1;
- goto end;
- }
-
- ret = print_notification(notification);
- lttng_notification_destroy(notification);
- if (ret) {
- goto end;
- }
- }
-end:
- lttng_triggers_destroy(triggers);
- lttng_notification_channel_destroy(notification_channel);
- return !!ret;
-}
--- /dev/null
+/*
+ * Copyright (C) 2020 Jérémie Galarneau <jeremie.galarneau@efficios.com>
+ *
+ * SPDX-License-Identifier: MIT
+ *
+ */
+
+#include <lttng/lttng.h>
+
+#include <inttypes.h>
+#include <stdbool.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/time.h>
+#include <time.h>
+
+#include <common/macros.h>
+
+static int print_capture(const struct lttng_condition *condition,
+ const struct lttng_event_field_value *capture,
+ unsigned int indent_level);
+static int print_array(const struct lttng_condition *condition,
+ const struct lttng_event_field_value *array,
+ unsigned int indent_level);
+
+static void indent(unsigned int indentation_level)
+{
+ unsigned int i;
+ for (i = 0; i < indentation_level; i++) {
+ printf(" ");
+ }
+}
+
+static void print_one_event_expr(const struct lttng_event_expr *event_expr)
+{
+ enum lttng_event_expr_type type;
+
+ type = lttng_event_expr_get_type(event_expr);
+
+ switch (type) {
+ case LTTNG_EVENT_EXPR_TYPE_EVENT_PAYLOAD_FIELD:
+ {
+ const char *name;
+
+ name = lttng_event_expr_event_payload_field_get_name(
+ event_expr);
+ printf("%s", name);
+
+ break;
+ }
+
+ case LTTNG_EVENT_EXPR_TYPE_CHANNEL_CONTEXT_FIELD:
+ {
+ const char *name;
+
+ name = lttng_event_expr_channel_context_field_get_name(
+ event_expr);
+ printf("$ctx.%s", name);
+
+ break;
+ }
+
+ case LTTNG_EVENT_EXPR_TYPE_APP_SPECIFIC_CONTEXT_FIELD:
+ {
+ const char *provider_name;
+ const char *type_name;
+
+ provider_name = lttng_event_expr_app_specific_context_field_get_provider_name(
+ event_expr);
+ type_name = lttng_event_expr_app_specific_context_field_get_type_name(
+ event_expr);
+
+ printf("$app.%s:%s", provider_name, type_name);
+
+ break;
+ }
+
+ case LTTNG_EVENT_EXPR_TYPE_ARRAY_FIELD_ELEMENT:
+ {
+ unsigned int index;
+ const struct lttng_event_expr *parent_expr;
+ enum lttng_event_expr_status status;
+
+ parent_expr = lttng_event_expr_array_field_element_get_parent_expr(
+ event_expr);
+ LTTNG_ASSERT(parent_expr != NULL);
+
+ print_one_event_expr(parent_expr);
+
+ status = lttng_event_expr_array_field_element_get_index(
+ event_expr, &index);
+ LTTNG_ASSERT(status == LTTNG_EVENT_EXPR_STATUS_OK);
+
+ printf("[%u]", index);
+
+ break;
+ }
+
+ default:
+ abort();
+ }
+}
+
+static bool action_group_contains_notify(
+ const struct lttng_action *action_group)
+{
+ unsigned int i, count;
+ enum lttng_action_status status =
+ lttng_action_list_get_count(action_group, &count);
+
+ if (status != LTTNG_ACTION_STATUS_OK) {
+ printf("Failed to get action count from action group\n");
+ exit(1);
+ }
+
+ for (i = 0; i < count; i++) {
+ const struct lttng_action *action =
+ lttng_action_list_get_at_index(action_group, i);
+ const enum lttng_action_type action_type =
+ lttng_action_get_type(action);
+
+ if (action_type == LTTNG_ACTION_TYPE_NOTIFY) {
+ return true;
+ }
+ }
+ return false;
+}
+
+static int print_capture(const struct lttng_condition *condition,
+ const struct lttng_event_field_value *capture,
+ unsigned int indent_level)
+{
+ int ret = 0;
+ enum lttng_event_field_value_status event_field_status;
+ uint64_t u_val;
+ int64_t s_val;
+ double d_val;
+ const char *string_val = NULL;
+
+ switch (lttng_event_field_value_get_type(capture)) {
+ case LTTNG_EVENT_FIELD_VALUE_TYPE_UNSIGNED_INT:
+ {
+ event_field_status =
+ lttng_event_field_value_unsigned_int_get_value(
+ capture, &u_val);
+ if (event_field_status != LTTNG_EVENT_FIELD_VALUE_STATUS_OK) {
+ ret = 1;
+ goto end;
+ }
+
+ printf("[Unsigned int] %" PRIu64, u_val);
+ break;
+ }
+ case LTTNG_EVENT_FIELD_VALUE_TYPE_SIGNED_INT:
+ {
+ event_field_status =
+ lttng_event_field_value_signed_int_get_value(
+ capture, &s_val);
+ if (event_field_status != LTTNG_EVENT_FIELD_VALUE_STATUS_OK) {
+ ret = 1;
+ goto end;
+ }
+
+ printf("[Signed int] %" PRId64, s_val);
+ break;
+ }
+ case LTTNG_EVENT_FIELD_VALUE_TYPE_UNSIGNED_ENUM:
+ {
+ event_field_status =
+ lttng_event_field_value_unsigned_int_get_value(
+ capture, &u_val);
+ if (event_field_status != LTTNG_EVENT_FIELD_VALUE_STATUS_OK) {
+ ret = 1;
+ goto end;
+ }
+
+ printf("[Unsigned enum] %" PRIu64, u_val);
+ break;
+ }
+ case LTTNG_EVENT_FIELD_VALUE_TYPE_SIGNED_ENUM:
+ {
+ event_field_status =
+ lttng_event_field_value_signed_int_get_value(
+ capture, &s_val);
+ if (event_field_status != LTTNG_EVENT_FIELD_VALUE_STATUS_OK) {
+ ret = 1;
+ goto end;
+ }
+
+ printf("[Signed enum] %" PRId64, s_val);
+ break;
+ }
+ case LTTNG_EVENT_FIELD_VALUE_TYPE_REAL:
+ {
+ event_field_status = lttng_event_field_value_real_get_value(
+ capture, &d_val);
+ if (event_field_status != LTTNG_EVENT_FIELD_VALUE_STATUS_OK) {
+ ret = 1;
+ goto end;
+ }
+
+ printf("[Real] %lf", d_val);
+ break;
+ }
+ case LTTNG_EVENT_FIELD_VALUE_TYPE_STRING:
+ {
+ event_field_status = lttng_event_field_value_string_get_value(
+ capture, &string_val);
+ if (event_field_status != LTTNG_EVENT_FIELD_VALUE_STATUS_OK) {
+ ret = 1;
+ goto end;
+ }
+
+ printf("[String] %s", string_val);
+ break;
+ }
+ case LTTNG_EVENT_FIELD_VALUE_TYPE_ARRAY:
+ printf("[Array] [\n");
+ print_array(condition, capture, indent_level);
+ indent(indent_level);
+ printf("]\n");
+ break;
+ case LTTNG_EVENT_FIELD_VALUE_TYPE_UNKNOWN:
+ case LTTNG_EVENT_FIELD_VALUE_TYPE_INVALID:
+ default:
+ ret = 1;
+ break;
+ }
+
+end:
+ return ret;
+}
+
+static void print_unavailabe(void)
+{
+ printf("Capture unavailable");
+}
+
+static int print_array(const struct lttng_condition *condition,
+ const struct lttng_event_field_value *array,
+ unsigned int indent_level)
+{
+ int ret = 0;
+ enum lttng_event_field_value_status event_field_status;
+ unsigned int captured_field_count;
+
+ event_field_status = lttng_event_field_value_array_get_length(
+ array, &captured_field_count);
+ if (event_field_status != LTTNG_EVENT_FIELD_VALUE_STATUS_OK) {
+ ret = 1;
+ goto end;
+ }
+
+ for (unsigned int i = 0; i < captured_field_count; i++) {
+ const struct lttng_event_field_value *captured_field = NULL;
+ const struct lttng_event_expr *expr =
+ lttng_condition_event_rule_matches_get_capture_descriptor_at_index(
+ condition, i);
+ LTTNG_ASSERT(expr);
+
+ indent(indent_level + 1);
+
+ printf("Field: ");
+ print_one_event_expr(expr);
+ printf(" Value: ");
+
+ event_field_status =
+ lttng_event_field_value_array_get_element_at_index(
+ array, i, &captured_field);
+ if (event_field_status != LTTNG_EVENT_FIELD_VALUE_STATUS_OK) {
+ if (event_field_status ==
+ LTTNG_EVENT_FIELD_VALUE_STATUS_UNAVAILABLE) {
+ print_unavailabe();
+ } else {
+ ret = 1;
+ goto end;
+ }
+ } else {
+ print_capture(condition, captured_field,
+ indent_level + 1);
+ }
+
+ if (i + 1 < captured_field_count) {
+ printf(",");
+ } else {
+ printf(".");
+ }
+ printf("\n");
+ }
+
+end:
+ return ret;
+}
+
+static int print_captures(struct lttng_notification *notification)
+{
+ int ret = 0;
+ const struct lttng_evaluation *evaluation =
+ lttng_notification_get_evaluation(notification);
+ const struct lttng_condition *condition =
+ lttng_notification_get_condition(notification);
+
+ /* Status */
+ enum lttng_condition_status condition_status;
+ enum lttng_evaluation_event_rule_matches_status evaluation_status;
+
+ const struct lttng_event_field_value *captured_field_array = NULL;
+ unsigned int expected_capture_field_count;
+
+ LTTNG_ASSERT(lttng_evaluation_get_type(evaluation) ==
+ LTTNG_CONDITION_TYPE_EVENT_RULE_MATCHES);
+
+ condition_status =
+ lttng_condition_event_rule_matches_get_capture_descriptor_count(
+ condition,
+ &expected_capture_field_count);
+ if (condition_status != LTTNG_CONDITION_STATUS_OK) {
+ ret = 1;
+ goto end;
+ }
+
+ if (expected_capture_field_count == 0) {
+ ret = 0;
+ goto end;
+ }
+
+ evaluation_status =
+ lttng_evaluation_event_rule_matches_get_captured_values(
+ evaluation, &captured_field_array);
+ if (evaluation_status != LTTNG_EVALUATION_EVENT_RULE_MATCHES_STATUS_OK) {
+ ret = 1;
+ goto end;
+ }
+
+ printf("Captured field values:\n");
+ print_array(condition, captured_field_array, 1);
+end:
+ return ret;
+}
+
+static int print_notification(struct lttng_notification *notification)
+{
+ int ret = 0;
+ const struct lttng_evaluation *evaluation =
+ lttng_notification_get_evaluation(notification);
+ const enum lttng_condition_type type =
+ lttng_evaluation_get_type(evaluation);
+
+ switch (type) {
+ case LTTNG_CONDITION_TYPE_SESSION_CONSUMED_SIZE:
+ printf("Received consumed size notification\n");
+ break;
+ case LTTNG_CONDITION_TYPE_BUFFER_USAGE_LOW:
+ case LTTNG_CONDITION_TYPE_BUFFER_USAGE_HIGH:
+ printf("Received buffer usage notification\n");
+ break;
+ case LTTNG_CONDITION_TYPE_SESSION_ROTATION_ONGOING:
+ printf("Received session rotation ongoing notification\n");
+ break;
+ case LTTNG_CONDITION_TYPE_SESSION_ROTATION_COMPLETED:
+ printf("Received session rotation completed notification\n");
+ break;
+ case LTTNG_CONDITION_TYPE_EVENT_RULE_MATCHES:
+ {
+ const char *trigger_name;
+ enum lttng_trigger_status trigger_status;
+ char time_str[64];
+ struct timeval tv;
+ time_t the_time;
+ const struct lttng_trigger *trigger = NULL;
+
+ gettimeofday(&tv, NULL);
+ the_time = tv.tv_sec;
+
+ strftime(time_str, sizeof(time_str), "[%m-%d-%Y] %T",
+ localtime(&the_time));
+ printf("%s.%ld - ", time_str, tv.tv_usec);
+
+ trigger = lttng_notification_get_trigger(notification);
+ if (!trigger) {
+ fprintf(stderr, "Failed to retrieve notification's trigger");
+ goto end;
+ }
+
+ trigger_status = lttng_trigger_get_name(trigger, &trigger_name);
+ if (trigger_status != LTTNG_TRIGGER_STATUS_OK) {
+ fprintf(stderr, "Failed to retrieve trigger's name");
+ goto end;
+ }
+
+ printf("Received notification of event rule matches trigger \"%s\"\n",
+ trigger_name);
+ ret = print_captures(notification);
+ break;
+ }
+ default:
+ fprintf(stderr, "Unknown notification type (%d)\n", type);
+ }
+
+end:
+ return ret;
+}
+
+int main(int argc, char **argv)
+{
+ int ret;
+ struct lttng_triggers *triggers = NULL;
+ unsigned int count, i, j, subcription_count = 0, trigger_count;
+ enum lttng_trigger_status trigger_status;
+ struct lttng_notification_channel *notification_channel = NULL;
+
+ if (argc < 2) {
+ fprintf(stderr, "Missing trigger name(s)\n");
+ fprintf(stderr, "Usage: notification-client TRIGGER_NAME ...");
+ ret = -1;
+ goto end;
+ }
+
+ trigger_count = argc - 1;
+
+ notification_channel = lttng_notification_channel_create(
+ lttng_session_daemon_notification_endpoint);
+ if (!notification_channel) {
+ fprintf(stderr, "Failed to create notification channel\n");
+ ret = -1;
+ goto end;
+ }
+
+ ret = lttng_list_triggers(&triggers);
+ if (ret != LTTNG_OK) {
+ fprintf(stderr, "Failed to list triggers\n");
+ goto end;
+ }
+
+ trigger_status = lttng_triggers_get_count(triggers, &count);
+ if (trigger_status != LTTNG_TRIGGER_STATUS_OK) {
+ fprintf(stderr, "Failed to get trigger count\n");
+ ret = -1;
+ goto end;
+ }
+
+ for (i = 0; i < count; i++) {
+ const struct lttng_trigger *trigger =
+ lttng_triggers_get_at_index(triggers, i);
+ const struct lttng_condition *condition =
+ lttng_trigger_get_const_condition(trigger);
+ const struct lttng_action *action =
+ lttng_trigger_get_const_action(trigger);
+ const enum lttng_action_type action_type =
+ lttng_action_get_type(action);
+ enum lttng_notification_channel_status channel_status;
+ const char *trigger_name = NULL;
+ bool subscribe = false;
+
+ lttng_trigger_get_name(trigger, &trigger_name);
+ for (j = 0; j < trigger_count; j++) {
+ if (!strcmp(trigger_name, argv[j + 1])) {
+ subscribe = true;
+ break;
+ }
+ }
+
+ if (!subscribe) {
+ continue;
+ }
+
+ if (!((action_type == LTTNG_ACTION_TYPE_LIST &&
+ action_group_contains_notify(action)) ||
+ action_type == LTTNG_ACTION_TYPE_NOTIFY)) {
+ printf("The action of trigger \"%s\" is not \"notify\", skipping.\n",
+ trigger_name);
+ continue;
+ }
+
+ channel_status = lttng_notification_channel_subscribe(
+ notification_channel, condition);
+ if (channel_status ==
+ LTTNG_NOTIFICATION_CHANNEL_STATUS_ALREADY_SUBSCRIBED) {
+ continue;
+ }
+ if (channel_status) {
+ fprintf(stderr, "Failed to subscribe to notifications of trigger \"%s\"\n",
+ trigger_name);
+ ret = -1;
+ goto end;
+ }
+
+ printf("Subscribed to notifications of trigger \"%s\"\n",
+ trigger_name);
+ subcription_count++;
+ }
+
+ if (subcription_count == 0) {
+ printf("No matching trigger with a notify action found.\n");
+ ret = 0;
+ goto end;
+ }
+
+ for (;;) {
+ struct lttng_notification *notification;
+ enum lttng_notification_channel_status channel_status;
+
+ channel_status =
+ lttng_notification_channel_get_next_notification(
+ notification_channel,
+ ¬ification);
+ switch (channel_status) {
+ case LTTNG_NOTIFICATION_CHANNEL_STATUS_NOTIFICATIONS_DROPPED:
+ printf("Dropped notification\n");
+ break;
+ case LTTNG_NOTIFICATION_CHANNEL_STATUS_INTERRUPTED:
+ ret = 0;
+ goto end;
+ case LTTNG_NOTIFICATION_CHANNEL_STATUS_OK:
+ break;
+ case LTTNG_NOTIFICATION_CHANNEL_STATUS_CLOSED:
+ printf("Notification channel was closed by peer.\n");
+ break;
+ default:
+ fprintf(stderr, "A communication error occurred on the notification channel.\n");
+ ret = -1;
+ goto end;
+ }
+
+ ret = print_notification(notification);
+ lttng_notification_destroy(notification);
+ if (ret) {
+ goto end;
+ }
+ }
+end:
+ lttng_triggers_destroy(triggers);
+ lttng_notification_channel_destroy(notification_channel);
+ return !!ret;
+}
EXTRA_DIST += test_ust test_ust_tracefile_count test_lttng_ust
endif
-live_test_SOURCES = live_test.c
+live_test_SOURCES = live_test.cpp
live_test_LDADD = $(LIBTAP) $(LIBLTTNG_SESSIOND_COMMON) $(DL_LIBS)
all-local:
+++ /dev/null
-/*
- * Copyright (C) 2013 Julien Desfossez <jdesfossez@efficios.com>
- *
- * SPDX-License-Identifier: GPL-2.0-only
- *
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-#include <common/compat/time.h>
-#include <sys/types.h>
-#include <inttypes.h>
-#include <stdlib.h>
-#include <sys/socket.h>
-#include <netinet/in.h>
-#include <netdb.h>
-#include <fcntl.h>
-#include <sys/mman.h>
-#include <sys/stat.h>
-
-#include <tap/tap.h>
-#include <lttng/lttng.h>
-
-#include <urcu/list.h>
-#include <common/common.h>
-
-#include <bin/lttng-relayd/lttng-viewer-abi.h>
-#include <common/index/ctf-index.h>
-
-#include <common/compat/errno.h>
-#include <common/compat/endian.h>
-
-#define SESSION1 "test1"
-#define RELAYD_URL "net://localhost"
-#define LIVE_TIMER 2000000
-
-/* Number of TAP tests in this file */
-#define NUM_TESTS 11
-#define mmap_size 524288
-
-#ifdef HAVE_LIBLTTNG_UST_CTL
-#include <lttng/lttng-export.h>
-#include <lttng/ust-sigbus.h>
-LTTNG_EXPORT DEFINE_LTTNG_UST_SIGBUS_STATE();
-#endif
-
-static int control_sock;
-struct live_session *session;
-
-static int first_packet_offset;
-static int first_packet_len;
-static int first_packet_stream_id = -1;
-
-struct viewer_stream {
- uint64_t id;
- uint64_t ctf_trace_id;
- void *mmap_base;
- int fd;
- int metadata_flag;
- int first_read;
- char path[PATH_MAX];
-};
-
-struct live_session {
- struct viewer_stream *streams;
- uint64_t live_timer_interval;
- uint64_t stream_count;
-};
-
-static
-ssize_t lttng_live_recv(int fd, void *buf, size_t len)
-{
- ssize_t ret;
- size_t copied = 0, to_copy = len;
-
- do {
- ret = recv(fd, buf + copied, to_copy, 0);
- if (ret > 0) {
- LTTNG_ASSERT(ret <= to_copy);
- copied += ret;
- to_copy -= ret;
- }
- } while ((ret > 0 && to_copy > 0)
- || (ret < 0 && errno == EINTR));
- if (ret > 0)
- ret = copied;
- /* ret = 0 means orderly shutdown, ret < 0 is error. */
- return ret;
-}
-
-static
-ssize_t lttng_live_send(int fd, const void *buf, size_t len)
-{
- ssize_t ret;
-
- do {
- ret = send(fd, buf, len, MSG_NOSIGNAL);
- } while (ret < 0 && errno == EINTR);
- return ret;
-}
-
-static
-int connect_viewer(const char *hostname)
-{
- struct hostent *host;
- struct sockaddr_in server_addr;
- int ret;
-
- host = gethostbyname(hostname);
- if (!host) {
- ret = -1;
- goto end;
- }
-
- if ((control_sock = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
- PERROR("Socket");
- ret = -1;
- goto end;
- }
-
- server_addr.sin_family = AF_INET;
- server_addr.sin_port = htons(5344);
- server_addr.sin_addr = *((struct in_addr *) host->h_addr);
- bzero(&(server_addr.sin_zero), 8);
-
- if (connect(control_sock, (struct sockaddr *) &server_addr,
- sizeof(struct sockaddr)) == -1) {
- PERROR("Connect");
- ret = -1;
- goto end;
- }
-
- server_addr.sin_family = AF_INET;
- server_addr.sin_port = htons(5345);
- server_addr.sin_addr = *((struct in_addr *) host->h_addr);
- bzero(&(server_addr.sin_zero), 8);
-
- ret = 0;
-
-end:
- return ret;
-}
-
-static
-int establish_connection(void)
-{
- struct lttng_viewer_cmd cmd;
- struct lttng_viewer_connect connect;
- ssize_t ret_len;
-
- cmd.cmd = htobe32(LTTNG_VIEWER_CONNECT);
- cmd.data_size = htobe64(sizeof(connect));
- cmd.cmd_version = htobe32(0);
-
- memset(&connect, 0, sizeof(connect));
- connect.major = htobe32(VERSION_MAJOR);
- connect.minor = htobe32(VERSION_MINOR);
- connect.type = htobe32(LTTNG_VIEWER_CLIENT_COMMAND);
-
- ret_len = lttng_live_send(control_sock, &cmd, sizeof(cmd));
- if (ret_len < 0) {
- diag("Error sending cmd");
- goto error;
- }
- ret_len = lttng_live_send(control_sock, &connect, sizeof(connect));
- if (ret_len < 0) {
- diag("Error sending version");
- goto error;
- }
-
- ret_len = lttng_live_recv(control_sock, &connect, sizeof(connect));
- if (ret_len == 0) {
- diag("[error] Remote side has closed connection");
- goto error;
- }
- if (ret_len < 0) {
- diag("Error receiving version");
- goto error;
- }
- return 0;
-
-error:
- return -1;
-}
-
-/*
- * Returns the number of sessions, should be 1 during the unit test.
- */
-static
-int list_sessions(uint64_t *session_id)
-{
- struct lttng_viewer_cmd cmd;
- struct lttng_viewer_list_sessions list;
- struct lttng_viewer_session lsession;
- int i;
- ssize_t ret_len;
- int first_session = 0;
-
- cmd.cmd = htobe32(LTTNG_VIEWER_LIST_SESSIONS);
- cmd.data_size = htobe64(0);
- cmd.cmd_version = htobe32(0);
-
- ret_len = lttng_live_send(control_sock, &cmd, sizeof(cmd));
- if (ret_len < 0) {
- diag("Error sending cmd");
- goto error;
- }
-
- ret_len = lttng_live_recv(control_sock, &list, sizeof(list));
- if (ret_len == 0) {
- diag("[error] Remote side has closed connection");
- goto error;
- }
- if (ret_len < 0) {
- diag("Error receiving session list");
- goto error;
- }
-
- for (i = 0; i < be32toh(list.sessions_count); i++) {
- ret_len = lttng_live_recv(control_sock, &lsession, sizeof(lsession));
- if (ret_len < 0) {
- diag("Error receiving session");
- goto error;
- }
- if (lsession.streams > 0 && first_session <= 0) {
- first_session = be64toh(lsession.id);
- *session_id = first_session;
- }
- }
-
- return be32toh(list.sessions_count);
-
-error:
- return -1;
-}
-
-static
-int create_viewer_session(void)
-{
- struct lttng_viewer_cmd cmd;
- struct lttng_viewer_create_session_response resp;
- ssize_t ret_len;
-
- cmd.cmd = htobe32(LTTNG_VIEWER_CREATE_SESSION);
- cmd.data_size = htobe64(0);
- cmd.cmd_version = htobe32(0);
-
- ret_len = lttng_live_send(control_sock, &cmd, sizeof(cmd));
- if (ret_len < 0) {
- diag("[error] Error sending cmd");
- goto error;
- }
- LTTNG_ASSERT(ret_len == sizeof(cmd));
-
- ret_len = lttng_live_recv(control_sock, &resp, sizeof(resp));
- if (ret_len == 0) {
- diag("[error] Remote side has closed connection");
- goto error;
- }
- if (ret_len < 0) {
- diag("[error] Error receiving create session reply");
- goto error;
- }
- LTTNG_ASSERT(ret_len == sizeof(resp));
-
- if (be32toh(resp.status) != LTTNG_VIEWER_CREATE_SESSION_OK) {
- diag("[error] Error creating viewer session");
- goto error;
- }
- return 0;
-
-error:
- return -1;
-}
-
-static
-int attach_session(uint64_t id)
-{
- struct lttng_viewer_cmd cmd;
- struct lttng_viewer_attach_session_request rq;
- struct lttng_viewer_attach_session_response rp;
- struct lttng_viewer_stream stream;
- int i;
- ssize_t ret_len;
-
- session = zmalloc(sizeof(struct live_session));
- if (!session) {
- goto error;
- }
-
- cmd.cmd = htobe32(LTTNG_VIEWER_ATTACH_SESSION);
- cmd.data_size = htobe64(sizeof(rq));
- cmd.cmd_version = htobe32(0);
-
- memset(&rq, 0, sizeof(rq));
- rq.session_id = htobe64(id);
- rq.seek = htobe32(LTTNG_VIEWER_SEEK_BEGINNING);
-
- ret_len = lttng_live_send(control_sock, &cmd, sizeof(cmd));
- if (ret_len < 0) {
- diag("Error sending cmd LTTNG_VIEWER_ATTACH_SESSION");
- goto error;
- }
- ret_len = lttng_live_send(control_sock, &rq, sizeof(rq));
- if (ret_len < 0) {
- diag("Error sending attach request");
- goto error;
- }
-
- ret_len = lttng_live_recv(control_sock, &rp, sizeof(rp));
- if (ret_len == 0) {
- diag("[error] Remote side has closed connection");
- goto error;
- }
- if (ret_len < 0) {
- diag("Error receiving attach response");
- goto error;
- }
- if (be32toh(rp.status) != LTTNG_VIEWER_ATTACH_OK) {
- goto error;
- }
-
- session->stream_count = be32toh(rp.streams_count);
- if (session->stream_count == 0) {
- diag("Got session stream count == 0");
- goto error;
- }
- session->streams = zmalloc(session->stream_count *
- sizeof(struct viewer_stream));
- if (!session->streams) {
- goto error;
- }
-
- for (i = 0; i < be32toh(rp.streams_count); i++) {
- ret_len = lttng_live_recv(control_sock, &stream, sizeof(stream));
- if (ret_len == 0) {
- diag("[error] Remote side has closed connection");
- goto error;
- }
- if (ret_len < 0) {
- diag("Error receiving stream");
- goto error;
- }
- session->streams[i].id = be64toh(stream.id);
-
- session->streams[i].ctf_trace_id = be64toh(stream.ctf_trace_id);
- session->streams[i].first_read = 1;
- session->streams[i].mmap_base = mmap(NULL, mmap_size,
- PROT_READ | PROT_WRITE,
- MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
- if (session->streams[i].mmap_base == MAP_FAILED) {
- diag("mmap error");
- goto error;
- }
-
- if (be32toh(stream.metadata_flag)) {
- session->streams[i].metadata_flag = 1;
- }
- }
- return session->stream_count;
-
-error:
- return -1;
-}
-
-static
-int get_metadata(void)
-{
- struct lttng_viewer_cmd cmd;
- struct lttng_viewer_get_metadata rq;
- struct lttng_viewer_metadata_packet rp;
- ssize_t ret_len;
- int ret;
- uint64_t i;
- char *data = NULL;
- uint64_t len = 0;
- int metadata_stream_id = -1;
-
- cmd.cmd = htobe32(LTTNG_VIEWER_GET_METADATA);
- cmd.data_size = htobe64(sizeof(rq));
- cmd.cmd_version = htobe32(0);
-
- for (i = 0; i < session->stream_count; i++) {
- if (session->streams[i].metadata_flag) {
- metadata_stream_id = i;
- break;
- }
- }
-
- if (metadata_stream_id < 0) {
- diag("No metadata stream found");
- goto error;
- }
-
- rq.stream_id = htobe64(session->streams[metadata_stream_id].id);
-
-retry:
- ret_len = lttng_live_send(control_sock, &cmd, sizeof(cmd));
- if (ret_len < 0) {
- diag("Error sending cmd");
- goto error;
- }
- ret_len = lttng_live_send(control_sock, &rq, sizeof(rq));
- if (ret_len < 0) {
- diag("Error sending get_metadata request");
- goto error;
- }
- ret_len = lttng_live_recv(control_sock, &rp, sizeof(rp));
- if (ret_len == 0) {
- diag("[error] Remote side has closed connection");
- goto error;
- }
- if (ret_len < 0) {
- diag("Error receiving metadata response");
- goto error;
- }
- switch (be32toh(rp.status)) {
- case LTTNG_VIEWER_METADATA_OK:
- break;
- case LTTNG_VIEWER_NO_NEW_METADATA:
- diag("Got LTTNG_VIEWER_NO_NEW_METADATA:");
- usleep(50);
- goto retry;
- case LTTNG_VIEWER_METADATA_ERR:
- diag("Got LTTNG_VIEWER_METADATA_ERR:");
- goto error;
- default:
- diag("Got unknown status during LTTNG_VIEWER_GET_METADATA");
- goto error;
- }
-
- len = be64toh(rp.len);
- if (len <= 0) {
- goto error;
- }
-
- data = zmalloc(len);
- if (!data) {
- PERROR("relay data zmalloc");
- goto error;
- }
- ret_len = lttng_live_recv(control_sock, data, len);
- if (ret_len == 0) {
- diag("[error] Remote side has closed connection");
- goto error_free_data;
- }
- if (ret_len < 0) {
- diag("Error receiving trace packet");
- goto error_free_data;
- }
- free(data);
- ret = len;
-
- return ret;
-
-error_free_data:
- free(data);
-error:
- return -1;
-}
-
-static
-int get_next_index(void)
-{
- struct lttng_viewer_cmd cmd;
- struct lttng_viewer_get_next_index rq;
- struct lttng_viewer_index rp;
- ssize_t ret_len;
- int id;
-
- cmd.cmd = htobe32(LTTNG_VIEWER_GET_NEXT_INDEX);
- cmd.data_size = htobe64(sizeof(rq));
- cmd.cmd_version = htobe32(0);
-
- for (id = 0; id < session->stream_count; id++) {
- if (session->streams[id].metadata_flag) {
- continue;
- }
- memset(&rq, 0, sizeof(rq));
- rq.stream_id = htobe64(session->streams[id].id);
-
-retry:
- ret_len = lttng_live_send(control_sock, &cmd, sizeof(cmd));
- if (ret_len < 0) {
- diag("Error sending cmd");
- goto error;
- }
- ret_len = lttng_live_send(control_sock, &rq, sizeof(rq));
- if (ret_len < 0) {
- diag("Error sending get_next_index request");
- goto error;
- }
- ret_len = lttng_live_recv(control_sock, &rp, sizeof(rp));
- if (ret_len == 0) {
- diag("[error] Remote side has closed connection");
- goto error;
- }
- if (ret_len < 0) {
- diag("Error receiving index response");
- goto error;
- }
-
- rp.flags = be32toh(rp.flags);
-
- switch (be32toh(rp.status)) {
- case LTTNG_VIEWER_INDEX_INACTIVE:
- /* Skip this stream. */
- diag("Got LTTNG_VIEWER_INDEX_INACTIVE");
- continue;
- case LTTNG_VIEWER_INDEX_OK:
- break;
- case LTTNG_VIEWER_INDEX_RETRY:
- sleep(1);
- goto retry;
- case LTTNG_VIEWER_INDEX_HUP:
- diag("Got LTTNG_VIEWER_INDEX_HUP");
- session->streams[id].id = -1ULL;
- session->streams[id].fd = -1;
- goto error;
- case LTTNG_VIEWER_INDEX_ERR:
- diag("Got LTTNG_VIEWER_INDEX_ERR");
- goto error;
- default:
- diag("Unknown reply status during LTTNG_VIEWER_GET_NEXT_INDEX (%d)", be32toh(rp.status));
- goto error;
- }
- if (first_packet_stream_id < 0) {
- /*
- * Initialize the first packet stream id. That is,
- * the first active stream encoutered.
- */
- first_packet_offset = be64toh(rp.offset);
- first_packet_len = be64toh(rp.packet_size) / CHAR_BIT;
- first_packet_stream_id = id;
- diag("Got first packet index with offset %d and len %d",
- first_packet_offset, first_packet_len);
- }
- }
- return 0;
-
-error:
- return -1;
-}
-
-static
-int get_data_packet(int id, uint64_t offset,
- uint64_t len)
-{
- struct lttng_viewer_cmd cmd;
- struct lttng_viewer_get_packet rq;
- struct lttng_viewer_trace_packet rp;
- ssize_t ret_len;
-
- cmd.cmd = htobe32(LTTNG_VIEWER_GET_PACKET);
- cmd.data_size = htobe64(sizeof(rq));
- cmd.cmd_version = htobe32(0);
-
- memset(&rq, 0, sizeof(rq));
- rq.stream_id = htobe64(session->streams[id].id);
- /* Already in big endian. */
- rq.offset = offset;
- rq.len = htobe32(len);
-
- ret_len = lttng_live_send(control_sock, &cmd, sizeof(cmd));
- if (ret_len < 0) {
- diag("Error sending cmd");
- goto error;
- }
- ret_len = lttng_live_send(control_sock, &rq, sizeof(rq));
- if (ret_len < 0) {
- diag("Error sending get_data_packet request");
- goto error;
- }
- ret_len = lttng_live_recv(control_sock, &rp, sizeof(rp));
- if (ret_len == 0) {
- diag("[error] Remote side has closed connection");
- goto error;
- }
- if (ret_len < 0) {
- diag("Error receiving data response");
- goto error;
- }
- rp.flags = be32toh(rp.flags);
-
- switch (be32toh(rp.status)) {
- case LTTNG_VIEWER_GET_PACKET_OK:
- len = be32toh(rp.len);
- if (len == 0) {
- diag("Got LTTNG_VIEWER_GET_PACKET_OK, but len == 0");
- goto error;
- }
- break;
- case LTTNG_VIEWER_GET_PACKET_RETRY:
- diag("Got LTTNG_VIEWER_GET_PACKET_RETRY:");
- goto error;
- case LTTNG_VIEWER_GET_PACKET_ERR:
- if (rp.flags & LTTNG_VIEWER_FLAG_NEW_METADATA) {
- diag("Got LTTNG_VIEWER_GET_PACKET_ERR with NEW_METADATA flag");
- goto end;
- }
- diag("Got LTTNG_VIEWER_GET_PACKET_ERR:");
- goto error;
- default:
- diag("Got unknown status code during LTTNG_VIEWER_GET_PACKET");
- goto error;
- }
-
- if (len > mmap_size) {
- diag("mmap_size not big enough");
- goto error;
- }
-
- ret_len = lttng_live_recv(control_sock, session->streams[id].mmap_base, len);
- if (ret_len == 0) {
- diag("[error] Remote side has closed connection");
- goto error;
- }
- if (ret_len < 0) {
- diag("Error receiving trace packet");
- goto error;
- }
-end:
- return 0;
-error:
- return -1;
-}
-
-static
-int detach_viewer_session(uint64_t id)
-{
- struct lttng_viewer_cmd cmd;
- struct lttng_viewer_detach_session_response resp;
- struct lttng_viewer_detach_session_request rq;
- int ret;
- ssize_t ret_len;
-
- cmd.cmd = htobe32(LTTNG_VIEWER_DETACH_SESSION);
- cmd.data_size = htobe64(sizeof(rq));
- cmd.cmd_version = htobe32(0);
-
- memset(&rq, 0, sizeof(rq));
- rq.session_id = htobe64(id);
-
- ret_len = lttng_live_send(control_sock, &cmd, sizeof(cmd));
- if (ret_len < 0) {
- fprintf(stderr, "[error] Error sending cmd\n");
- ret = ret_len;
- goto error;
- }
-
- ret_len = lttng_live_send(control_sock, &rq, sizeof(rq));
- if (ret_len < 0) {
- fprintf(stderr, "Error sending attach request\n");
- ret = ret_len;
- goto error;
- }
-
- ret_len = lttng_live_recv(control_sock, &resp, sizeof(resp));
- if (ret_len < 0) {
- fprintf(stderr, "[error] Error receiving detach session reply\n");
- ret = ret_len;
- goto error;
- }
-
- if (be32toh(resp.status) != LTTNG_VIEWER_DETACH_SESSION_OK) {
- fprintf(stderr, "[error] Error detaching viewer session\n");
- ret = -1;
- goto error;
- }
- ret = 0;
-
-error:
- return ret;
-}
-
-int main(int argc, char **argv)
-{
- int ret;
- uint64_t session_id;
-
- plan_tests(NUM_TESTS);
-
- diag("Live unit tests");
-
- ret = connect_viewer("localhost");
- ok(ret == 0, "Connect viewer to relayd");
-
- ret = establish_connection();
- ok(ret == 0, "Established connection and version check with %d.%d",
- VERSION_MAJOR, VERSION_MINOR);
-
- ret = list_sessions(&session_id);
- ok(ret > 0, "List sessions : %d session(s)", ret);
- if (ret < 0) {
- goto end;
- }
-
- ret = create_viewer_session();
- ok(ret == 0, "Create viewer session");
-
- ret = attach_session(session_id);
- ok(ret > 0, "Attach to session, %d stream(s) received", ret);
-
- ret = get_metadata();
- ok(ret > 0, "Get metadata, received %d bytes", ret);
-
- ret = get_next_index();
- ok(ret == 0, "Get one index per stream");
-
- ret = get_data_packet(first_packet_stream_id, first_packet_offset,
- first_packet_len);
- ok(ret == 0,
- "Get one data packet for stream %d, offset %d, len %d",
- first_packet_stream_id, first_packet_offset,
- first_packet_len);
-
- ret = detach_viewer_session(session_id);
- ok(ret == 0, "Detach viewer session");
-
- ret = list_sessions(&session_id);
- ok(ret > 0, "List sessions : %d session(s)", ret);
-
- ret = attach_session(session_id);
- ok(ret > 0, "Attach to session, %d streams received", ret);
-end:
- return exit_status();
-}
--- /dev/null
+/*
+ * Copyright (C) 2013 Julien Desfossez <jdesfossez@efficios.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0-only
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <common/compat/time.h>
+#include <sys/types.h>
+#include <inttypes.h>
+#include <stdlib.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netdb.h>
+#include <fcntl.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+
+#include <tap/tap.h>
+#include <lttng/lttng.h>
+
+#include <urcu/list.h>
+#include <common/common.h>
+
+#include <bin/lttng-relayd/lttng-viewer-abi.h>
+#include <common/index/ctf-index.h>
+
+#include <common/compat/errno.h>
+#include <common/compat/endian.h>
+
+#define SESSION1 "test1"
+#define RELAYD_URL "net://localhost"
+#define LIVE_TIMER 2000000
+
+/* Number of TAP tests in this file */
+#define NUM_TESTS 11
+#define mmap_size 524288
+
+#ifdef HAVE_LIBLTTNG_UST_CTL
+#include <lttng/lttng-export.h>
+#include <lttng/ust-sigbus.h>
+LTTNG_EXPORT DEFINE_LTTNG_UST_SIGBUS_STATE();
+#endif
+
+static int control_sock;
+struct live_session *session;
+
+static int first_packet_offset;
+static int first_packet_len;
+static int first_packet_stream_id = -1;
+
+struct viewer_stream {
+ uint64_t id;
+ uint64_t ctf_trace_id;
+ void *mmap_base;
+ int fd;
+ int metadata_flag;
+ int first_read;
+ char path[PATH_MAX];
+};
+
+struct live_session {
+ struct viewer_stream *streams;
+ uint64_t live_timer_interval;
+ uint64_t stream_count;
+};
+
+static
+ssize_t lttng_live_recv(int fd, void *buf, size_t len)
+{
+ ssize_t ret;
+ size_t copied = 0, to_copy = len;
+
+ do {
+ ret = recv(fd, (char *) buf + copied, to_copy, 0);
+ if (ret > 0) {
+ LTTNG_ASSERT(ret <= to_copy);
+ copied += ret;
+ to_copy -= ret;
+ }
+ } while ((ret > 0 && to_copy > 0)
+ || (ret < 0 && errno == EINTR));
+ if (ret > 0)
+ ret = copied;
+ /* ret = 0 means orderly shutdown, ret < 0 is error. */
+ return ret;
+}
+
+static
+ssize_t lttng_live_send(int fd, const void *buf, size_t len)
+{
+ ssize_t ret;
+
+ do {
+ ret = send(fd, buf, len, MSG_NOSIGNAL);
+ } while (ret < 0 && errno == EINTR);
+ return ret;
+}
+
+static
+int connect_viewer(const char *hostname)
+{
+ struct hostent *host;
+ struct sockaddr_in server_addr;
+ int ret;
+
+ host = gethostbyname(hostname);
+ if (!host) {
+ ret = -1;
+ goto end;
+ }
+
+ if ((control_sock = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
+ PERROR("Socket");
+ ret = -1;
+ goto end;
+ }
+
+ server_addr.sin_family = AF_INET;
+ server_addr.sin_port = htons(5344);
+ server_addr.sin_addr = *((struct in_addr *) host->h_addr);
+ bzero(&(server_addr.sin_zero), 8);
+
+ if (connect(control_sock, (struct sockaddr *) &server_addr,
+ sizeof(struct sockaddr)) == -1) {
+ PERROR("Connect");
+ ret = -1;
+ goto end;
+ }
+
+ server_addr.sin_family = AF_INET;
+ server_addr.sin_port = htons(5345);
+ server_addr.sin_addr = *((struct in_addr *) host->h_addr);
+ bzero(&(server_addr.sin_zero), 8);
+
+ ret = 0;
+
+end:
+ return ret;
+}
+
+static
+int establish_connection(void)
+{
+ struct lttng_viewer_cmd cmd;
+ struct lttng_viewer_connect connect;
+ ssize_t ret_len;
+
+ cmd.cmd = htobe32(LTTNG_VIEWER_CONNECT);
+ cmd.data_size = htobe64(sizeof(connect));
+ cmd.cmd_version = htobe32(0);
+
+ memset(&connect, 0, sizeof(connect));
+ connect.major = htobe32(VERSION_MAJOR);
+ connect.minor = htobe32(VERSION_MINOR);
+ connect.type = htobe32(LTTNG_VIEWER_CLIENT_COMMAND);
+
+ ret_len = lttng_live_send(control_sock, &cmd, sizeof(cmd));
+ if (ret_len < 0) {
+ diag("Error sending cmd");
+ goto error;
+ }
+ ret_len = lttng_live_send(control_sock, &connect, sizeof(connect));
+ if (ret_len < 0) {
+ diag("Error sending version");
+ goto error;
+ }
+
+ ret_len = lttng_live_recv(control_sock, &connect, sizeof(connect));
+ if (ret_len == 0) {
+ diag("[error] Remote side has closed connection");
+ goto error;
+ }
+ if (ret_len < 0) {
+ diag("Error receiving version");
+ goto error;
+ }
+ return 0;
+
+error:
+ return -1;
+}
+
+/*
+ * Returns the number of sessions, should be 1 during the unit test.
+ */
+static
+int list_sessions(uint64_t *session_id)
+{
+ struct lttng_viewer_cmd cmd;
+ struct lttng_viewer_list_sessions list;
+ struct lttng_viewer_session lsession;
+ int i;
+ ssize_t ret_len;
+ int first_session = 0;
+
+ cmd.cmd = htobe32(LTTNG_VIEWER_LIST_SESSIONS);
+ cmd.data_size = htobe64(0);
+ cmd.cmd_version = htobe32(0);
+
+ ret_len = lttng_live_send(control_sock, &cmd, sizeof(cmd));
+ if (ret_len < 0) {
+ diag("Error sending cmd");
+ goto error;
+ }
+
+ ret_len = lttng_live_recv(control_sock, &list, sizeof(list));
+ if (ret_len == 0) {
+ diag("[error] Remote side has closed connection");
+ goto error;
+ }
+ if (ret_len < 0) {
+ diag("Error receiving session list");
+ goto error;
+ }
+
+ for (i = 0; i < be32toh(list.sessions_count); i++) {
+ ret_len = lttng_live_recv(control_sock, &lsession, sizeof(lsession));
+ if (ret_len < 0) {
+ diag("Error receiving session");
+ goto error;
+ }
+ if (lsession.streams > 0 && first_session <= 0) {
+ first_session = be64toh(lsession.id);
+ *session_id = first_session;
+ }
+ }
+
+ return be32toh(list.sessions_count);
+
+error:
+ return -1;
+}
+
+static
+int create_viewer_session(void)
+{
+ struct lttng_viewer_cmd cmd;
+ struct lttng_viewer_create_session_response resp;
+ ssize_t ret_len;
+
+ cmd.cmd = htobe32(LTTNG_VIEWER_CREATE_SESSION);
+ cmd.data_size = htobe64(0);
+ cmd.cmd_version = htobe32(0);
+
+ ret_len = lttng_live_send(control_sock, &cmd, sizeof(cmd));
+ if (ret_len < 0) {
+ diag("[error] Error sending cmd");
+ goto error;
+ }
+ LTTNG_ASSERT(ret_len == sizeof(cmd));
+
+ ret_len = lttng_live_recv(control_sock, &resp, sizeof(resp));
+ if (ret_len == 0) {
+ diag("[error] Remote side has closed connection");
+ goto error;
+ }
+ if (ret_len < 0) {
+ diag("[error] Error receiving create session reply");
+ goto error;
+ }
+ LTTNG_ASSERT(ret_len == sizeof(resp));
+
+ if (be32toh(resp.status) != LTTNG_VIEWER_CREATE_SESSION_OK) {
+ diag("[error] Error creating viewer session");
+ goto error;
+ }
+ return 0;
+
+error:
+ return -1;
+}
+
+static
+int attach_session(uint64_t id)
+{
+ struct lttng_viewer_cmd cmd;
+ struct lttng_viewer_attach_session_request rq;
+ struct lttng_viewer_attach_session_response rp;
+ struct lttng_viewer_stream stream;
+ int i;
+ ssize_t ret_len;
+
+ session = (live_session *) zmalloc(sizeof(struct live_session));
+ if (!session) {
+ goto error;
+ }
+
+ cmd.cmd = htobe32(LTTNG_VIEWER_ATTACH_SESSION);
+ cmd.data_size = htobe64(sizeof(rq));
+ cmd.cmd_version = htobe32(0);
+
+ memset(&rq, 0, sizeof(rq));
+ rq.session_id = htobe64(id);
+ rq.seek = htobe32(LTTNG_VIEWER_SEEK_BEGINNING);
+
+ ret_len = lttng_live_send(control_sock, &cmd, sizeof(cmd));
+ if (ret_len < 0) {
+ diag("Error sending cmd LTTNG_VIEWER_ATTACH_SESSION");
+ goto error;
+ }
+ ret_len = lttng_live_send(control_sock, &rq, sizeof(rq));
+ if (ret_len < 0) {
+ diag("Error sending attach request");
+ goto error;
+ }
+
+ ret_len = lttng_live_recv(control_sock, &rp, sizeof(rp));
+ if (ret_len == 0) {
+ diag("[error] Remote side has closed connection");
+ goto error;
+ }
+ if (ret_len < 0) {
+ diag("Error receiving attach response");
+ goto error;
+ }
+ if (be32toh(rp.status) != LTTNG_VIEWER_ATTACH_OK) {
+ goto error;
+ }
+
+ session->stream_count = be32toh(rp.streams_count);
+ if (session->stream_count == 0) {
+ diag("Got session stream count == 0");
+ goto error;
+ }
+ session->streams = (viewer_stream *) zmalloc(session->stream_count *
+ sizeof(struct viewer_stream));
+ if (!session->streams) {
+ goto error;
+ }
+
+ for (i = 0; i < be32toh(rp.streams_count); i++) {
+ ret_len = lttng_live_recv(control_sock, &stream, sizeof(stream));
+ if (ret_len == 0) {
+ diag("[error] Remote side has closed connection");
+ goto error;
+ }
+ if (ret_len < 0) {
+ diag("Error receiving stream");
+ goto error;
+ }
+ session->streams[i].id = be64toh(stream.id);
+
+ session->streams[i].ctf_trace_id = be64toh(stream.ctf_trace_id);
+ session->streams[i].first_read = 1;
+ session->streams[i].mmap_base = mmap(NULL, mmap_size,
+ PROT_READ | PROT_WRITE,
+ MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
+ if (session->streams[i].mmap_base == MAP_FAILED) {
+ diag("mmap error");
+ goto error;
+ }
+
+ if (be32toh(stream.metadata_flag)) {
+ session->streams[i].metadata_flag = 1;
+ }
+ }
+ return session->stream_count;
+
+error:
+ return -1;
+}
+
+static
+int get_metadata(void)
+{
+ struct lttng_viewer_cmd cmd;
+ struct lttng_viewer_get_metadata rq;
+ struct lttng_viewer_metadata_packet rp;
+ ssize_t ret_len;
+ int ret;
+ uint64_t i;
+ char *data = NULL;
+ uint64_t len = 0;
+ int metadata_stream_id = -1;
+
+ cmd.cmd = htobe32(LTTNG_VIEWER_GET_METADATA);
+ cmd.data_size = htobe64(sizeof(rq));
+ cmd.cmd_version = htobe32(0);
+
+ for (i = 0; i < session->stream_count; i++) {
+ if (session->streams[i].metadata_flag) {
+ metadata_stream_id = i;
+ break;
+ }
+ }
+
+ if (metadata_stream_id < 0) {
+ diag("No metadata stream found");
+ goto error;
+ }
+
+ rq.stream_id = htobe64(session->streams[metadata_stream_id].id);
+
+retry:
+ ret_len = lttng_live_send(control_sock, &cmd, sizeof(cmd));
+ if (ret_len < 0) {
+ diag("Error sending cmd");
+ goto error;
+ }
+ ret_len = lttng_live_send(control_sock, &rq, sizeof(rq));
+ if (ret_len < 0) {
+ diag("Error sending get_metadata request");
+ goto error;
+ }
+ ret_len = lttng_live_recv(control_sock, &rp, sizeof(rp));
+ if (ret_len == 0) {
+ diag("[error] Remote side has closed connection");
+ goto error;
+ }
+ if (ret_len < 0) {
+ diag("Error receiving metadata response");
+ goto error;
+ }
+ switch (be32toh(rp.status)) {
+ case LTTNG_VIEWER_METADATA_OK:
+ break;
+ case LTTNG_VIEWER_NO_NEW_METADATA:
+ diag("Got LTTNG_VIEWER_NO_NEW_METADATA:");
+ usleep(50);
+ goto retry;
+ case LTTNG_VIEWER_METADATA_ERR:
+ diag("Got LTTNG_VIEWER_METADATA_ERR:");
+ goto error;
+ default:
+ diag("Got unknown status during LTTNG_VIEWER_GET_METADATA");
+ goto error;
+ }
+
+ len = be64toh(rp.len);
+ if (len <= 0) {
+ goto error;
+ }
+
+ data = (char *) zmalloc(len);
+ if (!data) {
+ PERROR("relay data zmalloc");
+ goto error;
+ }
+ ret_len = lttng_live_recv(control_sock, data, len);
+ if (ret_len == 0) {
+ diag("[error] Remote side has closed connection");
+ goto error_free_data;
+ }
+ if (ret_len < 0) {
+ diag("Error receiving trace packet");
+ goto error_free_data;
+ }
+ free(data);
+ ret = len;
+
+ return ret;
+
+error_free_data:
+ free(data);
+error:
+ return -1;
+}
+
+static
+int get_next_index(void)
+{
+ struct lttng_viewer_cmd cmd;
+ struct lttng_viewer_get_next_index rq;
+ struct lttng_viewer_index rp;
+ ssize_t ret_len;
+ int id;
+
+ cmd.cmd = htobe32(LTTNG_VIEWER_GET_NEXT_INDEX);
+ cmd.data_size = htobe64(sizeof(rq));
+ cmd.cmd_version = htobe32(0);
+
+ for (id = 0; id < session->stream_count; id++) {
+ if (session->streams[id].metadata_flag) {
+ continue;
+ }
+ memset(&rq, 0, sizeof(rq));
+ rq.stream_id = htobe64(session->streams[id].id);
+
+retry:
+ ret_len = lttng_live_send(control_sock, &cmd, sizeof(cmd));
+ if (ret_len < 0) {
+ diag("Error sending cmd");
+ goto error;
+ }
+ ret_len = lttng_live_send(control_sock, &rq, sizeof(rq));
+ if (ret_len < 0) {
+ diag("Error sending get_next_index request");
+ goto error;
+ }
+ ret_len = lttng_live_recv(control_sock, &rp, sizeof(rp));
+ if (ret_len == 0) {
+ diag("[error] Remote side has closed connection");
+ goto error;
+ }
+ if (ret_len < 0) {
+ diag("Error receiving index response");
+ goto error;
+ }
+
+ rp.flags = be32toh(rp.flags);
+
+ switch (be32toh(rp.status)) {
+ case LTTNG_VIEWER_INDEX_INACTIVE:
+ /* Skip this stream. */
+ diag("Got LTTNG_VIEWER_INDEX_INACTIVE");
+ continue;
+ case LTTNG_VIEWER_INDEX_OK:
+ break;
+ case LTTNG_VIEWER_INDEX_RETRY:
+ sleep(1);
+ goto retry;
+ case LTTNG_VIEWER_INDEX_HUP:
+ diag("Got LTTNG_VIEWER_INDEX_HUP");
+ session->streams[id].id = -1ULL;
+ session->streams[id].fd = -1;
+ goto error;
+ case LTTNG_VIEWER_INDEX_ERR:
+ diag("Got LTTNG_VIEWER_INDEX_ERR");
+ goto error;
+ default:
+ diag("Unknown reply status during LTTNG_VIEWER_GET_NEXT_INDEX (%d)", be32toh(rp.status));
+ goto error;
+ }
+ if (first_packet_stream_id < 0) {
+ /*
+ * Initialize the first packet stream id. That is,
+ * the first active stream encoutered.
+ */
+ first_packet_offset = be64toh(rp.offset);
+ first_packet_len = be64toh(rp.packet_size) / CHAR_BIT;
+ first_packet_stream_id = id;
+ diag("Got first packet index with offset %d and len %d",
+ first_packet_offset, first_packet_len);
+ }
+ }
+ return 0;
+
+error:
+ return -1;
+}
+
+static
+int get_data_packet(int id, uint64_t offset,
+ uint64_t len)
+{
+ struct lttng_viewer_cmd cmd;
+ struct lttng_viewer_get_packet rq;
+ struct lttng_viewer_trace_packet rp;
+ ssize_t ret_len;
+
+ cmd.cmd = htobe32(LTTNG_VIEWER_GET_PACKET);
+ cmd.data_size = htobe64(sizeof(rq));
+ cmd.cmd_version = htobe32(0);
+
+ memset(&rq, 0, sizeof(rq));
+ rq.stream_id = htobe64(session->streams[id].id);
+ /* Already in big endian. */
+ rq.offset = offset;
+ rq.len = htobe32(len);
+
+ ret_len = lttng_live_send(control_sock, &cmd, sizeof(cmd));
+ if (ret_len < 0) {
+ diag("Error sending cmd");
+ goto error;
+ }
+ ret_len = lttng_live_send(control_sock, &rq, sizeof(rq));
+ if (ret_len < 0) {
+ diag("Error sending get_data_packet request");
+ goto error;
+ }
+ ret_len = lttng_live_recv(control_sock, &rp, sizeof(rp));
+ if (ret_len == 0) {
+ diag("[error] Remote side has closed connection");
+ goto error;
+ }
+ if (ret_len < 0) {
+ diag("Error receiving data response");
+ goto error;
+ }
+ rp.flags = be32toh(rp.flags);
+
+ switch (be32toh(rp.status)) {
+ case LTTNG_VIEWER_GET_PACKET_OK:
+ len = be32toh(rp.len);
+ if (len == 0) {
+ diag("Got LTTNG_VIEWER_GET_PACKET_OK, but len == 0");
+ goto error;
+ }
+ break;
+ case LTTNG_VIEWER_GET_PACKET_RETRY:
+ diag("Got LTTNG_VIEWER_GET_PACKET_RETRY:");
+ goto error;
+ case LTTNG_VIEWER_GET_PACKET_ERR:
+ if (rp.flags & LTTNG_VIEWER_FLAG_NEW_METADATA) {
+ diag("Got LTTNG_VIEWER_GET_PACKET_ERR with NEW_METADATA flag");
+ goto end;
+ }
+ diag("Got LTTNG_VIEWER_GET_PACKET_ERR:");
+ goto error;
+ default:
+ diag("Got unknown status code during LTTNG_VIEWER_GET_PACKET");
+ goto error;
+ }
+
+ if (len > mmap_size) {
+ diag("mmap_size not big enough");
+ goto error;
+ }
+
+ ret_len = lttng_live_recv(control_sock, session->streams[id].mmap_base, len);
+ if (ret_len == 0) {
+ diag("[error] Remote side has closed connection");
+ goto error;
+ }
+ if (ret_len < 0) {
+ diag("Error receiving trace packet");
+ goto error;
+ }
+end:
+ return 0;
+error:
+ return -1;
+}
+
+static
+int detach_viewer_session(uint64_t id)
+{
+ struct lttng_viewer_cmd cmd;
+ struct lttng_viewer_detach_session_response resp;
+ struct lttng_viewer_detach_session_request rq;
+ int ret;
+ ssize_t ret_len;
+
+ cmd.cmd = htobe32(LTTNG_VIEWER_DETACH_SESSION);
+ cmd.data_size = htobe64(sizeof(rq));
+ cmd.cmd_version = htobe32(0);
+
+ memset(&rq, 0, sizeof(rq));
+ rq.session_id = htobe64(id);
+
+ ret_len = lttng_live_send(control_sock, &cmd, sizeof(cmd));
+ if (ret_len < 0) {
+ fprintf(stderr, "[error] Error sending cmd\n");
+ ret = ret_len;
+ goto error;
+ }
+
+ ret_len = lttng_live_send(control_sock, &rq, sizeof(rq));
+ if (ret_len < 0) {
+ fprintf(stderr, "Error sending attach request\n");
+ ret = ret_len;
+ goto error;
+ }
+
+ ret_len = lttng_live_recv(control_sock, &resp, sizeof(resp));
+ if (ret_len < 0) {
+ fprintf(stderr, "[error] Error receiving detach session reply\n");
+ ret = ret_len;
+ goto error;
+ }
+
+ if (be32toh(resp.status) != LTTNG_VIEWER_DETACH_SESSION_OK) {
+ fprintf(stderr, "[error] Error detaching viewer session\n");
+ ret = -1;
+ goto error;
+ }
+ ret = 0;
+
+error:
+ return ret;
+}
+
+int main(int argc, char **argv)
+{
+ int ret;
+ uint64_t session_id;
+
+ plan_tests(NUM_TESTS);
+
+ diag("Live unit tests");
+
+ ret = connect_viewer("localhost");
+ ok(ret == 0, "Connect viewer to relayd");
+
+ ret = establish_connection();
+ ok(ret == 0, "Established connection and version check with %d.%d",
+ VERSION_MAJOR, VERSION_MINOR);
+
+ ret = list_sessions(&session_id);
+ ok(ret > 0, "List sessions : %d session(s)", ret);
+ if (ret < 0) {
+ goto end;
+ }
+
+ ret = create_viewer_session();
+ ok(ret == 0, "Create viewer session");
+
+ ret = attach_session(session_id);
+ ok(ret > 0, "Attach to session, %d stream(s) received", ret);
+
+ ret = get_metadata();
+ ok(ret > 0, "Get metadata, received %d bytes", ret);
+
+ ret = get_next_index();
+ ok(ret == 0, "Get one index per stream");
+
+ ret = get_data_packet(first_packet_stream_id, first_packet_offset,
+ first_packet_len);
+ ok(ret == 0,
+ "Get one data packet for stream %d, offset %d, len %d",
+ first_packet_stream_id, first_packet_offset,
+ first_packet_len);
+
+ ret = detach_viewer_session(session_id);
+ ok(ret == 0, "Detach viewer session");
+
+ ret = list_sessions(&session_id);
+ ok(ret > 0, "List sessions : %d session(s)", ret);
+
+ ret = attach_session(session_id);
+ ok(ret > 0, "Attach to session, %d streams received", ret);
+end:
+ return exit_status();
+}
# SPDX-License-Identifier: GPL-2.0-only
-AM_CFLAGS += -I$(top_srcdir)/tests/utils
+AM_CPPFLAGS += -I$(top_srcdir)/tests/utils
LIBTAP=$(top_builddir)/tests/utils/tap/libtap.la
LIB_LTTNG_CTL = $(top_builddir)/src/lib/lttng-ctl/liblttng-ctl.la
base_client.c \
consumer_testpoints.cpp \
sessiond_testpoints.cpp \
- notification.c \
+ notification.cpp \
test_notification_kernel_buffer_usage \
test_notification_kernel_capture \
test_notification_kernel_error \
base_client_SOURCES = base_client.c
base_client_LDADD = $(LIB_LTTNG_CTL)
-notification_SOURCES = notification.c
+notification_SOURCES = notification.cpp
# Tests the deprecated lttng_register_trigger() interface
-notification_CFLAGS = -Wno-deprecated-declarations $(AM_CFLAGS)
+notification_CXXFLAGS = -Wno-deprecated-declarations $(AM_CXXFLAGS)
notification_LDADD = $(LIB_LTTNG_CTL) $(LIBTAP) -lm
rotation_SOURCES = rotation.c
static char *pause_pipe_path;
static struct lttng_pipe *pause_pipe;
static int *data_consumption_state;
-static enum lttng_consumer_type (*lttng_consumer_get_type)(void);
+using lttng_consumer_get_type_func = enum lttng_consumer_type (*)();
+static lttng_consumer_get_type_func lttng_consumer_get_type;
int lttng_opt_verbose;
int lttng_opt_mi;
+++ /dev/null
-/*
- * notification.c
- *
- * Tests suite for LTTng notification API
- *
- * Copyright (C) 2017 Jonathan Rajotte <jonathan.rajotte-julien@efficios.com>
- *
- * SPDX-License-Identifier: MIT
- *
- */
-
-#include <math.h>
-#include <stdbool.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-#include <inttypes.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <fcntl.h>
-#include <signal.h>
-#include <poll.h>
-
-#include <common/compat/errno.h>
-#include <common/macros.h>
-#include <lttng/lttng.h>
-
-#include <tap/tap.h>
-
-#define FIELD_NAME_MAX_LEN 256
-
-/* A callback to populate the condition capture descriptor. */
-typedef int (*condition_capture_desc_cb)(struct lttng_condition *condition);
-
-/* A callback for captured field validation. */
-typedef int (*validate_cb)(const struct lttng_event_field_value *event_field, unsigned iteration);
-
-int nb_args = 0;
-int named_pipe_args_start = 0;
-pid_t app_pid = 0;
-const char *app_state_file = NULL;
-
-enum field_type {
- FIELD_TYPE_PAYLOAD,
- FIELD_TYPE_CONTEXT,
- FIELD_TYPE_APP_CONTEXT,
- FIELD_TYPE_ARRAY_FIELD,
-};
-
-struct capture_base_field_tuple {
- char* field_name;
- enum field_type field_type;
- /* Do we expect a userspace capture? */
- bool expected_ust;
- /* Do we expect a kernel capture? */
- bool expected_kernel;
- validate_cb validate_ust;
- validate_cb validate_kernel;
-};
-
-static
-const char *field_value_type_to_str(enum lttng_event_field_value_type type)
-{
- switch (type) {
- case LTTNG_EVENT_FIELD_VALUE_TYPE_UNKNOWN:
- return "UNKNOWN";
- case LTTNG_EVENT_FIELD_VALUE_TYPE_INVALID:
- return "INVALID";
- case LTTNG_EVENT_FIELD_VALUE_TYPE_UNSIGNED_INT:
- return "UNSIGNED INT";
- case LTTNG_EVENT_FIELD_VALUE_TYPE_SIGNED_INT:
- return "SIGNED INT";
- case LTTNG_EVENT_FIELD_VALUE_TYPE_UNSIGNED_ENUM:
- return "UNSIGNED ENUM";
- case LTTNG_EVENT_FIELD_VALUE_TYPE_SIGNED_ENUM:
- return "SIGNED ENUM";
- case LTTNG_EVENT_FIELD_VALUE_TYPE_REAL:
- return "REAL";
- case LTTNG_EVENT_FIELD_VALUE_TYPE_STRING:
- return "STRING";
- case LTTNG_EVENT_FIELD_VALUE_TYPE_ARRAY:
- return "ARRAY";
- default:
- abort();
- }
-}
-
-static int validate_type(const struct lttng_event_field_value *event_field,
- enum lttng_event_field_value_type expect)
-{
- int ret;
- enum lttng_event_field_value_type value;
-
- value = lttng_event_field_value_get_type(event_field);
- if (value == LTTNG_EVENT_FIELD_VALUE_TYPE_INVALID) {
- ret = 1;
- goto end;
- }
-
- ok(expect == value, "Expected field type %s, got %s",
- field_value_type_to_str(expect),
- field_value_type_to_str(value));
-
- ret = expect != value;
-
-end:
- return ret;
-}
-
-/*
- * Validate unsigned captured field against the iteration number.
- */
-static int validate_unsigned_int_field(
- const struct lttng_event_field_value *event_field,
- unsigned int expected_value)
-{
- int ret;
- uint64_t value;
- enum lttng_event_field_value_status status;
-
- ret = validate_type(
- event_field, LTTNG_EVENT_FIELD_VALUE_TYPE_UNSIGNED_INT);
- if (ret) {
- goto end;
- }
-
- status = lttng_event_field_value_unsigned_int_get_value(
- event_field, &value);
- if (status != LTTNG_EVENT_FIELD_VALUE_STATUS_OK) {
- fail("lttng_event_field_value_unsigned_int_get_value returned an error: status = %d",
- (int) status);
- ret = 1;
- goto end;
- }
-
- ok(value == (uint64_t) expected_value,
- "Expected unsigned integer value %u, got %" PRIu64,
- expected_value, value);
-
- ret = value != (uint64_t) expected_value;
-
-end:
- return ret;
-}
-
-/*
- * Validate signed captured field.
- */
-static int validate_signed_int_field(
- const struct lttng_event_field_value *event_field,
- unsigned int iteration)
-{
- int ret;
- const int64_t expected = -1;
- int64_t value;
- enum lttng_event_field_value_status status;
-
- /* Unused. */
- (void) iteration;
-
- ret = validate_type(
- event_field, LTTNG_EVENT_FIELD_VALUE_TYPE_SIGNED_INT);
- if (ret) {
- goto end;
- }
-
- status = lttng_event_field_value_signed_int_get_value(
- event_field, &value);
- if (status != LTTNG_EVENT_FIELD_VALUE_STATUS_OK) {
- fail("lttng_event_field_value_signed_int_get_value returned an error: status = %d",
- (int) status);
- ret = 1;
- goto end;
- }
-
- ok(value == expected,
- "Expected signed integer value %" PRId64
- ", got %" PRId64,
- expected, value);
-
- ret = value != expected;
-
-end:
-
- return ret;
-}
-
-/*
- * Validate array of unsigned int.
- */
-static int validate_array_unsigned_int_field(
- const struct lttng_event_field_value *event_field,
- unsigned int iteration)
-{
- int ret;
- enum lttng_event_field_value_status status;
- const unsigned int expected = 3;
- unsigned int i, count;
-
- /* Unused. */
- (void) iteration;
-
- ret = validate_type(event_field, LTTNG_EVENT_FIELD_VALUE_TYPE_ARRAY);
- if (ret) {
- goto end;
- }
-
- status = lttng_event_field_value_array_get_length(event_field, &count);
- if (status != LTTNG_EVENT_FIELD_VALUE_STATUS_OK) {
- fail("lttng_event_field_value_array_get_length");
- ret = 1;
- goto end;
- }
-
- ok(count == expected, "Expected %d subelements, got %d", expected,
- count);
- if (count != expected) {
- ret = 1;
- goto end;
- }
-
- for (i = 1; i < count + 1; i++) {
- const struct lttng_event_field_value *value;
-
- status = lttng_event_field_value_array_get_element_at_index(
- event_field, i - 1, &value);
- if (status != LTTNG_EVENT_FIELD_VALUE_STATUS_OK) {
- fail("lttng_event_field_value_array_get_element_at_index returned an error: status = %d",
- (int) status);
- ret = 1;
- goto end;
- }
-
- ret = validate_unsigned_int_field(value, i);
- if (ret) {
- goto end;
- }
- }
-
- ret = 0;
-end:
-
- return ret;
-}
-
-static int validate_array_unsigned_int_field_at_index(
- const struct lttng_event_field_value *event_field,
- unsigned int iteration)
-{
- int ret;
- const uint64_t expected_value = 2;
- enum lttng_event_field_value_status status;
- uint64_t value;
-
- /* Unused. */
- (void) iteration;
-
- ret = validate_type(
- event_field, LTTNG_EVENT_FIELD_VALUE_TYPE_UNSIGNED_INT);
- if (ret) {
- goto end;
- }
-
- status = lttng_event_field_value_unsigned_int_get_value(
- event_field, &value);
- if (status != LTTNG_EVENT_FIELD_VALUE_STATUS_OK) {
- fail("lttng_event_field_value_unsigned_int_get_value returned an error: status = %d",
- (int) status);
- ret = 1;
- goto end;
- }
-
- ok(value == expected_value,
- "Expected unsigned integer value %u, got %" PRIu64,
- expected_value, value);
-
- ret = 0;
-end:
- return ret;
-}
-
-/*
- * Validate sequence for a string (seqfield1):
- *
- * Value: "test" encoded in UTF-8: [116, 101, 115, 116]
- */
-static int validate_seqfield1(const struct lttng_event_field_value *event_field,
- unsigned int iteration)
-{
- int ret;
- enum lttng_event_field_value_status status;
- unsigned int i, count;
- const unsigned int expect[] = {116, 101, 115, 116};
- const size_t array_count = sizeof(expect) / sizeof(*expect);
-
- /* Unused. */
- (void) iteration;
-
- ret = validate_type(event_field, LTTNG_EVENT_FIELD_VALUE_TYPE_ARRAY);
- if (ret) {
- goto end;
- }
-
- status = lttng_event_field_value_array_get_length(event_field, &count);
- if (status != LTTNG_EVENT_FIELD_VALUE_STATUS_OK) {
- fail("lttng_event_field_value_array_get_length returned an error: status = %d",
- (int) status);
- ret = 1;
- goto end;
- }
-
- ok(count == array_count, "Expected %zu array sub-elements, got %d",
- array_count, count);
- if (count != array_count) {
- ret = 1;
- goto end;
- }
-
- for (i = 0; i < count; i++) {
- const struct lttng_event_field_value *value;
-
- status = lttng_event_field_value_array_get_element_at_index(
- event_field, i, &value);
- if (status != LTTNG_EVENT_FIELD_VALUE_STATUS_OK) {
- fail("lttng_event_field_value_array_get_element_at_index returned an error: status = %d",
- (int) status);
- ret = 1;
- goto end;
- }
-
- ret = validate_unsigned_int_field(value, expect[i]);
- if (ret) {
- goto end;
- }
- }
-
- ret = 0;
-end:
- return ret;
-}
-
-static int validate_string(
- const struct lttng_event_field_value *event_field,
- const char *expect)
-{
- int ret;
- const char *value = NULL;
- enum lttng_event_field_value_status status;
-
- ret = validate_type(event_field, LTTNG_EVENT_FIELD_VALUE_TYPE_STRING);
- if (ret) {
- goto end;
- }
-
- status = lttng_event_field_value_string_get_value(event_field, &value);
- if (!value) {
- fail("lttng_event_field_value_array_get_length returned an error: status = %d",
- (int) status);
- ret = 1;
- goto end;
- }
-
- ok(!strcmp(value, expect), "Expected string value \"%s\", got \"%s\"",
- expect, value);
-
- ret = 0;
-end:
-
- return ret;
-}
-
-/*
- * Validate string. Expected value is "test".
- */
-static int validate_string_test(
- const struct lttng_event_field_value *event_field,
- unsigned int iteration)
-{
- const char * const expect = "test";
-
- /* Unused. */
- (void) iteration;
-
- return validate_string(event_field, expect);
-}
-
-/*
- * Validate escaped string. Expected value is "\*".
- */
-static int validate_string_escaped(
- const struct lttng_event_field_value *event_field,
- unsigned int iteration)
-{
- const char * const expect = "\\*";
-
- /* Unused. */
- (void) iteration;
-
- return validate_string(event_field, expect);
-}
-
-/*
- * Validate real field.
- */
-static int validate_real(
- const struct lttng_event_field_value *event_field,
- double expect)
-{
- int ret;
- double value;
- enum lttng_event_field_value_status status;
-
- ret = validate_type(event_field, LTTNG_EVENT_FIELD_VALUE_TYPE_REAL);
- if (ret) {
- goto end;
- }
-
- status = lttng_event_field_value_real_get_value(event_field, &value);
- if (status != LTTNG_EVENT_FIELD_VALUE_STATUS_OK) {
- fail("lttng_event_field_value_real_get_value returned an error: status = %d",
- (int) status);
- ret = 1;
- goto end;
- }
-
- ok(value == expect, "Expected real value %f, got %f", expect, value);
- ret = value != expect;
-end:
- return ret;
-}
-
-/*
- * Validate floatfield.
- */
-static int validate_floatfield(
- const struct lttng_event_field_value *event_field,
- unsigned int iteration)
-{
- const double expect = 2222.0;
-
- /* Unused. */
- (void) iteration;
-
- return validate_real(event_field, expect);
-}
-
-/*
- * Validate doublefield.
- */
-static int validate_doublefield(
- const struct lttng_event_field_value *event_field,
- unsigned int iteration)
-{
- const double expect = 2.0;
-
- /* Unused. */
- (void) iteration;
-
- return validate_real(event_field, expect);
-}
-
-/*
- * Validate enum0: enum0 = ( "AUTO: EXPECT 0" : container = 0 )
- */
-static int validate_enum0(const struct lttng_event_field_value *event_field,
- unsigned int iteration)
-{
- int ret;
- enum lttng_event_field_value_status status;
- uint64_t value;
- const uint64_t expected_value = 0;
-
- /* Unused. */
- (void) iteration;
-
- ret = validate_type(event_field,
- LTTNG_EVENT_FIELD_VALUE_TYPE_UNSIGNED_ENUM);
- if (ret) {
- goto end;
- }
-
- status = lttng_event_field_value_unsigned_int_get_value(
- event_field, &value);
- if (status != LTTNG_EVENT_FIELD_VALUE_STATUS_OK) {
- fail("lttng_event_field_value_unsigned_int_get_value returned an error: status = %d",
- (int) status);
- ret = 1;
- goto end;
- }
-
- ok(value == expected_value,
- "Expected enum value %" PRIu64 ", got %" PRIu64,
- expected_value, value);
-
-end:
- return ret;
-}
-
-/*
- * Validate enumnegative: enumnegative = ( "AUTO: EXPECT 0" : container = 0 )
- *
- * We expect 2 labels here.
- */
-static int validate_enumnegative(
- const struct lttng_event_field_value *event_field,
- unsigned int iteration)
-{
- int ret;
- enum lttng_event_field_value_status status;
- int64_t value;
- const int64_t expected_value = -1;
-
- /* Unused. */
- (void) iteration;
-
- ret = validate_type(event_field,
- LTTNG_EVENT_FIELD_VALUE_TYPE_SIGNED_ENUM);
- if (ret) {
- goto end;
- }
-
- status = lttng_event_field_value_signed_int_get_value(
- event_field, &value);
- if (status != LTTNG_EVENT_FIELD_VALUE_STATUS_OK) {
- fail("lttng_event_field_value_unsigned_int_get_value");
- ret = 1;
- goto end;
- }
-
- ok(value == expected_value,
- "Expected enum value %" PRId64 ", got %" PRId64,
- expected_value, value);
-
-end:
- return ret;
-}
-
-static int validate_context_procname_ust(
- const struct lttng_event_field_value *event_field,
- unsigned int iteration)
-{
- /* Unused. */
- (void) iteration;
- return validate_string(event_field, "gen-ust-events");
-}
-
-static int validate_context_procname_kernel(
- const struct lttng_event_field_value *event_field,
- unsigned int iteration)
-{
- /* Unused. */
- (void) iteration;
- return validate_string(event_field, "echo");
-}
-
-struct capture_base_field_tuple test_capture_base_fields[] = {
- { "DOESNOTEXIST", FIELD_TYPE_PAYLOAD, false, false, NULL, NULL },
- { "intfield", FIELD_TYPE_PAYLOAD, true, true, validate_unsigned_int_field, validate_unsigned_int_field },
- { "longfield", FIELD_TYPE_PAYLOAD, true, true, validate_unsigned_int_field, validate_unsigned_int_field },
- { "signedfield", FIELD_TYPE_PAYLOAD, true, true, validate_signed_int_field, validate_signed_int_field },
- { "arrfield1", FIELD_TYPE_PAYLOAD, true, true, validate_array_unsigned_int_field, validate_array_unsigned_int_field },
- { "arrfield2", FIELD_TYPE_PAYLOAD, true, true, validate_string_test, validate_string_test },
- { "arrfield3", FIELD_TYPE_PAYLOAD, true, true, validate_array_unsigned_int_field, validate_array_unsigned_int_field },
- { "seqfield1", FIELD_TYPE_PAYLOAD, true, true, validate_seqfield1, validate_seqfield1 },
- { "seqfield2", FIELD_TYPE_PAYLOAD, true, true, validate_string_test, validate_string_test },
- { "seqfield3", FIELD_TYPE_PAYLOAD, true, true, validate_array_unsigned_int_field, validate_array_unsigned_int_field },
- { "seqfield4", FIELD_TYPE_PAYLOAD, true, true, validate_array_unsigned_int_field, validate_array_unsigned_int_field },
- { "arrfield1[1]", FIELD_TYPE_ARRAY_FIELD, true, true, validate_array_unsigned_int_field_at_index, validate_array_unsigned_int_field_at_index },
- { "stringfield", FIELD_TYPE_PAYLOAD, true, true, validate_string_test, validate_string_test },
- { "stringfield2", FIELD_TYPE_PAYLOAD, true, true, validate_string_escaped, validate_string_escaped },
- { "floatfield", FIELD_TYPE_PAYLOAD, true, false, validate_floatfield, validate_floatfield },
- { "doublefield", FIELD_TYPE_PAYLOAD, true, false, validate_doublefield, validate_doublefield },
- { "enum0", FIELD_TYPE_PAYLOAD, true, true, validate_enum0, validate_enum0 },
- { "enumnegative", FIELD_TYPE_PAYLOAD, true, true, validate_enumnegative, validate_enumnegative },
- { "$ctx.procname", FIELD_TYPE_CONTEXT, true, true, validate_context_procname_ust, validate_context_procname_kernel },
-};
-
-static const char *get_notification_trigger_name(
- struct lttng_notification *notification)
-{
- const char *trigger_name = NULL;
- enum lttng_trigger_status trigger_status;
- const struct lttng_trigger *trigger;
-
- trigger = lttng_notification_get_trigger(notification);
- if (!trigger) {
- fail("Failed to get trigger from notification");
- goto end;
- }
-
- trigger_status = lttng_trigger_get_name(trigger, &trigger_name);
- switch (trigger_status) {
- case LTTNG_TRIGGER_STATUS_OK:
- break;
- case LTTNG_TRIGGER_STATUS_UNSET:
- trigger_name = "(anonymous)";
- break;
- default:
- fail("Failed to get name from notification's trigger");
- goto end;
- }
-
-end:
- return trigger_name;
-}
-
-static int validator_notification_trigger_name(
- struct lttng_notification *notification,
- const char *trigger_name)
-{
- int ret;
- bool name_is_equal;
- const char *name;
-
- LTTNG_ASSERT(notification);
- LTTNG_ASSERT(trigger_name);
-
- name = get_notification_trigger_name(notification);
- if (name == NULL) {
- ret = 1;
- goto end;
- }
-
- name_is_equal = (strcmp(trigger_name, name) == 0);
- ok(name_is_equal, "Expected trigger name: %s got %s", trigger_name,
- name);
-
- ret = !name_is_equal;
-
-end:
- return ret;
-}
-
-static
-void wait_on_file(const char *path, bool file_exist)
-{
- if (!path) {
- return;
- }
- for (;;) {
- int ret;
- struct stat buf;
-
- ret = stat(path, &buf);
- if (ret == -1 && errno == ENOENT) {
- if (file_exist) {
- /*
- * The file does not exist. wait a bit and
- * continue looping until it does.
- */
- (void) poll(NULL, 0, 10);
- continue;
- }
-
- /*
- * File does not exist and the exit condition we want.
- * Break from the loop and return.
- */
- break;
- }
- if (ret) {
- perror("stat");
- exit(EXIT_FAILURE);
- }
- /*
- * stat() returned 0, so the file exists. break now only if
- * that's the exit condition we want.
- */
- if (file_exist) {
- break;
- }
- }
-}
-
-static
-int write_pipe(const char *path, uint8_t data)
-{
- int ret = 0;
- int fd = 0;
-
- fd = open(path, O_WRONLY | O_NONBLOCK);
- if (fd < 0) {
- perror("Could not open consumer control named pipe");
- goto end;
- }
-
- ret = write(fd, &data , sizeof(data));
- if (ret < 1) {
- perror("Named pipe write failed");
- if (close(fd)) {
- perror("Named pipe close failed");
- }
- ret = -1;
- goto end;
- }
-
- ret = close(fd);
- if (ret < 0) {
- perror("Name pipe closing failed");
- ret = -1;
- goto end;
- }
-end:
- return ret;
-}
-
-static
-int stop_consumer(const char **argv)
-{
- int ret = 0, i;
-
- for (i = named_pipe_args_start; i < nb_args; i++) {
- ret = write_pipe(argv[i], 49);
- }
- return ret;
-}
-
-static
-int resume_consumer(const char **argv)
-{
- int ret = 0, i;
-
- for (i = named_pipe_args_start; i < nb_args; i++) {
- ret = write_pipe(argv[i], 0);
- }
- return ret;
-}
-
-static
-int suspend_application(void)
-{
- int ret;
- struct stat buf;
-
- if (!stat(app_state_file, &buf)) {
- fail("App is already in a suspended state.");
- ret = -1;
- goto error;
- }
-
- /*
- * Send SIGUSR1 to application instructing it to bypass tracepoint.
- */
- LTTNG_ASSERT(app_pid > 1);
-
- ret = kill(app_pid, SIGUSR1);
- if (ret) {
- fail("SIGUSR1 failed. errno %d", errno);
- ret = -1;
- goto error;
- }
-
- wait_on_file(app_state_file, true);
-
-error:
- return ret;
-
-}
-
-static
-int resume_application(void)
-{
- int ret;
- struct stat buf;
-
- ret = stat(app_state_file, &buf);
- if (ret == -1 && errno == ENOENT) {
- fail("State file does not exist");
- goto error;
- }
- if (ret) {
- perror("stat");
- goto error;
- }
-
- LTTNG_ASSERT(app_pid > 1);
-
- ret = kill(app_pid, SIGUSR1);
- if (ret) {
- fail("SIGUSR1 failed. errno %d", errno);
- ret = -1;
- goto error;
- }
-
- wait_on_file(app_state_file, false);
-
-error:
- return ret;
-
-}
-
-
-static
-void test_triggers_buffer_usage_condition(const char *session_name,
- const char *channel_name,
- enum lttng_domain_type domain_type,
- enum lttng_condition_type condition_type)
-{
- unsigned int test_vector_size = 5, i;
- enum lttng_condition_status condition_status;
- struct lttng_action *action;
-
- /* Set-up */
- action = lttng_action_notify_create();
- if (!action) {
- fail("Setup error on action creation");
- goto end;
- }
-
- /* Test lttng_register_trigger with null value */
- ok(lttng_register_trigger(NULL) == -LTTNG_ERR_INVALID, "Registering a NULL trigger fails as expected");
-
- /* Test: register a trigger */
-
- for (i = 0; i < pow(2,test_vector_size); i++) {
- int loop_ret = 0;
- char *test_tuple_string = NULL;
- unsigned int mask_position = 0;
- bool session_name_set = false;
- bool channel_name_set = false;
- bool threshold_ratio_set = false;
- bool threshold_byte_set = false;
- bool domain_type_set = false;
-
- struct lttng_trigger *trigger = NULL;
- struct lttng_condition *condition = NULL;
-
- /* Create base condition */
- switch (condition_type) {
- case LTTNG_CONDITION_TYPE_BUFFER_USAGE_LOW:
- condition = lttng_condition_buffer_usage_low_create();
- break;
- case LTTNG_CONDITION_TYPE_BUFFER_USAGE_HIGH:
- condition = lttng_condition_buffer_usage_high_create();
- break;
- default:
- loop_ret = 1;
- goto loop_end;
- }
-
- if (!condition) {
- loop_ret = 1;
- goto loop_end;
-
- }
-
- /* Prepare the condition for trigger registration test */
-
- /* Set session name */
- if ((1 << mask_position) & i) {
- condition_status = lttng_condition_buffer_usage_set_session_name(
- condition, session_name);
- if (condition_status != LTTNG_CONDITION_STATUS_OK) {
- loop_ret = 1;
- goto loop_end;
- }
- session_name_set = true;
- }
- mask_position++;
-
- /* Set channel name */
- if ((1 << mask_position) & i) {
- condition_status = lttng_condition_buffer_usage_set_channel_name(
- condition, channel_name);
- if (condition_status != LTTNG_CONDITION_STATUS_OK) {
- loop_ret = 1;
- goto loop_end;
- }
- channel_name_set = true;
- }
- mask_position++;
-
- /* Set threshold ratio */
- if ((1 << mask_position) & i) {
- condition_status = lttng_condition_buffer_usage_set_threshold_ratio(
- condition, 0.0);
- if (condition_status != LTTNG_CONDITION_STATUS_OK) {
- loop_ret = 1;
- goto loop_end;
- }
- threshold_ratio_set = true;
- }
- mask_position++;
-
- /* Set threshold byte */
- if ((1 << mask_position) & i) {
- condition_status = lttng_condition_buffer_usage_set_threshold(
- condition, 0);
- if (condition_status != LTTNG_CONDITION_STATUS_OK) {
- loop_ret = 1;
- goto loop_end;
- }
- threshold_byte_set = true;
- }
- mask_position++;
-
- /* Set domain type */
- if ((1 << mask_position) & i) {
- condition_status = lttng_condition_buffer_usage_set_domain_type(
- condition, LTTNG_DOMAIN_UST);
- if (condition_status != LTTNG_CONDITION_STATUS_OK) {
- loop_ret = 1;
- goto loop_end;
- }
- domain_type_set = true;
- }
-
- /* Safety check */
- if (mask_position != test_vector_size -1) {
- LTTNG_ASSERT("Logic error for test vector generation");
- }
-
- loop_ret = asprintf(&test_tuple_string, "session name %s, channel name %s, threshold ratio %s, threshold byte %s, domain type %s",
- session_name_set ? "set" : "unset",
- channel_name_set ? "set" : "unset",
- threshold_ratio_set ? "set" : "unset",
- threshold_byte_set ? "set" : "unset",
- domain_type_set? "set" : "unset");
- if (!test_tuple_string || loop_ret < 0) {
- loop_ret = 1;
- goto loop_end;
- }
-
- /* Create trigger */
- trigger = lttng_trigger_create(condition, action);
- if (!trigger) {
- loop_ret = 1;
- goto loop_end;
- }
-
- loop_ret = lttng_register_trigger(trigger);
-
-loop_end:
- if (loop_ret == 1) {
- fail("Setup error occurred for tuple: %s", test_tuple_string);
- goto loop_cleanup;
- }
-
- /* This combination happens three times */
- if (session_name_set && channel_name_set
- && (threshold_ratio_set || threshold_byte_set)
- && domain_type_set) {
- ok(loop_ret == 0, "Trigger is registered: %s", test_tuple_string);
-
- /*
- * Test that a trigger cannot be registered
- * multiple time.
- */
- loop_ret = lttng_register_trigger(trigger);
- ok(loop_ret == -LTTNG_ERR_TRIGGER_EXISTS, "Re-register trigger fails as expected: %s", test_tuple_string);
-
- /* Test that a trigger can be unregistered */
- loop_ret = lttng_unregister_trigger(trigger);
- ok(loop_ret == 0, "Unregister trigger: %s", test_tuple_string);
-
- /*
- * Test that unregistration of a non-previously
- * registered trigger fail.
- */
- loop_ret = lttng_unregister_trigger(trigger);
- ok(loop_ret == -LTTNG_ERR_TRIGGER_NOT_FOUND, "Unregister of a non-registered trigger fails as expected: %s", test_tuple_string);
- } else {
- ok(loop_ret == -LTTNG_ERR_INVALID_TRIGGER, "Trigger is invalid as expected and cannot be registered: %s", test_tuple_string);
- }
-
-loop_cleanup:
- free(test_tuple_string);
- lttng_trigger_destroy(trigger);
- lttng_condition_destroy(condition);
- }
-
-end:
- lttng_action_destroy(action);
-}
-
-static
-void wait_data_pending(const char *session_name)
-{
- int ret;
-
- do {
- ret = lttng_data_pending(session_name);
- LTTNG_ASSERT(ret >= 0);
- } while (ret != 0);
-}
-
-static
-int setup_buffer_usage_condition(struct lttng_condition *condition,
- const char *condition_name,
- const char *session_name,
- const char *channel_name,
- const enum lttng_domain_type domain_type)
-{
- enum lttng_condition_status condition_status;
- int ret = 0;
-
- condition_status = lttng_condition_buffer_usage_set_session_name(
- condition, session_name);
- if (condition_status != LTTNG_CONDITION_STATUS_OK) {
- fail("Failed to set session name on creation of condition `%s`",
- condition_name);
- ret = -1;
- goto end;
- }
-
- condition_status = lttng_condition_buffer_usage_set_channel_name(
- condition, channel_name);
- if (condition_status != LTTNG_CONDITION_STATUS_OK) {
- fail("Failed to set channel name on creation of condition `%s`",
- condition_name);
- ret = -1;
- goto end;
- }
-
- condition_status = lttng_condition_buffer_usage_set_domain_type(
- condition, domain_type);
- if (condition_status != LTTNG_CONDITION_STATUS_OK) {
- fail("Failed to set domain type on creation of condition `%s`",
- condition_name);
- ret = -1;
- goto end;
- }
-
-end:
- return ret;
-}
-
-static
-void test_invalid_channel_subscription(
- const enum lttng_domain_type domain_type)
-{
- enum lttng_condition_status condition_status;
- enum lttng_notification_channel_status nc_status;
- struct lttng_condition *dummy_condition = NULL;
- struct lttng_condition *dummy_invalid_condition = NULL;
- struct lttng_notification_channel *notification_channel = NULL;
- int ret = 0;
-
- notification_channel = lttng_notification_channel_create(
- lttng_session_daemon_notification_endpoint);
- ok(notification_channel, "Notification channel object creation");
- if (!notification_channel) {
- goto end;
- }
-
- /*
- * Create a dummy, empty (thus invalid) condition to test error paths.
- */
- dummy_invalid_condition = lttng_condition_buffer_usage_low_create();
- if (!dummy_invalid_condition) {
- fail("Setup error on condition creation");
- goto end;
- }
-
- /*
- * Test subscription and unsubscription of an invalid condition to/from
- * a channel.
- */
- nc_status = lttng_notification_channel_subscribe(
- notification_channel, dummy_invalid_condition);
- ok(nc_status == LTTNG_NOTIFICATION_CHANNEL_STATUS_INVALID,
- "Subscribing to an invalid condition");
-
- nc_status = lttng_notification_channel_unsubscribe(
- notification_channel, dummy_invalid_condition);
- ok(nc_status == LTTNG_NOTIFICATION_CHANNEL_STATUS_INVALID,
- "Unsubscribing from an invalid condition");
-
- /* Create a valid dummy condition with a ratio of 0.5 */
- dummy_condition = lttng_condition_buffer_usage_low_create();
- if (!dummy_condition) {
- fail("Setup error on dummy_condition creation");
- goto end;
- }
-
- condition_status = lttng_condition_buffer_usage_set_threshold_ratio(
- dummy_condition, 0.5);
- if (condition_status != LTTNG_CONDITION_STATUS_OK) {
- fail("Setup error on condition creation");
- goto end;
- }
-
- ret = setup_buffer_usage_condition(dummy_condition, "dummy_condition",
- "dummy_session", "dummy_channel", domain_type);
- if (ret) {
- fail("Setup error on dummy condition creation");
- goto end;
- }
-
- /*
- * Test subscription and unsubscription to/from a channel with invalid
- * parameters.
- */
- nc_status = lttng_notification_channel_subscribe(NULL, NULL);
- ok(nc_status == LTTNG_NOTIFICATION_CHANNEL_STATUS_INVALID,
- "Notification channel subscription is invalid: NULL, NULL");
-
- nc_status = lttng_notification_channel_subscribe(
- notification_channel, NULL);
- ok(nc_status == LTTNG_NOTIFICATION_CHANNEL_STATUS_INVALID,
- "Notification channel subscription is invalid: NON-NULL, NULL");
-
- nc_status = lttng_notification_channel_subscribe(NULL, dummy_condition);
- ok(nc_status == LTTNG_NOTIFICATION_CHANNEL_STATUS_INVALID,
- "Notification channel subscription is invalid: NULL, NON-NULL");
-
- nc_status = lttng_notification_channel_unsubscribe(
- notification_channel, dummy_condition);
- ok(nc_status == LTTNG_NOTIFICATION_CHANNEL_STATUS_UNKNOWN_CONDITION,
- "Unsubscribing from a valid unknown condition");
-
-end:
- lttng_notification_channel_destroy(notification_channel);
- lttng_condition_destroy(dummy_invalid_condition);
- lttng_condition_destroy(dummy_condition);
- return;
-}
-
-enum buffer_usage_type {
- BUFFER_USAGE_TYPE_LOW,
- BUFFER_USAGE_TYPE_HIGH,
-};
-
-static int register_buffer_usage_notify_trigger(const char *session_name,
- const char *channel_name,
- const enum lttng_domain_type domain_type,
- enum buffer_usage_type buffer_usage_type,
- double ratio,
- struct lttng_condition **condition,
- struct lttng_action **action,
- struct lttng_trigger **trigger)
-{
- enum lttng_condition_status condition_status;
- struct lttng_action *tmp_action = NULL;
- struct lttng_condition *tmp_condition = NULL;
- struct lttng_trigger *tmp_trigger = NULL;
- int ret = 0;
-
- /* Set-up */
- tmp_action = lttng_action_notify_create();
- if (!action) {
- fail("Setup error on action creation");
- ret = -1;
- goto error;
- }
-
- if (buffer_usage_type == BUFFER_USAGE_TYPE_LOW) {
- tmp_condition = lttng_condition_buffer_usage_low_create();
- } else {
- tmp_condition = lttng_condition_buffer_usage_high_create();
- }
-
- if (!tmp_condition) {
- fail("Setup error on condition creation");
- ret = -1;
- goto error;
- }
-
- /* Set the buffer usage threashold */
- condition_status = lttng_condition_buffer_usage_set_threshold_ratio(
- tmp_condition, ratio);
- if (condition_status != LTTNG_CONDITION_STATUS_OK) {
- fail("Setup error on condition creation");
- ret = -1;
- goto error;
- }
-
- ret = setup_buffer_usage_condition(tmp_condition, "condition_name",
- session_name, channel_name, domain_type);
- if (ret) {
- fail("Setup error on condition creation");
- ret = -1;
- goto error;
- }
-
- /* Register the trigger for condition. */
- tmp_trigger = lttng_trigger_create(tmp_condition, tmp_action);
- if (!tmp_trigger) {
- fail("Setup error on trigger creation");
- ret = -1;
- goto error;
- }
-
- ret = lttng_register_trigger(tmp_trigger);
- if (ret) {
- fail("Setup error on trigger registration");
- ret = -1;
- goto error;
- }
-
- *condition = tmp_condition;
- *trigger = tmp_trigger;
- *action = tmp_action;
- goto end;
-
-error:
- lttng_action_destroy(tmp_action);
- lttng_condition_destroy(tmp_condition);
- lttng_trigger_destroy(tmp_trigger);
-
-end:
- return ret;
-}
-
-static void test_subscription_twice(const char *session_name,
- const char *channel_name,
- const enum lttng_domain_type domain_type)
-{
- int ret = 0;
- enum lttng_notification_channel_status nc_status;
-
- struct lttng_action *action = NULL;
- struct lttng_notification_channel *notification_channel = NULL;
- struct lttng_trigger *trigger = NULL;
-
- struct lttng_condition *condition = NULL;
-
- ret = register_buffer_usage_notify_trigger(session_name, channel_name,
- domain_type, BUFFER_USAGE_TYPE_LOW, 0.99, &condition,
- &action, &trigger);
- if (ret) {
- fail("Setup error on trigger registration in %s()",
- __FUNCTION__);
- goto end;
- }
-
- /* Begin testing. */
- notification_channel = lttng_notification_channel_create(
- lttng_session_daemon_notification_endpoint);
- ok(notification_channel, "Notification channel object creation");
- if (!notification_channel) {
- goto end;
- }
-
- /* Subscribe a valid condition. */
- nc_status = lttng_notification_channel_subscribe(
- notification_channel, condition);
- ok(nc_status == LTTNG_NOTIFICATION_CHANNEL_STATUS_OK,
- "Subscribe to condition");
-
- /* Subscribing again should fail. */
- nc_status = lttng_notification_channel_subscribe(
- notification_channel, condition);
- ok(nc_status == LTTNG_NOTIFICATION_CHANNEL_STATUS_ALREADY_SUBSCRIBED,
- "Subscribe to a condition for which subscription was already done");
-
-end:
- ret = lttng_unregister_trigger(trigger);
- if (ret) {
- fail("Failed to unregister trigger in %s()", __FUNCTION__);
- }
-
- lttng_trigger_destroy(trigger);
- lttng_notification_channel_destroy(notification_channel);
- lttng_action_destroy(action);
- lttng_condition_destroy(condition);
-}
-
-static void test_buffer_usage_notification_channel(const char *session_name,
- const char *channel_name,
- const enum lttng_domain_type domain_type,
- const char **argv)
-{
- int ret = 0;
- enum lttng_notification_channel_status nc_status;
-
- struct lttng_action *low_action = NULL;
- struct lttng_action *high_action = NULL;
- struct lttng_notification *notification = NULL;
- struct lttng_notification_channel *notification_channel = NULL;
- struct lttng_trigger *low_trigger = NULL;
- struct lttng_trigger *high_trigger = NULL;
-
- struct lttng_condition *low_condition = NULL;
- struct lttng_condition *high_condition = NULL;
-
- const double low_ratio = 0.0;
- const double high_ratio = 0.90;
-
- ret = register_buffer_usage_notify_trigger(session_name, channel_name,
- domain_type, BUFFER_USAGE_TYPE_LOW, low_ratio,
- &low_condition, &low_action, &low_trigger);
- if (ret) {
- fail("Setup error on low trigger registration");
- goto end;
- }
-
- ret = register_buffer_usage_notify_trigger(session_name, channel_name,
- domain_type, BUFFER_USAGE_TYPE_HIGH, high_ratio,
- &high_condition, &high_action, &high_trigger);
- if (ret) {
- fail("Setup error on high trigger registration");
- goto end;
- }
-
- /* Begin testing */
- notification_channel = lttng_notification_channel_create(
- lttng_session_daemon_notification_endpoint);
- ok(notification_channel, "Notification channel object creation");
- if (!notification_channel) {
- goto end;
- }
-
- /* Subscribe a valid low condition */
- nc_status = lttng_notification_channel_subscribe(
- notification_channel, low_condition);
- ok(nc_status == LTTNG_NOTIFICATION_CHANNEL_STATUS_OK,
- "Subscribe to low condition");
-
- /* Subscribe a valid high condition */
- nc_status = lttng_notification_channel_subscribe(
- notification_channel, high_condition);
- ok(nc_status == LTTNG_NOTIFICATION_CHANNEL_STATUS_OK,
- "Subscribe to high condition");
-
- resume_application();
-
- /* Wait for notification to happen */
- stop_consumer(argv);
- lttng_start_tracing(session_name);
-
- /* Wait for high notification */
- do {
- nc_status = lttng_notification_channel_get_next_notification(
- notification_channel, ¬ification);
- } while (nc_status == LTTNG_NOTIFICATION_CHANNEL_STATUS_INTERRUPTED);
- ok(nc_status == LTTNG_NOTIFICATION_CHANNEL_STATUS_OK && notification &&
- lttng_condition_get_type(lttng_notification_get_condition(
- notification)) ==
- LTTNG_CONDITION_TYPE_BUFFER_USAGE_HIGH,
- "High notification received after intermediary communication");
- lttng_notification_destroy(notification);
- notification = NULL;
-
- suspend_application();
- lttng_stop_tracing_no_wait(session_name);
- resume_consumer(argv);
- wait_data_pending(session_name);
-
- /*
- * Test that communication still work even if there is notification
- * waiting for consumption.
- */
-
- nc_status = lttng_notification_channel_unsubscribe(
- notification_channel, low_condition);
- ok(nc_status == LTTNG_NOTIFICATION_CHANNEL_STATUS_OK,
- "Unsubscribe with pending notification");
-
- nc_status = lttng_notification_channel_subscribe(
- notification_channel, low_condition);
- ok(nc_status == LTTNG_NOTIFICATION_CHANNEL_STATUS_OK,
- "Subscribe with pending notification");
-
- do {
- nc_status = lttng_notification_channel_get_next_notification(
- notification_channel, ¬ification);
- } while (nc_status == LTTNG_NOTIFICATION_CHANNEL_STATUS_INTERRUPTED);
- ok(nc_status == LTTNG_NOTIFICATION_CHANNEL_STATUS_OK && notification &&
- lttng_condition_get_type(lttng_notification_get_condition(
- notification)) ==
- LTTNG_CONDITION_TYPE_BUFFER_USAGE_LOW,
- "Low notification received after intermediary communication");
- lttng_notification_destroy(notification);
- notification = NULL;
-
- /* Stop consumer to force a high notification */
- stop_consumer(argv);
- resume_application();
- lttng_start_tracing(session_name);
-
- do {
- nc_status = lttng_notification_channel_get_next_notification(
- notification_channel, ¬ification);
- } while (nc_status == LTTNG_NOTIFICATION_CHANNEL_STATUS_INTERRUPTED);
- ok(nc_status == LTTNG_NOTIFICATION_CHANNEL_STATUS_OK && notification &&
- lttng_condition_get_type(lttng_notification_get_condition(
- notification)) ==
- LTTNG_CONDITION_TYPE_BUFFER_USAGE_HIGH,
- "High notification received after intermediary communication");
- lttng_notification_destroy(notification);
- notification = NULL;
-
- suspend_application();
- lttng_stop_tracing_no_wait(session_name);
- resume_consumer(argv);
- wait_data_pending(session_name);
-
- do {
- nc_status = lttng_notification_channel_get_next_notification(
- notification_channel, ¬ification);
- } while (nc_status == LTTNG_NOTIFICATION_CHANNEL_STATUS_INTERRUPTED);
- ok(nc_status == LTTNG_NOTIFICATION_CHANNEL_STATUS_OK && notification &&
- lttng_condition_get_type(lttng_notification_get_condition(
- notification)) ==
- LTTNG_CONDITION_TYPE_BUFFER_USAGE_LOW,
- "Low notification received after re-subscription");
- lttng_notification_destroy(notification);
- notification = NULL;
-
- stop_consumer(argv);
- resume_application();
- /* Stop consumer to force a high notification */
- lttng_start_tracing(session_name);
-
- do {
- nc_status = lttng_notification_channel_get_next_notification(
- notification_channel, ¬ification);
- } while (nc_status == LTTNG_NOTIFICATION_CHANNEL_STATUS_INTERRUPTED);
- ok(nc_status == LTTNG_NOTIFICATION_CHANNEL_STATUS_OK && notification &&
- lttng_condition_get_type(lttng_notification_get_condition(
- notification)) ==
- LTTNG_CONDITION_TYPE_BUFFER_USAGE_HIGH,
- "High notification");
- lttng_notification_destroy(notification);
- notification = NULL;
-
- suspend_application();
-
- /* Resume consumer to allow event consumption */
- lttng_stop_tracing_no_wait(session_name);
- resume_consumer(argv);
- wait_data_pending(session_name);
-
- nc_status = lttng_notification_channel_unsubscribe(
- notification_channel, low_condition);
- ok(nc_status == LTTNG_NOTIFICATION_CHANNEL_STATUS_OK,
- "Unsubscribe low condition with pending notification");
-
- nc_status = lttng_notification_channel_unsubscribe(
- notification_channel, high_condition);
- ok(nc_status == LTTNG_NOTIFICATION_CHANNEL_STATUS_OK,
- "Unsubscribe high condition with pending notification");
-
-end:
- lttng_notification_channel_destroy(notification_channel);
- lttng_trigger_destroy(low_trigger);
- lttng_trigger_destroy(high_trigger);
- lttng_action_destroy(low_action);
- lttng_action_destroy(high_action);
- lttng_condition_destroy(low_condition);
- lttng_condition_destroy(high_condition);
-}
-
-static void create_tracepoint_event_rule_trigger(const char *event_pattern,
- const char *trigger_name,
- const char *filter,
- unsigned int exclusion_count,
- const char * const *exclusions,
- enum lttng_domain_type domain_type,
- condition_capture_desc_cb capture_desc_cb,
- struct lttng_condition **condition,
- struct lttng_trigger **trigger)
-{
- typedef struct lttng_event_rule *(*event_rule_create)(void);
- typedef enum lttng_event_rule_status (
- *event_rule_set_name_pattern)(
- struct lttng_event_rule *rule,
- const char *pattern);
- typedef enum lttng_event_rule_status (*event_rule_set_filter)(
- struct lttng_event_rule *rule,
- const char *expression);
- typedef enum lttng_event_rule_status (
- *event_rule_add_name_pattern_exclusion)(
- struct lttng_event_rule * rule, const char *exclusion);
-
- enum lttng_event_rule_status event_rule_status;
- struct lttng_action *tmp_action = NULL;
- struct lttng_event_rule *event_rule = NULL;
- struct lttng_condition *tmp_condition = NULL;
- struct lttng_trigger *tmp_trigger = NULL;
- int ret;
- enum lttng_error_code ret_code;
- event_rule_create create;
- event_rule_set_name_pattern set_name_pattern;
- event_rule_set_filter set_filter;
- event_rule_add_name_pattern_exclusion add_name_pattern_exclusion;
-
- LTTNG_ASSERT(event_pattern);
- LTTNG_ASSERT(trigger_name);
- LTTNG_ASSERT(condition);
- LTTNG_ASSERT(trigger);
-
- /* Set the function pointers based on the domain type. */
- switch (domain_type) {
- case LTTNG_DOMAIN_UST:
- create = lttng_event_rule_user_tracepoint_create;
- set_name_pattern = lttng_event_rule_user_tracepoint_set_name_pattern;
- set_filter = lttng_event_rule_user_tracepoint_set_filter;
- add_name_pattern_exclusion = lttng_event_rule_user_tracepoint_add_name_pattern_exclusion;
- break;
- case LTTNG_DOMAIN_KERNEL:
- create = lttng_event_rule_kernel_tracepoint_create;
- set_name_pattern = lttng_event_rule_kernel_tracepoint_set_name_pattern;
- set_filter = lttng_event_rule_kernel_tracepoint_set_filter;
- add_name_pattern_exclusion = NULL;
- break;
- default:
- abort();
- break;
- }
-
- event_rule = create();
- ok(event_rule, "Tracepoint event rule object creation");
-
- event_rule_status = set_name_pattern(event_rule, event_pattern);
- ok(event_rule_status == LTTNG_EVENT_RULE_STATUS_OK,
- "Setting tracepoint event rule pattern: '%s'",
- event_pattern);
-
- if (filter) {
- event_rule_status = set_filter(event_rule, filter);
- ok(event_rule_status == LTTNG_EVENT_RULE_STATUS_OK,
- "Setting tracepoint event rule filter: '%s'",
- filter);
- }
-
- if (exclusions) {
- int i;
- bool success = true;
-
- LTTNG_ASSERT(domain_type == LTTNG_DOMAIN_UST);
- LTTNG_ASSERT(add_name_pattern_exclusion != NULL);
- LTTNG_ASSERT(exclusion_count > 0);
-
- for (i = 0; i < exclusion_count; i++) {
- event_rule_status = add_name_pattern_exclusion(
- event_rule, exclusions[i]);
- if (event_rule_status != LTTNG_EVENT_RULE_STATUS_OK) {
- fail("Setting tracepoint event rule exclusion '%s'.",
- exclusions[i]);
- success = false;
- }
- }
-
- ok(success, "Setting tracepoint event rule exclusions");
- }
-
- tmp_condition = lttng_condition_event_rule_matches_create(event_rule);
- ok(tmp_condition, "Condition event rule object creation");
-
- if (capture_desc_cb) {
- ret = capture_desc_cb(tmp_condition);
- if (ret) {
- fail("Failed to generate the condition capture descriptor");
- abort();
- }
- }
-
- tmp_action = lttng_action_notify_create();
- ok(tmp_action, "Action event rule object creation");
-
- tmp_trigger = lttng_trigger_create(tmp_condition, tmp_action);
- ok(tmp_trigger, "Trigger object creation %s", trigger_name);
-
- ret_code = lttng_register_trigger_with_name(tmp_trigger, trigger_name);
- ok(ret_code == LTTNG_OK, "Trigger registration %s", trigger_name);
-
- lttng_event_rule_destroy(event_rule);
-
- *condition = tmp_condition;
- *trigger = tmp_trigger;
-
- return;
-}
-
-static struct lttng_notification *get_next_notification(
- struct lttng_notification_channel *notification_channel)
-{
- struct lttng_notification *local_notification = NULL;
- enum lttng_notification_channel_status status;
-
- /* Receive the next notification. */
- status = lttng_notification_channel_get_next_notification(
- notification_channel, &local_notification);
-
- switch (status) {
- case LTTNG_NOTIFICATION_CHANNEL_STATUS_OK:
- break;
- case LTTNG_NOTIFICATION_CHANNEL_STATUS_NOTIFICATIONS_DROPPED:
- fail("Notifications have been dropped");
- local_notification = NULL;
- break;
- default:
- /* Unhandled conditions / errors. */
- fail("Failed to get next notification (unknown notification channel status): status = %d",
- (int) status);
- local_notification = NULL;
- break;
- }
-
- return local_notification;
-}
-
-static void test_tracepoint_event_rule_notification(
- enum lttng_domain_type domain_type)
-{
- int i;
- int ret;
- const int notification_count = 3;
- enum lttng_notification_channel_status nc_status;
- struct lttng_action *action = NULL;
- struct lttng_condition *condition = NULL;
- struct lttng_notification_channel *notification_channel = NULL;
- struct lttng_trigger *trigger = NULL;
- const char * const trigger_name = "my_precious";
- const char *pattern;
-
- if (domain_type == LTTNG_DOMAIN_UST) {
- pattern = "tp:tptest";
- } else {
- pattern = "lttng_test_filter_event";
- }
-
- create_tracepoint_event_rule_trigger(pattern, trigger_name, NULL, 0,
- NULL, domain_type, NULL, &condition, &trigger);
-
- notification_channel = lttng_notification_channel_create(
- lttng_session_daemon_notification_endpoint);
- ok(notification_channel, "Notification channel object creation");
-
- nc_status = lttng_notification_channel_subscribe(
- notification_channel, condition);
- ok(nc_status == LTTNG_NOTIFICATION_CHANNEL_STATUS_OK,
- "Subscribe to tracepoint event rule condition");
-
- resume_application();
-
- /* Get notifications. */
- for (i = 0; i < notification_count; i++) {
- struct lttng_notification *notification = get_next_notification(
- notification_channel);
-
- ok(notification, "Received notification (%d/%d)", i + 1,
- notification_count);
-
- /* Error. */
- if (notification == NULL) {
- goto end;
- }
-
- ret = validator_notification_trigger_name(notification, trigger_name);
- lttng_notification_destroy(notification);
- if (ret) {
- goto end;
- }
- }
-
-end:
- suspend_application();
- lttng_notification_channel_destroy(notification_channel);
- lttng_unregister_trigger(trigger);
- lttng_trigger_destroy(trigger);
- lttng_action_destroy(action);
- lttng_condition_destroy(condition);
- return;
-}
-
-static void test_tracepoint_event_rule_notification_filter(
- enum lttng_domain_type domain_type)
-{
- int i;
- const int notification_count = 3;
- enum lttng_notification_channel_status nc_status;
- struct lttng_condition *ctrl_condition = NULL, *condition = NULL;
- struct lttng_notification_channel *notification_channel = NULL;
- struct lttng_trigger *ctrl_trigger = NULL, *trigger = NULL;
- const char * const ctrl_trigger_name = "control_trigger";
- const char * const trigger_name = "trigger";
- const char *pattern;
- int ctrl_count = 0, count = 0;
-
- if (domain_type == LTTNG_DOMAIN_UST) {
- pattern = "tp:tptest";
- } else {
- pattern = "lttng_test_filter_event";
- }
-
- notification_channel = lttng_notification_channel_create(
- lttng_session_daemon_notification_endpoint);
- ok(notification_channel, "Notification channel object creation");
-
- create_tracepoint_event_rule_trigger(pattern, ctrl_trigger_name, NULL,
- 0, NULL, domain_type, NULL, &ctrl_condition, &ctrl_trigger);
-
- nc_status = lttng_notification_channel_subscribe(
- notification_channel, ctrl_condition);
- ok(nc_status == LTTNG_NOTIFICATION_CHANNEL_STATUS_OK,
- "Subscribe to tracepoint event rule condition");
-
- /*
- * Attach a filter expression to get notification only if the
- * `intfield` is even.
- */
- create_tracepoint_event_rule_trigger(pattern, trigger_name,
- "(intfield & 1) == 0", 0, NULL, domain_type, NULL, &condition,
- &trigger);
-
- nc_status = lttng_notification_channel_subscribe(
- notification_channel, condition);
- ok(nc_status == LTTNG_NOTIFICATION_CHANNEL_STATUS_OK,
- "Subscribe to tracepoint event rule condition");
-
- /*
- * We registered 2 notifications triggers, one with a filter and one
- * without (control). The one with a filter will only fired when the
- * `intfield` is a multiple of 2. We should get two times as many
- * control notifications as filter notifications.
- */
- resume_application();
-
- /*
- * Get 3 notifications. We should get 1 for the regular trigger (with
- * the filter) and 2 from the control trigger. This works whatever
- * the order we receive the notifications.
- */
- for (i = 0; i < notification_count; i++) {
- const char *name;
- struct lttng_notification *notification = get_next_notification(
- notification_channel);
-
- ok(notification, "Received notification (%d/%d)", i + 1,
- notification_count);
-
- /* Error. */
- if (notification == NULL) {
- goto end;
- }
-
- name = get_notification_trigger_name(notification);
- if (name == NULL) {
- lttng_notification_destroy(notification);
- goto end;
- }
-
- if (strcmp(ctrl_trigger_name, name) == 0) {
- ctrl_count++;
- } else if (strcmp(trigger_name, name) == 0) {
- count++;
- }
-
- lttng_notification_destroy(notification);
- }
-
- ok(ctrl_count / 2 == count,
- "Get twice as many control notif as of regular notif");
-
-end:
- suspend_application();
-
- lttng_unregister_trigger(trigger);
- lttng_unregister_trigger(ctrl_trigger);
- lttng_notification_channel_destroy(notification_channel);
- lttng_trigger_destroy(trigger);
- lttng_trigger_destroy(ctrl_trigger);
- lttng_condition_destroy(condition);
- lttng_condition_destroy(ctrl_condition);
-}
-
-static void test_tracepoint_event_rule_notification_exclusion(
- enum lttng_domain_type domain_type)
-{
- enum lttng_notification_channel_status nc_status;
- struct lttng_condition *ctrl_condition = NULL, *condition = NULL;
- struct lttng_notification_channel *notification_channel = NULL;
- struct lttng_trigger *ctrl_trigger = NULL, *trigger = NULL;
- int ctrl_count = 0, count = 0, i;
- const int notification_count = 6;
- const char * const ctrl_trigger_name = "control_exclusion_trigger";
- const char * const trigger_name = "exclusion_trigger";
- const char * const pattern = "tp:tptest*";
- const char * const exclusions[] = {
- "tp:tptest2",
- "tp:tptest3",
- "tp:tptest4",
- "tp:tptest5"
- };
-
- notification_channel = lttng_notification_channel_create(
- lttng_session_daemon_notification_endpoint);
- ok(notification_channel, "Notification channel object creation");
-
- create_tracepoint_event_rule_trigger(pattern, ctrl_trigger_name, NULL,
- 0, NULL, domain_type, NULL, &ctrl_condition,
- &ctrl_trigger);
-
- nc_status = lttng_notification_channel_subscribe(
- notification_channel, ctrl_condition);
- ok(nc_status == LTTNG_NOTIFICATION_CHANNEL_STATUS_OK,
- "Subscribe to tracepoint event rule condition");
-
- create_tracepoint_event_rule_trigger(pattern, trigger_name, NULL, 4,
- exclusions, domain_type, NULL, &condition,
- &trigger);
-
- nc_status = lttng_notification_channel_subscribe(
- notification_channel, condition);
- ok(nc_status == LTTNG_NOTIFICATION_CHANNEL_STATUS_OK,
- "Subscribe to tracepoint event rule condition");
-
- /*
- * We registered 2 notifications triggers, one with an exclusion and
- * one without (control).
- * - The trigger with an exclusion will fire once every iteration.
- * - The trigger without an exclusion will fire 5 times every
- * iteration.
- *
- * We should get 5 times as many notifications from the control
- * trigger.
- */
- resume_application();
-
- /*
- * Get 6 notifications. We should get 1 for the regular trigger (with
- * the exclusion) and 5 from the control trigger. This works whatever
- * the order we receive the notifications.
- */
- for (i = 0; i < notification_count; i++) {
- const char *name;
- struct lttng_notification *notification = get_next_notification(
- notification_channel);
-
- ok(notification, "Received notification (%d/%d)", i + 1,
- notification_count);
-
- /* Error. */
- if (notification == NULL) {
- goto end;
- }
-
- name = get_notification_trigger_name(notification);
- if (name == NULL) {
- lttng_notification_destroy(notification);
- goto end;
- }
-
- if (strcmp(ctrl_trigger_name, name) == 0) {
- ctrl_count++;
- } else if (strcmp(trigger_name, name) == 0) {
- count++;
- }
-
- lttng_notification_destroy(notification);
- }
-
- ok(ctrl_count / 5 == count,
- "Got 5 times as many control notif as of regular notif");
-
-end:
- suspend_application();
-
- lttng_unregister_trigger(trigger);
- lttng_unregister_trigger(ctrl_trigger);
- lttng_notification_channel_destroy(notification_channel);
- lttng_trigger_destroy(trigger);
- lttng_trigger_destroy(ctrl_trigger);
- lttng_condition_destroy(condition);
- lttng_condition_destroy(ctrl_condition);
- return;
-}
-
-static void test_kprobe_event_rule_notification(
- enum lttng_domain_type domain_type)
-{
- int i, ret;
- enum lttng_error_code ret_code;
- const int notification_count = 3;
- enum lttng_notification_channel_status nc_status;
- enum lttng_event_rule_status event_rule_status;
- struct lttng_notification_channel *notification_channel = NULL;
- struct lttng_condition *condition = NULL;
- struct lttng_kernel_probe_location *location = NULL;
- struct lttng_event_rule *event_rule = NULL;
- struct lttng_action *action = NULL;
- struct lttng_trigger *trigger = NULL;
- const char * const trigger_name = "kprobe_trigger";
- const char * const symbol_name = "lttng_test_filter_event_write";
-
- action = lttng_action_notify_create();
- if (!action) {
- fail("Failed to create notify action");
- goto end;
- }
-
- location = lttng_kernel_probe_location_symbol_create(symbol_name, 0);
- if (!location) {
- fail("Failed to create kernel probe location");
- goto end;
- }
-
- notification_channel = lttng_notification_channel_create(
- lttng_session_daemon_notification_endpoint);
- ok(notification_channel, "Notification channel object creation");
-
- event_rule = lttng_event_rule_kernel_kprobe_create(location);
- ok(event_rule, "kprobe event rule object creation");
-
- event_rule_status = lttng_event_rule_kernel_kprobe_set_event_name(
- event_rule, trigger_name);
- ok(event_rule_status == LTTNG_EVENT_RULE_STATUS_OK,
- "Setting kprobe event rule name: '%s'", trigger_name);
-
- condition = lttng_condition_event_rule_matches_create(event_rule);
- ok(condition, "Condition event rule object creation");
-
- /* Register the trigger for condition. */
- trigger = lttng_trigger_create(condition, action);
- if (!trigger) {
- fail("Failed to create trigger with kernel probe event rule condition and notify action");
- goto end;
- }
-
- ret_code = lttng_register_trigger_with_name(trigger, trigger_name);
- if (ret_code != LTTNG_OK) {
- fail("Failed to register trigger with kernel probe event rule condition and notify action");
- goto end;
- }
-
- nc_status = lttng_notification_channel_subscribe(
- notification_channel, condition);
- ok(nc_status == LTTNG_NOTIFICATION_CHANNEL_STATUS_OK,
- "Subscribe to tracepoint event rule condition");
-
- resume_application();
-
- for (i = 0; i < notification_count; i++) {
- struct lttng_notification *notification = get_next_notification(
- notification_channel);
-
- ok(notification, "Received notification (%d/%d)", i + 1,
- notification_count);
-
- /* Error. */
- if (notification == NULL) {
- goto end;
- }
-
- ret = validator_notification_trigger_name(notification, trigger_name);
- lttng_notification_destroy(notification);
- if (ret) {
- goto end;
- }
- }
-
-end:
- suspend_application();
- lttng_notification_channel_destroy(notification_channel);
- lttng_unregister_trigger(trigger);
- lttng_trigger_destroy(trigger);
- lttng_action_destroy(action);
- lttng_event_rule_destroy(event_rule);
- lttng_condition_destroy(condition);
- lttng_kernel_probe_location_destroy(location);
- return;
-}
-
-static void test_uprobe_event_rule_notification(
- enum lttng_domain_type domain_type,
- const char *testapp_path,
- const char *test_symbol_name)
-{
- int i, ret;
- enum lttng_error_code ret_code;
- const int notification_count = 3;
- enum lttng_notification_channel_status nc_status;
- enum lttng_event_rule_status event_rule_status;
- struct lttng_notification_channel *notification_channel = NULL;
- struct lttng_userspace_probe_location *probe_location = NULL;
- struct lttng_userspace_probe_location_lookup_method *lookup_method =
- NULL;
- struct lttng_condition *condition = NULL;
- struct lttng_event_rule *event_rule = NULL;
- struct lttng_action *action = NULL;
- struct lttng_trigger *trigger = NULL;
- const char * const trigger_name = "uprobe_trigger";
-
- action = lttng_action_notify_create();
- if (!action) {
- fail("Failed to create notify action");
- goto end;
- }
-
- lookup_method = lttng_userspace_probe_location_lookup_method_function_elf_create();
- if (!lookup_method) {
- fail("Setup error on userspace probe lookup method creation");
- goto end;
- }
-
- probe_location = lttng_userspace_probe_location_function_create(
- testapp_path, test_symbol_name, lookup_method);
- if (!probe_location) {
- fail("Failed to create userspace probe location");
- goto end;
- }
-
- notification_channel = lttng_notification_channel_create(
- lttng_session_daemon_notification_endpoint);
- ok(notification_channel, "Notification channel object creation");
-
- event_rule = lttng_event_rule_kernel_uprobe_create(probe_location);
- ok(event_rule, "kprobe event rule object creation");
-
- event_rule_status = lttng_event_rule_kernel_uprobe_set_event_name(
- event_rule, trigger_name);
- ok(event_rule_status == LTTNG_EVENT_RULE_STATUS_OK,
- "Setting uprobe event rule name: '%s'", trigger_name);
-
- condition = lttng_condition_event_rule_matches_create(event_rule);
- ok(condition, "Condition event rule object creation");
-
- /* Register the trigger for condition. */
- trigger = lttng_trigger_create(condition, action);
- if (!trigger) {
- fail("Failed to create trigger with userspace probe event rule condition and notify action");
- goto end;
- }
-
- ret_code = lttng_register_trigger_with_name(trigger, trigger_name);
- if (ret_code != LTTNG_OK) {
- fail("Failed to register trigger with userspace probe event rule condition and notify action");
- goto end;
- }
-
- nc_status = lttng_notification_channel_subscribe(
- notification_channel, condition);
- ok(nc_status == LTTNG_NOTIFICATION_CHANNEL_STATUS_OK,
- "Subscribe to tracepoint event rule condition");
-
- resume_application();
-
- for (i = 0; i < 3; i++) {
- struct lttng_notification *notification = get_next_notification(
- notification_channel);
-
- ok(notification, "Received notification (%d/%d)", i + 1,
- notification_count);
-
- /* Error. */
- if (notification == NULL) {
- goto end;
- }
-
- ret = validator_notification_trigger_name(notification, trigger_name);
- lttng_notification_destroy(notification);
- if (ret) {
- goto end;
- }
- }
-end:
- suspend_application();
-
- lttng_notification_channel_destroy(notification_channel);
- lttng_unregister_trigger(trigger);
- lttng_trigger_destroy(trigger);
- lttng_action_destroy(action);
- lttng_userspace_probe_location_destroy(probe_location);
- lttng_event_rule_destroy(event_rule);
- lttng_condition_destroy(condition);
- return;
-}
-
-static void test_syscall_event_rule_notification(
- enum lttng_domain_type domain_type)
-{
- int i, ret;
- enum lttng_error_code ret_code;
- const int notification_count = 3;
- enum lttng_notification_channel_status nc_status;
- enum lttng_event_rule_status event_rule_status;
- struct lttng_notification_channel *notification_channel = NULL;
- struct lttng_condition *condition = NULL;
- struct lttng_event_rule *event_rule = NULL;
- struct lttng_action *action = NULL;
- struct lttng_trigger *trigger = NULL;
- const char * const trigger_name = "syscall_trigger";
- const char * const syscall_name = "openat";
-
- action = lttng_action_notify_create();
- if (!action) {
- fail("Failed to create notify action");
- goto end;
- }
-
- notification_channel = lttng_notification_channel_create(
- lttng_session_daemon_notification_endpoint);
- ok(notification_channel, "Notification channel object creation");
-
- event_rule = lttng_event_rule_kernel_syscall_create(LTTNG_EVENT_RULE_KERNEL_SYSCALL_EMISSION_SITE_ENTRY);
- ok(event_rule, "syscall event rule object creation");
-
- event_rule_status = lttng_event_rule_kernel_syscall_set_name_pattern(
- event_rule, syscall_name);
- ok(event_rule_status == LTTNG_EVENT_RULE_STATUS_OK,
- "Setting syscall event rule pattern: '%s'", syscall_name);
-
- condition = lttng_condition_event_rule_matches_create(event_rule);
- ok(condition, "Condition syscall event rule object creation");
-
- /* Register the trigger for condition. */
- trigger = lttng_trigger_create(condition, action);
- if (!trigger) {
- fail("Failed to create trigger with syscall event rule condition and notify action");
- goto end;
- }
-
- ret_code = lttng_register_trigger_with_name(trigger, trigger_name);
- if (ret_code != LTTNG_OK) {
- fail("Failed to register trigger with syscall event rule condition and notify action");
- goto end;
- }
-
- nc_status = lttng_notification_channel_subscribe(
- notification_channel, condition);
- ok(nc_status == LTTNG_NOTIFICATION_CHANNEL_STATUS_OK,
- "Subscribe to tracepoint event rule condition");
-
- resume_application();
-
- for (i = 0; i < notification_count; i++) {
- struct lttng_notification *notification = get_next_notification(
- notification_channel);
-
- ok(notification, "Received notification (%d/%d)", i + 1,
- notification_count);
-
- /* Error. */
- if (notification == NULL) {
- goto end;
- }
-
- ret = validator_notification_trigger_name(notification, trigger_name);
- lttng_notification_destroy(notification);
- if (ret) {
- goto end;
- }
- }
-end:
- suspend_application();
- lttng_notification_channel_destroy(notification_channel);
- lttng_unregister_trigger(trigger);
- lttng_trigger_destroy(trigger);
- lttng_action_destroy(action);
- lttng_condition_destroy(condition);
- return;
-}
-
-static void test_syscall_event_rule_notification_filter(
- enum lttng_domain_type domain_type)
-{
- int i, ret;
- enum lttng_error_code ret_code;
- const int notification_count = 3;
- enum lttng_notification_channel_status nc_status;
- enum lttng_event_rule_status event_rule_status;
- struct lttng_notification_channel *notification_channel = NULL;
- struct lttng_condition *condition = NULL;
- struct lttng_event_rule *event_rule = NULL;
- struct lttng_action *action = NULL;
- struct lttng_trigger *trigger = NULL;
- const char * const trigger_name = "syscall_trigger";
- const char * const syscall_name = "openat";
- const char * const filter_pattern = "filename == \"/proc/cpuinfo\"";
-
- action = lttng_action_notify_create();
- if (!action) {
- fail("Failed to create notify action");
- goto end;
- }
-
- notification_channel = lttng_notification_channel_create(
- lttng_session_daemon_notification_endpoint);
- ok(notification_channel, "Notification channel object creation");
-
- event_rule = lttng_event_rule_kernel_syscall_create(LTTNG_EVENT_RULE_KERNEL_SYSCALL_EMISSION_SITE_ENTRY);
- ok(event_rule, "syscall event rule object creation");
-
- event_rule_status = lttng_event_rule_kernel_syscall_set_name_pattern(
- event_rule, syscall_name);
- ok(event_rule_status == LTTNG_EVENT_RULE_STATUS_OK,
- "Setting syscall event rule pattern: '%s'", syscall_name);
-
- event_rule_status = lttng_event_rule_kernel_syscall_set_filter(
- event_rule, filter_pattern);
- ok(event_rule_status == LTTNG_EVENT_RULE_STATUS_OK,
- "Setting filter: '%s'", filter_pattern);
-
- condition = lttng_condition_event_rule_matches_create(event_rule);
- ok(condition, "Condition event rule object creation");
-
- /* Register the triggers for condition */
- trigger = lttng_trigger_create(condition, action);
- if (!trigger) {
- fail("Failed to create trigger with syscall filtering event rule condition and notify action");
- goto end;
- }
-
- ret_code = lttng_register_trigger_with_name(trigger, trigger_name);
- if (ret_code != LTTNG_OK) {
- fail("Failed to register trigger with syscall filtering event rule condition and notify action");
- goto end;
- }
-
- nc_status = lttng_notification_channel_subscribe(
- notification_channel, condition);
- ok(nc_status == LTTNG_NOTIFICATION_CHANNEL_STATUS_OK,
- "Subscribe to tracepoint event rule condition");
-
- resume_application();
-
- for (i = 0; i < notification_count; i++) {
- struct lttng_notification *notification = get_next_notification(
- notification_channel);
-
- ok(notification, "Received notification (%d/%d)", i + 1,
- notification_count);
-
- /* Error. */
- if (notification == NULL) {
- goto end;
- }
-
- ret = validator_notification_trigger_name(notification, trigger_name);
- lttng_notification_destroy(notification);
- if (ret) {
- goto end;
- }
- }
-
-end:
- suspend_application();
-
- lttng_unregister_trigger(trigger);
- lttng_notification_channel_destroy(notification_channel);
- lttng_trigger_destroy(trigger);
- lttng_event_rule_destroy(event_rule);
- lttng_condition_destroy(condition);
- return;
-}
-
-static int generate_capture_descr(struct lttng_condition *condition)
-{
- int ret, i;
- struct lttng_event_expr *expr = NULL;
- const unsigned int basic_field_count = sizeof(test_capture_base_fields) /
- sizeof(*test_capture_base_fields);
- enum lttng_condition_status cond_status;
-
- for (i = 0; i < basic_field_count; i++) {
- diag("Adding capture descriptor '%s'",
- test_capture_base_fields[i].field_name);
-
- switch (test_capture_base_fields[i].field_type) {
- case FIELD_TYPE_PAYLOAD:
- expr = lttng_event_expr_event_payload_field_create(
- test_capture_base_fields[i].field_name);
- break;
- case FIELD_TYPE_CONTEXT:
- expr = lttng_event_expr_channel_context_field_create(
- test_capture_base_fields[i].field_name);
- break;
- case FIELD_TYPE_ARRAY_FIELD:
- {
- int nb_matches;
- unsigned int index;
- char field_name[FIELD_NAME_MAX_LEN];
- struct lttng_event_expr *array_expr = NULL;
-
- nb_matches = sscanf(test_capture_base_fields[i].field_name,
- "%[^[][%u]", field_name, &index);
- if (nb_matches != 2) {
- fail("Unexpected array field name format: field name = '%s'",
- test_capture_base_fields[i].field_name);
- ret = 1;
- goto end;
- }
-
- array_expr = lttng_event_expr_event_payload_field_create(
- field_name);
-
- expr = lttng_event_expr_array_field_element_create(
- array_expr, index);
- break;
- }
- case FIELD_TYPE_APP_CONTEXT:
- fail("Application context tests are not implemented yet.");
- /* fallthrough. */
- default:
- ret = 1;
- goto end;
- }
-
- if (expr == NULL) {
- fail("Failed to create capture expression");
- ret = -1;
- goto end;
- }
-
- cond_status = lttng_condition_event_rule_matches_append_capture_descriptor(
- condition, expr);
- if (cond_status != LTTNG_CONDITION_STATUS_OK) {
- fail("Failed to append capture descriptor");
- ret = -1;
- lttng_event_expr_destroy(expr);
- goto end;
- }
- }
-
- ret = 0;
-
-end:
- return ret;
-}
-
-static int validator_notification_trigger_capture(
- enum lttng_domain_type domain,
- struct lttng_notification *notification,
- const int iteration)
-{
- int ret;
- unsigned int capture_count, i;
- enum lttng_evaluation_event_rule_matches_status
- event_rule_matches_evaluation_status;
- enum lttng_event_field_value_status event_field_value_status;
- const struct lttng_evaluation *evaluation;
- const struct lttng_event_field_value *captured_fields;
- bool at_least_one_error = false;
-
- evaluation = lttng_notification_get_evaluation(notification);
- if (evaluation == NULL) {
- fail("Failed to get evaluation from notification during trigger capture test");
- ret = 1;
- goto end;
- }
-
- event_rule_matches_evaluation_status =
- lttng_evaluation_event_rule_matches_get_captured_values(
- evaluation, &captured_fields);
- if (event_rule_matches_evaluation_status !=
- LTTNG_EVALUATION_EVENT_RULE_MATCHES_STATUS_OK) {
- diag("Failed to get event rule evaluation captured values: status = %d",
- (int) event_rule_matches_evaluation_status);
- ret = 1;
- goto end;
- }
-
- event_field_value_status =
- lttng_event_field_value_array_get_length(captured_fields,
- &capture_count);
- if (event_field_value_status != LTTNG_EVENT_FIELD_VALUE_STATUS_OK) {
- fail("Failed to get count of captured value field array");
- ret = 1;
- goto end;
- }
-
- for (i = 0; i < capture_count; i++) {
- const struct lttng_event_field_value *captured_field = NULL;
- validate_cb validate;
- bool expected;
-
- diag("Validating capture of field '%s'",
- test_capture_base_fields[i].field_name);
- event_field_value_status =
- lttng_event_field_value_array_get_element_at_index(
- captured_fields, i,
- &captured_field);
-
- switch(domain) {
- case LTTNG_DOMAIN_UST:
- expected = test_capture_base_fields[i].expected_ust;
- break;
- case LTTNG_DOMAIN_KERNEL:
- expected = test_capture_base_fields[i].expected_kernel;
- break;
- default:
- fail("Unexpected domain encountered: domain = %d",
- (int) domain);
- ret = 1;
- goto end;
- }
-
- if (domain == LTTNG_DOMAIN_UST) {
- validate = test_capture_base_fields[i].validate_ust;
- } else {
- validate = test_capture_base_fields[i].validate_kernel;
- }
-
- if (!expected) {
- ok(event_field_value_status == LTTNG_EVENT_FIELD_VALUE_STATUS_UNAVAILABLE,
- "No payload captured");
- continue;
- }
-
- if (event_field_value_status != LTTNG_EVENT_FIELD_VALUE_STATUS_OK) {
- if (event_field_value_status ==
- LTTNG_EVENT_FIELD_VALUE_STATUS_UNAVAILABLE) {
- fail("Expected a capture but it is unavailable");
- } else {
- fail("lttng_event_field_value_array_get_element_at_index returned an error: status = %d",
- (int) event_field_value_status);
- }
-
- ret = 1;
- goto end;
- }
-
- diag("Captured field of type %s",
- field_value_type_to_str(
- lttng_event_field_value_get_type(captured_field)));
-
- LTTNG_ASSERT(validate);
- ret = validate(captured_field, iteration);
- if (ret) {
- at_least_one_error = true;
- }
- }
-
- ret = at_least_one_error;
-
-end:
- return ret;
-}
-
-static void test_tracepoint_event_rule_notification_capture(
- enum lttng_domain_type domain_type)
-{
- enum lttng_notification_channel_status nc_status;
-
- int i, ret;
- struct lttng_condition *condition = NULL;
- struct lttng_notification_channel *notification_channel = NULL;
- struct lttng_trigger *trigger = NULL;
- const char *trigger_name = "my_precious";
- const char *pattern;
-
- if (domain_type == LTTNG_DOMAIN_UST) {
- pattern = "tp:tptest";
- } else {
- pattern = "lttng_test_filter_event";
- }
-
- create_tracepoint_event_rule_trigger(pattern, trigger_name, NULL, 0,
- NULL, domain_type, generate_capture_descr, &condition,
- &trigger);
-
- notification_channel = lttng_notification_channel_create(
- lttng_session_daemon_notification_endpoint);
- ok(notification_channel, "Notification channel object creation");
-
- nc_status = lttng_notification_channel_subscribe(
- notification_channel, condition);
- ok(nc_status == LTTNG_NOTIFICATION_CHANNEL_STATUS_OK,
- "Subscribe to tracepoint event rule condition");
-
- resume_application();
-
- /* Get 3 notifications */
- for (i = 0; i < 3; i++) {
- struct lttng_notification *notification = get_next_notification(
- notification_channel);
- ok(notification, "Received notification");
-
- /* Error */
- if (notification == NULL) {
- goto end;
- }
-
- ret = validator_notification_trigger_name(notification, trigger_name);
- if (ret) {
- lttng_notification_destroy(notification);
- goto end;
- }
-
- ret = validator_notification_trigger_capture(domain_type, notification, i);
- if (ret) {
- lttng_notification_destroy(notification);
- goto end;
- }
-
- lttng_notification_destroy(notification);
- }
-
-end:
- suspend_application();
- lttng_notification_channel_destroy(notification_channel);
- lttng_unregister_trigger(trigger);
- lttng_trigger_destroy(trigger);
- lttng_condition_destroy(condition);
- return;
-}
-
-int main(int argc, const char *argv[])
-{
- int test_scenario;
- const char *domain_type_string = NULL;
- enum lttng_domain_type domain_type = LTTNG_DOMAIN_NONE;
-
- if (argc < 5) {
- fail("Missing test scenario, domain type, pid, or application state file argument(s)");
- goto error;
- }
-
- test_scenario = atoi(argv[1]);
- domain_type_string = argv[2];
- app_pid = (pid_t) atoi(argv[3]);
- app_state_file = argv[4];
-
- if (!strcmp("LTTNG_DOMAIN_UST", domain_type_string)) {
- domain_type = LTTNG_DOMAIN_UST;
- }
- if (!strcmp("LTTNG_DOMAIN_KERNEL", domain_type_string)) {
- domain_type = LTTNG_DOMAIN_KERNEL;
- }
- if (domain_type == LTTNG_DOMAIN_NONE) {
- fail("Unknown domain type");
- goto error;
- }
-
- /*
- * Test cases are responsible for resuming the app when needed
- * and making sure it's suspended when returning.
- */
- suspend_application();
-
- switch (test_scenario) {
- case 1:
- {
- plan_tests(41);
-
- /* Test cases that need gen-ust-event testapp. */
- diag("Test basic notification error paths for %s domain",
- domain_type_string);
- test_invalid_channel_subscription(domain_type);
-
- diag("Test tracepoint event rule notifications for domain %s",
- domain_type_string);
- test_tracepoint_event_rule_notification(domain_type);
-
- diag("Test tracepoint event rule notifications with filter for domain %s",
- domain_type_string);
- test_tracepoint_event_rule_notification_filter(domain_type);
- break;
- }
- case 2:
- {
- const char *session_name, *channel_name;
-
- /* Test cases that need a tracing session enabled. */
- plan_tests(99);
-
- /*
- * Argument 7 and upward are named pipe location for consumerd
- * control.
- */
- named_pipe_args_start = 7;
-
- if (argc < 8) {
- fail("Missing parameter for tests to run %d", argc);
- goto error;
- }
-
- nb_args = argc;
-
- session_name = argv[5];
- channel_name = argv[6];
-
- test_subscription_twice(session_name, channel_name,
- domain_type);
-
- diag("Test trigger for domain %s with buffer_usage_low condition",
- domain_type_string);
- test_triggers_buffer_usage_condition(session_name, channel_name,
- domain_type,
- LTTNG_CONDITION_TYPE_BUFFER_USAGE_LOW);
-
- diag("Test trigger for domain %s with buffer_usage_high condition",
- domain_type_string);
- test_triggers_buffer_usage_condition(session_name, channel_name,
- domain_type,
- LTTNG_CONDITION_TYPE_BUFFER_USAGE_HIGH);
-
- diag("Test buffer usage notification channel api for domain %s",
- domain_type_string);
- test_buffer_usage_notification_channel(session_name, channel_name,
- domain_type, argv);
- break;
- }
- case 3:
- {
- /*
- * Test cases that need a test app with more than one event
- * type.
- */
- plan_tests(23);
-
- /*
- * At the moment, the only test case of this scenario is
- * exclusion which is only supported by UST.
- */
- LTTNG_ASSERT(domain_type == LTTNG_DOMAIN_UST);
- diag("Test tracepoint event rule notifications with exclusion for domain %s",
- domain_type_string);
- test_tracepoint_event_rule_notification_exclusion(domain_type);
-
- break;
- }
- case 4:
- {
- plan_tests(11);
- /* Test cases that need the kernel tracer. */
- LTTNG_ASSERT(domain_type == LTTNG_DOMAIN_KERNEL);
-
- diag("Test kprobe event rule notifications for domain %s",
- domain_type_string);
-
- test_kprobe_event_rule_notification(domain_type);
-
- break;
- }
- case 5:
- {
- plan_tests(23);
- /* Test cases that need the kernel tracer. */
- LTTNG_ASSERT(domain_type == LTTNG_DOMAIN_KERNEL);
-
- diag("Test syscall event rule notifications for domain %s",
- domain_type_string);
-
- test_syscall_event_rule_notification(domain_type);
-
- diag("Test syscall filtering event rule notifications for domain %s",
- domain_type_string);
-
- test_syscall_event_rule_notification_filter(domain_type);
-
- break;
- }
- case 6:
- {
- const char *testapp_path, *test_symbol_name;
-
- plan_tests(11);
-
- if (argc < 7) {
- fail("Missing parameter for tests to run %d", argc);
- goto error;
- }
-
- testapp_path = argv[5];
- test_symbol_name = argv[6];
- /* Test cases that need the kernel tracer. */
- LTTNG_ASSERT(domain_type == LTTNG_DOMAIN_KERNEL);
-
- diag("Test userspace-probe event rule notifications for domain %s",
- domain_type_string);
-
- test_uprobe_event_rule_notification(
- domain_type, testapp_path, test_symbol_name);
-
- break;
- }
- case 7:
- {
- switch(domain_type) {
- case LTTNG_DOMAIN_UST:
- plan_tests(221);
- break;
- case LTTNG_DOMAIN_KERNEL:
- plan_tests(215);
- break;
- default:
- abort();
- }
-
- diag("Test tracepoint event rule notification captures for domain %s",
- domain_type_string);
- test_tracepoint_event_rule_notification_capture(domain_type);
-
- break;
- }
-
- default:
- abort();
- }
-
-error:
- return exit_status();
-}
-
--- /dev/null
+/*
+ * notification.c
+ *
+ * Tests suite for LTTng notification API
+ *
+ * Copyright (C) 2017 Jonathan Rajotte <jonathan.rajotte-julien@efficios.com>
+ *
+ * SPDX-License-Identifier: MIT
+ *
+ */
+
+#include <math.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <inttypes.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <poll.h>
+
+#include <common/compat/errno.h>
+#include <common/macros.h>
+#include <lttng/lttng.h>
+
+#include <tap/tap.h>
+
+#define FIELD_NAME_MAX_LEN 256
+
+/* A callback to populate the condition capture descriptor. */
+typedef int (*condition_capture_desc_cb)(struct lttng_condition *condition);
+
+/* A callback for captured field validation. */
+typedef int (*validate_cb)(const struct lttng_event_field_value *event_field, unsigned iteration);
+
+int nb_args = 0;
+int named_pipe_args_start = 0;
+pid_t app_pid = 0;
+const char *app_state_file = NULL;
+
+enum field_type {
+ FIELD_TYPE_PAYLOAD,
+ FIELD_TYPE_CONTEXT,
+ FIELD_TYPE_APP_CONTEXT,
+ FIELD_TYPE_ARRAY_FIELD,
+};
+
+struct capture_base_field_tuple {
+ const char *field_name;
+ enum field_type field_type;
+ /* Do we expect a userspace capture? */
+ bool expected_ust;
+ /* Do we expect a kernel capture? */
+ bool expected_kernel;
+ validate_cb validate_ust;
+ validate_cb validate_kernel;
+};
+
+static
+const char *field_value_type_to_str(enum lttng_event_field_value_type type)
+{
+ switch (type) {
+ case LTTNG_EVENT_FIELD_VALUE_TYPE_UNKNOWN:
+ return "UNKNOWN";
+ case LTTNG_EVENT_FIELD_VALUE_TYPE_INVALID:
+ return "INVALID";
+ case LTTNG_EVENT_FIELD_VALUE_TYPE_UNSIGNED_INT:
+ return "UNSIGNED INT";
+ case LTTNG_EVENT_FIELD_VALUE_TYPE_SIGNED_INT:
+ return "SIGNED INT";
+ case LTTNG_EVENT_FIELD_VALUE_TYPE_UNSIGNED_ENUM:
+ return "UNSIGNED ENUM";
+ case LTTNG_EVENT_FIELD_VALUE_TYPE_SIGNED_ENUM:
+ return "SIGNED ENUM";
+ case LTTNG_EVENT_FIELD_VALUE_TYPE_REAL:
+ return "REAL";
+ case LTTNG_EVENT_FIELD_VALUE_TYPE_STRING:
+ return "STRING";
+ case LTTNG_EVENT_FIELD_VALUE_TYPE_ARRAY:
+ return "ARRAY";
+ default:
+ abort();
+ }
+}
+
+static int validate_type(const struct lttng_event_field_value *event_field,
+ enum lttng_event_field_value_type expect)
+{
+ int ret;
+ enum lttng_event_field_value_type value;
+
+ value = lttng_event_field_value_get_type(event_field);
+ if (value == LTTNG_EVENT_FIELD_VALUE_TYPE_INVALID) {
+ ret = 1;
+ goto end;
+ }
+
+ ok(expect == value, "Expected field type %s, got %s",
+ field_value_type_to_str(expect),
+ field_value_type_to_str(value));
+
+ ret = expect != value;
+
+end:
+ return ret;
+}
+
+/*
+ * Validate unsigned captured field against the iteration number.
+ */
+static int validate_unsigned_int_field(
+ const struct lttng_event_field_value *event_field,
+ unsigned int expected_value)
+{
+ int ret;
+ uint64_t value;
+ enum lttng_event_field_value_status status;
+
+ ret = validate_type(
+ event_field, LTTNG_EVENT_FIELD_VALUE_TYPE_UNSIGNED_INT);
+ if (ret) {
+ goto end;
+ }
+
+ status = lttng_event_field_value_unsigned_int_get_value(
+ event_field, &value);
+ if (status != LTTNG_EVENT_FIELD_VALUE_STATUS_OK) {
+ fail("lttng_event_field_value_unsigned_int_get_value returned an error: status = %d",
+ (int) status);
+ ret = 1;
+ goto end;
+ }
+
+ ok(value == (uint64_t) expected_value,
+ "Expected unsigned integer value %u, got %" PRIu64,
+ expected_value, value);
+
+ ret = value != (uint64_t) expected_value;
+
+end:
+ return ret;
+}
+
+/*
+ * Validate signed captured field.
+ */
+static int validate_signed_int_field(
+ const struct lttng_event_field_value *event_field,
+ unsigned int iteration)
+{
+ int ret;
+ const int64_t expected = -1;
+ int64_t value;
+ enum lttng_event_field_value_status status;
+
+ /* Unused. */
+ (void) iteration;
+
+ ret = validate_type(
+ event_field, LTTNG_EVENT_FIELD_VALUE_TYPE_SIGNED_INT);
+ if (ret) {
+ goto end;
+ }
+
+ status = lttng_event_field_value_signed_int_get_value(
+ event_field, &value);
+ if (status != LTTNG_EVENT_FIELD_VALUE_STATUS_OK) {
+ fail("lttng_event_field_value_signed_int_get_value returned an error: status = %d",
+ (int) status);
+ ret = 1;
+ goto end;
+ }
+
+ ok(value == expected,
+ "Expected signed integer value %" PRId64
+ ", got %" PRId64,
+ expected, value);
+
+ ret = value != expected;
+
+end:
+
+ return ret;
+}
+
+/*
+ * Validate array of unsigned int.
+ */
+static int validate_array_unsigned_int_field(
+ const struct lttng_event_field_value *event_field,
+ unsigned int iteration)
+{
+ int ret;
+ enum lttng_event_field_value_status status;
+ const unsigned int expected = 3;
+ unsigned int i, count;
+
+ /* Unused. */
+ (void) iteration;
+
+ ret = validate_type(event_field, LTTNG_EVENT_FIELD_VALUE_TYPE_ARRAY);
+ if (ret) {
+ goto end;
+ }
+
+ status = lttng_event_field_value_array_get_length(event_field, &count);
+ if (status != LTTNG_EVENT_FIELD_VALUE_STATUS_OK) {
+ fail("lttng_event_field_value_array_get_length");
+ ret = 1;
+ goto end;
+ }
+
+ ok(count == expected, "Expected %d subelements, got %d", expected,
+ count);
+ if (count != expected) {
+ ret = 1;
+ goto end;
+ }
+
+ for (i = 1; i < count + 1; i++) {
+ const struct lttng_event_field_value *value;
+
+ status = lttng_event_field_value_array_get_element_at_index(
+ event_field, i - 1, &value);
+ if (status != LTTNG_EVENT_FIELD_VALUE_STATUS_OK) {
+ fail("lttng_event_field_value_array_get_element_at_index returned an error: status = %d",
+ (int) status);
+ ret = 1;
+ goto end;
+ }
+
+ ret = validate_unsigned_int_field(value, i);
+ if (ret) {
+ goto end;
+ }
+ }
+
+ ret = 0;
+end:
+
+ return ret;
+}
+
+static int validate_array_unsigned_int_field_at_index(
+ const struct lttng_event_field_value *event_field,
+ unsigned int iteration)
+{
+ int ret;
+ const uint64_t expected_value = 2;
+ enum lttng_event_field_value_status status;
+ uint64_t value;
+
+ /* Unused. */
+ (void) iteration;
+
+ ret = validate_type(
+ event_field, LTTNG_EVENT_FIELD_VALUE_TYPE_UNSIGNED_INT);
+ if (ret) {
+ goto end;
+ }
+
+ status = lttng_event_field_value_unsigned_int_get_value(
+ event_field, &value);
+ if (status != LTTNG_EVENT_FIELD_VALUE_STATUS_OK) {
+ fail("lttng_event_field_value_unsigned_int_get_value returned an error: status = %d",
+ (int) status);
+ ret = 1;
+ goto end;
+ }
+
+ ok(value == expected_value,
+ "Expected unsigned integer value %u, got %" PRIu64,
+ expected_value, value);
+
+ ret = 0;
+end:
+ return ret;
+}
+
+/*
+ * Validate sequence for a string (seqfield1):
+ *
+ * Value: "test" encoded in UTF-8: [116, 101, 115, 116]
+ */
+static int validate_seqfield1(const struct lttng_event_field_value *event_field,
+ unsigned int iteration)
+{
+ int ret;
+ enum lttng_event_field_value_status status;
+ unsigned int i, count;
+ const unsigned int expect[] = {116, 101, 115, 116};
+ const size_t array_count = sizeof(expect) / sizeof(*expect);
+
+ /* Unused. */
+ (void) iteration;
+
+ ret = validate_type(event_field, LTTNG_EVENT_FIELD_VALUE_TYPE_ARRAY);
+ if (ret) {
+ goto end;
+ }
+
+ status = lttng_event_field_value_array_get_length(event_field, &count);
+ if (status != LTTNG_EVENT_FIELD_VALUE_STATUS_OK) {
+ fail("lttng_event_field_value_array_get_length returned an error: status = %d",
+ (int) status);
+ ret = 1;
+ goto end;
+ }
+
+ ok(count == array_count, "Expected %zu array sub-elements, got %d",
+ array_count, count);
+ if (count != array_count) {
+ ret = 1;
+ goto end;
+ }
+
+ for (i = 0; i < count; i++) {
+ const struct lttng_event_field_value *value;
+
+ status = lttng_event_field_value_array_get_element_at_index(
+ event_field, i, &value);
+ if (status != LTTNG_EVENT_FIELD_VALUE_STATUS_OK) {
+ fail("lttng_event_field_value_array_get_element_at_index returned an error: status = %d",
+ (int) status);
+ ret = 1;
+ goto end;
+ }
+
+ ret = validate_unsigned_int_field(value, expect[i]);
+ if (ret) {
+ goto end;
+ }
+ }
+
+ ret = 0;
+end:
+ return ret;
+}
+
+static int validate_string(
+ const struct lttng_event_field_value *event_field,
+ const char *expect)
+{
+ int ret;
+ const char *value = NULL;
+ enum lttng_event_field_value_status status;
+
+ ret = validate_type(event_field, LTTNG_EVENT_FIELD_VALUE_TYPE_STRING);
+ if (ret) {
+ goto end;
+ }
+
+ status = lttng_event_field_value_string_get_value(event_field, &value);
+ if (!value) {
+ fail("lttng_event_field_value_array_get_length returned an error: status = %d",
+ (int) status);
+ ret = 1;
+ goto end;
+ }
+
+ ok(!strcmp(value, expect), "Expected string value \"%s\", got \"%s\"",
+ expect, value);
+
+ ret = 0;
+end:
+
+ return ret;
+}
+
+/*
+ * Validate string. Expected value is "test".
+ */
+static int validate_string_test(
+ const struct lttng_event_field_value *event_field,
+ unsigned int iteration)
+{
+ const char * const expect = "test";
+
+ /* Unused. */
+ (void) iteration;
+
+ return validate_string(event_field, expect);
+}
+
+/*
+ * Validate escaped string. Expected value is "\*".
+ */
+static int validate_string_escaped(
+ const struct lttng_event_field_value *event_field,
+ unsigned int iteration)
+{
+ const char * const expect = "\\*";
+
+ /* Unused. */
+ (void) iteration;
+
+ return validate_string(event_field, expect);
+}
+
+/*
+ * Validate real field.
+ */
+static int validate_real(
+ const struct lttng_event_field_value *event_field,
+ double expect)
+{
+ int ret;
+ double value;
+ enum lttng_event_field_value_status status;
+
+ ret = validate_type(event_field, LTTNG_EVENT_FIELD_VALUE_TYPE_REAL);
+ if (ret) {
+ goto end;
+ }
+
+ status = lttng_event_field_value_real_get_value(event_field, &value);
+ if (status != LTTNG_EVENT_FIELD_VALUE_STATUS_OK) {
+ fail("lttng_event_field_value_real_get_value returned an error: status = %d",
+ (int) status);
+ ret = 1;
+ goto end;
+ }
+
+ ok(value == expect, "Expected real value %f, got %f", expect, value);
+ ret = value != expect;
+end:
+ return ret;
+}
+
+/*
+ * Validate floatfield.
+ */
+static int validate_floatfield(
+ const struct lttng_event_field_value *event_field,
+ unsigned int iteration)
+{
+ const double expect = 2222.0;
+
+ /* Unused. */
+ (void) iteration;
+
+ return validate_real(event_field, expect);
+}
+
+/*
+ * Validate doublefield.
+ */
+static int validate_doublefield(
+ const struct lttng_event_field_value *event_field,
+ unsigned int iteration)
+{
+ const double expect = 2.0;
+
+ /* Unused. */
+ (void) iteration;
+
+ return validate_real(event_field, expect);
+}
+
+/*
+ * Validate enum0: enum0 = ( "AUTO: EXPECT 0" : container = 0 )
+ */
+static int validate_enum0(const struct lttng_event_field_value *event_field,
+ unsigned int iteration)
+{
+ int ret;
+ enum lttng_event_field_value_status status;
+ uint64_t value;
+ const uint64_t expected_value = 0;
+
+ /* Unused. */
+ (void) iteration;
+
+ ret = validate_type(event_field,
+ LTTNG_EVENT_FIELD_VALUE_TYPE_UNSIGNED_ENUM);
+ if (ret) {
+ goto end;
+ }
+
+ status = lttng_event_field_value_unsigned_int_get_value(
+ event_field, &value);
+ if (status != LTTNG_EVENT_FIELD_VALUE_STATUS_OK) {
+ fail("lttng_event_field_value_unsigned_int_get_value returned an error: status = %d",
+ (int) status);
+ ret = 1;
+ goto end;
+ }
+
+ ok(value == expected_value,
+ "Expected enum value %" PRIu64 ", got %" PRIu64,
+ expected_value, value);
+
+end:
+ return ret;
+}
+
+/*
+ * Validate enumnegative: enumnegative = ( "AUTO: EXPECT 0" : container = 0 )
+ *
+ * We expect 2 labels here.
+ */
+static int validate_enumnegative(
+ const struct lttng_event_field_value *event_field,
+ unsigned int iteration)
+{
+ int ret;
+ enum lttng_event_field_value_status status;
+ int64_t value;
+ const int64_t expected_value = -1;
+
+ /* Unused. */
+ (void) iteration;
+
+ ret = validate_type(event_field,
+ LTTNG_EVENT_FIELD_VALUE_TYPE_SIGNED_ENUM);
+ if (ret) {
+ goto end;
+ }
+
+ status = lttng_event_field_value_signed_int_get_value(
+ event_field, &value);
+ if (status != LTTNG_EVENT_FIELD_VALUE_STATUS_OK) {
+ fail("lttng_event_field_value_unsigned_int_get_value");
+ ret = 1;
+ goto end;
+ }
+
+ ok(value == expected_value,
+ "Expected enum value %" PRId64 ", got %" PRId64,
+ expected_value, value);
+
+end:
+ return ret;
+}
+
+static int validate_context_procname_ust(
+ const struct lttng_event_field_value *event_field,
+ unsigned int iteration)
+{
+ /* Unused. */
+ (void) iteration;
+ return validate_string(event_field, "gen-ust-events");
+}
+
+static int validate_context_procname_kernel(
+ const struct lttng_event_field_value *event_field,
+ unsigned int iteration)
+{
+ /* Unused. */
+ (void) iteration;
+ return validate_string(event_field, "echo");
+}
+
+struct capture_base_field_tuple test_capture_base_fields[] = {
+ { "DOESNOTEXIST", FIELD_TYPE_PAYLOAD, false, false, NULL, NULL },
+ { "intfield", FIELD_TYPE_PAYLOAD, true, true, validate_unsigned_int_field, validate_unsigned_int_field },
+ { "longfield", FIELD_TYPE_PAYLOAD, true, true, validate_unsigned_int_field, validate_unsigned_int_field },
+ { "signedfield", FIELD_TYPE_PAYLOAD, true, true, validate_signed_int_field, validate_signed_int_field },
+ { "arrfield1", FIELD_TYPE_PAYLOAD, true, true, validate_array_unsigned_int_field, validate_array_unsigned_int_field },
+ { "arrfield2", FIELD_TYPE_PAYLOAD, true, true, validate_string_test, validate_string_test },
+ { "arrfield3", FIELD_TYPE_PAYLOAD, true, true, validate_array_unsigned_int_field, validate_array_unsigned_int_field },
+ { "seqfield1", FIELD_TYPE_PAYLOAD, true, true, validate_seqfield1, validate_seqfield1 },
+ { "seqfield2", FIELD_TYPE_PAYLOAD, true, true, validate_string_test, validate_string_test },
+ { "seqfield3", FIELD_TYPE_PAYLOAD, true, true, validate_array_unsigned_int_field, validate_array_unsigned_int_field },
+ { "seqfield4", FIELD_TYPE_PAYLOAD, true, true, validate_array_unsigned_int_field, validate_array_unsigned_int_field },
+ { "arrfield1[1]", FIELD_TYPE_ARRAY_FIELD, true, true, validate_array_unsigned_int_field_at_index, validate_array_unsigned_int_field_at_index },
+ { "stringfield", FIELD_TYPE_PAYLOAD, true, true, validate_string_test, validate_string_test },
+ { "stringfield2", FIELD_TYPE_PAYLOAD, true, true, validate_string_escaped, validate_string_escaped },
+ { "floatfield", FIELD_TYPE_PAYLOAD, true, false, validate_floatfield, validate_floatfield },
+ { "doublefield", FIELD_TYPE_PAYLOAD, true, false, validate_doublefield, validate_doublefield },
+ { "enum0", FIELD_TYPE_PAYLOAD, true, true, validate_enum0, validate_enum0 },
+ { "enumnegative", FIELD_TYPE_PAYLOAD, true, true, validate_enumnegative, validate_enumnegative },
+ { "$ctx.procname", FIELD_TYPE_CONTEXT, true, true, validate_context_procname_ust, validate_context_procname_kernel },
+};
+
+static const char *get_notification_trigger_name(
+ struct lttng_notification *notification)
+{
+ const char *trigger_name = NULL;
+ enum lttng_trigger_status trigger_status;
+ const struct lttng_trigger *trigger;
+
+ trigger = lttng_notification_get_trigger(notification);
+ if (!trigger) {
+ fail("Failed to get trigger from notification");
+ goto end;
+ }
+
+ trigger_status = lttng_trigger_get_name(trigger, &trigger_name);
+ switch (trigger_status) {
+ case LTTNG_TRIGGER_STATUS_OK:
+ break;
+ case LTTNG_TRIGGER_STATUS_UNSET:
+ trigger_name = "(anonymous)";
+ break;
+ default:
+ fail("Failed to get name from notification's trigger");
+ goto end;
+ }
+
+end:
+ return trigger_name;
+}
+
+static int validator_notification_trigger_name(
+ struct lttng_notification *notification,
+ const char *trigger_name)
+{
+ int ret;
+ bool name_is_equal;
+ const char *name;
+
+ LTTNG_ASSERT(notification);
+ LTTNG_ASSERT(trigger_name);
+
+ name = get_notification_trigger_name(notification);
+ if (name == NULL) {
+ ret = 1;
+ goto end;
+ }
+
+ name_is_equal = (strcmp(trigger_name, name) == 0);
+ ok(name_is_equal, "Expected trigger name: %s got %s", trigger_name,
+ name);
+
+ ret = !name_is_equal;
+
+end:
+ return ret;
+}
+
+static
+void wait_on_file(const char *path, bool file_exist)
+{
+ if (!path) {
+ return;
+ }
+ for (;;) {
+ int ret;
+ struct stat buf;
+
+ ret = stat(path, &buf);
+ if (ret == -1 && errno == ENOENT) {
+ if (file_exist) {
+ /*
+ * The file does not exist. wait a bit and
+ * continue looping until it does.
+ */
+ (void) poll(NULL, 0, 10);
+ continue;
+ }
+
+ /*
+ * File does not exist and the exit condition we want.
+ * Break from the loop and return.
+ */
+ break;
+ }
+ if (ret) {
+ perror("stat");
+ exit(EXIT_FAILURE);
+ }
+ /*
+ * stat() returned 0, so the file exists. break now only if
+ * that's the exit condition we want.
+ */
+ if (file_exist) {
+ break;
+ }
+ }
+}
+
+static
+int write_pipe(const char *path, uint8_t data)
+{
+ int ret = 0;
+ int fd = 0;
+
+ fd = open(path, O_WRONLY | O_NONBLOCK);
+ if (fd < 0) {
+ perror("Could not open consumer control named pipe");
+ goto end;
+ }
+
+ ret = write(fd, &data , sizeof(data));
+ if (ret < 1) {
+ perror("Named pipe write failed");
+ if (close(fd)) {
+ perror("Named pipe close failed");
+ }
+ ret = -1;
+ goto end;
+ }
+
+ ret = close(fd);
+ if (ret < 0) {
+ perror("Name pipe closing failed");
+ ret = -1;
+ goto end;
+ }
+end:
+ return ret;
+}
+
+static
+int stop_consumer(const char **argv)
+{
+ int ret = 0, i;
+
+ for (i = named_pipe_args_start; i < nb_args; i++) {
+ ret = write_pipe(argv[i], 49);
+ }
+ return ret;
+}
+
+static
+int resume_consumer(const char **argv)
+{
+ int ret = 0, i;
+
+ for (i = named_pipe_args_start; i < nb_args; i++) {
+ ret = write_pipe(argv[i], 0);
+ }
+ return ret;
+}
+
+static
+int suspend_application(void)
+{
+ int ret;
+ struct stat buf;
+
+ if (!stat(app_state_file, &buf)) {
+ fail("App is already in a suspended state.");
+ ret = -1;
+ goto error;
+ }
+
+ /*
+ * Send SIGUSR1 to application instructing it to bypass tracepoint.
+ */
+ LTTNG_ASSERT(app_pid > 1);
+
+ ret = kill(app_pid, SIGUSR1);
+ if (ret) {
+ fail("SIGUSR1 failed. errno %d", errno);
+ ret = -1;
+ goto error;
+ }
+
+ wait_on_file(app_state_file, true);
+
+error:
+ return ret;
+
+}
+
+static
+int resume_application(void)
+{
+ int ret;
+ struct stat buf;
+
+ ret = stat(app_state_file, &buf);
+ if (ret == -1 && errno == ENOENT) {
+ fail("State file does not exist");
+ goto error;
+ }
+ if (ret) {
+ perror("stat");
+ goto error;
+ }
+
+ LTTNG_ASSERT(app_pid > 1);
+
+ ret = kill(app_pid, SIGUSR1);
+ if (ret) {
+ fail("SIGUSR1 failed. errno %d", errno);
+ ret = -1;
+ goto error;
+ }
+
+ wait_on_file(app_state_file, false);
+
+error:
+ return ret;
+
+}
+
+
+static
+void test_triggers_buffer_usage_condition(const char *session_name,
+ const char *channel_name,
+ enum lttng_domain_type domain_type,
+ enum lttng_condition_type condition_type)
+{
+ unsigned int test_vector_size = 5, i;
+ enum lttng_condition_status condition_status;
+ struct lttng_action *action;
+
+ /* Set-up */
+ action = lttng_action_notify_create();
+ if (!action) {
+ fail("Setup error on action creation");
+ goto end;
+ }
+
+ /* Test lttng_register_trigger with null value */
+ ok(lttng_register_trigger(NULL) == -LTTNG_ERR_INVALID, "Registering a NULL trigger fails as expected");
+
+ /* Test: register a trigger */
+
+ for (i = 0; i < pow(2,test_vector_size); i++) {
+ int loop_ret = 0;
+ char *test_tuple_string = NULL;
+ unsigned int mask_position = 0;
+ bool session_name_set = false;
+ bool channel_name_set = false;
+ bool threshold_ratio_set = false;
+ bool threshold_byte_set = false;
+ bool domain_type_set = false;
+
+ struct lttng_trigger *trigger = NULL;
+ struct lttng_condition *condition = NULL;
+
+ /* Create base condition */
+ switch (condition_type) {
+ case LTTNG_CONDITION_TYPE_BUFFER_USAGE_LOW:
+ condition = lttng_condition_buffer_usage_low_create();
+ break;
+ case LTTNG_CONDITION_TYPE_BUFFER_USAGE_HIGH:
+ condition = lttng_condition_buffer_usage_high_create();
+ break;
+ default:
+ loop_ret = 1;
+ goto loop_end;
+ }
+
+ if (!condition) {
+ loop_ret = 1;
+ goto loop_end;
+
+ }
+
+ /* Prepare the condition for trigger registration test */
+
+ /* Set session name */
+ if ((1 << mask_position) & i) {
+ condition_status = lttng_condition_buffer_usage_set_session_name(
+ condition, session_name);
+ if (condition_status != LTTNG_CONDITION_STATUS_OK) {
+ loop_ret = 1;
+ goto loop_end;
+ }
+ session_name_set = true;
+ }
+ mask_position++;
+
+ /* Set channel name */
+ if ((1 << mask_position) & i) {
+ condition_status = lttng_condition_buffer_usage_set_channel_name(
+ condition, channel_name);
+ if (condition_status != LTTNG_CONDITION_STATUS_OK) {
+ loop_ret = 1;
+ goto loop_end;
+ }
+ channel_name_set = true;
+ }
+ mask_position++;
+
+ /* Set threshold ratio */
+ if ((1 << mask_position) & i) {
+ condition_status = lttng_condition_buffer_usage_set_threshold_ratio(
+ condition, 0.0);
+ if (condition_status != LTTNG_CONDITION_STATUS_OK) {
+ loop_ret = 1;
+ goto loop_end;
+ }
+ threshold_ratio_set = true;
+ }
+ mask_position++;
+
+ /* Set threshold byte */
+ if ((1 << mask_position) & i) {
+ condition_status = lttng_condition_buffer_usage_set_threshold(
+ condition, 0);
+ if (condition_status != LTTNG_CONDITION_STATUS_OK) {
+ loop_ret = 1;
+ goto loop_end;
+ }
+ threshold_byte_set = true;
+ }
+ mask_position++;
+
+ /* Set domain type */
+ if ((1 << mask_position) & i) {
+ condition_status = lttng_condition_buffer_usage_set_domain_type(
+ condition, LTTNG_DOMAIN_UST);
+ if (condition_status != LTTNG_CONDITION_STATUS_OK) {
+ loop_ret = 1;
+ goto loop_end;
+ }
+ domain_type_set = true;
+ }
+
+ /* Safety check */
+ if (mask_position != test_vector_size -1) {
+ LTTNG_ASSERT("Logic error for test vector generation");
+ }
+
+ loop_ret = asprintf(&test_tuple_string, "session name %s, channel name %s, threshold ratio %s, threshold byte %s, domain type %s",
+ session_name_set ? "set" : "unset",
+ channel_name_set ? "set" : "unset",
+ threshold_ratio_set ? "set" : "unset",
+ threshold_byte_set ? "set" : "unset",
+ domain_type_set? "set" : "unset");
+ if (!test_tuple_string || loop_ret < 0) {
+ loop_ret = 1;
+ goto loop_end;
+ }
+
+ /* Create trigger */
+ trigger = lttng_trigger_create(condition, action);
+ if (!trigger) {
+ loop_ret = 1;
+ goto loop_end;
+ }
+
+ loop_ret = lttng_register_trigger(trigger);
+
+loop_end:
+ if (loop_ret == 1) {
+ fail("Setup error occurred for tuple: %s", test_tuple_string);
+ goto loop_cleanup;
+ }
+
+ /* This combination happens three times */
+ if (session_name_set && channel_name_set
+ && (threshold_ratio_set || threshold_byte_set)
+ && domain_type_set) {
+ ok(loop_ret == 0, "Trigger is registered: %s", test_tuple_string);
+
+ /*
+ * Test that a trigger cannot be registered
+ * multiple time.
+ */
+ loop_ret = lttng_register_trigger(trigger);
+ ok(loop_ret == -LTTNG_ERR_TRIGGER_EXISTS, "Re-register trigger fails as expected: %s", test_tuple_string);
+
+ /* Test that a trigger can be unregistered */
+ loop_ret = lttng_unregister_trigger(trigger);
+ ok(loop_ret == 0, "Unregister trigger: %s", test_tuple_string);
+
+ /*
+ * Test that unregistration of a non-previously
+ * registered trigger fail.
+ */
+ loop_ret = lttng_unregister_trigger(trigger);
+ ok(loop_ret == -LTTNG_ERR_TRIGGER_NOT_FOUND, "Unregister of a non-registered trigger fails as expected: %s", test_tuple_string);
+ } else {
+ ok(loop_ret == -LTTNG_ERR_INVALID_TRIGGER, "Trigger is invalid as expected and cannot be registered: %s", test_tuple_string);
+ }
+
+loop_cleanup:
+ free(test_tuple_string);
+ lttng_trigger_destroy(trigger);
+ lttng_condition_destroy(condition);
+ }
+
+end:
+ lttng_action_destroy(action);
+}
+
+static
+void wait_data_pending(const char *session_name)
+{
+ int ret;
+
+ do {
+ ret = lttng_data_pending(session_name);
+ LTTNG_ASSERT(ret >= 0);
+ } while (ret != 0);
+}
+
+static
+int setup_buffer_usage_condition(struct lttng_condition *condition,
+ const char *condition_name,
+ const char *session_name,
+ const char *channel_name,
+ const enum lttng_domain_type domain_type)
+{
+ enum lttng_condition_status condition_status;
+ int ret = 0;
+
+ condition_status = lttng_condition_buffer_usage_set_session_name(
+ condition, session_name);
+ if (condition_status != LTTNG_CONDITION_STATUS_OK) {
+ fail("Failed to set session name on creation of condition `%s`",
+ condition_name);
+ ret = -1;
+ goto end;
+ }
+
+ condition_status = lttng_condition_buffer_usage_set_channel_name(
+ condition, channel_name);
+ if (condition_status != LTTNG_CONDITION_STATUS_OK) {
+ fail("Failed to set channel name on creation of condition `%s`",
+ condition_name);
+ ret = -1;
+ goto end;
+ }
+
+ condition_status = lttng_condition_buffer_usage_set_domain_type(
+ condition, domain_type);
+ if (condition_status != LTTNG_CONDITION_STATUS_OK) {
+ fail("Failed to set domain type on creation of condition `%s`",
+ condition_name);
+ ret = -1;
+ goto end;
+ }
+
+end:
+ return ret;
+}
+
+static
+void test_invalid_channel_subscription(
+ const enum lttng_domain_type domain_type)
+{
+ enum lttng_condition_status condition_status;
+ enum lttng_notification_channel_status nc_status;
+ struct lttng_condition *dummy_condition = NULL;
+ struct lttng_condition *dummy_invalid_condition = NULL;
+ struct lttng_notification_channel *notification_channel = NULL;
+ int ret = 0;
+
+ notification_channel = lttng_notification_channel_create(
+ lttng_session_daemon_notification_endpoint);
+ ok(notification_channel, "Notification channel object creation");
+ if (!notification_channel) {
+ goto end;
+ }
+
+ /*
+ * Create a dummy, empty (thus invalid) condition to test error paths.
+ */
+ dummy_invalid_condition = lttng_condition_buffer_usage_low_create();
+ if (!dummy_invalid_condition) {
+ fail("Setup error on condition creation");
+ goto end;
+ }
+
+ /*
+ * Test subscription and unsubscription of an invalid condition to/from
+ * a channel.
+ */
+ nc_status = lttng_notification_channel_subscribe(
+ notification_channel, dummy_invalid_condition);
+ ok(nc_status == LTTNG_NOTIFICATION_CHANNEL_STATUS_INVALID,
+ "Subscribing to an invalid condition");
+
+ nc_status = lttng_notification_channel_unsubscribe(
+ notification_channel, dummy_invalid_condition);
+ ok(nc_status == LTTNG_NOTIFICATION_CHANNEL_STATUS_INVALID,
+ "Unsubscribing from an invalid condition");
+
+ /* Create a valid dummy condition with a ratio of 0.5 */
+ dummy_condition = lttng_condition_buffer_usage_low_create();
+ if (!dummy_condition) {
+ fail("Setup error on dummy_condition creation");
+ goto end;
+ }
+
+ condition_status = lttng_condition_buffer_usage_set_threshold_ratio(
+ dummy_condition, 0.5);
+ if (condition_status != LTTNG_CONDITION_STATUS_OK) {
+ fail("Setup error on condition creation");
+ goto end;
+ }
+
+ ret = setup_buffer_usage_condition(dummy_condition, "dummy_condition",
+ "dummy_session", "dummy_channel", domain_type);
+ if (ret) {
+ fail("Setup error on dummy condition creation");
+ goto end;
+ }
+
+ /*
+ * Test subscription and unsubscription to/from a channel with invalid
+ * parameters.
+ */
+ nc_status = lttng_notification_channel_subscribe(NULL, NULL);
+ ok(nc_status == LTTNG_NOTIFICATION_CHANNEL_STATUS_INVALID,
+ "Notification channel subscription is invalid: NULL, NULL");
+
+ nc_status = lttng_notification_channel_subscribe(
+ notification_channel, NULL);
+ ok(nc_status == LTTNG_NOTIFICATION_CHANNEL_STATUS_INVALID,
+ "Notification channel subscription is invalid: NON-NULL, NULL");
+
+ nc_status = lttng_notification_channel_subscribe(NULL, dummy_condition);
+ ok(nc_status == LTTNG_NOTIFICATION_CHANNEL_STATUS_INVALID,
+ "Notification channel subscription is invalid: NULL, NON-NULL");
+
+ nc_status = lttng_notification_channel_unsubscribe(
+ notification_channel, dummy_condition);
+ ok(nc_status == LTTNG_NOTIFICATION_CHANNEL_STATUS_UNKNOWN_CONDITION,
+ "Unsubscribing from a valid unknown condition");
+
+end:
+ lttng_notification_channel_destroy(notification_channel);
+ lttng_condition_destroy(dummy_invalid_condition);
+ lttng_condition_destroy(dummy_condition);
+ return;
+}
+
+enum buffer_usage_type {
+ BUFFER_USAGE_TYPE_LOW,
+ BUFFER_USAGE_TYPE_HIGH,
+};
+
+static int register_buffer_usage_notify_trigger(const char *session_name,
+ const char *channel_name,
+ const enum lttng_domain_type domain_type,
+ enum buffer_usage_type buffer_usage_type,
+ double ratio,
+ struct lttng_condition **condition,
+ struct lttng_action **action,
+ struct lttng_trigger **trigger)
+{
+ enum lttng_condition_status condition_status;
+ struct lttng_action *tmp_action = NULL;
+ struct lttng_condition *tmp_condition = NULL;
+ struct lttng_trigger *tmp_trigger = NULL;
+ int ret = 0;
+
+ /* Set-up */
+ tmp_action = lttng_action_notify_create();
+ if (!action) {
+ fail("Setup error on action creation");
+ ret = -1;
+ goto error;
+ }
+
+ if (buffer_usage_type == BUFFER_USAGE_TYPE_LOW) {
+ tmp_condition = lttng_condition_buffer_usage_low_create();
+ } else {
+ tmp_condition = lttng_condition_buffer_usage_high_create();
+ }
+
+ if (!tmp_condition) {
+ fail("Setup error on condition creation");
+ ret = -1;
+ goto error;
+ }
+
+ /* Set the buffer usage threashold */
+ condition_status = lttng_condition_buffer_usage_set_threshold_ratio(
+ tmp_condition, ratio);
+ if (condition_status != LTTNG_CONDITION_STATUS_OK) {
+ fail("Setup error on condition creation");
+ ret = -1;
+ goto error;
+ }
+
+ ret = setup_buffer_usage_condition(tmp_condition, "condition_name",
+ session_name, channel_name, domain_type);
+ if (ret) {
+ fail("Setup error on condition creation");
+ ret = -1;
+ goto error;
+ }
+
+ /* Register the trigger for condition. */
+ tmp_trigger = lttng_trigger_create(tmp_condition, tmp_action);
+ if (!tmp_trigger) {
+ fail("Setup error on trigger creation");
+ ret = -1;
+ goto error;
+ }
+
+ ret = lttng_register_trigger(tmp_trigger);
+ if (ret) {
+ fail("Setup error on trigger registration");
+ ret = -1;
+ goto error;
+ }
+
+ *condition = tmp_condition;
+ *trigger = tmp_trigger;
+ *action = tmp_action;
+ goto end;
+
+error:
+ lttng_action_destroy(tmp_action);
+ lttng_condition_destroy(tmp_condition);
+ lttng_trigger_destroy(tmp_trigger);
+
+end:
+ return ret;
+}
+
+static void test_subscription_twice(const char *session_name,
+ const char *channel_name,
+ const enum lttng_domain_type domain_type)
+{
+ int ret = 0;
+ enum lttng_notification_channel_status nc_status;
+
+ struct lttng_action *action = NULL;
+ struct lttng_notification_channel *notification_channel = NULL;
+ struct lttng_trigger *trigger = NULL;
+
+ struct lttng_condition *condition = NULL;
+
+ ret = register_buffer_usage_notify_trigger(session_name, channel_name,
+ domain_type, BUFFER_USAGE_TYPE_LOW, 0.99, &condition,
+ &action, &trigger);
+ if (ret) {
+ fail("Setup error on trigger registration in %s()",
+ __FUNCTION__);
+ goto end;
+ }
+
+ /* Begin testing. */
+ notification_channel = lttng_notification_channel_create(
+ lttng_session_daemon_notification_endpoint);
+ ok(notification_channel, "Notification channel object creation");
+ if (!notification_channel) {
+ goto end;
+ }
+
+ /* Subscribe a valid condition. */
+ nc_status = lttng_notification_channel_subscribe(
+ notification_channel, condition);
+ ok(nc_status == LTTNG_NOTIFICATION_CHANNEL_STATUS_OK,
+ "Subscribe to condition");
+
+ /* Subscribing again should fail. */
+ nc_status = lttng_notification_channel_subscribe(
+ notification_channel, condition);
+ ok(nc_status == LTTNG_NOTIFICATION_CHANNEL_STATUS_ALREADY_SUBSCRIBED,
+ "Subscribe to a condition for which subscription was already done");
+
+end:
+ ret = lttng_unregister_trigger(trigger);
+ if (ret) {
+ fail("Failed to unregister trigger in %s()", __FUNCTION__);
+ }
+
+ lttng_trigger_destroy(trigger);
+ lttng_notification_channel_destroy(notification_channel);
+ lttng_action_destroy(action);
+ lttng_condition_destroy(condition);
+}
+
+static void test_buffer_usage_notification_channel(const char *session_name,
+ const char *channel_name,
+ const enum lttng_domain_type domain_type,
+ const char **argv)
+{
+ int ret = 0;
+ enum lttng_notification_channel_status nc_status;
+
+ struct lttng_action *low_action = NULL;
+ struct lttng_action *high_action = NULL;
+ struct lttng_notification *notification = NULL;
+ struct lttng_notification_channel *notification_channel = NULL;
+ struct lttng_trigger *low_trigger = NULL;
+ struct lttng_trigger *high_trigger = NULL;
+
+ struct lttng_condition *low_condition = NULL;
+ struct lttng_condition *high_condition = NULL;
+
+ const double low_ratio = 0.0;
+ const double high_ratio = 0.90;
+
+ ret = register_buffer_usage_notify_trigger(session_name, channel_name,
+ domain_type, BUFFER_USAGE_TYPE_LOW, low_ratio,
+ &low_condition, &low_action, &low_trigger);
+ if (ret) {
+ fail("Setup error on low trigger registration");
+ goto end;
+ }
+
+ ret = register_buffer_usage_notify_trigger(session_name, channel_name,
+ domain_type, BUFFER_USAGE_TYPE_HIGH, high_ratio,
+ &high_condition, &high_action, &high_trigger);
+ if (ret) {
+ fail("Setup error on high trigger registration");
+ goto end;
+ }
+
+ /* Begin testing */
+ notification_channel = lttng_notification_channel_create(
+ lttng_session_daemon_notification_endpoint);
+ ok(notification_channel, "Notification channel object creation");
+ if (!notification_channel) {
+ goto end;
+ }
+
+ /* Subscribe a valid low condition */
+ nc_status = lttng_notification_channel_subscribe(
+ notification_channel, low_condition);
+ ok(nc_status == LTTNG_NOTIFICATION_CHANNEL_STATUS_OK,
+ "Subscribe to low condition");
+
+ /* Subscribe a valid high condition */
+ nc_status = lttng_notification_channel_subscribe(
+ notification_channel, high_condition);
+ ok(nc_status == LTTNG_NOTIFICATION_CHANNEL_STATUS_OK,
+ "Subscribe to high condition");
+
+ resume_application();
+
+ /* Wait for notification to happen */
+ stop_consumer(argv);
+ lttng_start_tracing(session_name);
+
+ /* Wait for high notification */
+ do {
+ nc_status = lttng_notification_channel_get_next_notification(
+ notification_channel, ¬ification);
+ } while (nc_status == LTTNG_NOTIFICATION_CHANNEL_STATUS_INTERRUPTED);
+ ok(nc_status == LTTNG_NOTIFICATION_CHANNEL_STATUS_OK && notification &&
+ lttng_condition_get_type(lttng_notification_get_condition(
+ notification)) ==
+ LTTNG_CONDITION_TYPE_BUFFER_USAGE_HIGH,
+ "High notification received after intermediary communication");
+ lttng_notification_destroy(notification);
+ notification = NULL;
+
+ suspend_application();
+ lttng_stop_tracing_no_wait(session_name);
+ resume_consumer(argv);
+ wait_data_pending(session_name);
+
+ /*
+ * Test that communication still work even if there is notification
+ * waiting for consumption.
+ */
+
+ nc_status = lttng_notification_channel_unsubscribe(
+ notification_channel, low_condition);
+ ok(nc_status == LTTNG_NOTIFICATION_CHANNEL_STATUS_OK,
+ "Unsubscribe with pending notification");
+
+ nc_status = lttng_notification_channel_subscribe(
+ notification_channel, low_condition);
+ ok(nc_status == LTTNG_NOTIFICATION_CHANNEL_STATUS_OK,
+ "Subscribe with pending notification");
+
+ do {
+ nc_status = lttng_notification_channel_get_next_notification(
+ notification_channel, ¬ification);
+ } while (nc_status == LTTNG_NOTIFICATION_CHANNEL_STATUS_INTERRUPTED);
+ ok(nc_status == LTTNG_NOTIFICATION_CHANNEL_STATUS_OK && notification &&
+ lttng_condition_get_type(lttng_notification_get_condition(
+ notification)) ==
+ LTTNG_CONDITION_TYPE_BUFFER_USAGE_LOW,
+ "Low notification received after intermediary communication");
+ lttng_notification_destroy(notification);
+ notification = NULL;
+
+ /* Stop consumer to force a high notification */
+ stop_consumer(argv);
+ resume_application();
+ lttng_start_tracing(session_name);
+
+ do {
+ nc_status = lttng_notification_channel_get_next_notification(
+ notification_channel, ¬ification);
+ } while (nc_status == LTTNG_NOTIFICATION_CHANNEL_STATUS_INTERRUPTED);
+ ok(nc_status == LTTNG_NOTIFICATION_CHANNEL_STATUS_OK && notification &&
+ lttng_condition_get_type(lttng_notification_get_condition(
+ notification)) ==
+ LTTNG_CONDITION_TYPE_BUFFER_USAGE_HIGH,
+ "High notification received after intermediary communication");
+ lttng_notification_destroy(notification);
+ notification = NULL;
+
+ suspend_application();
+ lttng_stop_tracing_no_wait(session_name);
+ resume_consumer(argv);
+ wait_data_pending(session_name);
+
+ do {
+ nc_status = lttng_notification_channel_get_next_notification(
+ notification_channel, ¬ification);
+ } while (nc_status == LTTNG_NOTIFICATION_CHANNEL_STATUS_INTERRUPTED);
+ ok(nc_status == LTTNG_NOTIFICATION_CHANNEL_STATUS_OK && notification &&
+ lttng_condition_get_type(lttng_notification_get_condition(
+ notification)) ==
+ LTTNG_CONDITION_TYPE_BUFFER_USAGE_LOW,
+ "Low notification received after re-subscription");
+ lttng_notification_destroy(notification);
+ notification = NULL;
+
+ stop_consumer(argv);
+ resume_application();
+ /* Stop consumer to force a high notification */
+ lttng_start_tracing(session_name);
+
+ do {
+ nc_status = lttng_notification_channel_get_next_notification(
+ notification_channel, ¬ification);
+ } while (nc_status == LTTNG_NOTIFICATION_CHANNEL_STATUS_INTERRUPTED);
+ ok(nc_status == LTTNG_NOTIFICATION_CHANNEL_STATUS_OK && notification &&
+ lttng_condition_get_type(lttng_notification_get_condition(
+ notification)) ==
+ LTTNG_CONDITION_TYPE_BUFFER_USAGE_HIGH,
+ "High notification");
+ lttng_notification_destroy(notification);
+ notification = NULL;
+
+ suspend_application();
+
+ /* Resume consumer to allow event consumption */
+ lttng_stop_tracing_no_wait(session_name);
+ resume_consumer(argv);
+ wait_data_pending(session_name);
+
+ nc_status = lttng_notification_channel_unsubscribe(
+ notification_channel, low_condition);
+ ok(nc_status == LTTNG_NOTIFICATION_CHANNEL_STATUS_OK,
+ "Unsubscribe low condition with pending notification");
+
+ nc_status = lttng_notification_channel_unsubscribe(
+ notification_channel, high_condition);
+ ok(nc_status == LTTNG_NOTIFICATION_CHANNEL_STATUS_OK,
+ "Unsubscribe high condition with pending notification");
+
+end:
+ lttng_notification_channel_destroy(notification_channel);
+ lttng_trigger_destroy(low_trigger);
+ lttng_trigger_destroy(high_trigger);
+ lttng_action_destroy(low_action);
+ lttng_action_destroy(high_action);
+ lttng_condition_destroy(low_condition);
+ lttng_condition_destroy(high_condition);
+}
+
+static void create_tracepoint_event_rule_trigger(const char *event_pattern,
+ const char *trigger_name,
+ const char *filter,
+ unsigned int exclusion_count,
+ const char * const *exclusions,
+ enum lttng_domain_type domain_type,
+ condition_capture_desc_cb capture_desc_cb,
+ struct lttng_condition **condition,
+ struct lttng_trigger **trigger)
+{
+ typedef struct lttng_event_rule *(*event_rule_create)(void);
+ typedef enum lttng_event_rule_status (
+ *event_rule_set_name_pattern)(
+ struct lttng_event_rule *rule,
+ const char *pattern);
+ typedef enum lttng_event_rule_status (*event_rule_set_filter)(
+ struct lttng_event_rule *rule,
+ const char *expression);
+ typedef enum lttng_event_rule_status (
+ *event_rule_add_name_pattern_exclusion)(
+ struct lttng_event_rule * rule, const char *exclusion);
+
+ enum lttng_event_rule_status event_rule_status;
+ struct lttng_action *tmp_action = NULL;
+ struct lttng_event_rule *event_rule = NULL;
+ struct lttng_condition *tmp_condition = NULL;
+ struct lttng_trigger *tmp_trigger = NULL;
+ int ret;
+ enum lttng_error_code ret_code;
+ event_rule_create create;
+ event_rule_set_name_pattern set_name_pattern;
+ event_rule_set_filter set_filter;
+ event_rule_add_name_pattern_exclusion add_name_pattern_exclusion;
+
+ LTTNG_ASSERT(event_pattern);
+ LTTNG_ASSERT(trigger_name);
+ LTTNG_ASSERT(condition);
+ LTTNG_ASSERT(trigger);
+
+ /* Set the function pointers based on the domain type. */
+ switch (domain_type) {
+ case LTTNG_DOMAIN_UST:
+ create = lttng_event_rule_user_tracepoint_create;
+ set_name_pattern = lttng_event_rule_user_tracepoint_set_name_pattern;
+ set_filter = lttng_event_rule_user_tracepoint_set_filter;
+ add_name_pattern_exclusion = lttng_event_rule_user_tracepoint_add_name_pattern_exclusion;
+ break;
+ case LTTNG_DOMAIN_KERNEL:
+ create = lttng_event_rule_kernel_tracepoint_create;
+ set_name_pattern = lttng_event_rule_kernel_tracepoint_set_name_pattern;
+ set_filter = lttng_event_rule_kernel_tracepoint_set_filter;
+ add_name_pattern_exclusion = NULL;
+ break;
+ default:
+ abort();
+ break;
+ }
+
+ event_rule = create();
+ ok(event_rule, "Tracepoint event rule object creation");
+
+ event_rule_status = set_name_pattern(event_rule, event_pattern);
+ ok(event_rule_status == LTTNG_EVENT_RULE_STATUS_OK,
+ "Setting tracepoint event rule pattern: '%s'",
+ event_pattern);
+
+ if (filter) {
+ event_rule_status = set_filter(event_rule, filter);
+ ok(event_rule_status == LTTNG_EVENT_RULE_STATUS_OK,
+ "Setting tracepoint event rule filter: '%s'",
+ filter);
+ }
+
+ if (exclusions) {
+ int i;
+ bool success = true;
+
+ LTTNG_ASSERT(domain_type == LTTNG_DOMAIN_UST);
+ LTTNG_ASSERT(add_name_pattern_exclusion != NULL);
+ LTTNG_ASSERT(exclusion_count > 0);
+
+ for (i = 0; i < exclusion_count; i++) {
+ event_rule_status = add_name_pattern_exclusion(
+ event_rule, exclusions[i]);
+ if (event_rule_status != LTTNG_EVENT_RULE_STATUS_OK) {
+ fail("Setting tracepoint event rule exclusion '%s'.",
+ exclusions[i]);
+ success = false;
+ }
+ }
+
+ ok(success, "Setting tracepoint event rule exclusions");
+ }
+
+ tmp_condition = lttng_condition_event_rule_matches_create(event_rule);
+ ok(tmp_condition, "Condition event rule object creation");
+
+ if (capture_desc_cb) {
+ ret = capture_desc_cb(tmp_condition);
+ if (ret) {
+ fail("Failed to generate the condition capture descriptor");
+ abort();
+ }
+ }
+
+ tmp_action = lttng_action_notify_create();
+ ok(tmp_action, "Action event rule object creation");
+
+ tmp_trigger = lttng_trigger_create(tmp_condition, tmp_action);
+ ok(tmp_trigger, "Trigger object creation %s", trigger_name);
+
+ ret_code = lttng_register_trigger_with_name(tmp_trigger, trigger_name);
+ ok(ret_code == LTTNG_OK, "Trigger registration %s", trigger_name);
+
+ lttng_event_rule_destroy(event_rule);
+
+ *condition = tmp_condition;
+ *trigger = tmp_trigger;
+
+ return;
+}
+
+static struct lttng_notification *get_next_notification(
+ struct lttng_notification_channel *notification_channel)
+{
+ struct lttng_notification *local_notification = NULL;
+ enum lttng_notification_channel_status status;
+
+ /* Receive the next notification. */
+ status = lttng_notification_channel_get_next_notification(
+ notification_channel, &local_notification);
+
+ switch (status) {
+ case LTTNG_NOTIFICATION_CHANNEL_STATUS_OK:
+ break;
+ case LTTNG_NOTIFICATION_CHANNEL_STATUS_NOTIFICATIONS_DROPPED:
+ fail("Notifications have been dropped");
+ local_notification = NULL;
+ break;
+ default:
+ /* Unhandled conditions / errors. */
+ fail("Failed to get next notification (unknown notification channel status): status = %d",
+ (int) status);
+ local_notification = NULL;
+ break;
+ }
+
+ return local_notification;
+}
+
+static void test_tracepoint_event_rule_notification(
+ enum lttng_domain_type domain_type)
+{
+ int i;
+ int ret;
+ const int notification_count = 3;
+ enum lttng_notification_channel_status nc_status;
+ struct lttng_action *action = NULL;
+ struct lttng_condition *condition = NULL;
+ struct lttng_notification_channel *notification_channel = NULL;
+ struct lttng_trigger *trigger = NULL;
+ const char * const trigger_name = "my_precious";
+ const char *pattern;
+
+ if (domain_type == LTTNG_DOMAIN_UST) {
+ pattern = "tp:tptest";
+ } else {
+ pattern = "lttng_test_filter_event";
+ }
+
+ create_tracepoint_event_rule_trigger(pattern, trigger_name, NULL, 0,
+ NULL, domain_type, NULL, &condition, &trigger);
+
+ notification_channel = lttng_notification_channel_create(
+ lttng_session_daemon_notification_endpoint);
+ ok(notification_channel, "Notification channel object creation");
+
+ nc_status = lttng_notification_channel_subscribe(
+ notification_channel, condition);
+ ok(nc_status == LTTNG_NOTIFICATION_CHANNEL_STATUS_OK,
+ "Subscribe to tracepoint event rule condition");
+
+ resume_application();
+
+ /* Get notifications. */
+ for (i = 0; i < notification_count; i++) {
+ struct lttng_notification *notification = get_next_notification(
+ notification_channel);
+
+ ok(notification, "Received notification (%d/%d)", i + 1,
+ notification_count);
+
+ /* Error. */
+ if (notification == NULL) {
+ goto end;
+ }
+
+ ret = validator_notification_trigger_name(notification, trigger_name);
+ lttng_notification_destroy(notification);
+ if (ret) {
+ goto end;
+ }
+ }
+
+end:
+ suspend_application();
+ lttng_notification_channel_destroy(notification_channel);
+ lttng_unregister_trigger(trigger);
+ lttng_trigger_destroy(trigger);
+ lttng_action_destroy(action);
+ lttng_condition_destroy(condition);
+ return;
+}
+
+static void test_tracepoint_event_rule_notification_filter(
+ enum lttng_domain_type domain_type)
+{
+ int i;
+ const int notification_count = 3;
+ enum lttng_notification_channel_status nc_status;
+ struct lttng_condition *ctrl_condition = NULL, *condition = NULL;
+ struct lttng_notification_channel *notification_channel = NULL;
+ struct lttng_trigger *ctrl_trigger = NULL, *trigger = NULL;
+ const char * const ctrl_trigger_name = "control_trigger";
+ const char * const trigger_name = "trigger";
+ const char *pattern;
+ int ctrl_count = 0, count = 0;
+
+ if (domain_type == LTTNG_DOMAIN_UST) {
+ pattern = "tp:tptest";
+ } else {
+ pattern = "lttng_test_filter_event";
+ }
+
+ notification_channel = lttng_notification_channel_create(
+ lttng_session_daemon_notification_endpoint);
+ ok(notification_channel, "Notification channel object creation");
+
+ create_tracepoint_event_rule_trigger(pattern, ctrl_trigger_name, NULL,
+ 0, NULL, domain_type, NULL, &ctrl_condition, &ctrl_trigger);
+
+ nc_status = lttng_notification_channel_subscribe(
+ notification_channel, ctrl_condition);
+ ok(nc_status == LTTNG_NOTIFICATION_CHANNEL_STATUS_OK,
+ "Subscribe to tracepoint event rule condition");
+
+ /*
+ * Attach a filter expression to get notification only if the
+ * `intfield` is even.
+ */
+ create_tracepoint_event_rule_trigger(pattern, trigger_name,
+ "(intfield & 1) == 0", 0, NULL, domain_type, NULL, &condition,
+ &trigger);
+
+ nc_status = lttng_notification_channel_subscribe(
+ notification_channel, condition);
+ ok(nc_status == LTTNG_NOTIFICATION_CHANNEL_STATUS_OK,
+ "Subscribe to tracepoint event rule condition");
+
+ /*
+ * We registered 2 notifications triggers, one with a filter and one
+ * without (control). The one with a filter will only fired when the
+ * `intfield` is a multiple of 2. We should get two times as many
+ * control notifications as filter notifications.
+ */
+ resume_application();
+
+ /*
+ * Get 3 notifications. We should get 1 for the regular trigger (with
+ * the filter) and 2 from the control trigger. This works whatever
+ * the order we receive the notifications.
+ */
+ for (i = 0; i < notification_count; i++) {
+ const char *name;
+ struct lttng_notification *notification = get_next_notification(
+ notification_channel);
+
+ ok(notification, "Received notification (%d/%d)", i + 1,
+ notification_count);
+
+ /* Error. */
+ if (notification == NULL) {
+ goto end;
+ }
+
+ name = get_notification_trigger_name(notification);
+ if (name == NULL) {
+ lttng_notification_destroy(notification);
+ goto end;
+ }
+
+ if (strcmp(ctrl_trigger_name, name) == 0) {
+ ctrl_count++;
+ } else if (strcmp(trigger_name, name) == 0) {
+ count++;
+ }
+
+ lttng_notification_destroy(notification);
+ }
+
+ ok(ctrl_count / 2 == count,
+ "Get twice as many control notif as of regular notif");
+
+end:
+ suspend_application();
+
+ lttng_unregister_trigger(trigger);
+ lttng_unregister_trigger(ctrl_trigger);
+ lttng_notification_channel_destroy(notification_channel);
+ lttng_trigger_destroy(trigger);
+ lttng_trigger_destroy(ctrl_trigger);
+ lttng_condition_destroy(condition);
+ lttng_condition_destroy(ctrl_condition);
+}
+
+static void test_tracepoint_event_rule_notification_exclusion(
+ enum lttng_domain_type domain_type)
+{
+ enum lttng_notification_channel_status nc_status;
+ struct lttng_condition *ctrl_condition = NULL, *condition = NULL;
+ struct lttng_notification_channel *notification_channel = NULL;
+ struct lttng_trigger *ctrl_trigger = NULL, *trigger = NULL;
+ int ctrl_count = 0, count = 0, i;
+ const int notification_count = 6;
+ const char * const ctrl_trigger_name = "control_exclusion_trigger";
+ const char * const trigger_name = "exclusion_trigger";
+ const char * const pattern = "tp:tptest*";
+ const char * const exclusions[] = {
+ "tp:tptest2",
+ "tp:tptest3",
+ "tp:tptest4",
+ "tp:tptest5"
+ };
+
+ notification_channel = lttng_notification_channel_create(
+ lttng_session_daemon_notification_endpoint);
+ ok(notification_channel, "Notification channel object creation");
+
+ create_tracepoint_event_rule_trigger(pattern, ctrl_trigger_name, NULL,
+ 0, NULL, domain_type, NULL, &ctrl_condition,
+ &ctrl_trigger);
+
+ nc_status = lttng_notification_channel_subscribe(
+ notification_channel, ctrl_condition);
+ ok(nc_status == LTTNG_NOTIFICATION_CHANNEL_STATUS_OK,
+ "Subscribe to tracepoint event rule condition");
+
+ create_tracepoint_event_rule_trigger(pattern, trigger_name, NULL, 4,
+ exclusions, domain_type, NULL, &condition,
+ &trigger);
+
+ nc_status = lttng_notification_channel_subscribe(
+ notification_channel, condition);
+ ok(nc_status == LTTNG_NOTIFICATION_CHANNEL_STATUS_OK,
+ "Subscribe to tracepoint event rule condition");
+
+ /*
+ * We registered 2 notifications triggers, one with an exclusion and
+ * one without (control).
+ * - The trigger with an exclusion will fire once every iteration.
+ * - The trigger without an exclusion will fire 5 times every
+ * iteration.
+ *
+ * We should get 5 times as many notifications from the control
+ * trigger.
+ */
+ resume_application();
+
+ /*
+ * Get 6 notifications. We should get 1 for the regular trigger (with
+ * the exclusion) and 5 from the control trigger. This works whatever
+ * the order we receive the notifications.
+ */
+ for (i = 0; i < notification_count; i++) {
+ const char *name;
+ struct lttng_notification *notification = get_next_notification(
+ notification_channel);
+
+ ok(notification, "Received notification (%d/%d)", i + 1,
+ notification_count);
+
+ /* Error. */
+ if (notification == NULL) {
+ goto end;
+ }
+
+ name = get_notification_trigger_name(notification);
+ if (name == NULL) {
+ lttng_notification_destroy(notification);
+ goto end;
+ }
+
+ if (strcmp(ctrl_trigger_name, name) == 0) {
+ ctrl_count++;
+ } else if (strcmp(trigger_name, name) == 0) {
+ count++;
+ }
+
+ lttng_notification_destroy(notification);
+ }
+
+ ok(ctrl_count / 5 == count,
+ "Got 5 times as many control notif as of regular notif");
+
+end:
+ suspend_application();
+
+ lttng_unregister_trigger(trigger);
+ lttng_unregister_trigger(ctrl_trigger);
+ lttng_notification_channel_destroy(notification_channel);
+ lttng_trigger_destroy(trigger);
+ lttng_trigger_destroy(ctrl_trigger);
+ lttng_condition_destroy(condition);
+ lttng_condition_destroy(ctrl_condition);
+ return;
+}
+
+static void test_kprobe_event_rule_notification(
+ enum lttng_domain_type domain_type)
+{
+ int i, ret;
+ enum lttng_error_code ret_code;
+ const int notification_count = 3;
+ enum lttng_notification_channel_status nc_status;
+ enum lttng_event_rule_status event_rule_status;
+ struct lttng_notification_channel *notification_channel = NULL;
+ struct lttng_condition *condition = NULL;
+ struct lttng_kernel_probe_location *location = NULL;
+ struct lttng_event_rule *event_rule = NULL;
+ struct lttng_action *action = NULL;
+ struct lttng_trigger *trigger = NULL;
+ const char * const trigger_name = "kprobe_trigger";
+ const char * const symbol_name = "lttng_test_filter_event_write";
+
+ action = lttng_action_notify_create();
+ if (!action) {
+ fail("Failed to create notify action");
+ goto end;
+ }
+
+ location = lttng_kernel_probe_location_symbol_create(symbol_name, 0);
+ if (!location) {
+ fail("Failed to create kernel probe location");
+ goto end;
+ }
+
+ notification_channel = lttng_notification_channel_create(
+ lttng_session_daemon_notification_endpoint);
+ ok(notification_channel, "Notification channel object creation");
+
+ event_rule = lttng_event_rule_kernel_kprobe_create(location);
+ ok(event_rule, "kprobe event rule object creation");
+
+ event_rule_status = lttng_event_rule_kernel_kprobe_set_event_name(
+ event_rule, trigger_name);
+ ok(event_rule_status == LTTNG_EVENT_RULE_STATUS_OK,
+ "Setting kprobe event rule name: '%s'", trigger_name);
+
+ condition = lttng_condition_event_rule_matches_create(event_rule);
+ ok(condition, "Condition event rule object creation");
+
+ /* Register the trigger for condition. */
+ trigger = lttng_trigger_create(condition, action);
+ if (!trigger) {
+ fail("Failed to create trigger with kernel probe event rule condition and notify action");
+ goto end;
+ }
+
+ ret_code = lttng_register_trigger_with_name(trigger, trigger_name);
+ if (ret_code != LTTNG_OK) {
+ fail("Failed to register trigger with kernel probe event rule condition and notify action");
+ goto end;
+ }
+
+ nc_status = lttng_notification_channel_subscribe(
+ notification_channel, condition);
+ ok(nc_status == LTTNG_NOTIFICATION_CHANNEL_STATUS_OK,
+ "Subscribe to tracepoint event rule condition");
+
+ resume_application();
+
+ for (i = 0; i < notification_count; i++) {
+ struct lttng_notification *notification = get_next_notification(
+ notification_channel);
+
+ ok(notification, "Received notification (%d/%d)", i + 1,
+ notification_count);
+
+ /* Error. */
+ if (notification == NULL) {
+ goto end;
+ }
+
+ ret = validator_notification_trigger_name(notification, trigger_name);
+ lttng_notification_destroy(notification);
+ if (ret) {
+ goto end;
+ }
+ }
+
+end:
+ suspend_application();
+ lttng_notification_channel_destroy(notification_channel);
+ lttng_unregister_trigger(trigger);
+ lttng_trigger_destroy(trigger);
+ lttng_action_destroy(action);
+ lttng_event_rule_destroy(event_rule);
+ lttng_condition_destroy(condition);
+ lttng_kernel_probe_location_destroy(location);
+ return;
+}
+
+static void test_uprobe_event_rule_notification(
+ enum lttng_domain_type domain_type,
+ const char *testapp_path,
+ const char *test_symbol_name)
+{
+ int i, ret;
+ enum lttng_error_code ret_code;
+ const int notification_count = 3;
+ enum lttng_notification_channel_status nc_status;
+ enum lttng_event_rule_status event_rule_status;
+ struct lttng_notification_channel *notification_channel = NULL;
+ struct lttng_userspace_probe_location *probe_location = NULL;
+ struct lttng_userspace_probe_location_lookup_method *lookup_method =
+ NULL;
+ struct lttng_condition *condition = NULL;
+ struct lttng_event_rule *event_rule = NULL;
+ struct lttng_action *action = NULL;
+ struct lttng_trigger *trigger = NULL;
+ const char * const trigger_name = "uprobe_trigger";
+
+ action = lttng_action_notify_create();
+ if (!action) {
+ fail("Failed to create notify action");
+ goto end;
+ }
+
+ lookup_method = lttng_userspace_probe_location_lookup_method_function_elf_create();
+ if (!lookup_method) {
+ fail("Setup error on userspace probe lookup method creation");
+ goto end;
+ }
+
+ probe_location = lttng_userspace_probe_location_function_create(
+ testapp_path, test_symbol_name, lookup_method);
+ if (!probe_location) {
+ fail("Failed to create userspace probe location");
+ goto end;
+ }
+
+ notification_channel = lttng_notification_channel_create(
+ lttng_session_daemon_notification_endpoint);
+ ok(notification_channel, "Notification channel object creation");
+
+ event_rule = lttng_event_rule_kernel_uprobe_create(probe_location);
+ ok(event_rule, "kprobe event rule object creation");
+
+ event_rule_status = lttng_event_rule_kernel_uprobe_set_event_name(
+ event_rule, trigger_name);
+ ok(event_rule_status == LTTNG_EVENT_RULE_STATUS_OK,
+ "Setting uprobe event rule name: '%s'", trigger_name);
+
+ condition = lttng_condition_event_rule_matches_create(event_rule);
+ ok(condition, "Condition event rule object creation");
+
+ /* Register the trigger for condition. */
+ trigger = lttng_trigger_create(condition, action);
+ if (!trigger) {
+ fail("Failed to create trigger with userspace probe event rule condition and notify action");
+ goto end;
+ }
+
+ ret_code = lttng_register_trigger_with_name(trigger, trigger_name);
+ if (ret_code != LTTNG_OK) {
+ fail("Failed to register trigger with userspace probe event rule condition and notify action");
+ goto end;
+ }
+
+ nc_status = lttng_notification_channel_subscribe(
+ notification_channel, condition);
+ ok(nc_status == LTTNG_NOTIFICATION_CHANNEL_STATUS_OK,
+ "Subscribe to tracepoint event rule condition");
+
+ resume_application();
+
+ for (i = 0; i < 3; i++) {
+ struct lttng_notification *notification = get_next_notification(
+ notification_channel);
+
+ ok(notification, "Received notification (%d/%d)", i + 1,
+ notification_count);
+
+ /* Error. */
+ if (notification == NULL) {
+ goto end;
+ }
+
+ ret = validator_notification_trigger_name(notification, trigger_name);
+ lttng_notification_destroy(notification);
+ if (ret) {
+ goto end;
+ }
+ }
+end:
+ suspend_application();
+
+ lttng_notification_channel_destroy(notification_channel);
+ lttng_unregister_trigger(trigger);
+ lttng_trigger_destroy(trigger);
+ lttng_action_destroy(action);
+ lttng_userspace_probe_location_destroy(probe_location);
+ lttng_event_rule_destroy(event_rule);
+ lttng_condition_destroy(condition);
+ return;
+}
+
+static void test_syscall_event_rule_notification(
+ enum lttng_domain_type domain_type)
+{
+ int i, ret;
+ enum lttng_error_code ret_code;
+ const int notification_count = 3;
+ enum lttng_notification_channel_status nc_status;
+ enum lttng_event_rule_status event_rule_status;
+ struct lttng_notification_channel *notification_channel = NULL;
+ struct lttng_condition *condition = NULL;
+ struct lttng_event_rule *event_rule = NULL;
+ struct lttng_action *action = NULL;
+ struct lttng_trigger *trigger = NULL;
+ const char * const trigger_name = "syscall_trigger";
+ const char * const syscall_name = "openat";
+
+ action = lttng_action_notify_create();
+ if (!action) {
+ fail("Failed to create notify action");
+ goto end;
+ }
+
+ notification_channel = lttng_notification_channel_create(
+ lttng_session_daemon_notification_endpoint);
+ ok(notification_channel, "Notification channel object creation");
+
+ event_rule = lttng_event_rule_kernel_syscall_create(LTTNG_EVENT_RULE_KERNEL_SYSCALL_EMISSION_SITE_ENTRY);
+ ok(event_rule, "syscall event rule object creation");
+
+ event_rule_status = lttng_event_rule_kernel_syscall_set_name_pattern(
+ event_rule, syscall_name);
+ ok(event_rule_status == LTTNG_EVENT_RULE_STATUS_OK,
+ "Setting syscall event rule pattern: '%s'", syscall_name);
+
+ condition = lttng_condition_event_rule_matches_create(event_rule);
+ ok(condition, "Condition syscall event rule object creation");
+
+ /* Register the trigger for condition. */
+ trigger = lttng_trigger_create(condition, action);
+ if (!trigger) {
+ fail("Failed to create trigger with syscall event rule condition and notify action");
+ goto end;
+ }
+
+ ret_code = lttng_register_trigger_with_name(trigger, trigger_name);
+ if (ret_code != LTTNG_OK) {
+ fail("Failed to register trigger with syscall event rule condition and notify action");
+ goto end;
+ }
+
+ nc_status = lttng_notification_channel_subscribe(
+ notification_channel, condition);
+ ok(nc_status == LTTNG_NOTIFICATION_CHANNEL_STATUS_OK,
+ "Subscribe to tracepoint event rule condition");
+
+ resume_application();
+
+ for (i = 0; i < notification_count; i++) {
+ struct lttng_notification *notification = get_next_notification(
+ notification_channel);
+
+ ok(notification, "Received notification (%d/%d)", i + 1,
+ notification_count);
+
+ /* Error. */
+ if (notification == NULL) {
+ goto end;
+ }
+
+ ret = validator_notification_trigger_name(notification, trigger_name);
+ lttng_notification_destroy(notification);
+ if (ret) {
+ goto end;
+ }
+ }
+end:
+ suspend_application();
+ lttng_notification_channel_destroy(notification_channel);
+ lttng_unregister_trigger(trigger);
+ lttng_trigger_destroy(trigger);
+ lttng_action_destroy(action);
+ lttng_condition_destroy(condition);
+ return;
+}
+
+static void test_syscall_event_rule_notification_filter(
+ enum lttng_domain_type domain_type)
+{
+ int i, ret;
+ enum lttng_error_code ret_code;
+ const int notification_count = 3;
+ enum lttng_notification_channel_status nc_status;
+ enum lttng_event_rule_status event_rule_status;
+ struct lttng_notification_channel *notification_channel = NULL;
+ struct lttng_condition *condition = NULL;
+ struct lttng_event_rule *event_rule = NULL;
+ struct lttng_action *action = NULL;
+ struct lttng_trigger *trigger = NULL;
+ const char * const trigger_name = "syscall_trigger";
+ const char * const syscall_name = "openat";
+ const char * const filter_pattern = "filename == \"/proc/cpuinfo\"";
+
+ action = lttng_action_notify_create();
+ if (!action) {
+ fail("Failed to create notify action");
+ goto end;
+ }
+
+ notification_channel = lttng_notification_channel_create(
+ lttng_session_daemon_notification_endpoint);
+ ok(notification_channel, "Notification channel object creation");
+
+ event_rule = lttng_event_rule_kernel_syscall_create(LTTNG_EVENT_RULE_KERNEL_SYSCALL_EMISSION_SITE_ENTRY);
+ ok(event_rule, "syscall event rule object creation");
+
+ event_rule_status = lttng_event_rule_kernel_syscall_set_name_pattern(
+ event_rule, syscall_name);
+ ok(event_rule_status == LTTNG_EVENT_RULE_STATUS_OK,
+ "Setting syscall event rule pattern: '%s'", syscall_name);
+
+ event_rule_status = lttng_event_rule_kernel_syscall_set_filter(
+ event_rule, filter_pattern);
+ ok(event_rule_status == LTTNG_EVENT_RULE_STATUS_OK,
+ "Setting filter: '%s'", filter_pattern);
+
+ condition = lttng_condition_event_rule_matches_create(event_rule);
+ ok(condition, "Condition event rule object creation");
+
+ /* Register the triggers for condition */
+ trigger = lttng_trigger_create(condition, action);
+ if (!trigger) {
+ fail("Failed to create trigger with syscall filtering event rule condition and notify action");
+ goto end;
+ }
+
+ ret_code = lttng_register_trigger_with_name(trigger, trigger_name);
+ if (ret_code != LTTNG_OK) {
+ fail("Failed to register trigger with syscall filtering event rule condition and notify action");
+ goto end;
+ }
+
+ nc_status = lttng_notification_channel_subscribe(
+ notification_channel, condition);
+ ok(nc_status == LTTNG_NOTIFICATION_CHANNEL_STATUS_OK,
+ "Subscribe to tracepoint event rule condition");
+
+ resume_application();
+
+ for (i = 0; i < notification_count; i++) {
+ struct lttng_notification *notification = get_next_notification(
+ notification_channel);
+
+ ok(notification, "Received notification (%d/%d)", i + 1,
+ notification_count);
+
+ /* Error. */
+ if (notification == NULL) {
+ goto end;
+ }
+
+ ret = validator_notification_trigger_name(notification, trigger_name);
+ lttng_notification_destroy(notification);
+ if (ret) {
+ goto end;
+ }
+ }
+
+end:
+ suspend_application();
+
+ lttng_unregister_trigger(trigger);
+ lttng_notification_channel_destroy(notification_channel);
+ lttng_trigger_destroy(trigger);
+ lttng_event_rule_destroy(event_rule);
+ lttng_condition_destroy(condition);
+ return;
+}
+
+static int generate_capture_descr(struct lttng_condition *condition)
+{
+ int ret, i;
+ struct lttng_event_expr *expr = NULL;
+ const unsigned int basic_field_count = sizeof(test_capture_base_fields) /
+ sizeof(*test_capture_base_fields);
+ enum lttng_condition_status cond_status;
+
+ for (i = 0; i < basic_field_count; i++) {
+ diag("Adding capture descriptor '%s'",
+ test_capture_base_fields[i].field_name);
+
+ switch (test_capture_base_fields[i].field_type) {
+ case FIELD_TYPE_PAYLOAD:
+ expr = lttng_event_expr_event_payload_field_create(
+ test_capture_base_fields[i].field_name);
+ break;
+ case FIELD_TYPE_CONTEXT:
+ expr = lttng_event_expr_channel_context_field_create(
+ test_capture_base_fields[i].field_name);
+ break;
+ case FIELD_TYPE_ARRAY_FIELD:
+ {
+ int nb_matches;
+ unsigned int index;
+ char field_name[FIELD_NAME_MAX_LEN];
+ struct lttng_event_expr *array_expr = NULL;
+
+ nb_matches = sscanf(test_capture_base_fields[i].field_name,
+ "%[^[][%u]", field_name, &index);
+ if (nb_matches != 2) {
+ fail("Unexpected array field name format: field name = '%s'",
+ test_capture_base_fields[i].field_name);
+ ret = 1;
+ goto end;
+ }
+
+ array_expr = lttng_event_expr_event_payload_field_create(
+ field_name);
+
+ expr = lttng_event_expr_array_field_element_create(
+ array_expr, index);
+ break;
+ }
+ case FIELD_TYPE_APP_CONTEXT:
+ fail("Application context tests are not implemented yet.");
+ /* fallthrough. */
+ default:
+ ret = 1;
+ goto end;
+ }
+
+ if (expr == NULL) {
+ fail("Failed to create capture expression");
+ ret = -1;
+ goto end;
+ }
+
+ cond_status = lttng_condition_event_rule_matches_append_capture_descriptor(
+ condition, expr);
+ if (cond_status != LTTNG_CONDITION_STATUS_OK) {
+ fail("Failed to append capture descriptor");
+ ret = -1;
+ lttng_event_expr_destroy(expr);
+ goto end;
+ }
+ }
+
+ ret = 0;
+
+end:
+ return ret;
+}
+
+static int validator_notification_trigger_capture(
+ enum lttng_domain_type domain,
+ struct lttng_notification *notification,
+ const int iteration)
+{
+ int ret;
+ unsigned int capture_count, i;
+ enum lttng_evaluation_event_rule_matches_status
+ event_rule_matches_evaluation_status;
+ enum lttng_event_field_value_status event_field_value_status;
+ const struct lttng_evaluation *evaluation;
+ const struct lttng_event_field_value *captured_fields;
+ bool at_least_one_error = false;
+
+ evaluation = lttng_notification_get_evaluation(notification);
+ if (evaluation == NULL) {
+ fail("Failed to get evaluation from notification during trigger capture test");
+ ret = 1;
+ goto end;
+ }
+
+ event_rule_matches_evaluation_status =
+ lttng_evaluation_event_rule_matches_get_captured_values(
+ evaluation, &captured_fields);
+ if (event_rule_matches_evaluation_status !=
+ LTTNG_EVALUATION_EVENT_RULE_MATCHES_STATUS_OK) {
+ diag("Failed to get event rule evaluation captured values: status = %d",
+ (int) event_rule_matches_evaluation_status);
+ ret = 1;
+ goto end;
+ }
+
+ event_field_value_status =
+ lttng_event_field_value_array_get_length(captured_fields,
+ &capture_count);
+ if (event_field_value_status != LTTNG_EVENT_FIELD_VALUE_STATUS_OK) {
+ fail("Failed to get count of captured value field array");
+ ret = 1;
+ goto end;
+ }
+
+ for (i = 0; i < capture_count; i++) {
+ const struct lttng_event_field_value *captured_field = NULL;
+ validate_cb validate;
+ bool expected;
+
+ diag("Validating capture of field '%s'",
+ test_capture_base_fields[i].field_name);
+ event_field_value_status =
+ lttng_event_field_value_array_get_element_at_index(
+ captured_fields, i,
+ &captured_field);
+
+ switch(domain) {
+ case LTTNG_DOMAIN_UST:
+ expected = test_capture_base_fields[i].expected_ust;
+ break;
+ case LTTNG_DOMAIN_KERNEL:
+ expected = test_capture_base_fields[i].expected_kernel;
+ break;
+ default:
+ fail("Unexpected domain encountered: domain = %d",
+ (int) domain);
+ ret = 1;
+ goto end;
+ }
+
+ if (domain == LTTNG_DOMAIN_UST) {
+ validate = test_capture_base_fields[i].validate_ust;
+ } else {
+ validate = test_capture_base_fields[i].validate_kernel;
+ }
+
+ if (!expected) {
+ ok(event_field_value_status == LTTNG_EVENT_FIELD_VALUE_STATUS_UNAVAILABLE,
+ "No payload captured");
+ continue;
+ }
+
+ if (event_field_value_status != LTTNG_EVENT_FIELD_VALUE_STATUS_OK) {
+ if (event_field_value_status ==
+ LTTNG_EVENT_FIELD_VALUE_STATUS_UNAVAILABLE) {
+ fail("Expected a capture but it is unavailable");
+ } else {
+ fail("lttng_event_field_value_array_get_element_at_index returned an error: status = %d",
+ (int) event_field_value_status);
+ }
+
+ ret = 1;
+ goto end;
+ }
+
+ diag("Captured field of type %s",
+ field_value_type_to_str(
+ lttng_event_field_value_get_type(captured_field)));
+
+ LTTNG_ASSERT(validate);
+ ret = validate(captured_field, iteration);
+ if (ret) {
+ at_least_one_error = true;
+ }
+ }
+
+ ret = at_least_one_error;
+
+end:
+ return ret;
+}
+
+static void test_tracepoint_event_rule_notification_capture(
+ enum lttng_domain_type domain_type)
+{
+ enum lttng_notification_channel_status nc_status;
+
+ int i, ret;
+ struct lttng_condition *condition = NULL;
+ struct lttng_notification_channel *notification_channel = NULL;
+ struct lttng_trigger *trigger = NULL;
+ const char *trigger_name = "my_precious";
+ const char *pattern;
+
+ if (domain_type == LTTNG_DOMAIN_UST) {
+ pattern = "tp:tptest";
+ } else {
+ pattern = "lttng_test_filter_event";
+ }
+
+ create_tracepoint_event_rule_trigger(pattern, trigger_name, NULL, 0,
+ NULL, domain_type, generate_capture_descr, &condition,
+ &trigger);
+
+ notification_channel = lttng_notification_channel_create(
+ lttng_session_daemon_notification_endpoint);
+ ok(notification_channel, "Notification channel object creation");
+
+ nc_status = lttng_notification_channel_subscribe(
+ notification_channel, condition);
+ ok(nc_status == LTTNG_NOTIFICATION_CHANNEL_STATUS_OK,
+ "Subscribe to tracepoint event rule condition");
+
+ resume_application();
+
+ /* Get 3 notifications */
+ for (i = 0; i < 3; i++) {
+ struct lttng_notification *notification = get_next_notification(
+ notification_channel);
+ ok(notification, "Received notification");
+
+ /* Error */
+ if (notification == NULL) {
+ goto end;
+ }
+
+ ret = validator_notification_trigger_name(notification, trigger_name);
+ if (ret) {
+ lttng_notification_destroy(notification);
+ goto end;
+ }
+
+ ret = validator_notification_trigger_capture(domain_type, notification, i);
+ if (ret) {
+ lttng_notification_destroy(notification);
+ goto end;
+ }
+
+ lttng_notification_destroy(notification);
+ }
+
+end:
+ suspend_application();
+ lttng_notification_channel_destroy(notification_channel);
+ lttng_unregister_trigger(trigger);
+ lttng_trigger_destroy(trigger);
+ lttng_condition_destroy(condition);
+ return;
+}
+
+int main(int argc, const char *argv[])
+{
+ int test_scenario;
+ const char *domain_type_string = NULL;
+ enum lttng_domain_type domain_type = LTTNG_DOMAIN_NONE;
+
+ if (argc < 5) {
+ fail("Missing test scenario, domain type, pid, or application state file argument(s)");
+ goto error;
+ }
+
+ test_scenario = atoi(argv[1]);
+ domain_type_string = argv[2];
+ app_pid = (pid_t) atoi(argv[3]);
+ app_state_file = argv[4];
+
+ if (!strcmp("LTTNG_DOMAIN_UST", domain_type_string)) {
+ domain_type = LTTNG_DOMAIN_UST;
+ }
+ if (!strcmp("LTTNG_DOMAIN_KERNEL", domain_type_string)) {
+ domain_type = LTTNG_DOMAIN_KERNEL;
+ }
+ if (domain_type == LTTNG_DOMAIN_NONE) {
+ fail("Unknown domain type");
+ goto error;
+ }
+
+ /*
+ * Test cases are responsible for resuming the app when needed
+ * and making sure it's suspended when returning.
+ */
+ suspend_application();
+
+ switch (test_scenario) {
+ case 1:
+ {
+ plan_tests(41);
+
+ /* Test cases that need gen-ust-event testapp. */
+ diag("Test basic notification error paths for %s domain",
+ domain_type_string);
+ test_invalid_channel_subscription(domain_type);
+
+ diag("Test tracepoint event rule notifications for domain %s",
+ domain_type_string);
+ test_tracepoint_event_rule_notification(domain_type);
+
+ diag("Test tracepoint event rule notifications with filter for domain %s",
+ domain_type_string);
+ test_tracepoint_event_rule_notification_filter(domain_type);
+ break;
+ }
+ case 2:
+ {
+ const char *session_name, *channel_name;
+
+ /* Test cases that need a tracing session enabled. */
+ plan_tests(99);
+
+ /*
+ * Argument 7 and upward are named pipe location for consumerd
+ * control.
+ */
+ named_pipe_args_start = 7;
+
+ if (argc < 8) {
+ fail("Missing parameter for tests to run %d", argc);
+ goto error;
+ }
+
+ nb_args = argc;
+
+ session_name = argv[5];
+ channel_name = argv[6];
+
+ test_subscription_twice(session_name, channel_name,
+ domain_type);
+
+ diag("Test trigger for domain %s with buffer_usage_low condition",
+ domain_type_string);
+ test_triggers_buffer_usage_condition(session_name, channel_name,
+ domain_type,
+ LTTNG_CONDITION_TYPE_BUFFER_USAGE_LOW);
+
+ diag("Test trigger for domain %s with buffer_usage_high condition",
+ domain_type_string);
+ test_triggers_buffer_usage_condition(session_name, channel_name,
+ domain_type,
+ LTTNG_CONDITION_TYPE_BUFFER_USAGE_HIGH);
+
+ diag("Test buffer usage notification channel api for domain %s",
+ domain_type_string);
+ test_buffer_usage_notification_channel(session_name, channel_name,
+ domain_type, argv);
+ break;
+ }
+ case 3:
+ {
+ /*
+ * Test cases that need a test app with more than one event
+ * type.
+ */
+ plan_tests(23);
+
+ /*
+ * At the moment, the only test case of this scenario is
+ * exclusion which is only supported by UST.
+ */
+ LTTNG_ASSERT(domain_type == LTTNG_DOMAIN_UST);
+ diag("Test tracepoint event rule notifications with exclusion for domain %s",
+ domain_type_string);
+ test_tracepoint_event_rule_notification_exclusion(domain_type);
+
+ break;
+ }
+ case 4:
+ {
+ plan_tests(11);
+ /* Test cases that need the kernel tracer. */
+ LTTNG_ASSERT(domain_type == LTTNG_DOMAIN_KERNEL);
+
+ diag("Test kprobe event rule notifications for domain %s",
+ domain_type_string);
+
+ test_kprobe_event_rule_notification(domain_type);
+
+ break;
+ }
+ case 5:
+ {
+ plan_tests(23);
+ /* Test cases that need the kernel tracer. */
+ LTTNG_ASSERT(domain_type == LTTNG_DOMAIN_KERNEL);
+
+ diag("Test syscall event rule notifications for domain %s",
+ domain_type_string);
+
+ test_syscall_event_rule_notification(domain_type);
+
+ diag("Test syscall filtering event rule notifications for domain %s",
+ domain_type_string);
+
+ test_syscall_event_rule_notification_filter(domain_type);
+
+ break;
+ }
+ case 6:
+ {
+ const char *testapp_path, *test_symbol_name;
+
+ plan_tests(11);
+
+ if (argc < 7) {
+ fail("Missing parameter for tests to run %d", argc);
+ goto error;
+ }
+
+ testapp_path = argv[5];
+ test_symbol_name = argv[6];
+ /* Test cases that need the kernel tracer. */
+ LTTNG_ASSERT(domain_type == LTTNG_DOMAIN_KERNEL);
+
+ diag("Test userspace-probe event rule notifications for domain %s",
+ domain_type_string);
+
+ test_uprobe_event_rule_notification(
+ domain_type, testapp_path, test_symbol_name);
+
+ break;
+ }
+ case 7:
+ {
+ switch(domain_type) {
+ case LTTNG_DOMAIN_UST:
+ plan_tests(221);
+ break;
+ case LTTNG_DOMAIN_KERNEL:
+ plan_tests(215);
+ break;
+ default:
+ abort();
+ }
+
+ diag("Test tracepoint event rule notification captures for domain %s",
+ domain_type_string);
+ test_tracepoint_event_rule_notification_capture(domain_type);
+
+ break;
+ }
+
+ default:
+ abort();
+ }
+
+error:
+ return exit_status();
+}
+
LIBLTTNG_CTL=$(top_builddir)/src/lib/lttng-ctl/liblttng-ctl.la
noinst_PROGRAMS = hidden_trigger
-hidden_trigger_CFLAGS = $(AM_CFLAGS)
-hidden_trigger_SOURCES = hidden_trigger.c
+hidden_trigger_SOURCES = hidden_trigger.cpp
hidden_trigger_LDADD = $(LIBTAP) $(LIBLTTNG_CTL)
noinst_SCRIPTS = test_hidden_trigger
+++ /dev/null
-/*
- * trigger_name.c
- *
- * Test that hidden triggers are not visible to liblttng-ctl.
- *
- * Copyright (C) 2021 Jérémie Galarneau <jeremie.galarneau@efficios.com>
- *
- * SPDX-License-Identifier: MIT
- *
- */
-
-#include <stdint.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-
-#include <tap/tap.h>
-
-#include <common/macros.h>
-#include <lttng/lttng.h>
-
-#define TEST_COUNT 1
-
-#define TEST_SESSION_NAME "test_session"
-#define TEST_CHANNEL_NAME "test_channel"
-
-static
-int get_registered_triggers_count(void)
-{
- int ret;
- enum lttng_error_code ret_code;
- enum lttng_trigger_status trigger_status;
- struct lttng_triggers *triggers = NULL;
- unsigned int trigger_count;
-
- ret_code = lttng_list_triggers(&triggers);
- if (ret_code != LTTNG_OK) {
- fail("Failed to list triggers");
- ret = -1;
- goto end;
- }
-
- trigger_status = lttng_triggers_get_count(triggers, &trigger_count);
- if (trigger_status != LTTNG_TRIGGER_STATUS_OK) {
- fail("Failed to get count of triggers returned by listing");
- ret = -1;
- goto end;
- }
-
- ret = (int) trigger_count;
-
-end:
- lttng_triggers_destroy(triggers);
- return ret;
-}
-
-static
-int setup_session_with_size_rotation_schedule(const char *session_output_path)
-{
- int ret;
- struct lttng_session_descriptor *session_desriptor = NULL;
- enum lttng_error_code ret_code;
- struct lttng_handle ust_channel_handle = {
- .session_name = TEST_SESSION_NAME,
- .domain.type = LTTNG_DOMAIN_UST,
- .domain.buf_type = LTTNG_BUFFER_PER_UID,
- };
- struct lttng_channel channel_cfg = {
- .name = TEST_CHANNEL_NAME,
- .enabled = 1,
- .attr.overwrite = -1,
- .attr.subbuf_size = sysconf(_SC_PAGE_SIZE) * 8,
- .attr.num_subbuf = 8,
- .attr.output = LTTNG_EVENT_MMAP,
- };
- enum lttng_rotation_status rotation_status;
- struct lttng_rotation_schedule *rotation_schedule = NULL;
-
- session_desriptor = lttng_session_descriptor_local_create(
- TEST_SESSION_NAME, session_output_path);
- if (!session_desriptor) {
- fail("Failed to create session descriptor for session `%s`",
- TEST_SESSION_NAME);
- ret = -1;
- goto end;
- }
-
- ret_code = lttng_create_session_ext(session_desriptor);
- if (ret_code != LTTNG_OK) {
- fail("Failed to create session `%s`: %s", TEST_SESSION_NAME,
- lttng_strerror(-ret_code));
- ret = -1;
- goto end;
- }
-
- ret = lttng_enable_channel(&ust_channel_handle, &channel_cfg);
- if (ret) {
- fail("Failed to enable channel `%s`: %s", TEST_CHANNEL_NAME,
- lttng_strerror(ret));
- ret = -1;
- goto end;
- }
-
- ret = lttng_start_tracing(TEST_SESSION_NAME);
- if (ret) {
- fail("Failed to start session `%s`: %s", TEST_SESSION_NAME,
- lttng_strerror(ret));
- ret = -1;
- goto end;
- }
-
- rotation_schedule = lttng_rotation_schedule_size_threshold_create();
- if (!rotation_schedule) {
- fail("Failed to create rotation schedule descriptor");
- ret = -1;
- goto end;
- }
-
- /*
- * The rotation schedule size threshold doesn't matter; no event rules
- * were specified so the session consumed size should not grow over
- * time.
- */
- rotation_status = lttng_rotation_schedule_size_threshold_set_threshold(
- rotation_schedule, sysconf(_SC_PAGE_SIZE) * 4096);
- if (rotation_status != LTTNG_ROTATION_STATUS_OK) {
- fail("Failed to set size threshold of session rotation schedule");
- ret = -1;
- goto end;
- }
-
- rotation_status = lttng_session_add_rotation_schedule(
- TEST_SESSION_NAME, rotation_schedule);
- if (rotation_status != LTTNG_ROTATION_STATUS_OK) {
- fail("Failed to set size-based rotation schedule on session `%s`",
- TEST_SESSION_NAME);
- ret = -1;
- goto end;
- }
-
- ret = 0;
-end:
- lttng_session_descriptor_destroy(session_desriptor);
- lttng_rotation_schedule_destroy(rotation_schedule);
- return ret;
-}
-
-int main(int argc, const char **argv)
-{
- int ret;
-
- if (argc != 2) {
- fail("Missing trace path");
- goto end;
- }
-
- plan_tests(TEST_COUNT);
-
- if (get_registered_triggers_count() != 0) {
- fail("Session daemon already has registered triggers, bailing out");
- goto end;
- }
-
- ret = setup_session_with_size_rotation_schedule(argv[1]);
- if (ret) {
- goto end;
- }
-
- ok(get_registered_triggers_count() == 0,
- "No triggers visible while session has an enabled size-based rotation schedule");
-
- ret = lttng_destroy_session(TEST_SESSION_NAME);
- if (ret) {
- fail("Failed to destroy session `%s`", TEST_SESSION_NAME);
- goto end;
- }
-end:
- return exit_status();
-}
--- /dev/null
+/*
+ * trigger_name.c
+ *
+ * Test that hidden triggers are not visible to liblttng-ctl.
+ *
+ * Copyright (C) 2021 Jérémie Galarneau <jeremie.galarneau@efficios.com>
+ *
+ * SPDX-License-Identifier: MIT
+ *
+ */
+
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <tap/tap.h>
+
+#include <common/macros.h>
+#include <lttng/lttng.h>
+
+#define TEST_COUNT 1
+
+#define TEST_SESSION_NAME "test_session"
+#define TEST_CHANNEL_NAME "test_channel"
+
+static
+int get_registered_triggers_count(void)
+{
+ int ret;
+ enum lttng_error_code ret_code;
+ enum lttng_trigger_status trigger_status;
+ struct lttng_triggers *triggers = NULL;
+ unsigned int trigger_count;
+
+ ret_code = lttng_list_triggers(&triggers);
+ if (ret_code != LTTNG_OK) {
+ fail("Failed to list triggers");
+ ret = -1;
+ goto end;
+ }
+
+ trigger_status = lttng_triggers_get_count(triggers, &trigger_count);
+ if (trigger_status != LTTNG_TRIGGER_STATUS_OK) {
+ fail("Failed to get count of triggers returned by listing");
+ ret = -1;
+ goto end;
+ }
+
+ ret = (int) trigger_count;
+
+end:
+ lttng_triggers_destroy(triggers);
+ return ret;
+}
+
+static
+int setup_session_with_size_rotation_schedule(const char *session_output_path)
+{
+ int ret;
+ struct lttng_session_descriptor *session_desriptor = NULL;
+ enum lttng_error_code ret_code;
+ struct lttng_handle ust_channel_handle = {
+ TEST_SESSION_NAME,
+ {
+ .type = LTTNG_DOMAIN_UST,
+ .buf_type = LTTNG_BUFFER_PER_UID,
+ }
+ };
+
+ lttng_channel channel_cfg {};
+ strcpy(channel_cfg.name, TEST_CHANNEL_NAME);
+ channel_cfg.enabled = 1;
+ channel_cfg.attr.overwrite = -1;
+ channel_cfg.attr.subbuf_size = (uint64_t) sysconf(_SC_PAGE_SIZE) * 8;
+ channel_cfg.attr.num_subbuf = 8;
+ channel_cfg.attr.output = LTTNG_EVENT_MMAP;
+
+ enum lttng_rotation_status rotation_status;
+ struct lttng_rotation_schedule *rotation_schedule = NULL;
+
+ session_desriptor = lttng_session_descriptor_local_create(
+ TEST_SESSION_NAME, session_output_path);
+ if (!session_desriptor) {
+ fail("Failed to create session descriptor for session `%s`",
+ TEST_SESSION_NAME);
+ ret = -1;
+ goto end;
+ }
+
+ ret_code = lttng_create_session_ext(session_desriptor);
+ if (ret_code != LTTNG_OK) {
+ fail("Failed to create session `%s`: %s", TEST_SESSION_NAME,
+ lttng_strerror(-ret_code));
+ ret = -1;
+ goto end;
+ }
+
+ ret = lttng_enable_channel(&ust_channel_handle, &channel_cfg);
+ if (ret) {
+ fail("Failed to enable channel `%s`: %s", TEST_CHANNEL_NAME,
+ lttng_strerror(ret));
+ ret = -1;
+ goto end;
+ }
+
+ ret = lttng_start_tracing(TEST_SESSION_NAME);
+ if (ret) {
+ fail("Failed to start session `%s`: %s", TEST_SESSION_NAME,
+ lttng_strerror(ret));
+ ret = -1;
+ goto end;
+ }
+
+ rotation_schedule = lttng_rotation_schedule_size_threshold_create();
+ if (!rotation_schedule) {
+ fail("Failed to create rotation schedule descriptor");
+ ret = -1;
+ goto end;
+ }
+
+ /*
+ * The rotation schedule size threshold doesn't matter; no event rules
+ * were specified so the session consumed size should not grow over
+ * time.
+ */
+ rotation_status = lttng_rotation_schedule_size_threshold_set_threshold(
+ rotation_schedule, sysconf(_SC_PAGE_SIZE) * 4096);
+ if (rotation_status != LTTNG_ROTATION_STATUS_OK) {
+ fail("Failed to set size threshold of session rotation schedule");
+ ret = -1;
+ goto end;
+ }
+
+ rotation_status = lttng_session_add_rotation_schedule(
+ TEST_SESSION_NAME, rotation_schedule);
+ if (rotation_status != LTTNG_ROTATION_STATUS_OK) {
+ fail("Failed to set size-based rotation schedule on session `%s`",
+ TEST_SESSION_NAME);
+ ret = -1;
+ goto end;
+ }
+
+ ret = 0;
+end:
+ lttng_session_descriptor_destroy(session_desriptor);
+ lttng_rotation_schedule_destroy(rotation_schedule);
+ return ret;
+}
+
+int main(int argc, const char **argv)
+{
+ int ret;
+
+ if (argc != 2) {
+ fail("Missing trace path");
+ goto end;
+ }
+
+ plan_tests(TEST_COUNT);
+
+ if (get_registered_triggers_count() != 0) {
+ fail("Session daemon already has registered triggers, bailing out");
+ goto end;
+ }
+
+ ret = setup_session_with_size_rotation_schedule(argv[1]);
+ if (ret) {
+ goto end;
+ }
+
+ ok(get_registered_triggers_count() == 0,
+ "No triggers visible while session has an enabled size-based rotation schedule");
+
+ ret = lttng_destroy_session(TEST_SESSION_NAME);
+ if (ret) {
+ fail("Failed to destroy session `%s`", TEST_SESSION_NAME);
+ goto end;
+ }
+end:
+ return exit_status();
+}
noinst_PROGRAMS = trigger_name
# This test explicitly tests APIs that were marked as deprecated.
-trigger_name_CFLAGS = -Wno-deprecated-declarations $(AM_CFLAGS)
-trigger_name_SOURCES = trigger_name.c
+trigger_name_CXXFLAGS = -Wno-deprecated-declarations $(AM_CXXFLAGS)
+trigger_name_SOURCES = trigger_name.cpp
trigger_name_LDADD = $(LIBTAP) $(LIBLTTNG_CTL)
noinst_SCRIPTS = test_trigger_name_backwards_compat
+++ /dev/null
-/*
- * trigger_name.c
- *
- * Tests suite for anonymous, named, and automatic name triggers.
- *
- * Copyright (C) 2021 Jérémie Galarneau <jeremie.galarneau@efficios.com>
- *
- * SPDX-License-Identifier: MIT
- *
- */
-
-#include <stdio.h>
-#include <unistd.h>
-#include <tap/tap.h>
-#include <stdint.h>
-#include <string.h>
-#include <lttng/lttng.h>
-#include <common/macros.h>
-
-#define TEST_COUNT 70
-
-enum unregistration_trigger_instance {
- UNREGISTRATION_TRIGGER_INSTANCE_USED_FOR_REGISTRATION,
- UNREGISTRATION_TRIGGER_INSTANCE_FROM_LISTING,
-};
-
-typedef void (*test_function)(enum unregistration_trigger_instance);
-
-static
-const char *get_trigger_name(const struct lttng_trigger *trigger)
-{
- const char *trigger_name;
- enum lttng_trigger_status trigger_status;
-
- trigger_status = lttng_trigger_get_name(trigger, &trigger_name);
- switch (trigger_status) {
- case LTTNG_TRIGGER_STATUS_OK:
- break;
- case LTTNG_TRIGGER_STATUS_UNSET:
- trigger_name = "(anonymous)";
- break;
- default:
- trigger_name = "(failed to get name)";
- break;
- }
-
- return trigger_name;
-}
-
-static
-const char *unregistration_trigger_instance_name(
- enum unregistration_trigger_instance unregistration_trigger)
-{
- const char *name;
-
- switch (unregistration_trigger) {
- case UNREGISTRATION_TRIGGER_INSTANCE_FROM_LISTING:
- name = "from listing";
- break;
- case UNREGISTRATION_TRIGGER_INSTANCE_USED_FOR_REGISTRATION:
- name = "used for registration";
- break;
- default:
- abort();
- }
-
- return name;
-}
-
-/*
- * Returns a negative error code on error, else the number of unregistered
- * triggers.
- */
-static
-int unregister_all_triggers(void)
-{
- int ret;
- enum lttng_error_code ret_code;
- enum lttng_trigger_status trigger_status;
- struct lttng_triggers *triggers = NULL;
- unsigned int trigger_count, i, unregistered_trigger_count = 0;
-
- ret_code = lttng_list_triggers(&triggers);
- if (ret_code != LTTNG_OK) {
- fail("Failed to list triggers");
- ret = -1;
- goto end;
- }
-
- trigger_status = lttng_triggers_get_count(triggers, &trigger_count);
- if (trigger_status != LTTNG_TRIGGER_STATUS_OK) {
- fail("Failed to get count of triggers returned by listing");
- ret = -1;
- goto end;
- }
-
- for (i = 0; i < trigger_count; i++) {
- const struct lttng_trigger *trigger;
-
- trigger = lttng_triggers_get_at_index(triggers, i);
- LTTNG_ASSERT(trigger);
-
- ret = lttng_unregister_trigger(trigger);
- if (ret) {
- fail("Failed to unregister trigger: trigger name = '%s'");
- goto end;
- }
-
- unregistered_trigger_count++;
- }
-
- ret = (int) unregistered_trigger_count;
-
-end:
- lttng_triggers_destroy(triggers);
- return ret;
-}
-
-static
-int get_registered_triggers_count(void)
-{
- int ret;
- enum lttng_error_code ret_code;
- enum lttng_trigger_status trigger_status;
- struct lttng_triggers *triggers = NULL;
- unsigned int trigger_count;
-
- ret_code = lttng_list_triggers(&triggers);
- if (ret_code != LTTNG_OK) {
- fail("Failed to list triggers");
- ret = -1;
- goto end;
- }
-
- trigger_status = lttng_triggers_get_count(triggers, &trigger_count);
- if (trigger_status != LTTNG_TRIGGER_STATUS_OK) {
- fail("Failed to get count of triggers returned by listing");
- ret = -1;
- goto end;
- }
-
- ret = (int) trigger_count;
-
-end:
- lttng_triggers_destroy(triggers);
- return ret;
-}
-
-/*
- * Create a generic trigger. The specifics of the condition and action are not
- * important for the purposes of this test.
- */
-static
-struct lttng_trigger *create_trigger(uint64_t threshold)
-{
- struct lttng_condition *condition = NULL;
- struct lttng_action *action = NULL;
- struct lttng_trigger *trigger = NULL;
- enum lttng_condition_status condition_status;
- const char * const session_name = "test session";
-
- condition = lttng_condition_session_consumed_size_create();
- if (!condition) {
- fail("Failed to create 'session consumed size' condition");
- goto end;
- }
-
- condition_status = lttng_condition_session_consumed_size_set_session_name(condition, session_name);
- if (condition_status != LTTNG_CONDITION_STATUS_OK) {
- fail("Failed to set session name on 'session consumed size' condition");
- goto end;
- }
-
- condition_status = lttng_condition_session_consumed_size_set_threshold(
- condition, threshold);
- if (condition_status != LTTNG_CONDITION_STATUS_OK) {
- fail("Failed to set threshold on 'session consumed size' condition");
- goto end;
- }
-
- action = lttng_action_notify_create();
- if (!action) {
- fail("Failed to create 'notify' action");
- goto end;
- }
-
- trigger = lttng_trigger_create(condition, action);
- if (!trigger) {
- fail("Failed to create trigger");
- goto end;
- }
-
-end:
- lttng_condition_destroy(condition);
- lttng_action_destroy(action);
- return trigger;
-}
-
-static
-void register_anonymous_trigger(
- enum unregistration_trigger_instance unregistration_trigger)
-{
- int ret;
- struct lttng_trigger *trigger = create_trigger(0xbadc0ffee);
- enum lttng_trigger_status trigger_status;
- const char *trigger_name;
- struct lttng_triggers *triggers = NULL;
- unsigned int trigger_count, i;
- enum lttng_error_code ret_code;
-
- diag("Register an anonymous trigger (Unregistration performed with the trigger instance %s)",
- unregistration_trigger_instance_name(
- unregistration_trigger));
-
- if (!trigger) {
- fail("Failed to create trigger");
- goto end;
- }
-
- ret = lttng_register_trigger(trigger);
- ok(ret == 0, "Registered anonymous trigger");
-
- trigger_status = lttng_trigger_get_name(trigger, &trigger_name);
- ok(trigger_status == LTTNG_TRIGGER_STATUS_UNSET,
- "Anonymous trigger name remains unset after registration: trigger name = '%s'",
- get_trigger_name(trigger));
-
- ret_code = lttng_list_triggers(&triggers);
- if (ret_code != LTTNG_OK) {
- fail("Failed to list triggers");
- ret = -1;
- goto end;
- }
-
- trigger_status = lttng_triggers_get_count(triggers, &trigger_count);
- if (trigger_status != LTTNG_TRIGGER_STATUS_OK) {
- fail("Failed to get count of triggers returned by listing");
- ret = -1;
- goto end;
- }
-
- ok(trigger_count == 1, "Trigger listing returns 1 trigger");
-
- for (i = 0; i < trigger_count; i++) {
- const struct lttng_trigger *trigger_from_listing;
-
- trigger_from_listing = lttng_triggers_get_at_index(triggers, i);
- LTTNG_ASSERT(trigger_from_listing);
-
- trigger_status = lttng_trigger_get_name(trigger_from_listing, &trigger_name);
- ok(trigger_status == LTTNG_TRIGGER_STATUS_UNSET,
- "Anonymous trigger returned by listing has an unset name: trigger name = '%s'",
- get_trigger_name(trigger_from_listing));
-
- if (unregistration_trigger == UNREGISTRATION_TRIGGER_INSTANCE_FROM_LISTING) {
- ret = lttng_unregister_trigger(trigger_from_listing);
- ok(ret == 0, "Successfully unregistered anonymous trigger using the trigger instance returned by the listing");
- }
- }
-
- if (unregistration_trigger == UNREGISTRATION_TRIGGER_INSTANCE_USED_FOR_REGISTRATION) {
- ret = lttng_unregister_trigger(trigger);
- ok(ret == 0, "Successfully unregistered anonymous trigger using the trigger instance used on registration");
- }
-
-end:
- lttng_triggers_destroy(triggers);
- lttng_trigger_destroy(trigger);
-}
-
-static
-void register_named_trigger(
- enum unregistration_trigger_instance unregistration_trigger)
-{
- int ret;
- struct lttng_trigger *trigger = create_trigger(0xbadc0ffee);
- enum lttng_trigger_status trigger_status;
- const char *returned_trigger_name;
- struct lttng_triggers *triggers = NULL;
- unsigned int trigger_count, i;
- enum lttng_error_code ret_code;
- const char * const trigger_name = "some name that is hopefully unique";
-
- diag("Register a named trigger (Unregistration performed with the trigger instance %s)",
- unregistration_trigger_instance_name(
- unregistration_trigger));
-
- if (!trigger) {
- fail("Failed to create trigger");
- goto end;
- }
-
- ret_code = lttng_register_trigger_with_name(trigger, trigger_name);
- ok(ret_code == LTTNG_OK, "Registered trigger with name: trigger name = '%s'",
- get_trigger_name(trigger));
-
- trigger_status = lttng_trigger_get_name(trigger, &returned_trigger_name);
- ok(trigger_status == LTTNG_TRIGGER_STATUS_OK,
- "Trigger name is set after registration: trigger name = '%s'",
- get_trigger_name(trigger));
-
- ok(!strcmp(get_trigger_name(trigger), trigger_name),
- "Name set on trigger after registration is correct");
-
- ret_code = lttng_list_triggers(&triggers);
- if (ret_code != LTTNG_OK) {
- fail("Failed to list triggers");
- ret = -1;
- goto end;
- }
-
- trigger_status = lttng_triggers_get_count(triggers, &trigger_count);
- if (trigger_status != LTTNG_TRIGGER_STATUS_OK) {
- fail("Failed to get count of triggers returned by listing");
- ret = -1;
- goto end;
- }
-
- ok(trigger_count == 1, "Trigger listing returns 1 trigger");
-
- for (i = 0; i < trigger_count; i++) {
- const struct lttng_trigger *trigger_from_listing;
-
- trigger_from_listing = lttng_triggers_get_at_index(triggers, i);
- LTTNG_ASSERT(trigger_from_listing);
-
- trigger_status = lttng_trigger_get_name(trigger_from_listing, &returned_trigger_name);
- ok(trigger_status == LTTNG_TRIGGER_STATUS_OK,
- "Trigger returned by listing has a name: trigger name = '%s'",
- get_trigger_name(trigger_from_listing));
-
- ok(!strcmp(get_trigger_name(trigger_from_listing),
- trigger_name),
- "Name set on trigger returned from listing is correct: name returned from listing = '%s', expected name = '%s'",
- get_trigger_name(trigger_from_listing),
- trigger_name);
-
- if (unregistration_trigger == UNREGISTRATION_TRIGGER_INSTANCE_FROM_LISTING) {
- ret = lttng_unregister_trigger(trigger_from_listing);
- ok(ret == 0, "Successfully unregistered named trigger using the trigger instance returned by the listing");
- }
- }
-
- if (unregistration_trigger == UNREGISTRATION_TRIGGER_INSTANCE_USED_FOR_REGISTRATION) {
- ret = lttng_unregister_trigger(trigger);
- ok(ret == 0, "Successfully unregistered named trigger using the trigger instance used on registration");
- }
-
-end:
- lttng_triggers_destroy(triggers);
- lttng_trigger_destroy(trigger);
-}
-
-static
-void register_automatic_name_trigger(
- enum unregistration_trigger_instance unregistration_trigger)
-{
- int ret;
- struct lttng_trigger *trigger = create_trigger(0xbadc0ffee);
- enum lttng_trigger_status trigger_status;
- const char *returned_trigger_name;
- struct lttng_triggers *triggers = NULL;
- unsigned int trigger_count, i;
- enum lttng_error_code ret_code;
-
- diag("Register an automatic name trigger (Unregistration performed with the trigger instance %s)",
- unregistration_trigger_instance_name(
- unregistration_trigger));
-
- if (!trigger) {
- fail("Failed to create trigger");
- goto end;
- }
-
- ret_code = lttng_register_trigger_with_automatic_name(trigger);
- ok(ret_code == LTTNG_OK, "Registered trigger with automatic name");
-
- trigger_status = lttng_trigger_get_name(trigger, &returned_trigger_name);
- ok(trigger_status == LTTNG_TRIGGER_STATUS_OK,
- "Trigger name is set after registration: trigger name = '%s'",
- get_trigger_name(trigger));
-
- ok(returned_trigger_name && strlen(returned_trigger_name) > 0,
- "Automatic name set on trigger after registration longer is not an empty string");
-
- ret_code = lttng_list_triggers(&triggers);
- if (ret_code != LTTNG_OK) {
- fail("Failed to list triggers");
- ret = -1;
- goto end;
- }
-
- trigger_status = lttng_triggers_get_count(triggers, &trigger_count);
- if (trigger_status != LTTNG_TRIGGER_STATUS_OK) {
- fail("Failed to get count of triggers returned by listing");
- ret = -1;
- goto end;
- }
-
- ok(trigger_count == 1, "Trigger listing returns 1 trigger");
-
- for (i = 0; i < trigger_count; i++) {
- const struct lttng_trigger *trigger_from_listing;
-
- trigger_from_listing = lttng_triggers_get_at_index(triggers, i);
- LTTNG_ASSERT(trigger_from_listing);
-
- trigger_status = lttng_trigger_get_name(trigger_from_listing, &returned_trigger_name);
- ok(trigger_status == LTTNG_TRIGGER_STATUS_OK,
- "Trigger returned by listing has a name: trigger name = '%s'",
- get_trigger_name(trigger_from_listing));
-
- if (unregistration_trigger == UNREGISTRATION_TRIGGER_INSTANCE_FROM_LISTING) {
- ret = lttng_unregister_trigger(trigger_from_listing);
- ok(ret == 0, "Successfully unregistered automatic name trigger using the trigger instance returned by the listing");
- }
- }
-
- if (unregistration_trigger == UNREGISTRATION_TRIGGER_INSTANCE_USED_FOR_REGISTRATION) {
- ret = lttng_unregister_trigger(trigger);
- ok(ret == 0, "Successfully unregistered automatic trigger using the trigger instance used on registration");
- }
-
-end:
- lttng_triggers_destroy(triggers);
- lttng_trigger_destroy(trigger);
-}
-
-static
-void double_register_anonymous_trigger(
- enum unregistration_trigger_instance unregistration_trigger)
-{
- int ret;
- struct lttng_trigger *trigger = create_trigger(0xbadc0ffee);
- struct lttng_triggers *triggers = NULL;
-
- diag("Register duplicate anonymous trigger (Unregistration performed with the trigger instance %s)",
- unregistration_trigger_instance_name(
- unregistration_trigger));
-
- if (!trigger) {
- fail("Failed to create trigger");
- goto end;
- }
-
- ret = lttng_register_trigger(trigger);
- ok(ret == 0, "Registered anonymous trigger");
-
- ret = lttng_register_trigger(trigger);
- ok(ret == -LTTNG_ERR_TRIGGER_EXISTS,
- "Registering identical anonymous trigger fails with `LTTNG_ERR_TRIGGER_EXISTS`");
-
-
- if (unregistration_trigger == UNREGISTRATION_TRIGGER_INSTANCE_USED_FOR_REGISTRATION) {
- ret = lttng_unregister_trigger(trigger);
- ok(ret == 0, "Successfully unregistered anonymous trigger using the trigger instance used on registration");
- } else {
- ok(get_registered_triggers_count() == 1,
- "Trigger listing returns 1 trigger");
- ok(unregister_all_triggers() == 1,
- "Successfully unregistered anonymous trigger using the trigger instance returned by the listing");
- }
-
-end:
- lttng_triggers_destroy(triggers);
- lttng_trigger_destroy(trigger);
-}
-
-static
-void double_register_named_trigger(
- enum unregistration_trigger_instance unregistration_trigger)
-{
- int ret;
- struct lttng_trigger *trigger_a = create_trigger(0xbadc0ffee);
- struct lttng_trigger *trigger_b = create_trigger(0xbadc0ffee);
- struct lttng_triggers *triggers = NULL;
- const char * const trigger_name = "a unique trigger name";
- enum lttng_error_code ret_code;
-
- diag("Register duplicate named trigger (Unregistration performed with the trigger instance %s)",
- unregistration_trigger_instance_name(
- unregistration_trigger));
-
- if (!trigger_a || !trigger_b) {
- fail("Failed to create triggers");
- goto end;
- }
-
- ret_code = lttng_register_trigger_with_name(trigger_a, trigger_name);
- ok(ret_code == LTTNG_OK, "Registered named trigger");
-
- ret = lttng_register_trigger(trigger_a);
- ok(ret == -LTTNG_ERR_INVALID,
- "Registering a trigger instance already used for registration fails with `LTTNG_ERR_INVALID` (anonymous registration)");
-
- ret_code = lttng_register_trigger_with_name(trigger_a, trigger_name);
- ok(ret_code == LTTNG_ERR_INVALID,
- "Registering a trigger instance already used for registration fails with `LTTNG_ERR_INVALID` (register with name)");
-
- ret_code = lttng_register_trigger_with_automatic_name(trigger_a);
- ok(ret_code == LTTNG_ERR_INVALID,
- "Registering a trigger instance already used for registration fails with `LTTNG_ERR_INVALID` (register with automatic name)");
-
- ret_code = lttng_register_trigger_with_name(trigger_b, trigger_name);
- ok(ret_code == LTTNG_ERR_TRIGGER_EXISTS, "Registering trigger with an already used name fails with `LTTNG_ERR_TRIGGER_EXISTS`");
-
- if (unregistration_trigger == UNREGISTRATION_TRIGGER_INSTANCE_USED_FOR_REGISTRATION) {
- ret = lttng_unregister_trigger(trigger_a);
- ok(ret == 0, "Successfully unregistered named trigger using the trigger instance used on registration");
- } else {
- ok(get_registered_triggers_count() == 1,
- "Trigger listing returns 1 trigger");
- ok(unregister_all_triggers() == 1,
- "Successfully unregistered named trigger using the trigger instance returned by the listing");
- }
-
-end:
- lttng_triggers_destroy(triggers);
- lttng_trigger_destroy(trigger_a);
- lttng_trigger_destroy(trigger_b);
-}
-
-static
-void double_register_automatic_name_trigger(
- enum unregistration_trigger_instance unregistration_trigger)
-{
- int ret;
- struct lttng_trigger *trigger_a = create_trigger(0xbadc0ffee);
- struct lttng_trigger *trigger_b = create_trigger(0xbadc0ffee);
- struct lttng_triggers *triggers = NULL;
- enum lttng_error_code ret_code;
-
- diag("Register duplicate automatic name trigger (Unregistration performed with the trigger instance %s)",
- unregistration_trigger_instance_name(
- unregistration_trigger));
-
- if (!trigger_a || !trigger_b) {
- fail("Failed to create triggers");
- goto end;
- }
-
- ret_code = lttng_register_trigger_with_automatic_name(trigger_a);
- ok(ret_code == LTTNG_OK, "Registered automatic name trigger: trigger name = '%s'", get_trigger_name(trigger_a));
-
- ret = lttng_register_trigger_with_automatic_name(trigger_b);
- ok(ret_code == LTTNG_OK, "Registering an identical trigger instance with an automatic name succeeds: trigger name = '%s'", get_trigger_name(trigger_b));
-
- ok(strcmp(get_trigger_name(trigger_a), get_trigger_name(trigger_b)),
- "Two identical triggers registered with an automatic name have different names");
-
- if (unregistration_trigger == UNREGISTRATION_TRIGGER_INSTANCE_USED_FOR_REGISTRATION) {
- ret = lttng_unregister_trigger(trigger_a);
- ok(ret == 0, "Successfully unregistered automatic trigger A using the trigger instance used on registration");
-
- ret = lttng_unregister_trigger(trigger_b);
- ok(ret == 0, "Successfully unregistered automatic trigger B using the trigger instance used on registration");
- } else {
- ok(get_registered_triggers_count() == 2,
- "Trigger listing returns 2 trigger");
- ok(unregister_all_triggers() == 2,
- "Successfully unregistered automatic name triggers using the trigger instance returned by the listing");
- }
-
-end:
- lttng_triggers_destroy(triggers);
- lttng_trigger_destroy(trigger_a);
- lttng_trigger_destroy(trigger_b);
-}
-
-static
-void register_multiple_anonymous_triggers(void)
-{
- int ret;
- struct lttng_trigger *trigger_a = create_trigger(0xbadc0ffee);
- struct lttng_trigger *trigger_b = create_trigger(0xbadf00d);
-
- diag("Register two different anonymous triggers");
-
- if (!trigger_a || !trigger_b) {
- fail("Failed to create triggers");
- goto end;
- }
-
- ret = lttng_register_trigger(trigger_a);
- ok(ret == 0, "Registered first anonymous trigger");
-
- ret = lttng_register_trigger(trigger_b);
- ok(ret == 0, "Registered second anonymous trigger");
-
- ok(get_registered_triggers_count() == 2,
- "Trigger listing returns 2 trigger");
- ok(unregister_all_triggers() == 2,
- "Successfully unregistered two anonymous triggers");
-
-end:
- lttng_trigger_destroy(trigger_a);
- lttng_trigger_destroy(trigger_b);
-}
-
-const test_function test_functions[] = {
- register_anonymous_trigger,
- register_named_trigger,
- register_automatic_name_trigger,
- double_register_anonymous_trigger,
- double_register_named_trigger,
- double_register_automatic_name_trigger,
-};
-
-int main(int argc, const char **argv)
-{
- size_t i;
-
- plan_tests(TEST_COUNT);
-
- if (get_registered_triggers_count() != 0) {
- fail("Session daemon already has registered triggers, bailing out");
- goto end;
- }
-
- for (i = 0; i < ARRAY_SIZE(test_functions); i++) {
- const test_function fn = test_functions[i];
-
- fn(UNREGISTRATION_TRIGGER_INSTANCE_FROM_LISTING);
- if (get_registered_triggers_count() != 0) {
- fail("Previous test left registered triggers, bailing out");
- goto end;
- }
- }
-
- for (i = 0; i < ARRAY_SIZE(test_functions); i++) {
- const test_function fn = test_functions[i];
-
- fn(UNREGISTRATION_TRIGGER_INSTANCE_USED_FOR_REGISTRATION);
- if (get_registered_triggers_count() != 0) {
- fail("Previous test left registered triggers, bailing out");
- goto end;
- }
- }
-
- register_multiple_anonymous_triggers();
-end:
- return exit_status();
-}
--- /dev/null
+/*
+ * trigger_name.c
+ *
+ * Tests suite for anonymous, named, and automatic name triggers.
+ *
+ * Copyright (C) 2021 Jérémie Galarneau <jeremie.galarneau@efficios.com>
+ *
+ * SPDX-License-Identifier: MIT
+ *
+ */
+
+#include <stdio.h>
+#include <unistd.h>
+#include <tap/tap.h>
+#include <stdint.h>
+#include <string.h>
+#include <lttng/lttng.h>
+#include <common/macros.h>
+
+#define TEST_COUNT 70
+
+enum unregistration_trigger_instance {
+ UNREGISTRATION_TRIGGER_INSTANCE_USED_FOR_REGISTRATION,
+ UNREGISTRATION_TRIGGER_INSTANCE_FROM_LISTING,
+};
+
+typedef void (*test_function)(enum unregistration_trigger_instance);
+
+static
+const char *get_trigger_name(const struct lttng_trigger *trigger)
+{
+ const char *trigger_name;
+ enum lttng_trigger_status trigger_status;
+
+ trigger_status = lttng_trigger_get_name(trigger, &trigger_name);
+ switch (trigger_status) {
+ case LTTNG_TRIGGER_STATUS_OK:
+ break;
+ case LTTNG_TRIGGER_STATUS_UNSET:
+ trigger_name = "(anonymous)";
+ break;
+ default:
+ trigger_name = "(failed to get name)";
+ break;
+ }
+
+ return trigger_name;
+}
+
+static
+const char *unregistration_trigger_instance_name(
+ enum unregistration_trigger_instance unregistration_trigger)
+{
+ const char *name;
+
+ switch (unregistration_trigger) {
+ case UNREGISTRATION_TRIGGER_INSTANCE_FROM_LISTING:
+ name = "from listing";
+ break;
+ case UNREGISTRATION_TRIGGER_INSTANCE_USED_FOR_REGISTRATION:
+ name = "used for registration";
+ break;
+ default:
+ abort();
+ }
+
+ return name;
+}
+
+/*
+ * Returns a negative error code on error, else the number of unregistered
+ * triggers.
+ */
+static
+int unregister_all_triggers(void)
+{
+ int ret;
+ enum lttng_error_code ret_code;
+ enum lttng_trigger_status trigger_status;
+ struct lttng_triggers *triggers = NULL;
+ unsigned int trigger_count, i, unregistered_trigger_count = 0;
+
+ ret_code = lttng_list_triggers(&triggers);
+ if (ret_code != LTTNG_OK) {
+ fail("Failed to list triggers");
+ ret = -1;
+ goto end;
+ }
+
+ trigger_status = lttng_triggers_get_count(triggers, &trigger_count);
+ if (trigger_status != LTTNG_TRIGGER_STATUS_OK) {
+ fail("Failed to get count of triggers returned by listing");
+ ret = -1;
+ goto end;
+ }
+
+ for (i = 0; i < trigger_count; i++) {
+ const struct lttng_trigger *trigger;
+
+ trigger = lttng_triggers_get_at_index(triggers, i);
+ LTTNG_ASSERT(trigger);
+
+ ret = lttng_unregister_trigger(trigger);
+ if (ret) {
+ fail("Failed to unregister trigger: trigger name = '%s'");
+ goto end;
+ }
+
+ unregistered_trigger_count++;
+ }
+
+ ret = (int) unregistered_trigger_count;
+
+end:
+ lttng_triggers_destroy(triggers);
+ return ret;
+}
+
+static
+int get_registered_triggers_count(void)
+{
+ int ret;
+ enum lttng_error_code ret_code;
+ enum lttng_trigger_status trigger_status;
+ struct lttng_triggers *triggers = NULL;
+ unsigned int trigger_count;
+
+ ret_code = lttng_list_triggers(&triggers);
+ if (ret_code != LTTNG_OK) {
+ fail("Failed to list triggers");
+ ret = -1;
+ goto end;
+ }
+
+ trigger_status = lttng_triggers_get_count(triggers, &trigger_count);
+ if (trigger_status != LTTNG_TRIGGER_STATUS_OK) {
+ fail("Failed to get count of triggers returned by listing");
+ ret = -1;
+ goto end;
+ }
+
+ ret = (int) trigger_count;
+
+end:
+ lttng_triggers_destroy(triggers);
+ return ret;
+}
+
+/*
+ * Create a generic trigger. The specifics of the condition and action are not
+ * important for the purposes of this test.
+ */
+static
+struct lttng_trigger *create_trigger(uint64_t threshold)
+{
+ struct lttng_condition *condition = NULL;
+ struct lttng_action *action = NULL;
+ struct lttng_trigger *trigger = NULL;
+ enum lttng_condition_status condition_status;
+ const char * const session_name = "test session";
+
+ condition = lttng_condition_session_consumed_size_create();
+ if (!condition) {
+ fail("Failed to create 'session consumed size' condition");
+ goto end;
+ }
+
+ condition_status = lttng_condition_session_consumed_size_set_session_name(condition, session_name);
+ if (condition_status != LTTNG_CONDITION_STATUS_OK) {
+ fail("Failed to set session name on 'session consumed size' condition");
+ goto end;
+ }
+
+ condition_status = lttng_condition_session_consumed_size_set_threshold(
+ condition, threshold);
+ if (condition_status != LTTNG_CONDITION_STATUS_OK) {
+ fail("Failed to set threshold on 'session consumed size' condition");
+ goto end;
+ }
+
+ action = lttng_action_notify_create();
+ if (!action) {
+ fail("Failed to create 'notify' action");
+ goto end;
+ }
+
+ trigger = lttng_trigger_create(condition, action);
+ if (!trigger) {
+ fail("Failed to create trigger");
+ goto end;
+ }
+
+end:
+ lttng_condition_destroy(condition);
+ lttng_action_destroy(action);
+ return trigger;
+}
+
+static
+void register_anonymous_trigger(
+ enum unregistration_trigger_instance unregistration_trigger)
+{
+ int ret;
+ struct lttng_trigger *trigger = create_trigger(0xbadc0ffee);
+ enum lttng_trigger_status trigger_status;
+ const char *trigger_name;
+ struct lttng_triggers *triggers = NULL;
+ unsigned int trigger_count, i;
+ enum lttng_error_code ret_code;
+
+ diag("Register an anonymous trigger (Unregistration performed with the trigger instance %s)",
+ unregistration_trigger_instance_name(
+ unregistration_trigger));
+
+ if (!trigger) {
+ fail("Failed to create trigger");
+ goto end;
+ }
+
+ ret = lttng_register_trigger(trigger);
+ ok(ret == 0, "Registered anonymous trigger");
+
+ trigger_status = lttng_trigger_get_name(trigger, &trigger_name);
+ ok(trigger_status == LTTNG_TRIGGER_STATUS_UNSET,
+ "Anonymous trigger name remains unset after registration: trigger name = '%s'",
+ get_trigger_name(trigger));
+
+ ret_code = lttng_list_triggers(&triggers);
+ if (ret_code != LTTNG_OK) {
+ fail("Failed to list triggers");
+ ret = -1;
+ goto end;
+ }
+
+ trigger_status = lttng_triggers_get_count(triggers, &trigger_count);
+ if (trigger_status != LTTNG_TRIGGER_STATUS_OK) {
+ fail("Failed to get count of triggers returned by listing");
+ ret = -1;
+ goto end;
+ }
+
+ ok(trigger_count == 1, "Trigger listing returns 1 trigger");
+
+ for (i = 0; i < trigger_count; i++) {
+ const struct lttng_trigger *trigger_from_listing;
+
+ trigger_from_listing = lttng_triggers_get_at_index(triggers, i);
+ LTTNG_ASSERT(trigger_from_listing);
+
+ trigger_status = lttng_trigger_get_name(trigger_from_listing, &trigger_name);
+ ok(trigger_status == LTTNG_TRIGGER_STATUS_UNSET,
+ "Anonymous trigger returned by listing has an unset name: trigger name = '%s'",
+ get_trigger_name(trigger_from_listing));
+
+ if (unregistration_trigger == UNREGISTRATION_TRIGGER_INSTANCE_FROM_LISTING) {
+ ret = lttng_unregister_trigger(trigger_from_listing);
+ ok(ret == 0, "Successfully unregistered anonymous trigger using the trigger instance returned by the listing");
+ }
+ }
+
+ if (unregistration_trigger == UNREGISTRATION_TRIGGER_INSTANCE_USED_FOR_REGISTRATION) {
+ ret = lttng_unregister_trigger(trigger);
+ ok(ret == 0, "Successfully unregistered anonymous trigger using the trigger instance used on registration");
+ }
+
+end:
+ lttng_triggers_destroy(triggers);
+ lttng_trigger_destroy(trigger);
+}
+
+static
+void register_named_trigger(
+ enum unregistration_trigger_instance unregistration_trigger)
+{
+ int ret;
+ struct lttng_trigger *trigger = create_trigger(0xbadc0ffee);
+ enum lttng_trigger_status trigger_status;
+ const char *returned_trigger_name;
+ struct lttng_triggers *triggers = NULL;
+ unsigned int trigger_count, i;
+ enum lttng_error_code ret_code;
+ const char * const trigger_name = "some name that is hopefully unique";
+
+ diag("Register a named trigger (Unregistration performed with the trigger instance %s)",
+ unregistration_trigger_instance_name(
+ unregistration_trigger));
+
+ if (!trigger) {
+ fail("Failed to create trigger");
+ goto end;
+ }
+
+ ret_code = lttng_register_trigger_with_name(trigger, trigger_name);
+ ok(ret_code == LTTNG_OK, "Registered trigger with name: trigger name = '%s'",
+ get_trigger_name(trigger));
+
+ trigger_status = lttng_trigger_get_name(trigger, &returned_trigger_name);
+ ok(trigger_status == LTTNG_TRIGGER_STATUS_OK,
+ "Trigger name is set after registration: trigger name = '%s'",
+ get_trigger_name(trigger));
+
+ ok(!strcmp(get_trigger_name(trigger), trigger_name),
+ "Name set on trigger after registration is correct");
+
+ ret_code = lttng_list_triggers(&triggers);
+ if (ret_code != LTTNG_OK) {
+ fail("Failed to list triggers");
+ ret = -1;
+ goto end;
+ }
+
+ trigger_status = lttng_triggers_get_count(triggers, &trigger_count);
+ if (trigger_status != LTTNG_TRIGGER_STATUS_OK) {
+ fail("Failed to get count of triggers returned by listing");
+ ret = -1;
+ goto end;
+ }
+
+ ok(trigger_count == 1, "Trigger listing returns 1 trigger");
+
+ for (i = 0; i < trigger_count; i++) {
+ const struct lttng_trigger *trigger_from_listing;
+
+ trigger_from_listing = lttng_triggers_get_at_index(triggers, i);
+ LTTNG_ASSERT(trigger_from_listing);
+
+ trigger_status = lttng_trigger_get_name(trigger_from_listing, &returned_trigger_name);
+ ok(trigger_status == LTTNG_TRIGGER_STATUS_OK,
+ "Trigger returned by listing has a name: trigger name = '%s'",
+ get_trigger_name(trigger_from_listing));
+
+ ok(!strcmp(get_trigger_name(trigger_from_listing),
+ trigger_name),
+ "Name set on trigger returned from listing is correct: name returned from listing = '%s', expected name = '%s'",
+ get_trigger_name(trigger_from_listing),
+ trigger_name);
+
+ if (unregistration_trigger == UNREGISTRATION_TRIGGER_INSTANCE_FROM_LISTING) {
+ ret = lttng_unregister_trigger(trigger_from_listing);
+ ok(ret == 0, "Successfully unregistered named trigger using the trigger instance returned by the listing");
+ }
+ }
+
+ if (unregistration_trigger == UNREGISTRATION_TRIGGER_INSTANCE_USED_FOR_REGISTRATION) {
+ ret = lttng_unregister_trigger(trigger);
+ ok(ret == 0, "Successfully unregistered named trigger using the trigger instance used on registration");
+ }
+
+end:
+ lttng_triggers_destroy(triggers);
+ lttng_trigger_destroy(trigger);
+}
+
+static
+void register_automatic_name_trigger(
+ enum unregistration_trigger_instance unregistration_trigger)
+{
+ int ret;
+ struct lttng_trigger *trigger = create_trigger(0xbadc0ffee);
+ enum lttng_trigger_status trigger_status;
+ const char *returned_trigger_name;
+ struct lttng_triggers *triggers = NULL;
+ unsigned int trigger_count, i;
+ enum lttng_error_code ret_code;
+
+ diag("Register an automatic name trigger (Unregistration performed with the trigger instance %s)",
+ unregistration_trigger_instance_name(
+ unregistration_trigger));
+
+ if (!trigger) {
+ fail("Failed to create trigger");
+ goto end;
+ }
+
+ ret_code = lttng_register_trigger_with_automatic_name(trigger);
+ ok(ret_code == LTTNG_OK, "Registered trigger with automatic name");
+
+ trigger_status = lttng_trigger_get_name(trigger, &returned_trigger_name);
+ ok(trigger_status == LTTNG_TRIGGER_STATUS_OK,
+ "Trigger name is set after registration: trigger name = '%s'",
+ get_trigger_name(trigger));
+
+ ok(returned_trigger_name && strlen(returned_trigger_name) > 0,
+ "Automatic name set on trigger after registration longer is not an empty string");
+
+ ret_code = lttng_list_triggers(&triggers);
+ if (ret_code != LTTNG_OK) {
+ fail("Failed to list triggers");
+ ret = -1;
+ goto end;
+ }
+
+ trigger_status = lttng_triggers_get_count(triggers, &trigger_count);
+ if (trigger_status != LTTNG_TRIGGER_STATUS_OK) {
+ fail("Failed to get count of triggers returned by listing");
+ ret = -1;
+ goto end;
+ }
+
+ ok(trigger_count == 1, "Trigger listing returns 1 trigger");
+
+ for (i = 0; i < trigger_count; i++) {
+ const struct lttng_trigger *trigger_from_listing;
+
+ trigger_from_listing = lttng_triggers_get_at_index(triggers, i);
+ LTTNG_ASSERT(trigger_from_listing);
+
+ trigger_status = lttng_trigger_get_name(trigger_from_listing, &returned_trigger_name);
+ ok(trigger_status == LTTNG_TRIGGER_STATUS_OK,
+ "Trigger returned by listing has a name: trigger name = '%s'",
+ get_trigger_name(trigger_from_listing));
+
+ if (unregistration_trigger == UNREGISTRATION_TRIGGER_INSTANCE_FROM_LISTING) {
+ ret = lttng_unregister_trigger(trigger_from_listing);
+ ok(ret == 0, "Successfully unregistered automatic name trigger using the trigger instance returned by the listing");
+ }
+ }
+
+ if (unregistration_trigger == UNREGISTRATION_TRIGGER_INSTANCE_USED_FOR_REGISTRATION) {
+ ret = lttng_unregister_trigger(trigger);
+ ok(ret == 0, "Successfully unregistered automatic trigger using the trigger instance used on registration");
+ }
+
+end:
+ lttng_triggers_destroy(triggers);
+ lttng_trigger_destroy(trigger);
+}
+
+static
+void double_register_anonymous_trigger(
+ enum unregistration_trigger_instance unregistration_trigger)
+{
+ int ret;
+ struct lttng_trigger *trigger = create_trigger(0xbadc0ffee);
+ struct lttng_triggers *triggers = NULL;
+
+ diag("Register duplicate anonymous trigger (Unregistration performed with the trigger instance %s)",
+ unregistration_trigger_instance_name(
+ unregistration_trigger));
+
+ if (!trigger) {
+ fail("Failed to create trigger");
+ goto end;
+ }
+
+ ret = lttng_register_trigger(trigger);
+ ok(ret == 0, "Registered anonymous trigger");
+
+ ret = lttng_register_trigger(trigger);
+ ok(ret == -LTTNG_ERR_TRIGGER_EXISTS,
+ "Registering identical anonymous trigger fails with `LTTNG_ERR_TRIGGER_EXISTS`");
+
+
+ if (unregistration_trigger == UNREGISTRATION_TRIGGER_INSTANCE_USED_FOR_REGISTRATION) {
+ ret = lttng_unregister_trigger(trigger);
+ ok(ret == 0, "Successfully unregistered anonymous trigger using the trigger instance used on registration");
+ } else {
+ ok(get_registered_triggers_count() == 1,
+ "Trigger listing returns 1 trigger");
+ ok(unregister_all_triggers() == 1,
+ "Successfully unregistered anonymous trigger using the trigger instance returned by the listing");
+ }
+
+end:
+ lttng_triggers_destroy(triggers);
+ lttng_trigger_destroy(trigger);
+}
+
+static
+void double_register_named_trigger(
+ enum unregistration_trigger_instance unregistration_trigger)
+{
+ int ret;
+ struct lttng_trigger *trigger_a = create_trigger(0xbadc0ffee);
+ struct lttng_trigger *trigger_b = create_trigger(0xbadc0ffee);
+ struct lttng_triggers *triggers = NULL;
+ const char * const trigger_name = "a unique trigger name";
+ enum lttng_error_code ret_code;
+
+ diag("Register duplicate named trigger (Unregistration performed with the trigger instance %s)",
+ unregistration_trigger_instance_name(
+ unregistration_trigger));
+
+ if (!trigger_a || !trigger_b) {
+ fail("Failed to create triggers");
+ goto end;
+ }
+
+ ret_code = lttng_register_trigger_with_name(trigger_a, trigger_name);
+ ok(ret_code == LTTNG_OK, "Registered named trigger");
+
+ ret = lttng_register_trigger(trigger_a);
+ ok(ret == -LTTNG_ERR_INVALID,
+ "Registering a trigger instance already used for registration fails with `LTTNG_ERR_INVALID` (anonymous registration)");
+
+ ret_code = lttng_register_trigger_with_name(trigger_a, trigger_name);
+ ok(ret_code == LTTNG_ERR_INVALID,
+ "Registering a trigger instance already used for registration fails with `LTTNG_ERR_INVALID` (register with name)");
+
+ ret_code = lttng_register_trigger_with_automatic_name(trigger_a);
+ ok(ret_code == LTTNG_ERR_INVALID,
+ "Registering a trigger instance already used for registration fails with `LTTNG_ERR_INVALID` (register with automatic name)");
+
+ ret_code = lttng_register_trigger_with_name(trigger_b, trigger_name);
+ ok(ret_code == LTTNG_ERR_TRIGGER_EXISTS, "Registering trigger with an already used name fails with `LTTNG_ERR_TRIGGER_EXISTS`");
+
+ if (unregistration_trigger == UNREGISTRATION_TRIGGER_INSTANCE_USED_FOR_REGISTRATION) {
+ ret = lttng_unregister_trigger(trigger_a);
+ ok(ret == 0, "Successfully unregistered named trigger using the trigger instance used on registration");
+ } else {
+ ok(get_registered_triggers_count() == 1,
+ "Trigger listing returns 1 trigger");
+ ok(unregister_all_triggers() == 1,
+ "Successfully unregistered named trigger using the trigger instance returned by the listing");
+ }
+
+end:
+ lttng_triggers_destroy(triggers);
+ lttng_trigger_destroy(trigger_a);
+ lttng_trigger_destroy(trigger_b);
+}
+
+static
+void double_register_automatic_name_trigger(
+ enum unregistration_trigger_instance unregistration_trigger)
+{
+ int ret;
+ struct lttng_trigger *trigger_a = create_trigger(0xbadc0ffee);
+ struct lttng_trigger *trigger_b = create_trigger(0xbadc0ffee);
+ struct lttng_triggers *triggers = NULL;
+ enum lttng_error_code ret_code;
+
+ diag("Register duplicate automatic name trigger (Unregistration performed with the trigger instance %s)",
+ unregistration_trigger_instance_name(
+ unregistration_trigger));
+
+ if (!trigger_a || !trigger_b) {
+ fail("Failed to create triggers");
+ goto end;
+ }
+
+ ret_code = lttng_register_trigger_with_automatic_name(trigger_a);
+ ok(ret_code == LTTNG_OK, "Registered automatic name trigger: trigger name = '%s'", get_trigger_name(trigger_a));
+
+ ret = lttng_register_trigger_with_automatic_name(trigger_b);
+ ok(ret_code == LTTNG_OK, "Registering an identical trigger instance with an automatic name succeeds: trigger name = '%s'", get_trigger_name(trigger_b));
+
+ ok(strcmp(get_trigger_name(trigger_a), get_trigger_name(trigger_b)),
+ "Two identical triggers registered with an automatic name have different names");
+
+ if (unregistration_trigger == UNREGISTRATION_TRIGGER_INSTANCE_USED_FOR_REGISTRATION) {
+ ret = lttng_unregister_trigger(trigger_a);
+ ok(ret == 0, "Successfully unregistered automatic trigger A using the trigger instance used on registration");
+
+ ret = lttng_unregister_trigger(trigger_b);
+ ok(ret == 0, "Successfully unregistered automatic trigger B using the trigger instance used on registration");
+ } else {
+ ok(get_registered_triggers_count() == 2,
+ "Trigger listing returns 2 trigger");
+ ok(unregister_all_triggers() == 2,
+ "Successfully unregistered automatic name triggers using the trigger instance returned by the listing");
+ }
+
+end:
+ lttng_triggers_destroy(triggers);
+ lttng_trigger_destroy(trigger_a);
+ lttng_trigger_destroy(trigger_b);
+}
+
+static
+void register_multiple_anonymous_triggers(void)
+{
+ int ret;
+ struct lttng_trigger *trigger_a = create_trigger(0xbadc0ffee);
+ struct lttng_trigger *trigger_b = create_trigger(0xbadf00d);
+
+ diag("Register two different anonymous triggers");
+
+ if (!trigger_a || !trigger_b) {
+ fail("Failed to create triggers");
+ goto end;
+ }
+
+ ret = lttng_register_trigger(trigger_a);
+ ok(ret == 0, "Registered first anonymous trigger");
+
+ ret = lttng_register_trigger(trigger_b);
+ ok(ret == 0, "Registered second anonymous trigger");
+
+ ok(get_registered_triggers_count() == 2,
+ "Trigger listing returns 2 trigger");
+ ok(unregister_all_triggers() == 2,
+ "Successfully unregistered two anonymous triggers");
+
+end:
+ lttng_trigger_destroy(trigger_a);
+ lttng_trigger_destroy(trigger_b);
+}
+
+const test_function test_functions[] = {
+ register_anonymous_trigger,
+ register_named_trigger,
+ register_automatic_name_trigger,
+ double_register_anonymous_trigger,
+ double_register_named_trigger,
+ double_register_automatic_name_trigger,
+};
+
+int main(int argc, const char **argv)
+{
+ size_t i;
+
+ plan_tests(TEST_COUNT);
+
+ if (get_registered_triggers_count() != 0) {
+ fail("Session daemon already has registered triggers, bailing out");
+ goto end;
+ }
+
+ for (i = 0; i < ARRAY_SIZE(test_functions); i++) {
+ const test_function fn = test_functions[i];
+
+ fn(UNREGISTRATION_TRIGGER_INSTANCE_FROM_LISTING);
+ if (get_registered_triggers_count() != 0) {
+ fail("Previous test left registered triggers, bailing out");
+ goto end;
+ }
+ }
+
+ for (i = 0; i < ARRAY_SIZE(test_functions); i++) {
+ const test_function fn = test_functions[i];
+
+ fn(UNREGISTRATION_TRIGGER_INSTANCE_USED_FOR_REGISTRATION);
+ if (get_registered_triggers_count() != 0) {
+ fail("Previous test left registered triggers, bailing out");
+ goto end;
+ }
+ }
+
+ register_multiple_anonymous_triggers();
+end:
+ return exit_status();
+}
# SPDX-License-Identifier: GPL-2.0-only
-AM_CFLAGS += -I$(srcdir) -I$(top_srcdir)/tests/utils
+AM_CPPFLAGS += -I$(srcdir) -I$(top_srcdir)/tests/utils
LIBLTTNG_CTL=$(top_builddir)/src/lib/lttng-ctl/liblttng-ctl.la
noinst_PROGRAMS = \
notification_client_LDADD = $(LIBLTTNG_CTL) \
$(top_builddir)/tests/utils/libtestutils.la
-register_some_triggers_SOURCES = register-some-triggers.c
+register_some_triggers_SOURCES = register-some-triggers.cpp
register_some_triggers_LDADD = $(LIBLTTNG_CTL) \
$(top_builddir)/src/common/filter/libfilter.la \
$(top_builddir)/src/common/bytecode/libbytecode.la
+++ /dev/null
-/*
- * Copyright (C) 2021 Simon Marchi <simon.marchi@efficios.com>
- *
- * SPDX-License-Identifier: GPL-2.0-only
- *
- */
-
-/* Utility to register some triggers, for test purposes. */
-
-#include <common/filter/filter-ast.h>
-#include <common/macros.h>
-#include <lttng/lttng.h>
-
-#include <stdlib.h>
-#include <string.h>
-
-static void register_trigger(const char *trigger_name,
- struct lttng_condition *condition,
- struct lttng_action *action)
-{
- struct lttng_trigger *trigger;
- enum lttng_error_code ret;
-
- trigger = lttng_trigger_create(condition, action);
- ret = lttng_register_trigger_with_name(trigger, trigger_name);
- LTTNG_ASSERT(ret == LTTNG_OK);
-}
-
-/*
- * Register a trigger with the given condition and an action list containing a
- * single notify action.
- */
-static void register_trigger_action_list_notify(
- const char *trigger_name, struct lttng_condition *condition)
-{
- struct lttng_action *action_notify;
- struct lttng_action *action_list;
- enum lttng_action_status action_status;
-
- action_list = lttng_action_list_create();
- action_notify = lttng_action_notify_create();
- action_status = lttng_action_list_add_action(
- action_list, action_notify);
- LTTNG_ASSERT(action_status == LTTNG_ACTION_STATUS_OK);
-
- register_trigger(trigger_name, condition, action_list);
-}
-
-static struct lttng_condition *create_session_consumed_size_condition(
- const char *session_name, uint64_t threshold)
-{
- struct lttng_condition *condition;
- enum lttng_condition_status condition_status;
-
- condition = lttng_condition_session_consumed_size_create();
- condition_status =
- lttng_condition_session_consumed_size_set_session_name(
- condition, session_name);
- LTTNG_ASSERT(condition_status == LTTNG_CONDITION_STATUS_OK);
- condition_status = lttng_condition_session_consumed_size_set_threshold(
- condition, threshold);
- LTTNG_ASSERT(condition_status == LTTNG_CONDITION_STATUS_OK);
-
- return condition;
-}
-
-static void test_session_consumed_size_condition(void)
-{
- register_trigger_action_list_notify(
- "trigger-with-session-consumed-size-condition",
- create_session_consumed_size_condition(
- "the-session-name", 1234));
-}
-
-static void fill_buffer_usage_condition(struct lttng_condition *condition,
- const char *session_name,
- const char *channel_name,
- enum lttng_domain_type domain_type)
-{
- enum lttng_condition_status condition_status;
-
- condition_status = lttng_condition_buffer_usage_set_session_name(
- condition, session_name);
- LTTNG_ASSERT(condition_status == LTTNG_CONDITION_STATUS_OK);
- condition_status = lttng_condition_buffer_usage_set_channel_name(
- condition, channel_name);
- LTTNG_ASSERT(condition_status == LTTNG_CONDITION_STATUS_OK);
- condition_status = lttng_condition_buffer_usage_set_domain_type(
- condition, domain_type);
- LTTNG_ASSERT(condition_status == LTTNG_CONDITION_STATUS_OK);
-}
-
-static void fill_buffer_usage_bytes_condition(struct lttng_condition *condition,
- const char *session_name,
- const char *channel_name,
- enum lttng_domain_type domain_type,
- uint64_t threshold)
-{
- enum lttng_condition_status condition_status;
-
- fill_buffer_usage_condition(
- condition, session_name, channel_name, domain_type);
- condition_status = lttng_condition_buffer_usage_set_threshold(
- condition, threshold);
- LTTNG_ASSERT(condition_status == LTTNG_CONDITION_STATUS_OK);
-}
-
-static void fill_buffer_usage_ratio_condition(struct lttng_condition *condition,
- const char *session_name,
- const char *channel_name,
- enum lttng_domain_type domain_type,
- double ratio)
-{
- enum lttng_condition_status condition_status;
-
- fill_buffer_usage_condition(
- condition, session_name, channel_name, domain_type);
- condition_status = lttng_condition_buffer_usage_set_threshold_ratio(
- condition, ratio);
- LTTNG_ASSERT(condition_status == LTTNG_CONDITION_STATUS_OK);
-}
-
-static struct lttng_condition *create_buffer_usage_high_bytes_condition(
- const char *session_name,
- const char *channel_name,
- enum lttng_domain_type domain_type,
- uint64_t threshold)
-{
- struct lttng_condition *condition;
-
- condition = lttng_condition_buffer_usage_high_create();
- fill_buffer_usage_bytes_condition(condition, session_name, channel_name,
- domain_type, threshold);
-
- return condition;
-}
-
-static struct lttng_condition *create_buffer_usage_low_bytes_condition(
- const char *session_name,
- const char *channel_name,
- enum lttng_domain_type domain_type,
- uint64_t threshold)
-{
- struct lttng_condition *condition;
-
- condition = lttng_condition_buffer_usage_low_create();
- fill_buffer_usage_bytes_condition(condition, session_name, channel_name,
- domain_type, threshold);
-
- return condition;
-}
-
-static struct lttng_condition *create_buffer_usage_high_ratio_condition(
- const char *session_name,
- const char *channel_name,
- enum lttng_domain_type domain_type,
- double ratio)
-{
- struct lttng_condition *condition;
-
- condition = lttng_condition_buffer_usage_high_create();
- fill_buffer_usage_ratio_condition(condition, session_name, channel_name,
- domain_type, ratio);
-
- return condition;
-}
-
-static struct lttng_condition *create_buffer_usage_low_ratio_condition(
- const char *session_name,
- const char *channel_name,
- enum lttng_domain_type domain_type,
- double ratio)
-{
- struct lttng_condition *condition;
-
- condition = lttng_condition_buffer_usage_low_create();
- fill_buffer_usage_ratio_condition(condition, session_name, channel_name,
- domain_type, ratio);
-
- return condition;
-}
-
-static void test_buffer_usage_conditions(void)
-{
- register_trigger_action_list_notify(
- "trigger-with-buffer-usage-high-bytes-condition",
- create_buffer_usage_high_bytes_condition(
- "the-session-name", "the-channel-name",
- LTTNG_DOMAIN_UST, 1234));
-
- register_trigger_action_list_notify(
- "trigger-with-buffer-usage-low-bytes-condition",
- create_buffer_usage_low_bytes_condition(
- "the-session-name", "the-channel-name",
- LTTNG_DOMAIN_UST, 2345));
-
- register_trigger_action_list_notify(
- "trigger-with-buffer-usage-high-ratio-condition",
- create_buffer_usage_high_ratio_condition(
- "the-session-name", "the-channel-name",
- LTTNG_DOMAIN_UST, 0.25));
-
- register_trigger_action_list_notify(
- "trigger-with-buffer-usage-low-ratio-condition",
- create_buffer_usage_low_ratio_condition(
- "the-session-name", "the-channel-name",
- LTTNG_DOMAIN_UST, 0.4));
-}
-
-static void fill_session_rotation_condition(
- struct lttng_condition *condition, const char *session_name)
-{
- enum lttng_condition_status condition_status;
-
- condition_status = lttng_condition_session_rotation_set_session_name(
- condition, session_name);
- LTTNG_ASSERT(condition_status == LTTNG_CONDITION_STATUS_OK);
-}
-
-static struct lttng_condition *create_session_rotation_ongoing_condition(
- const char *session_name)
-{
- struct lttng_condition *condition;
-
- condition = lttng_condition_session_rotation_ongoing_create();
-
- fill_session_rotation_condition(condition, session_name);
-
- return condition;
-}
-
-static struct lttng_condition *create_session_rotation_completed_condition(
- const char *session_name)
-{
- struct lttng_condition *condition;
-
- condition = lttng_condition_session_rotation_completed_create();
-
- fill_session_rotation_condition(condition, session_name);
-
- return condition;
-}
-
-static void test_session_rotation_conditions(void)
-{
- register_trigger_action_list_notify(
- "trigger-with-session-rotation-ongoing-condition",
- create_session_rotation_ongoing_condition(
- "the-session-name"));
-
- register_trigger_action_list_notify(
- "trigger-with-session-rotation-completed-condition",
- create_session_rotation_completed_condition(
- "the-session-name"));
-}
-
-static struct {
- const char *name;
- void (*callback)(void);
-} tests[] = {
- {
- "test_session_consumed_size_condition",
- test_session_consumed_size_condition,
- },
- {"test_buffer_usage_conditions", test_buffer_usage_conditions},
- {"test_session_rotation_conditions",
- test_session_rotation_conditions},
-};
-
-static void show_known_tests(void)
-{
- size_t i;
-
- for (i = 0; i < ARRAY_SIZE(tests); i++) {
- fprintf(stderr, " - %s\n", tests[i].name);
- }
-}
-
-int main(int argc, char **argv)
-{
- const char *test;
- size_t i;
- int ret;
-
- if (argc != 2) {
- fprintf(stderr, "Usage: %s <test>\n", argv[0]);
- fprintf(stderr, "\n");
- fprintf(stderr, "Test must be one of:\n");
- show_known_tests();
- goto error;
- }
-
- test = argv[1];
-
- for (i = 0; i < ARRAY_SIZE(tests); i++) {
- if (strcmp(tests[i].name, test) == 0) {
- break;
- }
- }
-
- if (i == ARRAY_SIZE(tests)) {
- fprintf(stderr, "Unrecognized test `%s`\n", test);
- fprintf(stderr, "\n");
- fprintf(stderr, "Known tests:\n");
- show_known_tests();
- goto error;
- }
-
- tests[i].callback();
-
- ret = 0;
- goto end;
-
-error:
- ret = 1;
-
-end:
- return ret;
-}
--- /dev/null
+/*
+ * Copyright (C) 2021 Simon Marchi <simon.marchi@efficios.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0-only
+ *
+ */
+
+/* Utility to register some triggers, for test purposes. */
+
+#include <common/filter/filter-ast.h>
+#include <common/macros.h>
+#include <lttng/lttng.h>
+
+#include <stdlib.h>
+#include <string.h>
+
+static void register_trigger(const char *trigger_name,
+ struct lttng_condition *condition,
+ struct lttng_action *action)
+{
+ struct lttng_trigger *trigger;
+ enum lttng_error_code ret;
+
+ trigger = lttng_trigger_create(condition, action);
+ ret = lttng_register_trigger_with_name(trigger, trigger_name);
+ LTTNG_ASSERT(ret == LTTNG_OK);
+}
+
+/*
+ * Register a trigger with the given condition and an action list containing a
+ * single notify action.
+ */
+static void register_trigger_action_list_notify(
+ const char *trigger_name, struct lttng_condition *condition)
+{
+ struct lttng_action *action_notify;
+ struct lttng_action *action_list;
+ enum lttng_action_status action_status;
+
+ action_list = lttng_action_list_create();
+ action_notify = lttng_action_notify_create();
+ action_status = lttng_action_list_add_action(
+ action_list, action_notify);
+ LTTNG_ASSERT(action_status == LTTNG_ACTION_STATUS_OK);
+
+ register_trigger(trigger_name, condition, action_list);
+}
+
+static struct lttng_condition *create_session_consumed_size_condition(
+ const char *session_name, uint64_t threshold)
+{
+ struct lttng_condition *condition;
+ enum lttng_condition_status condition_status;
+
+ condition = lttng_condition_session_consumed_size_create();
+ condition_status =
+ lttng_condition_session_consumed_size_set_session_name(
+ condition, session_name);
+ LTTNG_ASSERT(condition_status == LTTNG_CONDITION_STATUS_OK);
+ condition_status = lttng_condition_session_consumed_size_set_threshold(
+ condition, threshold);
+ LTTNG_ASSERT(condition_status == LTTNG_CONDITION_STATUS_OK);
+
+ return condition;
+}
+
+static void test_session_consumed_size_condition(void)
+{
+ register_trigger_action_list_notify(
+ "trigger-with-session-consumed-size-condition",
+ create_session_consumed_size_condition(
+ "the-session-name", 1234));
+}
+
+static void fill_buffer_usage_condition(struct lttng_condition *condition,
+ const char *session_name,
+ const char *channel_name,
+ enum lttng_domain_type domain_type)
+{
+ enum lttng_condition_status condition_status;
+
+ condition_status = lttng_condition_buffer_usage_set_session_name(
+ condition, session_name);
+ LTTNG_ASSERT(condition_status == LTTNG_CONDITION_STATUS_OK);
+ condition_status = lttng_condition_buffer_usage_set_channel_name(
+ condition, channel_name);
+ LTTNG_ASSERT(condition_status == LTTNG_CONDITION_STATUS_OK);
+ condition_status = lttng_condition_buffer_usage_set_domain_type(
+ condition, domain_type);
+ LTTNG_ASSERT(condition_status == LTTNG_CONDITION_STATUS_OK);
+}
+
+static void fill_buffer_usage_bytes_condition(struct lttng_condition *condition,
+ const char *session_name,
+ const char *channel_name,
+ enum lttng_domain_type domain_type,
+ uint64_t threshold)
+{
+ enum lttng_condition_status condition_status;
+
+ fill_buffer_usage_condition(
+ condition, session_name, channel_name, domain_type);
+ condition_status = lttng_condition_buffer_usage_set_threshold(
+ condition, threshold);
+ LTTNG_ASSERT(condition_status == LTTNG_CONDITION_STATUS_OK);
+}
+
+static void fill_buffer_usage_ratio_condition(struct lttng_condition *condition,
+ const char *session_name,
+ const char *channel_name,
+ enum lttng_domain_type domain_type,
+ double ratio)
+{
+ enum lttng_condition_status condition_status;
+
+ fill_buffer_usage_condition(
+ condition, session_name, channel_name, domain_type);
+ condition_status = lttng_condition_buffer_usage_set_threshold_ratio(
+ condition, ratio);
+ LTTNG_ASSERT(condition_status == LTTNG_CONDITION_STATUS_OK);
+}
+
+static struct lttng_condition *create_buffer_usage_high_bytes_condition(
+ const char *session_name,
+ const char *channel_name,
+ enum lttng_domain_type domain_type,
+ uint64_t threshold)
+{
+ struct lttng_condition *condition;
+
+ condition = lttng_condition_buffer_usage_high_create();
+ fill_buffer_usage_bytes_condition(condition, session_name, channel_name,
+ domain_type, threshold);
+
+ return condition;
+}
+
+static struct lttng_condition *create_buffer_usage_low_bytes_condition(
+ const char *session_name,
+ const char *channel_name,
+ enum lttng_domain_type domain_type,
+ uint64_t threshold)
+{
+ struct lttng_condition *condition;
+
+ condition = lttng_condition_buffer_usage_low_create();
+ fill_buffer_usage_bytes_condition(condition, session_name, channel_name,
+ domain_type, threshold);
+
+ return condition;
+}
+
+static struct lttng_condition *create_buffer_usage_high_ratio_condition(
+ const char *session_name,
+ const char *channel_name,
+ enum lttng_domain_type domain_type,
+ double ratio)
+{
+ struct lttng_condition *condition;
+
+ condition = lttng_condition_buffer_usage_high_create();
+ fill_buffer_usage_ratio_condition(condition, session_name, channel_name,
+ domain_type, ratio);
+
+ return condition;
+}
+
+static struct lttng_condition *create_buffer_usage_low_ratio_condition(
+ const char *session_name,
+ const char *channel_name,
+ enum lttng_domain_type domain_type,
+ double ratio)
+{
+ struct lttng_condition *condition;
+
+ condition = lttng_condition_buffer_usage_low_create();
+ fill_buffer_usage_ratio_condition(condition, session_name, channel_name,
+ domain_type, ratio);
+
+ return condition;
+}
+
+static void test_buffer_usage_conditions(void)
+{
+ register_trigger_action_list_notify(
+ "trigger-with-buffer-usage-high-bytes-condition",
+ create_buffer_usage_high_bytes_condition(
+ "the-session-name", "the-channel-name",
+ LTTNG_DOMAIN_UST, 1234));
+
+ register_trigger_action_list_notify(
+ "trigger-with-buffer-usage-low-bytes-condition",
+ create_buffer_usage_low_bytes_condition(
+ "the-session-name", "the-channel-name",
+ LTTNG_DOMAIN_UST, 2345));
+
+ register_trigger_action_list_notify(
+ "trigger-with-buffer-usage-high-ratio-condition",
+ create_buffer_usage_high_ratio_condition(
+ "the-session-name", "the-channel-name",
+ LTTNG_DOMAIN_UST, 0.25));
+
+ register_trigger_action_list_notify(
+ "trigger-with-buffer-usage-low-ratio-condition",
+ create_buffer_usage_low_ratio_condition(
+ "the-session-name", "the-channel-name",
+ LTTNG_DOMAIN_UST, 0.4));
+}
+
+static void fill_session_rotation_condition(
+ struct lttng_condition *condition, const char *session_name)
+{
+ enum lttng_condition_status condition_status;
+
+ condition_status = lttng_condition_session_rotation_set_session_name(
+ condition, session_name);
+ LTTNG_ASSERT(condition_status == LTTNG_CONDITION_STATUS_OK);
+}
+
+static struct lttng_condition *create_session_rotation_ongoing_condition(
+ const char *session_name)
+{
+ struct lttng_condition *condition;
+
+ condition = lttng_condition_session_rotation_ongoing_create();
+
+ fill_session_rotation_condition(condition, session_name);
+
+ return condition;
+}
+
+static struct lttng_condition *create_session_rotation_completed_condition(
+ const char *session_name)
+{
+ struct lttng_condition *condition;
+
+ condition = lttng_condition_session_rotation_completed_create();
+
+ fill_session_rotation_condition(condition, session_name);
+
+ return condition;
+}
+
+static void test_session_rotation_conditions(void)
+{
+ register_trigger_action_list_notify(
+ "trigger-with-session-rotation-ongoing-condition",
+ create_session_rotation_ongoing_condition(
+ "the-session-name"));
+
+ register_trigger_action_list_notify(
+ "trigger-with-session-rotation-completed-condition",
+ create_session_rotation_completed_condition(
+ "the-session-name"));
+}
+
+static struct {
+ const char *name;
+ void (*callback)(void);
+} tests[] = {
+ {
+ "test_session_consumed_size_condition",
+ test_session_consumed_size_condition,
+ },
+ {"test_buffer_usage_conditions", test_buffer_usage_conditions},
+ {"test_session_rotation_conditions",
+ test_session_rotation_conditions},
+};
+
+static void show_known_tests(void)
+{
+ size_t i;
+
+ for (i = 0; i < ARRAY_SIZE(tests); i++) {
+ fprintf(stderr, " - %s\n", tests[i].name);
+ }
+}
+
+int main(int argc, char **argv)
+{
+ const char *test;
+ size_t i;
+ int ret;
+
+ if (argc != 2) {
+ fprintf(stderr, "Usage: %s <test>\n", argv[0]);
+ fprintf(stderr, "\n");
+ fprintf(stderr, "Test must be one of:\n");
+ show_known_tests();
+ goto error;
+ }
+
+ test = argv[1];
+
+ for (i = 0; i < ARRAY_SIZE(tests); i++) {
+ if (strcmp(tests[i].name, test) == 0) {
+ break;
+ }
+ }
+
+ if (i == ARRAY_SIZE(tests)) {
+ fprintf(stderr, "Unrecognized test `%s`\n", test);
+ fprintf(stderr, "\n");
+ fprintf(stderr, "Known tests:\n");
+ show_known_tests();
+ goto error;
+ }
+
+ tests[i].callback();
+
+ ret = 0;
+ goto end;
+
+error:
+ ret = 1;
+
+end:
+ return ret;
+}
dist_noinst_SCRIPTS = utils.sh test_utils.py babelstats.pl tap-driver.sh
noinst_LTLIBRARIES = libtestutils.la
-libtestutils_la_SOURCES = utils.c utils.h
+libtestutils_la_SOURCES = \
+ utils.cpp \
+ utils.h
all-local:
@if [ x"$(srcdir)" != x"$(builddir)" ]; then \
-I$(top_srcdir)/tests/utils/testapp
noinst_PROGRAMS = gen-ns-events
-gen_ns_events_SOURCES = gen-ns-events.c
+gen_ns_events_SOURCES = gen-ns-events.cpp
gen_ns_events_LDADD = \
$(top_builddir)/tests/utils/libtestutils.la \
$(DL_LIBS) $(POPT_LIBS)
+++ /dev/null
-/*
- * Copyright (C) 2019 Michael Jeanson <mjeanson@efficios.com>
- *
- * SPDX-License-Identifier: LGPL-2.1-only
- *
- */
-
-#ifndef _GNU_SOURCE
-#define _GNU_SOURCE
-#endif
-
-#include <popt.h>
-#include <sched.h>
-#include <stdarg.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <unistd.h>
-
-#include <common/compat/tid.h>
-
-#include "signal-helper.h"
-#include "utils.h"
-
-#define LTTNG_PROC_NS_PATH_MAX 40
-
-/*
- * The runner of this test validates that the kernel supports the
- * namespace for which it is invoked. However, these defines are added
- * to allow tests to run on systems that support a given namespace,
- * but that use a libc that doesn't define its associated clone flag.
- */
-#ifndef CLONE_NEWNS
-#define CLONE_NEWNS 0x00020000
-#endif
-#ifndef CLONE_NEWCGROUP
-#define CLONE_NEWCGROUP 0x02000000
-#endif
-#ifndef CLONE_NEWUTS
-#define CLONE_NEWUTS 0x04000000
-#endif
-#ifndef CLONE_NEWIPC
-#define CLONE_NEWIPC 0x08000000
-#endif
-#ifndef CLONE_NEWUSER
-#define CLONE_NEWUSER 0x10000000
-#endif
-#ifndef CLONE_NEWPID
-#define CLONE_NEWPID 0x20000000
-#endif
-#ifndef CLONE_NEWNET
-#define CLONE_NEWNET 0x40000000
-#endif
-#ifndef CLONE_NEWTIME
-#define CLONE_NEWTIME 0x00000080
-#endif
-
-static int debug = 0;
-static char *ns_opt = NULL;
-static char *before_unshare_wait_file_path = NULL;
-static char *after_unshare_wait_file_path = NULL;
-static char *after_unshare_signal_file_path = NULL;
-
-static struct poptOption opts[] = {
- /* longName, shortName, argInfo, argPtr, value, descrip, argDesc */
- { "debug", 'd', POPT_ARG_NONE, &debug, 0, "Enable debug output", NULL },
- { "ns", 'n', POPT_ARG_STRING, &ns_opt, 0, "Namespace short identifier", NULL },
- { "before", 'b', POPT_ARG_STRING, &before_unshare_wait_file_path, 0, "Wait for file before unshare", NULL },
- { "after", 'a', POPT_ARG_STRING, &after_unshare_wait_file_path, 0, "Wait for file after unshare", NULL },
- { "signal", 's', POPT_ARG_STRING, &after_unshare_signal_file_path, 0, "Create signal file after unshare", NULL },
- POPT_AUTOHELP
- { NULL, 0, 0, NULL, 0 }
-};
-
-static void debug_printf(const char *format, ...)
-{
- va_list args;
- va_start(args, format);
-
- if (debug) {
- vfprintf(stderr, format, args);
- }
-
- va_end(args);
-}
-
-static int get_ns_inum(const char *ns, ino_t *ns_inum)
-{
- int ret = 0;
- struct stat sb;
- char proc_ns_path[LTTNG_PROC_NS_PATH_MAX];
-
- /*
- * /proc/thread-self was introduced in kernel v3.17
- */
- if (snprintf(proc_ns_path, LTTNG_PROC_NS_PATH_MAX,
- "/proc/thread-self/ns/%s", ns) >= 0) {
- if (stat(proc_ns_path, &sb) == 0) {
- *ns_inum = sb.st_ino;
- } else {
- ret = -1;
- }
- goto end;
- }
-
- if (snprintf(proc_ns_path, LTTNG_PROC_NS_PATH_MAX,
- "/proc/self/task/%d/%s/net", lttng_gettid(), ns) >= 0) {
- if (stat(proc_ns_path, &sb) == 0) {
- *ns_inum = sb.st_ino;
- } else {
- ret = -1;
- }
- goto end;
- }
-end:
- return ret;
-}
-
-static int do_the_needful(int ns_flag, const char *ns_str)
-{
- int ret = 0;
- ino_t ns1, ns2;
-
- ret = get_ns_inum(ns_str, &ns1);
- if (ret) {
- debug_printf("Failed to get ns inode number for namespace %s",
- ns_str);
- ret = -1;
- goto end;
- }
- debug_printf("Initial %s ns inode number: %lu\n", ns_str, ns1);
-
- /* Wait on synchronization before unshare. */
- if (before_unshare_wait_file_path) {
- ret = wait_on_file(before_unshare_wait_file_path);
- if (ret != 0) {
- goto end;
- }
- }
-
- ret = unshare(ns_flag);
- if (ret == -1) {
- perror("Failed to unshare namespace");
- goto end;
- }
-
- ret = get_ns_inum(ns_str, &ns2);
- if (ret) {
- debug_printf("Failed to get ns inode number for namespace %s",
- ns_str);
- ret = -1;
- goto end;
- }
- debug_printf("Post unshare %s ns inode number: %lu\n", ns_str, ns2);
-
- /* Signal that the unshare call is completed. */
- if (after_unshare_signal_file_path) {
- ret = create_file(after_unshare_signal_file_path);
- if (ret != 0) {
- goto end;
- }
- }
-
- /* Wait on synchronization after unshare. */
- if (after_unshare_wait_file_path) {
- ret = wait_on_file(after_unshare_wait_file_path);
- if (ret != 0) {
- goto end;
- }
- }
-
-end:
- return ret;
-}
-
-int main(int argc, const char **argv)
-{
- int opt;
- int ret = EXIT_SUCCESS;
- poptContext pc;
-
- pc = poptGetContext(NULL, argc, argv, opts, 0);
- poptReadDefaultConfig(pc, 0);
-
- if (argc < 2) {
- poptPrintHelp(pc, stderr, 0);
- ret = EXIT_FAILURE;
- goto end;
- }
-
- while ((opt = poptGetNextOpt(pc)) >= 0) {
- switch (opt) {
- default:
- poptPrintUsage(pc, stderr, 0);
- ret = EXIT_FAILURE;
- goto end;
- }
- }
-
- if (opt < -1) {
- /* an error occurred during option processing */
- poptPrintUsage(pc, stderr, 0);
- fprintf(stderr, "%s: %s\n",
- poptBadOption(pc, POPT_BADOPTION_NOALIAS),
- poptStrerror(opt));
- ret = EXIT_FAILURE;
- goto end;
- }
-
- if (ns_opt == NULL) {
- poptPrintUsage(pc, stderr, 0);
- ret = EXIT_FAILURE;
- goto end;
- }
-
- if (set_signal_handler()) {
- ret = EXIT_FAILURE;
- goto end;
- }
-
- if (strncmp(ns_opt, "cgroup", 6) == 0) {
- ret = do_the_needful(CLONE_NEWCGROUP, "cgroup");
- } else if (strncmp(ns_opt, "ipc", 3) == 0) {
- ret = do_the_needful(CLONE_NEWIPC, "ipc");
- } else if (strncmp(ns_opt, "mnt", 3) == 0) {
- ret = do_the_needful(CLONE_NEWNS, "mnt");
- } else if (strncmp(ns_opt, "net", 3) == 0) {
- ret = do_the_needful(CLONE_NEWNET, "net");
- } else if (strncmp(ns_opt, "pid", 3) == 0) {
- ret = do_the_needful(CLONE_NEWPID, "pid");
- } else if (strncmp(ns_opt, "time", 4) == 0) {
- ret = do_the_needful(CLONE_NEWTIME, "time");
- } else if (strncmp(ns_opt, "user", 4) == 0) {
- /*
- * Will always fail, requires a single threaded application,
- * which can't happen with UST.
- */
- ret = do_the_needful(CLONE_NEWUSER, "user");
- } else if (strncmp(ns_opt, "uts", 3) == 0) {
- ret = do_the_needful(CLONE_NEWUTS, "uts");
- } else {
- printf("invalid ns id\n");
- ret = EXIT_FAILURE;
- goto end;
- }
- ret = ret ? EXIT_FAILURE : EXIT_SUCCESS;
-end:
- poptFreeContext(pc);
- return ret;
-}
--- /dev/null
+/*
+ * Copyright (C) 2019 Michael Jeanson <mjeanson@efficios.com>
+ *
+ * SPDX-License-Identifier: LGPL-2.1-only
+ *
+ */
+
+#ifndef _GNU_SOURCE
+#define _GNU_SOURCE
+#endif
+
+#include <popt.h>
+#include <sched.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <common/compat/tid.h>
+
+#include "signal-helper.h"
+#include "utils.h"
+
+#define LTTNG_PROC_NS_PATH_MAX 40
+
+/*
+ * The runner of this test validates that the kernel supports the
+ * namespace for which it is invoked. However, these defines are added
+ * to allow tests to run on systems that support a given namespace,
+ * but that use a libc that doesn't define its associated clone flag.
+ */
+#ifndef CLONE_NEWNS
+#define CLONE_NEWNS 0x00020000
+#endif
+#ifndef CLONE_NEWCGROUP
+#define CLONE_NEWCGROUP 0x02000000
+#endif
+#ifndef CLONE_NEWUTS
+#define CLONE_NEWUTS 0x04000000
+#endif
+#ifndef CLONE_NEWIPC
+#define CLONE_NEWIPC 0x08000000
+#endif
+#ifndef CLONE_NEWUSER
+#define CLONE_NEWUSER 0x10000000
+#endif
+#ifndef CLONE_NEWPID
+#define CLONE_NEWPID 0x20000000
+#endif
+#ifndef CLONE_NEWNET
+#define CLONE_NEWNET 0x40000000
+#endif
+#ifndef CLONE_NEWTIME
+#define CLONE_NEWTIME 0x00000080
+#endif
+
+static int debug = 0;
+static char *ns_opt = NULL;
+static char *before_unshare_wait_file_path = NULL;
+static char *after_unshare_wait_file_path = NULL;
+static char *after_unshare_signal_file_path = NULL;
+
+static struct poptOption opts[] = {
+ /* longName, shortName, argInfo, argPtr, value, descrip, argDesc */
+ { "debug", 'd', POPT_ARG_NONE, &debug, 0, "Enable debug output", NULL },
+ { "ns", 'n', POPT_ARG_STRING, &ns_opt, 0, "Namespace short identifier", NULL },
+ { "before", 'b', POPT_ARG_STRING, &before_unshare_wait_file_path, 0, "Wait for file before unshare", NULL },
+ { "after", 'a', POPT_ARG_STRING, &after_unshare_wait_file_path, 0, "Wait for file after unshare", NULL },
+ { "signal", 's', POPT_ARG_STRING, &after_unshare_signal_file_path, 0, "Create signal file after unshare", NULL },
+ POPT_AUTOHELP
+ { NULL, 0, 0, NULL, 0 }
+};
+
+static void debug_printf(const char *format, ...)
+{
+ va_list args;
+ va_start(args, format);
+
+ if (debug) {
+ vfprintf(stderr, format, args);
+ }
+
+ va_end(args);
+}
+
+static int get_ns_inum(const char *ns, ino_t *ns_inum)
+{
+ int ret = 0;
+ struct stat sb;
+ char proc_ns_path[LTTNG_PROC_NS_PATH_MAX];
+
+ /*
+ * /proc/thread-self was introduced in kernel v3.17
+ */
+ if (snprintf(proc_ns_path, LTTNG_PROC_NS_PATH_MAX,
+ "/proc/thread-self/ns/%s", ns) >= 0) {
+ if (stat(proc_ns_path, &sb) == 0) {
+ *ns_inum = sb.st_ino;
+ } else {
+ ret = -1;
+ }
+ goto end;
+ }
+
+ if (snprintf(proc_ns_path, LTTNG_PROC_NS_PATH_MAX,
+ "/proc/self/task/%d/%s/net", lttng_gettid(), ns) >= 0) {
+ if (stat(proc_ns_path, &sb) == 0) {
+ *ns_inum = sb.st_ino;
+ } else {
+ ret = -1;
+ }
+ goto end;
+ }
+end:
+ return ret;
+}
+
+static int do_the_needful(int ns_flag, const char *ns_str)
+{
+ int ret = 0;
+ ino_t ns1, ns2;
+
+ ret = get_ns_inum(ns_str, &ns1);
+ if (ret) {
+ debug_printf("Failed to get ns inode number for namespace %s",
+ ns_str);
+ ret = -1;
+ goto end;
+ }
+ debug_printf("Initial %s ns inode number: %lu\n", ns_str, ns1);
+
+ /* Wait on synchronization before unshare. */
+ if (before_unshare_wait_file_path) {
+ ret = wait_on_file(before_unshare_wait_file_path);
+ if (ret != 0) {
+ goto end;
+ }
+ }
+
+ ret = unshare(ns_flag);
+ if (ret == -1) {
+ perror("Failed to unshare namespace");
+ goto end;
+ }
+
+ ret = get_ns_inum(ns_str, &ns2);
+ if (ret) {
+ debug_printf("Failed to get ns inode number for namespace %s",
+ ns_str);
+ ret = -1;
+ goto end;
+ }
+ debug_printf("Post unshare %s ns inode number: %lu\n", ns_str, ns2);
+
+ /* Signal that the unshare call is completed. */
+ if (after_unshare_signal_file_path) {
+ ret = create_file(after_unshare_signal_file_path);
+ if (ret != 0) {
+ goto end;
+ }
+ }
+
+ /* Wait on synchronization after unshare. */
+ if (after_unshare_wait_file_path) {
+ ret = wait_on_file(after_unshare_wait_file_path);
+ if (ret != 0) {
+ goto end;
+ }
+ }
+
+end:
+ return ret;
+}
+
+int main(int argc, const char **argv)
+{
+ int opt;
+ int ret = EXIT_SUCCESS;
+ poptContext pc;
+
+ pc = poptGetContext(NULL, argc, argv, opts, 0);
+ poptReadDefaultConfig(pc, 0);
+
+ if (argc < 2) {
+ poptPrintHelp(pc, stderr, 0);
+ ret = EXIT_FAILURE;
+ goto end;
+ }
+
+ while ((opt = poptGetNextOpt(pc)) >= 0) {
+ switch (opt) {
+ default:
+ poptPrintUsage(pc, stderr, 0);
+ ret = EXIT_FAILURE;
+ goto end;
+ }
+ }
+
+ if (opt < -1) {
+ /* an error occurred during option processing */
+ poptPrintUsage(pc, stderr, 0);
+ fprintf(stderr, "%s: %s\n",
+ poptBadOption(pc, POPT_BADOPTION_NOALIAS),
+ poptStrerror(opt));
+ ret = EXIT_FAILURE;
+ goto end;
+ }
+
+ if (ns_opt == NULL) {
+ poptPrintUsage(pc, stderr, 0);
+ ret = EXIT_FAILURE;
+ goto end;
+ }
+
+ if (set_signal_handler()) {
+ ret = EXIT_FAILURE;
+ goto end;
+ }
+
+ if (strncmp(ns_opt, "cgroup", 6) == 0) {
+ ret = do_the_needful(CLONE_NEWCGROUP, "cgroup");
+ } else if (strncmp(ns_opt, "ipc", 3) == 0) {
+ ret = do_the_needful(CLONE_NEWIPC, "ipc");
+ } else if (strncmp(ns_opt, "mnt", 3) == 0) {
+ ret = do_the_needful(CLONE_NEWNS, "mnt");
+ } else if (strncmp(ns_opt, "net", 3) == 0) {
+ ret = do_the_needful(CLONE_NEWNET, "net");
+ } else if (strncmp(ns_opt, "pid", 3) == 0) {
+ ret = do_the_needful(CLONE_NEWPID, "pid");
+ } else if (strncmp(ns_opt, "time", 4) == 0) {
+ ret = do_the_needful(CLONE_NEWTIME, "time");
+ } else if (strncmp(ns_opt, "user", 4) == 0) {
+ /*
+ * Will always fail, requires a single threaded application,
+ * which can't happen with UST.
+ */
+ ret = do_the_needful(CLONE_NEWUSER, "user");
+ } else if (strncmp(ns_opt, "uts", 3) == 0) {
+ ret = do_the_needful(CLONE_NEWUTS, "uts");
+ } else {
+ printf("invalid ns id\n");
+ ret = EXIT_FAILURE;
+ goto end;
+ }
+ ret = ret ? EXIT_FAILURE : EXIT_SUCCESS;
+end:
+ poptFreeContext(pc);
+ return ret;
+}
# SPDX-License-Identifier: GPL-2.0-only
-AM_CFLAGS += -I$(top_srcdir)/tests/utils/
+AM_CPPFLAGS += -I$(top_srcdir)/tests/utils
noinst_PROGRAMS = gen-syscall-events
-gen_syscall_events_SOURCES = gen-syscall-events.c
+gen_syscall_events_SOURCES = gen-syscall-events.cpp
gen_syscall_events_LDADD = $(top_builddir)/tests/utils/libtestutils.la
+++ /dev/null
-/*
- * Copyright (C) 2017 Francis Deslauriers <francis.deslauriers@efficios.com>
- *
- * SPDX-License-Identifier: LGPL-2.1-only
- *
- */
-
-#include <fcntl.h>
-#include <stdio.h>
-#include <sys/syscall.h>
-#include <unistd.h>
-#include <common/error.h>
-#include <common/align.h>
-
-#include "utils.h"
-
-#define MAX_LEN 16
-
-/*
- * The LTTng system call tracing facilities can't handle page faults at the
- * moment. If a fault would occur while reading a syscall argument, the
- * tracer will report an empty string (""). Since the proper execution of the
- * tests which use this generator depends on some syscall string arguments being
- * present, this util allows us to mitigate the page-fault risk.
- *
- * This isn't a proper fix; it is simply the best we can do for now.
- * See bug #1261 for more context.
- */
-static
-void prefault_string(const char *p)
-{
- const char * const end = p + strlen(p) + 1;
-
- while (p < end) {
- /*
- * Trigger a read attempt on *p, faulting-in the pages
- * for reading.
- */
- asm volatile("" : : "m"(*p));
- p += sysconf(_SC_PAGE_SIZE);
- }
-}
-
-static
-int open_read_close(const char *path)
-{
- int fd, ret;
- char buf[MAX_LEN];
-
- /*
- * Start generating syscalls. We use syscall(2) to prevent libc from
- * changing the underlying syscall (e.g. calling openat(2) instead of
- * open(2)).
- */
- prefault_string(path);
- fd = syscall(SYS_openat, AT_FDCWD, path, O_RDONLY);
- if (fd < 0) {
- PERROR_NO_LOGGER("Failed to open file with openat(): path = '%s'", path);
- ret = -1;
- goto error;
- }
-
- ret = syscall(SYS_read, fd, buf, MAX_LEN);
- if (ret < 0) {
- PERROR_NO_LOGGER("Failed to read file: path = '%s', fd = %d, length = %d",
- path, fd, MAX_LEN);
- ret = -1;
- goto error;
- }
-
- ret = syscall(SYS_close, fd);
- if (ret == -1) {
- PERROR_NO_LOGGER("Failed to close file: path = '%s', fd = %d", path, fd);
- ret = -1;
- goto error;
- }
-
-error:
- return ret;
-}
-
-/*
- * The process waits for the creation of a file passed as argument from an
- * external processes to execute a syscall and exiting. This is useful for tests
- * in combinaison with LTTng's PID tracker feature where we can trace the kernel
- * events generated by our test process only.
- */
-int main(int argc, char **argv)
-{
- int ret;
- const char *start_file, *path1, *path2;
-
- if (argc != 4) {
- fprintf(stderr, "Error: Missing argument\n");
- fprintf(stderr, "USAGE: %s PATH_WAIT_FILE PATH1_TO_OPEN PATH2_TO_OPEN\n", argv[0]);
- ret = -1;
- goto error;
- }
-
- start_file = argv[1];
- path1 = argv[2];
- path2 = argv[3];
-
- /*
- * Wait for the start_file to be created by an external process
- * (typically the test script) before executing the syscalls.
- */
- ret = wait_on_file(start_file);
- if (ret != 0) {
- goto error;
- }
-
- /*
- * Start generating syscalls. We use syscall(2) to prevent libc to change
- * the underlying syscall. e.g. calling openat(2) instead of open(2).
- */
- ret = open_read_close(path1);
- if (ret == -1) {
- ret = -1;
- goto error;
- }
-
- ret = open_read_close(path2);
- if (ret == -1) {
- ret = -1;
- goto error;
- }
-
-error:
- return ret;
-}
--- /dev/null
+/*
+ * Copyright (C) 2017 Francis Deslauriers <francis.deslauriers@efficios.com>
+ *
+ * SPDX-License-Identifier: LGPL-2.1-only
+ *
+ */
+
+#include <fcntl.h>
+#include <stdio.h>
+#include <sys/syscall.h>
+#include <unistd.h>
+#include <common/error.h>
+#include <common/align.h>
+
+#include "utils.h"
+
+#define MAX_LEN 16
+
+/*
+ * The LTTng system call tracing facilities can't handle page faults at the
+ * moment. If a fault would occur while reading a syscall argument, the
+ * tracer will report an empty string (""). Since the proper execution of the
+ * tests which use this generator depends on some syscall string arguments being
+ * present, this util allows us to mitigate the page-fault risk.
+ *
+ * This isn't a proper fix; it is simply the best we can do for now.
+ * See bug #1261 for more context.
+ */
+static
+void prefault_string(const char *p)
+{
+ const char * const end = p + strlen(p) + 1;
+
+ while (p < end) {
+ /*
+ * Trigger a read attempt on *p, faulting-in the pages
+ * for reading.
+ */
+ asm volatile("" : : "m"(*p));
+ p += sysconf(_SC_PAGE_SIZE);
+ }
+}
+
+static
+int open_read_close(const char *path)
+{
+ int fd, ret;
+ char buf[MAX_LEN];
+
+ /*
+ * Start generating syscalls. We use syscall(2) to prevent libc from
+ * changing the underlying syscall (e.g. calling openat(2) instead of
+ * open(2)).
+ */
+ prefault_string(path);
+ fd = syscall(SYS_openat, AT_FDCWD, path, O_RDONLY);
+ if (fd < 0) {
+ PERROR_NO_LOGGER("Failed to open file with openat(): path = '%s'", path);
+ ret = -1;
+ goto error;
+ }
+
+ ret = syscall(SYS_read, fd, buf, MAX_LEN);
+ if (ret < 0) {
+ PERROR_NO_LOGGER("Failed to read file: path = '%s', fd = %d, length = %d",
+ path, fd, MAX_LEN);
+ ret = -1;
+ goto error;
+ }
+
+ ret = syscall(SYS_close, fd);
+ if (ret == -1) {
+ PERROR_NO_LOGGER("Failed to close file: path = '%s', fd = %d", path, fd);
+ ret = -1;
+ goto error;
+ }
+
+error:
+ return ret;
+}
+
+/*
+ * The process waits for the creation of a file passed as argument from an
+ * external processes to execute a syscall and exiting. This is useful for tests
+ * in combinaison with LTTng's PID tracker feature where we can trace the kernel
+ * events generated by our test process only.
+ */
+int main(int argc, char **argv)
+{
+ int ret;
+ const char *start_file, *path1, *path2;
+
+ if (argc != 4) {
+ fprintf(stderr, "Error: Missing argument\n");
+ fprintf(stderr, "USAGE: %s PATH_WAIT_FILE PATH1_TO_OPEN PATH2_TO_OPEN\n", argv[0]);
+ ret = -1;
+ goto error;
+ }
+
+ start_file = argv[1];
+ path1 = argv[2];
+ path2 = argv[3];
+
+ /*
+ * Wait for the start_file to be created by an external process
+ * (typically the test script) before executing the syscalls.
+ */
+ ret = wait_on_file(start_file);
+ if (ret != 0) {
+ goto error;
+ }
+
+ /*
+ * Start generating syscalls. We use syscall(2) to prevent libc to change
+ * the underlying syscall. e.g. calling openat(2) instead of open(2).
+ */
+ ret = open_read_close(path1);
+ if (ret == -1) {
+ ret = -1;
+ goto error;
+ }
+
+ ret = open_read_close(path2);
+ if (ret == -1) {
+ ret = -1;
+ goto error;
+ }
+
+error:
+ return ret;
+}
if HAVE_LIBLTTNG_UST_CTL
noinst_PROGRAMS = gen-ust-events-ns
-gen_ust_events_ns_SOURCES = gen-ust-events-ns.c tp.c tp.h
+gen_ust_events_ns_SOURCES = \
+ gen-ust-events-ns.cpp \
+ tp.c \
+ tp.h
gen_ust_events_ns_LDADD = $(UST_LIBS) -llttng-ust-fork \
$(top_builddir)/tests/utils/libtestutils.la \
$(DL_LIBS) $(POPT_LIBS)
+++ /dev/null
-/*
- * Copyright (C) 2019 Michael Jeanson <mjeanson@efficios.com>
- *
- * SPDX-License-Identifier: LGPL-2.1-only
- *
- */
-
-#ifndef _GNU_SOURCE
-#define _GNU_SOURCE
-#endif
-
-#include <popt.h>
-#include <sched.h>
-#include <stdarg.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <unistd.h>
-
-#include <common/compat/tid.h>
-
-#include "signal-helper.h"
-#include "utils.h"
-
-#define TRACEPOINT_DEFINE
-#include "tp.h"
-
-#define LTTNG_PROC_NS_PATH_MAX 40
-
-/*
- * The runner of this test validates that the kernel supports the
- * namespace for which it is invoked. However, these defines are added
- * to allow tests to run on systems that support a given namespace,
- * but that use a libc that doesn't define its associated clone flag.
- */
-#ifndef CLONE_NEWNS
-#define CLONE_NEWNS 0x00020000
-#endif
-#ifndef CLONE_NEWCGROUP
-#define CLONE_NEWCGROUP 0x02000000
-#endif
-#ifndef CLONE_NEWUTS
-#define CLONE_NEWUTS 0x04000000
-#endif
-#ifndef CLONE_NEWIPC
-#define CLONE_NEWIPC 0x08000000
-#endif
-#ifndef CLONE_NEWUSER
-#define CLONE_NEWUSER 0x10000000
-#endif
-#ifndef CLONE_NEWPID
-#define CLONE_NEWPID 0x20000000
-#endif
-#ifndef CLONE_NEWNET
-#define CLONE_NEWNET 0x40000000
-#endif
-#ifndef CLONE_NEWTIME
-#define CLONE_NEWTIME 0x00000080
-#endif
-
-static int nr_iter = 100;
-static int debug = 0;
-static char *ns_opt = NULL;
-static char *after_unshare_file_path = NULL;
-static char *before_second_event_file_path = NULL;
-
-static
-struct poptOption opts[] = {
- /* longName, shortName, argInfo, argPtr, value, descrip, argDesc */
- { "debug", 'd', POPT_ARG_NONE, &debug, 0, "Enable debug output", NULL },
- { "ns", 'n', POPT_ARG_STRING, &ns_opt, 0, "Namespace short identifier", NULL },
- { "iter", 'i', POPT_ARG_INT, &nr_iter, 0, "Number of tracepoint iterations", NULL },
- { "after", 'a', POPT_ARG_STRING, &after_unshare_file_path, 0, "after_unshare_file_path,", NULL },
- { "before", 'b', POPT_ARG_STRING, &before_second_event_file_path, 0, "before_second_event_file_path,", NULL },
- POPT_AUTOHELP
- { NULL, 0, 0, NULL, 0 }
-};
-
-static void debug_printf(const char *format, ...)
-{
- va_list args;
- va_start(args, format);
-
- if (debug) {
- vfprintf(stderr, format, args);
- }
-
- va_end(args);
-}
-
-static int get_ns_inum(const char *ns, ino_t *ns_inum)
-{
- int ret = -1;
- struct stat sb;
- char proc_ns_path[LTTNG_PROC_NS_PATH_MAX];
-
- /*
- * /proc/thread-self was introduced in kernel v3.17
- */
- if (snprintf(proc_ns_path, LTTNG_PROC_NS_PATH_MAX,
- "/proc/thread-self/ns/%s", ns) >= 0) {
- if (stat(proc_ns_path, &sb) == 0) {
- *ns_inum = sb.st_ino;
- ret = 0;
- }
- goto end;
- }
-
- if (snprintf(proc_ns_path, LTTNG_PROC_NS_PATH_MAX,
- "/proc/self/task/%d/%s/net", lttng_gettid(), ns) >= 0) {
- if (stat(proc_ns_path, &sb) == 0) {
- *ns_inum = sb.st_ino;
- ret = 0;
- }
- goto end;
- }
-end:
- return ret;
-}
-
-static int do_the_needful(int ns_flag, const char *ns_str)
-{
- int ret = 0, i;
- ino_t ns1, ns2;
-
- ret = get_ns_inum(ns_str, &ns1);
- if (ret) {
- debug_printf("Failed to get ns inode number for namespace %s",
- ns_str);
- ret = -1;
- goto end;
- }
- debug_printf("Initial %s ns inode number: %lu\n", ns_str, ns1);
-
- for (i = 0; nr_iter < 0 || i < nr_iter; i++) {
- tracepoint(tp, tptest, ns1);
- if (should_quit) {
- break;
- }
- }
-
- ret = unshare(ns_flag);
- if (ret == -1) {
- perror("Failed to unshare namespace");
- goto end;
- }
-
- ret = get_ns_inum(ns_str, &ns2);
- if (ret) {
- debug_printf("Failed to get ns inode number for namespace %s",
- ns_str);
- ret = -1;
- goto end;
- }
- debug_printf("Post unshare %s ns inode number: %lu\n", ns_str, ns2);
-
- /*
- * Signal that we emited the first event group and that the
- * unshare call is completed.
- */
- if (after_unshare_file_path) {
- ret = create_file(after_unshare_file_path);
- if (ret != 0) {
- goto end;
- }
- }
-
- /* Wait on synchronization before writing second event group. */
- if (before_second_event_file_path) {
- ret = wait_on_file(before_second_event_file_path);
- if (ret != 0) {
- goto end;
- }
- }
-
- for (i = 0; nr_iter < 0 || i < nr_iter; i++) {
- tracepoint(tp, tptest, ns2);
- if (should_quit) {
- break;
- }
- }
-
-end:
- return ret;
-}
-
-/*
- * Send X events, change NS, wait for file to sync with test script, send X
- * events in new NS
- */
-int main(int argc, const char **argv)
-{
- int opt;
- int ret = EXIT_SUCCESS;
- poptContext pc;
-
- pc = poptGetContext(NULL, argc, argv, opts, 0);
- poptReadDefaultConfig(pc, 0);
-
- if (argc < 2) {
- poptPrintHelp(pc, stderr, 0);
- ret = EXIT_FAILURE;
- goto end;
- }
-
- while ((opt = poptGetNextOpt(pc)) >= 0) {
- switch (opt) {
- default:
- poptPrintUsage(pc, stderr, 0);
- ret = EXIT_FAILURE;
- goto end;
- }
- }
-
- if (opt < -1) {
- /* An error occurred during option processing. */
- poptPrintUsage(pc, stderr, 0);
- fprintf(stderr, "%s: %s\n",
- poptBadOption(pc, POPT_BADOPTION_NOALIAS),
- poptStrerror(opt));
- ret = EXIT_FAILURE;
- goto end;
- }
-
- if (ns_opt == NULL) {
- poptPrintUsage(pc, stderr, 0);
- ret = EXIT_FAILURE;
- goto end;
- }
-
- if (set_signal_handler()) {
- ret = EXIT_FAILURE;
- goto end;
- }
-
- if (strncmp(ns_opt, "cgroup", 6) == 0) {
- ret = do_the_needful(CLONE_NEWCGROUP, "cgroup");
- } else if (strncmp(ns_opt, "ipc", 3) == 0) {
- ret = do_the_needful(CLONE_NEWIPC, "ipc");
- } else if (strncmp(ns_opt, "mnt", 3) == 0) {
- ret = do_the_needful(CLONE_NEWNS, "mnt");
- } else if (strncmp(ns_opt, "net", 3) == 0) {
- ret = do_the_needful(CLONE_NEWNET, "net");
- } else if (strncmp(ns_opt, "pid", 3) == 0) {
- ret = do_the_needful(CLONE_NEWPID, "pid");
- } else if (strncmp(ns_opt, "time", 4) == 0) {
- ret = do_the_needful(CLONE_NEWTIME, "time");
- } else if (strncmp(ns_opt, "user", 4) == 0) {
- /*
- * Will always fail, requires a single threaded application,
- * which can't happen with UST.
- */
- ret = do_the_needful(CLONE_NEWUSER, "user");
- } else if (strncmp(ns_opt, "uts", 3) == 0) {
- ret = do_the_needful(CLONE_NEWUTS, "uts");
- } else {
- printf("invalid ns id\n");
- ret = EXIT_FAILURE;
- goto end;
- }
- ret = ret ? EXIT_FAILURE : EXIT_SUCCESS;
-end:
- poptFreeContext(pc);
- return ret;
-}
--- /dev/null
+/*
+ * Copyright (C) 2019 Michael Jeanson <mjeanson@efficios.com>
+ *
+ * SPDX-License-Identifier: LGPL-2.1-only
+ *
+ */
+
+#ifndef _GNU_SOURCE
+#define _GNU_SOURCE
+#endif
+
+#include <popt.h>
+#include <sched.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <common/compat/tid.h>
+
+#include "signal-helper.h"
+#include "utils.h"
+
+#define TRACEPOINT_DEFINE
+#include "tp.h"
+
+#define LTTNG_PROC_NS_PATH_MAX 40
+
+/*
+ * The runner of this test validates that the kernel supports the
+ * namespace for which it is invoked. However, these defines are added
+ * to allow tests to run on systems that support a given namespace,
+ * but that use a libc that doesn't define its associated clone flag.
+ */
+#ifndef CLONE_NEWNS
+#define CLONE_NEWNS 0x00020000
+#endif
+#ifndef CLONE_NEWCGROUP
+#define CLONE_NEWCGROUP 0x02000000
+#endif
+#ifndef CLONE_NEWUTS
+#define CLONE_NEWUTS 0x04000000
+#endif
+#ifndef CLONE_NEWIPC
+#define CLONE_NEWIPC 0x08000000
+#endif
+#ifndef CLONE_NEWUSER
+#define CLONE_NEWUSER 0x10000000
+#endif
+#ifndef CLONE_NEWPID
+#define CLONE_NEWPID 0x20000000
+#endif
+#ifndef CLONE_NEWNET
+#define CLONE_NEWNET 0x40000000
+#endif
+#ifndef CLONE_NEWTIME
+#define CLONE_NEWTIME 0x00000080
+#endif
+
+static int nr_iter = 100;
+static int debug = 0;
+static char *ns_opt = NULL;
+static char *after_unshare_file_path = NULL;
+static char *before_second_event_file_path = NULL;
+
+static
+struct poptOption opts[] = {
+ /* longName, shortName, argInfo, argPtr, value, descrip, argDesc */
+ { "debug", 'd', POPT_ARG_NONE, &debug, 0, "Enable debug output", NULL },
+ { "ns", 'n', POPT_ARG_STRING, &ns_opt, 0, "Namespace short identifier", NULL },
+ { "iter", 'i', POPT_ARG_INT, &nr_iter, 0, "Number of tracepoint iterations", NULL },
+ { "after", 'a', POPT_ARG_STRING, &after_unshare_file_path, 0, "after_unshare_file_path,", NULL },
+ { "before", 'b', POPT_ARG_STRING, &before_second_event_file_path, 0, "before_second_event_file_path,", NULL },
+ POPT_AUTOHELP
+ { NULL, 0, 0, NULL, 0 }
+};
+
+static void debug_printf(const char *format, ...)
+{
+ va_list args;
+ va_start(args, format);
+
+ if (debug) {
+ vfprintf(stderr, format, args);
+ }
+
+ va_end(args);
+}
+
+static int get_ns_inum(const char *ns, ino_t *ns_inum)
+{
+ int ret = -1;
+ struct stat sb;
+ char proc_ns_path[LTTNG_PROC_NS_PATH_MAX];
+
+ /*
+ * /proc/thread-self was introduced in kernel v3.17
+ */
+ if (snprintf(proc_ns_path, LTTNG_PROC_NS_PATH_MAX,
+ "/proc/thread-self/ns/%s", ns) >= 0) {
+ if (stat(proc_ns_path, &sb) == 0) {
+ *ns_inum = sb.st_ino;
+ ret = 0;
+ }
+ goto end;
+ }
+
+ if (snprintf(proc_ns_path, LTTNG_PROC_NS_PATH_MAX,
+ "/proc/self/task/%d/%s/net", lttng_gettid(), ns) >= 0) {
+ if (stat(proc_ns_path, &sb) == 0) {
+ *ns_inum = sb.st_ino;
+ ret = 0;
+ }
+ goto end;
+ }
+end:
+ return ret;
+}
+
+static int do_the_needful(int ns_flag, const char *ns_str)
+{
+ int ret = 0, i;
+ ino_t ns1, ns2;
+
+ ret = get_ns_inum(ns_str, &ns1);
+ if (ret) {
+ debug_printf("Failed to get ns inode number for namespace %s",
+ ns_str);
+ ret = -1;
+ goto end;
+ }
+ debug_printf("Initial %s ns inode number: %lu\n", ns_str, ns1);
+
+ for (i = 0; nr_iter < 0 || i < nr_iter; i++) {
+ tracepoint(tp, tptest, ns1);
+ if (should_quit) {
+ break;
+ }
+ }
+
+ ret = unshare(ns_flag);
+ if (ret == -1) {
+ perror("Failed to unshare namespace");
+ goto end;
+ }
+
+ ret = get_ns_inum(ns_str, &ns2);
+ if (ret) {
+ debug_printf("Failed to get ns inode number for namespace %s",
+ ns_str);
+ ret = -1;
+ goto end;
+ }
+ debug_printf("Post unshare %s ns inode number: %lu\n", ns_str, ns2);
+
+ /*
+ * Signal that we emited the first event group and that the
+ * unshare call is completed.
+ */
+ if (after_unshare_file_path) {
+ ret = create_file(after_unshare_file_path);
+ if (ret != 0) {
+ goto end;
+ }
+ }
+
+ /* Wait on synchronization before writing second event group. */
+ if (before_second_event_file_path) {
+ ret = wait_on_file(before_second_event_file_path);
+ if (ret != 0) {
+ goto end;
+ }
+ }
+
+ for (i = 0; nr_iter < 0 || i < nr_iter; i++) {
+ tracepoint(tp, tptest, ns2);
+ if (should_quit) {
+ break;
+ }
+ }
+
+end:
+ return ret;
+}
+
+/*
+ * Send X events, change NS, wait for file to sync with test script, send X
+ * events in new NS
+ */
+int main(int argc, const char **argv)
+{
+ int opt;
+ int ret = EXIT_SUCCESS;
+ poptContext pc;
+
+ pc = poptGetContext(NULL, argc, argv, opts, 0);
+ poptReadDefaultConfig(pc, 0);
+
+ if (argc < 2) {
+ poptPrintHelp(pc, stderr, 0);
+ ret = EXIT_FAILURE;
+ goto end;
+ }
+
+ while ((opt = poptGetNextOpt(pc)) >= 0) {
+ switch (opt) {
+ default:
+ poptPrintUsage(pc, stderr, 0);
+ ret = EXIT_FAILURE;
+ goto end;
+ }
+ }
+
+ if (opt < -1) {
+ /* An error occurred during option processing. */
+ poptPrintUsage(pc, stderr, 0);
+ fprintf(stderr, "%s: %s\n",
+ poptBadOption(pc, POPT_BADOPTION_NOALIAS),
+ poptStrerror(opt));
+ ret = EXIT_FAILURE;
+ goto end;
+ }
+
+ if (ns_opt == NULL) {
+ poptPrintUsage(pc, stderr, 0);
+ ret = EXIT_FAILURE;
+ goto end;
+ }
+
+ if (set_signal_handler()) {
+ ret = EXIT_FAILURE;
+ goto end;
+ }
+
+ if (strncmp(ns_opt, "cgroup", 6) == 0) {
+ ret = do_the_needful(CLONE_NEWCGROUP, "cgroup");
+ } else if (strncmp(ns_opt, "ipc", 3) == 0) {
+ ret = do_the_needful(CLONE_NEWIPC, "ipc");
+ } else if (strncmp(ns_opt, "mnt", 3) == 0) {
+ ret = do_the_needful(CLONE_NEWNS, "mnt");
+ } else if (strncmp(ns_opt, "net", 3) == 0) {
+ ret = do_the_needful(CLONE_NEWNET, "net");
+ } else if (strncmp(ns_opt, "pid", 3) == 0) {
+ ret = do_the_needful(CLONE_NEWPID, "pid");
+ } else if (strncmp(ns_opt, "time", 4) == 0) {
+ ret = do_the_needful(CLONE_NEWTIME, "time");
+ } else if (strncmp(ns_opt, "user", 4) == 0) {
+ /*
+ * Will always fail, requires a single threaded application,
+ * which can't happen with UST.
+ */
+ ret = do_the_needful(CLONE_NEWUSER, "user");
+ } else if (strncmp(ns_opt, "uts", 3) == 0) {
+ ret = do_the_needful(CLONE_NEWUTS, "uts");
+ } else {
+ printf("invalid ns id\n");
+ ret = EXIT_FAILURE;
+ goto end;
+ }
+ ret = ret ? EXIT_FAILURE : EXIT_SUCCESS;
+end:
+ poptFreeContext(pc);
+ return ret;
+}
if HAVE_LIBLTTNG_UST_CTL
noinst_PROGRAMS = gen-ust-events
-gen_ust_events_SOURCES = gen-ust-events.c tp.c tp.h
+gen_ust_events_SOURCES = \
+ gen-ust-events.cpp \
+ tp.c \
+ tp.h
gen_ust_events_LDADD = $(UST_LIBS) \
$(top_builddir)/tests/utils/libtestutils.la \
$(DL_LIBS)
+++ /dev/null
-/*
- * Copyright (C) 2012 David Goulet <dgoulet@efficios.com>
- *
- * SPDX-License-Identifier: LGPL-2.1-only
- *
- */
-
-#define _LGPL_SOURCE
-#include <getopt.h>
-#include <arpa/inet.h>
-#include <fcntl.h>
-#include <stdarg.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/mman.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <unistd.h>
-#include <stdbool.h>
-#include <signal.h>
-#include <poll.h>
-#include <errno.h>
-#include "utils.h"
-#include "signal-helper.h"
-
-#define TRACEPOINT_DEFINE
-#include "tp.h"
-
-static struct option long_options[] =
-{
- /* These options set a flag. */
- {"iter", required_argument, 0, 'i'},
- {"wait", required_argument, 0, 'w'},
- {"sync-after-first-event", required_argument, 0, 'a'},
- {"sync-before-last-event", required_argument, 0, 'b'},
- {"sync-before-last-event-touch", required_argument, 0, 'c'},
- {"sync-before-exit", required_argument, 0, 'd'},
- {"sync-before-exit-touch", required_argument, 0, 'e'},
- {"emit-end-event", no_argument, 0, 'f'},
- {0, 0, 0, 0}
-};
-
-int main(int argc, char **argv)
-{
- unsigned int i, netint;
- int option_index;
- int option;
- long values[] = { 1, 2, 3 };
- char text[10] = "test";
- char escape[10] = "\\*";
- double dbl = 2.0;
- float flt = 2222.0;
- uint32_t net_values[] = { 1, 2, 3 };
- int nr_iter = 100, ret = 0, first_event_file_created = 0;
- useconds_t nr_usec = 0;
- char *after_first_event_file_path = NULL;
- char *before_last_event_file_path = NULL;
- /*
- * Touch a file to indicate that all events except one were
- * generated.
- */
- char *before_last_event_file_path_touch = NULL;
- /* Touch file when we are exiting */
- char *before_exit_file_path_touch = NULL;
- /* Wait on file before exiting */
- char *before_exit_file_path = NULL;
- /* Emit an end event */
- bool emit_end_event = false;
-
- for (i = 0; i < 3; i++) {
- net_values[i] = htonl(net_values[i]);
- }
-
- while ((option = getopt_long(argc, argv, "i:w:a:b:c:d:e:f",
- long_options, &option_index)) != -1) {
- switch (option) {
- case 'a':
- after_first_event_file_path = strdup(optarg);
- break;
- case 'b':
- before_last_event_file_path = strdup(optarg);
- break;
- case 'c':
- before_last_event_file_path_touch = strdup(optarg);
- break;
- case 'd':
- before_exit_file_path = strdup(optarg);
- break;
- case 'e':
- before_exit_file_path_touch = strdup(optarg);
- break;
- case 'f':
- emit_end_event = true;
- break;
- case 'i':
- nr_iter = atoi(optarg);
- break;
- case 'w':
- nr_usec = atoi(optarg);
- break;
- case '?':
- /* getopt_long already printed an error message. */
- default:
- ret = -1;
- goto end;
- }
- }
-
- if (optind != argc) {
- fprintf(stderr, "Error: takes long options only.\n");
-
- /*
- * Aborting the test program for now because callers typically don't check
- * the test program return value, and the transition from positional
- * arguments to getopt causes hangs when caller scripts are not updated.
- * An abort is easier to diagnose and fix. This is a temporary solution:
- * we should eventually ensure that all scripts test and report the test
- * app return values.
- */
- abort();
-
- ret = -1;
- goto end;
- }
-
-
- if (set_signal_handler()) {
- ret = -1;
- goto end;
- }
-
- for (i = 0; nr_iter < 0 || i < nr_iter; i++) {
- if (nr_iter >= 0 && i == nr_iter - 1) {
- if (before_last_event_file_path_touch) {
- ret = create_file(before_last_event_file_path_touch);
- if (ret != 0) {
- goto end;
- }
- }
-
- /*
- * Wait on synchronization before writing last
- * event.
- */
- if (before_last_event_file_path) {
- ret = wait_on_file(before_last_event_file_path);
- if (ret != 0) {
- goto end;
- }
- }
- }
- netint = htonl(i);
- tracepoint(tp, tptest, i, netint, values, text,
- strlen(text), escape, net_values, dbl, flt);
-
- /*
- * First loop we create the file if asked to indicate
- * that at least one tracepoint has been hit.
- */
- if (after_first_event_file_path && first_event_file_created == 0) {
- ret = create_file(after_first_event_file_path);
-
- if (ret != 0) {
- goto end;
- } else {
- first_event_file_created = 1;
- }
- }
-
- if (nr_usec) {
- if (usleep_safe(nr_usec)) {
- ret = -1;
- goto end;
- }
- }
- if (should_quit) {
- break;
- }
- }
-
- if (emit_end_event) {
- tracepoint(tp, end);
- }
-
- if (before_exit_file_path_touch) {
- ret = create_file(before_exit_file_path_touch);
- if (ret != 0) {
- goto end;
- }
- }
- if (before_exit_file_path) {
- ret = wait_on_file(before_exit_file_path);
- if (ret != 0) {
- goto end;
- }
- }
-end:
- free(after_first_event_file_path);
- free(before_last_event_file_path);
- free(before_last_event_file_path_touch);
- free(before_exit_file_path);
- free(before_exit_file_path_touch);
- exit(!ret ? EXIT_SUCCESS : EXIT_FAILURE);
-}
--- /dev/null
+/*
+ * Copyright (C) 2012 David Goulet <dgoulet@efficios.com>
+ *
+ * SPDX-License-Identifier: LGPL-2.1-only
+ *
+ */
+
+#define _LGPL_SOURCE
+#include <getopt.h>
+#include <arpa/inet.h>
+#include <fcntl.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <stdbool.h>
+#include <signal.h>
+#include <poll.h>
+#include <errno.h>
+#include "utils.h"
+#include "signal-helper.h"
+
+#define TRACEPOINT_DEFINE
+#include "tp.h"
+
+static struct option long_options[] =
+{
+ /* These options set a flag. */
+ {"iter", required_argument, 0, 'i'},
+ {"wait", required_argument, 0, 'w'},
+ {"sync-after-first-event", required_argument, 0, 'a'},
+ {"sync-before-last-event", required_argument, 0, 'b'},
+ {"sync-before-last-event-touch", required_argument, 0, 'c'},
+ {"sync-before-exit", required_argument, 0, 'd'},
+ {"sync-before-exit-touch", required_argument, 0, 'e'},
+ {"emit-end-event", no_argument, 0, 'f'},
+ {0, 0, 0, 0}
+};
+
+int main(int argc, char **argv)
+{
+ unsigned int i, netint;
+ int option_index;
+ int option;
+ long values[] = { 1, 2, 3 };
+ char text[10] = "test";
+ char escape[10] = "\\*";
+ double dbl = 2.0;
+ float flt = 2222.0;
+ uint32_t net_values[] = { 1, 2, 3 };
+ int nr_iter = 100, ret = 0, first_event_file_created = 0;
+ useconds_t nr_usec = 0;
+ char *after_first_event_file_path = NULL;
+ char *before_last_event_file_path = NULL;
+ /*
+ * Touch a file to indicate that all events except one were
+ * generated.
+ */
+ char *before_last_event_file_path_touch = NULL;
+ /* Touch file when we are exiting */
+ char *before_exit_file_path_touch = NULL;
+ /* Wait on file before exiting */
+ char *before_exit_file_path = NULL;
+ /* Emit an end event */
+ bool emit_end_event = false;
+
+ for (i = 0; i < 3; i++) {
+ net_values[i] = htonl(net_values[i]);
+ }
+
+ while ((option = getopt_long(argc, argv, "i:w:a:b:c:d:e:f",
+ long_options, &option_index)) != -1) {
+ switch (option) {
+ case 'a':
+ after_first_event_file_path = strdup(optarg);
+ break;
+ case 'b':
+ before_last_event_file_path = strdup(optarg);
+ break;
+ case 'c':
+ before_last_event_file_path_touch = strdup(optarg);
+ break;
+ case 'd':
+ before_exit_file_path = strdup(optarg);
+ break;
+ case 'e':
+ before_exit_file_path_touch = strdup(optarg);
+ break;
+ case 'f':
+ emit_end_event = true;
+ break;
+ case 'i':
+ nr_iter = atoi(optarg);
+ break;
+ case 'w':
+ nr_usec = atoi(optarg);
+ break;
+ case '?':
+ /* getopt_long already printed an error message. */
+ default:
+ ret = -1;
+ goto end;
+ }
+ }
+
+ if (optind != argc) {
+ fprintf(stderr, "Error: takes long options only.\n");
+
+ /*
+ * Aborting the test program for now because callers typically don't check
+ * the test program return value, and the transition from positional
+ * arguments to getopt causes hangs when caller scripts are not updated.
+ * An abort is easier to diagnose and fix. This is a temporary solution:
+ * we should eventually ensure that all scripts test and report the test
+ * app return values.
+ */
+ abort();
+
+ ret = -1;
+ goto end;
+ }
+
+
+ if (set_signal_handler()) {
+ ret = -1;
+ goto end;
+ }
+
+ for (i = 0; nr_iter < 0 || i < nr_iter; i++) {
+ if (nr_iter >= 0 && i == nr_iter - 1) {
+ if (before_last_event_file_path_touch) {
+ ret = create_file(before_last_event_file_path_touch);
+ if (ret != 0) {
+ goto end;
+ }
+ }
+
+ /*
+ * Wait on synchronization before writing last
+ * event.
+ */
+ if (before_last_event_file_path) {
+ ret = wait_on_file(before_last_event_file_path);
+ if (ret != 0) {
+ goto end;
+ }
+ }
+ }
+ netint = htonl(i);
+ tracepoint(tp, tptest, i, netint, values, text,
+ strlen(text), escape, net_values, dbl, flt);
+
+ /*
+ * First loop we create the file if asked to indicate
+ * that at least one tracepoint has been hit.
+ */
+ if (after_first_event_file_path && first_event_file_created == 0) {
+ ret = create_file(after_first_event_file_path);
+
+ if (ret != 0) {
+ goto end;
+ } else {
+ first_event_file_created = 1;
+ }
+ }
+
+ if (nr_usec) {
+ if (usleep_safe(nr_usec)) {
+ ret = -1;
+ goto end;
+ }
+ }
+ if (should_quit) {
+ break;
+ }
+ }
+
+ if (emit_end_event) {
+ tracepoint(tp, end);
+ }
+
+ if (before_exit_file_path_touch) {
+ ret = create_file(before_exit_file_path_touch);
+ if (ret != 0) {
+ goto end;
+ }
+ }
+ if (before_exit_file_path) {
+ ret = wait_on_file(before_exit_file_path);
+ if (ret != 0) {
+ goto end;
+ }
+ }
+end:
+ free(after_first_event_file_path);
+ free(before_last_event_file_path);
+ free(before_last_event_file_path_touch);
+ free(before_exit_file_path);
+ free(before_exit_file_path_touch);
+ exit(!ret ? EXIT_SUCCESS : EXIT_FAILURE);
+}
if HAVE_LIBLTTNG_UST_CTL
noinst_PROGRAMS = gen-ust-nevents-str
-gen_ust_nevents_str_SOURCES = gen-ust-nevents-str.c tp.c tp.h
+gen_ust_nevents_str_SOURCES = \
+ gen-ust-nevents-str.cpp \
+ tp.c \
+ tp.h
gen_ust_nevents_str_LDADD = $(UST_LIBS) \
$(top_builddir)/tests/utils/libtestutils.la \
$(DL_LIBS)
+++ /dev/null
-/*
- * Copyright (C) 2017 Philippe Proulx <pproulx@efficios.com>
- *
- * SPDX-License-Identifier: LGPL-2.1-only
- *
- */
-
-#define _LGPL_SOURCE
-#include <stdio.h>
-#include "signal-helper.h"
-
-#define TRACEPOINT_DEFINE
-#include "tp.h"
-
-int main(int argc, char **argv)
-{
- int count = 0, i = 0, arg_i = 0;
-
- if (set_signal_handler()) {
- return 1;
- }
-
- if (argc <= 3) {
- fprintf(stderr, "Usage: %s COUNT STRING [STRING]...\n",
- argv[0]);
- return 1;
- }
-
- if (argc >= 2) {
- count = atoi(argv[1]);
- }
-
- if (count < 0) {
- return 0;
- }
-
- for (i = 0, arg_i = 2; i < count; i++) {
- tracepoint(tp, the_string, i, arg_i, argv[arg_i]);
-
- arg_i++;
- if (arg_i == argc) {
- arg_i = 2;
- }
- if (should_quit) {
- break;
- }
- }
-
- return 0;
-}
--- /dev/null
+/*
+ * Copyright (C) 2017 Philippe Proulx <pproulx@efficios.com>
+ *
+ * SPDX-License-Identifier: LGPL-2.1-only
+ *
+ */
+
+#define _LGPL_SOURCE
+#include <stdio.h>
+#include "signal-helper.h"
+
+#define TRACEPOINT_DEFINE
+#include "tp.h"
+
+int main(int argc, char **argv)
+{
+ int count = 0, i = 0, arg_i = 0;
+
+ if (set_signal_handler()) {
+ return 1;
+ }
+
+ if (argc <= 3) {
+ fprintf(stderr, "Usage: %s COUNT STRING [STRING]...\n",
+ argv[0]);
+ return 1;
+ }
+
+ if (argc >= 2) {
+ count = atoi(argv[1]);
+ }
+
+ if (count < 0) {
+ return 0;
+ }
+
+ for (i = 0, arg_i = 2; i < count; i++) {
+ tracepoint(tp, the_string, i, arg_i, argv[arg_i]);
+
+ arg_i++;
+ if (arg_i == argc) {
+ arg_i = 2;
+ }
+ if (should_quit) {
+ break;
+ }
+ }
+
+ return 0;
+}
if HAVE_LIBLTTNG_UST_CTL
noinst_PROGRAMS = gen-ust-nevents
-gen_ust_nevents_SOURCES = gen-ust-nevents.c tp.c tp.h
+gen_ust_nevents_SOURCES = \
+ gen-ust-nevents.cpp \
+ tp.c \
+ tp.h
gen_ust_nevents_LDADD = $(UST_LIBS) \
$(top_builddir)/tests/utils/libtestutils.la \
$(DL_LIBS)
+++ /dev/null
-/*
- * Copyright (C) 2012 David Goulet <dgoulet@efficios.com>
- *
- * SPDX-License-Identifier: LGPL-2.1-only
- *
- */
-
-#define _LGPL_SOURCE
-#include <arpa/inet.h>
-#include <getopt.h>
-#include <stdarg.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/mman.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <unistd.h>
-#include "utils.h"
-#include "signal-helper.h"
-
-#define TRACEPOINT_DEFINE
-#include "tp.h"
-
-static struct option long_options[] =
-{
- /* These options set a flag. */
- {"iter", required_argument, 0, 'i'},
- {"wait", required_argument, 0, 'w'},
- {"create-in-main", required_argument, 0, 'm'},
- {"wait-before-first-event", required_argument, 0, 'b'},
- {0, 0, 0, 0}
-};
-
-int main(int argc, char **argv)
-{
- int i, netint, ret = 0, option_index, option;
- long values[] = { 1, 2, 3 };
- char text[10] = "test";
- double dbl = 2.0;
- float flt = 2222.0;
- unsigned int nr_iter = 100;
- useconds_t nr_usec = 0;
- char *wait_before_first_event_file_path = NULL;
- char *create_in_main_file_path = NULL;
-
- while ((option = getopt_long(argc, argv, "i:w:b:m:",
- long_options, &option_index)) != -1) {
- switch (option) {
- case 'b':
- wait_before_first_event_file_path = strdup(optarg);
- break;
- case 'm':
- create_in_main_file_path = strdup(optarg);
- break;
- case 'i':
- nr_iter = atoi(optarg);
- break;
- case 'w':
- nr_usec = atoi(optarg);
- break;
- case '?':
- /* getopt_long already printed an error message. */
- default:
- ret = -1;
- goto end;
- }
- }
-
- if (set_signal_handler()) {
- ret = -1;
- goto end;
- }
-
- /*
- * The two following sync points allow for tests to do work after the
- * app has started BUT before it generates any events.
- */
- if (create_in_main_file_path) {
- ret = create_file(create_in_main_file_path);
- if (ret != 0) {
- goto end;
- }
- }
-
- if (wait_before_first_event_file_path) {
- ret = wait_on_file(wait_before_first_event_file_path);
- if (ret != 0) {
- goto end;
- }
- }
-
- for (i = 0; i < nr_iter; i++) {
- netint = htonl(i);
- tracepoint(tp, tptest1, i, netint, values, text, strlen(text),
- dbl, flt);
- tracepoint(tp, tptest2, i, netint, values, text, strlen(text),
- dbl, flt);
- tracepoint(tp, tptest3, i, netint, values, text, strlen(text),
- dbl, flt);
- tracepoint(tp, tptest4, i, netint, values, text, strlen(text),
- dbl, flt);
- tracepoint(tp, tptest5, i, netint, values, text, strlen(text),
- dbl, flt);
- if (nr_usec) {
- if (usleep_safe(nr_usec)) {
- ret = -1;
- goto end;
- }
- }
- if (should_quit) {
- break;
- }
- }
-
-end:
- free(create_in_main_file_path);
- free(wait_before_first_event_file_path);
- exit(!ret ? EXIT_SUCCESS : EXIT_FAILURE);
-}
--- /dev/null
+/*
+ * Copyright (C) 2012 David Goulet <dgoulet@efficios.com>
+ *
+ * SPDX-License-Identifier: LGPL-2.1-only
+ *
+ */
+
+#define _LGPL_SOURCE
+#include <arpa/inet.h>
+#include <getopt.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include "utils.h"
+#include "signal-helper.h"
+
+#define TRACEPOINT_DEFINE
+#include "tp.h"
+
+static struct option long_options[] =
+{
+ /* These options set a flag. */
+ {"iter", required_argument, 0, 'i'},
+ {"wait", required_argument, 0, 'w'},
+ {"create-in-main", required_argument, 0, 'm'},
+ {"wait-before-first-event", required_argument, 0, 'b'},
+ {0, 0, 0, 0}
+};
+
+int main(int argc, char **argv)
+{
+ int i, netint, ret = 0, option_index, option;
+ long values[] = { 1, 2, 3 };
+ char text[10] = "test";
+ double dbl = 2.0;
+ float flt = 2222.0;
+ unsigned int nr_iter = 100;
+ useconds_t nr_usec = 0;
+ char *wait_before_first_event_file_path = NULL;
+ char *create_in_main_file_path = NULL;
+
+ while ((option = getopt_long(argc, argv, "i:w:b:m:",
+ long_options, &option_index)) != -1) {
+ switch (option) {
+ case 'b':
+ wait_before_first_event_file_path = strdup(optarg);
+ break;
+ case 'm':
+ create_in_main_file_path = strdup(optarg);
+ break;
+ case 'i':
+ nr_iter = atoi(optarg);
+ break;
+ case 'w':
+ nr_usec = atoi(optarg);
+ break;
+ case '?':
+ /* getopt_long already printed an error message. */
+ default:
+ ret = -1;
+ goto end;
+ }
+ }
+
+ if (set_signal_handler()) {
+ ret = -1;
+ goto end;
+ }
+
+ /*
+ * The two following sync points allow for tests to do work after the
+ * app has started BUT before it generates any events.
+ */
+ if (create_in_main_file_path) {
+ ret = create_file(create_in_main_file_path);
+ if (ret != 0) {
+ goto end;
+ }
+ }
+
+ if (wait_before_first_event_file_path) {
+ ret = wait_on_file(wait_before_first_event_file_path);
+ if (ret != 0) {
+ goto end;
+ }
+ }
+
+ for (i = 0; i < nr_iter; i++) {
+ netint = htonl(i);
+ tracepoint(tp, tptest1, i, netint, values, text, strlen(text),
+ dbl, flt);
+ tracepoint(tp, tptest2, i, netint, values, text, strlen(text),
+ dbl, flt);
+ tracepoint(tp, tptest3, i, netint, values, text, strlen(text),
+ dbl, flt);
+ tracepoint(tp, tptest4, i, netint, values, text, strlen(text),
+ dbl, flt);
+ tracepoint(tp, tptest5, i, netint, values, text, strlen(text),
+ dbl, flt);
+ if (nr_usec) {
+ if (usleep_safe(nr_usec)) {
+ ret = -1;
+ goto end;
+ }
+ }
+ if (should_quit) {
+ break;
+ }
+ }
+
+end:
+ free(create_in_main_file_path);
+ free(wait_before_first_event_file_path);
+ exit(!ret ? EXIT_SUCCESS : EXIT_FAILURE);
+}
if HAVE_LIBLTTNG_UST_CTL
noinst_PROGRAMS = gen-ust-tracef
-gen_ust_tracef_SOURCES = gen-ust-tracef.c
+gen_ust_tracef_SOURCES = gen-ust-tracef.cpp
gen_ust_tracef_LDADD = $(UST_LIBS) $(DL_LIBS)
endif
+++ /dev/null
-/*
- * Copyright (C) 2012 David Goulet <dgoulet@efficios.com>
- * Copyright (C) 2014 Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
- *
- * SPDX-License-Identifier: LGPL-2.1-only
- *
- */
-
-#define _LGPL_SOURCE
-#include <fcntl.h>
-#include <stdarg.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/mman.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <unistd.h>
-
-#include <common/macros.h>
-#include <lttng/tracef.h>
-#include "signal-helper.h"
-
-const char *str = "test string";
-
-static
-void create_file(const char *path)
-{
- int ret;
-
- LTTNG_ASSERT(path);
-
- ret = creat(path, S_IRWXU);
- if (ret < 0) {
- fprintf(stderr, "Failed to create file %s\n", path);
- return;
- }
-
- (void) close(ret);
-}
-
-int main(int argc, char **argv)
-{
- int i;
- unsigned int nr_iter = 100;
- useconds_t nr_usec = 0;
- char *tmp_file_path = NULL;
-
- if (set_signal_handler()) {
- return 1;
- }
-
- if (argc >= 2) {
- nr_iter = atoi(argv[1]);
- }
-
- if (argc >= 3) {
- /* By default, don't wait unless user specifies. */
- nr_usec = atoi(argv[2]);
- }
-
- if (argc >= 4) {
- tmp_file_path = argv[3];
- }
-
- for (i = 0; i < nr_iter; i++) {
- tracef("Test message %d with string \"%s\"", i, str);
-
- /*
- * First loop we create the file if asked to indicate
- * that at least one tracepoint has been hit.
- */
- if (i == 0 && tmp_file_path) {
- create_file(tmp_file_path);
- }
- usleep(nr_usec);
- if (should_quit) {
- break;
- }
- }
-
- return 0;
-}
--- /dev/null
+/*
+ * Copyright (C) 2012 David Goulet <dgoulet@efficios.com>
+ * Copyright (C) 2014 Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
+ *
+ * SPDX-License-Identifier: LGPL-2.1-only
+ *
+ */
+
+#define _LGPL_SOURCE
+#include <fcntl.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <common/macros.h>
+#include <lttng/tracef.h>
+#include "signal-helper.h"
+
+const char *str = "test string";
+
+static
+void create_file(const char *path)
+{
+ int ret;
+
+ LTTNG_ASSERT(path);
+
+ ret = creat(path, S_IRWXU);
+ if (ret < 0) {
+ fprintf(stderr, "Failed to create file %s\n", path);
+ return;
+ }
+
+ (void) close(ret);
+}
+
+int main(int argc, char **argv)
+{
+ int i;
+ unsigned int nr_iter = 100;
+ useconds_t nr_usec = 0;
+ char *tmp_file_path = NULL;
+
+ if (set_signal_handler()) {
+ return 1;
+ }
+
+ if (argc >= 2) {
+ nr_iter = atoi(argv[1]);
+ }
+
+ if (argc >= 3) {
+ /* By default, don't wait unless user specifies. */
+ nr_usec = atoi(argv[2]);
+ }
+
+ if (argc >= 4) {
+ tmp_file_path = argv[3];
+ }
+
+ for (i = 0; i < nr_iter; i++) {
+ tracef("Test message %d with string \"%s\"", i, str);
+
+ /*
+ * First loop we create the file if asked to indicate
+ * that at least one tracepoint has been hit.
+ */
+ if (i == 0 && tmp_file_path) {
+ create_file(tmp_file_path);
+ }
+ usleep(nr_usec);
+ if (should_quit) {
+ break;
+ }
+ }
+
+ return 0;
+}
int set_signal_handler(void)
{
int ret;
- struct sigaction sa = {
- .sa_flags = 0,
- .sa_handler = sighandler,
- };
+ struct sigaction sa {};
+ sa.sa_flags = 0;
+ sa.sa_handler = sighandler;
ret = sigemptyset(&sa.sa_mask);
if (ret) {
+++ /dev/null
-/*
- * Copyright (C) 2015 Jérémie Galarneau <jeremie.galarneau@efficios.com>
- *
- * SPDX-License-Identifier: LGPL-2.1-only
- *
- */
-
-#include <common/compat/time.h>
-#include <common/time.h>
-#include <fcntl.h>
-#include <poll.h>
-#include <stdbool.h>
-#include <stdint.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <unistd.h>
-
-#include <common/compat/errno.h>
-#include <common/macros.h>
-
-#include "utils.h"
-
-static inline
-int64_t elapsed_time_ns(struct timespec *t1, struct timespec *t2)
-{
- struct timespec delta;
-
- LTTNG_ASSERT(t1 && t2);
- delta.tv_sec = t2->tv_sec - t1->tv_sec;
- delta.tv_nsec = t2->tv_nsec - t1->tv_nsec;
- return ((int64_t) NSEC_PER_SEC * (int64_t) delta.tv_sec) +
- (int64_t) delta.tv_nsec;
-}
-
-int usleep_safe(useconds_t usec)
-{
- int ret = 0;
- struct timespec t1, t2;
- int64_t time_remaining_ns = (int64_t) usec * (int64_t) NSEC_PER_USEC;
-
- ret = lttng_clock_gettime(CLOCK_MONOTONIC, &t1);
- if (ret) {
- ret = -1;
- perror("clock_gettime");
- goto end;
- }
-
- while (time_remaining_ns > 0) {
- ret = usleep(time_remaining_ns / (int64_t) NSEC_PER_USEC);
- if (ret && errno != EINTR) {
- perror("usleep");
- goto end;
- }
-
- ret = lttng_clock_gettime(CLOCK_MONOTONIC, &t2);
- if (ret) {
- perror("clock_gettime");
- goto end;
- }
-
- time_remaining_ns -= elapsed_time_ns(&t1, &t2);
- }
-end:
- return ret;
-}
-
-int create_file(const char *path)
-{
- int ret;
-
- if (!path) {
- return -1;
- }
-
- ret = creat(path, S_IRWXU);
- if (ret < 0) {
- perror("creat");
- return -1;
- }
-
- ret = close(ret);
- if (ret < 0) {
- perror("close");
- return -1;
- }
-
- return 0;
-}
-
-int wait_on_file(const char *path)
-{
- int ret;
- struct stat buf;
-
- if (!path) {
- return -1;
- }
-
- for (;;) {
- ret = stat(path, &buf);
- if (ret == -1 && errno == ENOENT) {
- ret = poll(NULL, 0, 10); /* 10 ms delay */
- /* Should return 0 everytime */
- if (ret) {
- if (ret < 0) {
- perror("perror");
- } else {
- fprintf(stderr,
- "poll return value is larger than zero\n");
- }
- return -1;
- }
- continue; /* retry */
- }
- if (ret) {
- perror("stat");
- return -1;
- }
- break; /* found */
- }
-
- return 0;
-}
--- /dev/null
+/*
+ * Copyright (C) 2015 Jérémie Galarneau <jeremie.galarneau@efficios.com>
+ *
+ * SPDX-License-Identifier: LGPL-2.1-only
+ *
+ */
+
+#include <common/compat/time.h>
+#include <common/time.h>
+#include <fcntl.h>
+#include <poll.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <common/compat/errno.h>
+#include <common/macros.h>
+
+#include "utils.h"
+
+static inline
+int64_t elapsed_time_ns(struct timespec *t1, struct timespec *t2)
+{
+ struct timespec delta;
+
+ LTTNG_ASSERT(t1 && t2);
+ delta.tv_sec = t2->tv_sec - t1->tv_sec;
+ delta.tv_nsec = t2->tv_nsec - t1->tv_nsec;
+ return ((int64_t) NSEC_PER_SEC * (int64_t) delta.tv_sec) +
+ (int64_t) delta.tv_nsec;
+}
+
+int usleep_safe(useconds_t usec)
+{
+ int ret = 0;
+ struct timespec t1, t2;
+ int64_t time_remaining_ns = (int64_t) usec * (int64_t) NSEC_PER_USEC;
+
+ ret = lttng_clock_gettime(CLOCK_MONOTONIC, &t1);
+ if (ret) {
+ ret = -1;
+ perror("clock_gettime");
+ goto end;
+ }
+
+ while (time_remaining_ns > 0) {
+ ret = usleep(time_remaining_ns / (int64_t) NSEC_PER_USEC);
+ if (ret && errno != EINTR) {
+ perror("usleep");
+ goto end;
+ }
+
+ ret = lttng_clock_gettime(CLOCK_MONOTONIC, &t2);
+ if (ret) {
+ perror("clock_gettime");
+ goto end;
+ }
+
+ time_remaining_ns -= elapsed_time_ns(&t1, &t2);
+ }
+end:
+ return ret;
+}
+
+int create_file(const char *path)
+{
+ int ret;
+
+ if (!path) {
+ return -1;
+ }
+
+ ret = creat(path, S_IRWXU);
+ if (ret < 0) {
+ perror("creat");
+ return -1;
+ }
+
+ ret = close(ret);
+ if (ret < 0) {
+ perror("close");
+ return -1;
+ }
+
+ return 0;
+}
+
+int wait_on_file(const char *path)
+{
+ int ret;
+ struct stat buf;
+
+ if (!path) {
+ return -1;
+ }
+
+ for (;;) {
+ ret = stat(path, &buf);
+ if (ret == -1 && errno == ENOENT) {
+ ret = poll(NULL, 0, 10); /* 10 ms delay */
+ /* Should return 0 everytime */
+ if (ret) {
+ if (ret < 0) {
+ perror("perror");
+ } else {
+ fprintf(stderr,
+ "poll return value is larger than zero\n");
+ }
+ return -1;
+ }
+ continue; /* retry */
+ }
+ if (ret) {
+ perror("stat");
+ return -1;
+ }
+ break; /* found */
+ }
+
+ return 0;
+}
#ifndef TEST_UTILS_H
#define TEST_UTILS_H
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
#if !defined(__GLIBC__) || ((_POSIX_C_SOURCE >= 200112L || _XOPEN_SOURCE >= 600) && !defined(_GNU_SOURCE))
/*
int create_file(const char *path);
int wait_on_file(const char *path);
+#if defined(__cplusplus)
+}
+#endif
+
#endif /* TEST_UTILS_H */
# SPDX-License-Identifier: GPL-2.0-only
noinst_PROGRAMS = validate_xml extract_xml pretty_xml
-validate_xml_SOURCES = validate_xml.c
+validate_xml_SOURCES = validate_xml.cpp
validate_xml_CPPFLAGS = $(libxml2_CFLAGS) $(AM_CPPFLAGS)
validate_xml_LDADD = $(libxml2_LIBS)
-extract_xml_SOURCES = extract_xml.c
+extract_xml_SOURCES = extract_xml.cpp
extract_xml_CPPFLAGS = $(libxml2_CFLAGS) $(AM_CPPFLAGS)
extract_xml_LDADD = $(libxml2_LIBS)
+++ /dev/null
-/*
- * Copyright (C) 2014 Jonathan Rajotte <jonathan.r.julien@gmail.com>
- *
- * SPDX-License-Identifier: GPL-2.0-only
- *
- */
-
-/*
- * Usage: extract_xml [-v|-e] xml_path xpath_expression
- * Evaluate XPath expression and prints result node set.
- * args[1] path to the xml file
- * args[2] xpath expression to extract
- * If -e look if node exist return "true" else nothing
- * If -v is set the name of the node will appear with his value delimited by
- * a semicolon(;)
- * Ex:
- * Command:extract_xml ../file.xml /test/node/text()
- * Output:
- * a
- * b
- * c
- * With -v
- * node;a;
- * node;b;
- * node;c;
- */
-#include <stdbool.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-
-#include <libxml/tree.h>
-#include <libxml/parser.h>
-#include <libxml/xpath.h>
-#include <libxml/xpathInternals.h>
-#include <common/defaults.h>
-
-#if defined(LIBXML_XPATH_ENABLED)
-
-static int opt_verbose;
-static int node_exist;
-static bool result = false;
-
-/**
- * print_xpath_nodes:
- * nodes: the nodes set.
- * output: the output file handle.
- *
- * Print the node content to the file
- */
-static int print_xpath_nodes(xmlDocPtr doc, xmlNodeSetPtr nodes, FILE *output)
-{
- int ret = 0;
- int size;
- int i;
-
- xmlNodePtr cur;
- xmlChar *node_child_value_string = NULL;
-
- LTTNG_ASSERT(output);
- size = (nodes) ? nodes->nodeNr : 0;
-
- for (i = 0; i < size; ++i) {
- LTTNG_ASSERT(nodes->nodeTab[i]);
-
- if (nodes->nodeTab[i]->type == XML_NAMESPACE_DECL) {
- fprintf(stderr, "ERR:%s\n",
- "This executable does not support xml namespacing\n");
- ret = -1;
- goto end;
- } else if (nodes->nodeTab[i]->type == XML_ELEMENT_NODE) {
- cur = nodes->nodeTab[i];
-
- if (xmlChildElementCount(cur) == 0) {
- if (xmlNodeIsText(cur->children)) {
- node_child_value_string = xmlNodeListGetString(doc,
- cur->children, 1);
- if (node_exist) {
- result = true;
- } else if (opt_verbose) {
- fprintf(output, "%s;%s;\n", cur->name,
- node_child_value_string);
- } else {
- fprintf(output, "%s\n",
- node_child_value_string);
- }
- xmlFree(node_child_value_string);
- } else {
- /* We don't want to print non-final element */
- if (node_exist) {
- result = true;
- } else {
- fprintf(stderr, "ERR:%s\n",
- "Xpath expression return non-final xml element");
- ret = -1;
- goto end;
- }
- }
- } else {
- if (node_exist) {
- result = true;
- } else {
- /* We don't want to print non-final element */
- fprintf(stderr, "ERR:%s\n",
- "Xpath expression return non-final xml element");
- ret = -1;
- goto end;
- }
- }
-
- } else {
- cur = nodes->nodeTab[i];
- if (node_exist) {
- result = true;
- } else if (opt_verbose) {
- fprintf(output, "%s;%s;\n", cur->parent->name, cur->content);
- } else {
- fprintf(output, "%s\n", cur->content);
- }
- }
- }
- /* Command Success */
- ret = 0;
-
-end:
- return ret;
-}
-
-static int register_lttng_namespace(xmlXPathContextPtr xpathCtx)
-{
- int ret;
- xmlChar *prefix;
- xmlChar *ns = NULL;
-
- prefix = xmlCharStrdup("lttng");
- if (!prefix) {
- ret = -1;
- goto end;
- }
-
- ns = xmlCharStrdup(DEFAULT_LTTNG_MI_NAMESPACE);
- if (!ns) {
- ret = -1;
- goto end;
- }
-
- ret = xmlXPathRegisterNs(xpathCtx, prefix, ns);
-end:
- xmlFree(prefix);
- xmlFree(ns);
- return ret;
-}
-
-/*
- * Extract element corresponding to xpath
- * xml_path The path to the xml file
- * xpath: The xpath to evaluate.
- *
- * Evaluate an xpath expression onto an xml file.
- * and print the result one by line.
- *
- * Returns 0 on success and a negative value otherwise.
- */
-static int extract_xpath(const char *xml_path, const xmlChar *xpath)
-{
- int ret;
- xmlDocPtr doc = NULL;
- xmlXPathContextPtr xpathCtx = NULL;
- xmlXPathObjectPtr xpathObj = NULL;
-
- LTTNG_ASSERT(xml_path);
- LTTNG_ASSERT(xpath);
-
- /* Parse the xml file */
- doc = xmlParseFile(xml_path);
- if (!doc) {
- fprintf(stderr, "ERR parsing: xml file invalid \"%s\"\n", xml_path);
- return -1;
- }
-
- /* Initialize a xpath context */
- xpathCtx = xmlXPathNewContext(doc);
- if (!xpathCtx) {
- fprintf(stderr, "ERR: XPath context invalid\n");
- xmlFreeDoc(doc);
- return -1;
- }
-
- /* Register the LTTng MI namespace */
- ret = register_lttng_namespace(xpathCtx);
- if (ret) {
- fprintf(stderr, "ERR: Could not register lttng namespace\n");
- xmlXPathFreeContext(xpathCtx);
- xmlFreeDoc(doc);
- return -1;
- }
-
- /* Evaluate xpath expression */
- xpathObj = xmlXPathEvalExpression(xpath, xpathCtx);
- if (!xpathObj) {
- fprintf(stderr, "ERR: invalid xpath expression \"%s\"\n", xpath);
- xmlXPathFreeContext(xpathCtx);
- xmlFreeDoc(doc);
- return -1;
- }
-
- /* Print results */
- if (print_xpath_nodes(doc, xpathObj->nodesetval, stdout)) {
- xmlXPathFreeObject(xpathObj);
- xmlXPathFreeContext(xpathCtx);
- xmlFreeDoc(doc);
- return -1;
- }
- if (node_exist && result) {
- fprintf(stdout, "true\n");
- }
-
- /* Cleanup */
- xmlXPathFreeObject(xpathObj);
- xmlXPathFreeContext(xpathCtx);
- xmlFreeDoc(doc);
-
- return 0;
-}
-
-int main(int argc, char **argv)
-{
- int opt;
-
- /* Parse command line and process file */
- while ((opt = getopt(argc, argv, "ve")) != -1) {
- switch (opt) {
- case 'v':
- opt_verbose = 1;
- break;
- case 'e':
- node_exist = 1;
- break;
- default:
- abort();
- }
- }
-
- if (!(optind + 1 < argc)) {
- fprintf(stderr, "ERR:%s\n", "Arguments missing");
- return -1;
- }
-
- /* Init libxml */
- xmlInitParser();
- xmlKeepBlanksDefault(0);
- if (access(argv[optind], F_OK)) {
- fprintf(stderr, "ERR:%s\n", "Xml path not valid");
- return -1;
- }
- /* Do the main job */
- if (extract_xpath(argv[optind], (xmlChar *)argv[optind+1])) {
- return -1;
- }
-
- /* Shutdown libxml */
- xmlCleanupParser();
-
- return 0;
-}
-
-#else
-int main(void)
-{
- fprintf(stderr, "XPath support not compiled in\n");
- return -1;
-}
-#endif
--- /dev/null
+/*
+ * Copyright (C) 2014 Jonathan Rajotte <jonathan.r.julien@gmail.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0-only
+ *
+ */
+
+/*
+ * Usage: extract_xml [-v|-e] xml_path xpath_expression
+ * Evaluate XPath expression and prints result node set.
+ * args[1] path to the xml file
+ * args[2] xpath expression to extract
+ * If -e look if node exist return "true" else nothing
+ * If -v is set the name of the node will appear with his value delimited by
+ * a semicolon(;)
+ * Ex:
+ * Command:extract_xml ../file.xml /test/node/text()
+ * Output:
+ * a
+ * b
+ * c
+ * With -v
+ * node;a;
+ * node;b;
+ * node;c;
+ */
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <libxml/tree.h>
+#include <libxml/parser.h>
+#include <libxml/xpath.h>
+#include <libxml/xpathInternals.h>
+#include <common/defaults.h>
+
+#if defined(LIBXML_XPATH_ENABLED)
+
+static int opt_verbose;
+static int node_exist;
+static bool result = false;
+
+/**
+ * print_xpath_nodes:
+ * nodes: the nodes set.
+ * output: the output file handle.
+ *
+ * Print the node content to the file
+ */
+static int print_xpath_nodes(xmlDocPtr doc, xmlNodeSetPtr nodes, FILE *output)
+{
+ int ret = 0;
+ int size;
+ int i;
+
+ xmlNodePtr cur;
+ xmlChar *node_child_value_string = NULL;
+
+ LTTNG_ASSERT(output);
+ size = (nodes) ? nodes->nodeNr : 0;
+
+ for (i = 0; i < size; ++i) {
+ LTTNG_ASSERT(nodes->nodeTab[i]);
+
+ if (nodes->nodeTab[i]->type == XML_NAMESPACE_DECL) {
+ fprintf(stderr, "ERR:%s\n",
+ "This executable does not support xml namespacing\n");
+ ret = -1;
+ goto end;
+ } else if (nodes->nodeTab[i]->type == XML_ELEMENT_NODE) {
+ cur = nodes->nodeTab[i];
+
+ if (xmlChildElementCount(cur) == 0) {
+ if (xmlNodeIsText(cur->children)) {
+ node_child_value_string = xmlNodeListGetString(doc,
+ cur->children, 1);
+ if (node_exist) {
+ result = true;
+ } else if (opt_verbose) {
+ fprintf(output, "%s;%s;\n", cur->name,
+ node_child_value_string);
+ } else {
+ fprintf(output, "%s\n",
+ node_child_value_string);
+ }
+ xmlFree(node_child_value_string);
+ } else {
+ /* We don't want to print non-final element */
+ if (node_exist) {
+ result = true;
+ } else {
+ fprintf(stderr, "ERR:%s\n",
+ "Xpath expression return non-final xml element");
+ ret = -1;
+ goto end;
+ }
+ }
+ } else {
+ if (node_exist) {
+ result = true;
+ } else {
+ /* We don't want to print non-final element */
+ fprintf(stderr, "ERR:%s\n",
+ "Xpath expression return non-final xml element");
+ ret = -1;
+ goto end;
+ }
+ }
+
+ } else {
+ cur = nodes->nodeTab[i];
+ if (node_exist) {
+ result = true;
+ } else if (opt_verbose) {
+ fprintf(output, "%s;%s;\n", cur->parent->name, cur->content);
+ } else {
+ fprintf(output, "%s\n", cur->content);
+ }
+ }
+ }
+ /* Command Success */
+ ret = 0;
+
+end:
+ return ret;
+}
+
+static int register_lttng_namespace(xmlXPathContextPtr xpathCtx)
+{
+ int ret;
+ xmlChar *prefix;
+ xmlChar *ns = NULL;
+
+ prefix = xmlCharStrdup("lttng");
+ if (!prefix) {
+ ret = -1;
+ goto end;
+ }
+
+ ns = xmlCharStrdup(DEFAULT_LTTNG_MI_NAMESPACE);
+ if (!ns) {
+ ret = -1;
+ goto end;
+ }
+
+ ret = xmlXPathRegisterNs(xpathCtx, prefix, ns);
+end:
+ xmlFree(prefix);
+ xmlFree(ns);
+ return ret;
+}
+
+/*
+ * Extract element corresponding to xpath
+ * xml_path The path to the xml file
+ * xpath: The xpath to evaluate.
+ *
+ * Evaluate an xpath expression onto an xml file.
+ * and print the result one by line.
+ *
+ * Returns 0 on success and a negative value otherwise.
+ */
+static int extract_xpath(const char *xml_path, const xmlChar *xpath)
+{
+ int ret;
+ xmlDocPtr doc = NULL;
+ xmlXPathContextPtr xpathCtx = NULL;
+ xmlXPathObjectPtr xpathObj = NULL;
+
+ LTTNG_ASSERT(xml_path);
+ LTTNG_ASSERT(xpath);
+
+ /* Parse the xml file */
+ doc = xmlParseFile(xml_path);
+ if (!doc) {
+ fprintf(stderr, "ERR parsing: xml file invalid \"%s\"\n", xml_path);
+ return -1;
+ }
+
+ /* Initialize a xpath context */
+ xpathCtx = xmlXPathNewContext(doc);
+ if (!xpathCtx) {
+ fprintf(stderr, "ERR: XPath context invalid\n");
+ xmlFreeDoc(doc);
+ return -1;
+ }
+
+ /* Register the LTTng MI namespace */
+ ret = register_lttng_namespace(xpathCtx);
+ if (ret) {
+ fprintf(stderr, "ERR: Could not register lttng namespace\n");
+ xmlXPathFreeContext(xpathCtx);
+ xmlFreeDoc(doc);
+ return -1;
+ }
+
+ /* Evaluate xpath expression */
+ xpathObj = xmlXPathEvalExpression(xpath, xpathCtx);
+ if (!xpathObj) {
+ fprintf(stderr, "ERR: invalid xpath expression \"%s\"\n", xpath);
+ xmlXPathFreeContext(xpathCtx);
+ xmlFreeDoc(doc);
+ return -1;
+ }
+
+ /* Print results */
+ if (print_xpath_nodes(doc, xpathObj->nodesetval, stdout)) {
+ xmlXPathFreeObject(xpathObj);
+ xmlXPathFreeContext(xpathCtx);
+ xmlFreeDoc(doc);
+ return -1;
+ }
+ if (node_exist && result) {
+ fprintf(stdout, "true\n");
+ }
+
+ /* Cleanup */
+ xmlXPathFreeObject(xpathObj);
+ xmlXPathFreeContext(xpathCtx);
+ xmlFreeDoc(doc);
+
+ return 0;
+}
+
+int main(int argc, char **argv)
+{
+ int opt;
+
+ /* Parse command line and process file */
+ while ((opt = getopt(argc, argv, "ve")) != -1) {
+ switch (opt) {
+ case 'v':
+ opt_verbose = 1;
+ break;
+ case 'e':
+ node_exist = 1;
+ break;
+ default:
+ abort();
+ }
+ }
+
+ if (!(optind + 1 < argc)) {
+ fprintf(stderr, "ERR:%s\n", "Arguments missing");
+ return -1;
+ }
+
+ /* Init libxml */
+ xmlInitParser();
+ xmlKeepBlanksDefault(0);
+ if (access(argv[optind], F_OK)) {
+ fprintf(stderr, "ERR:%s\n", "Xml path not valid");
+ return -1;
+ }
+ /* Do the main job */
+ if (extract_xpath(argv[optind], (xmlChar *)argv[optind+1])) {
+ return -1;
+ }
+
+ /* Shutdown libxml */
+ xmlCleanupParser();
+
+ return 0;
+}
+
+#else
+int main(void)
+{
+ fprintf(stderr, "XPath support not compiled in\n");
+ return -1;
+}
+#endif
+++ /dev/null
-/*
- * Copyright (C) 2014 Jonathan Rajotte <jonathan.r.julien@gmail.com>
- *
- * SPDX-License-Identifier: LGPL-2.1-only
- *
- */
-
- /*
- * This script validate and xml from an xsd.
- * argv[1] Path of the xsd
- * argv[2] Path to the XML to be validated
- */
-
-#include <ctype.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <inttypes.h>
-#include <dirent.h>
-#include <unistd.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-
-#include <libxml/xmlschemas.h>
-#include <libxml/parser.h>
-
-#include <lttng/lttng-error.h>
-#include <common/macros.h>
-
-struct validation_ctx {
- xmlSchemaParserCtxtPtr parser_ctx;
- xmlSchemaPtr schema;
- xmlSchemaValidCtxtPtr schema_validation_ctx;
-};
-
-enum command_err_code {
- CMD_SUCCESS = 0,
- CMD_ERROR
-};
-
-static
-void xml_error_handler(void *ctx, const char *format, ...)
-{
- char *err_msg;
- va_list args;
- int ret;
-
- va_start(args, format);
- ret = vasprintf(&err_msg, format, args);
- va_end(args);
- if (ret == -1) {
- fprintf(stderr, "ERR: %s\n",
- "String allocation failed in xml error handle");
- return;
- }
-
- fprintf(stderr, "XML Error: %s\n", err_msg);
- free(err_msg);
-}
-
-static
-void fini_validation_ctx(
- struct validation_ctx *ctx)
-{
- if (ctx->parser_ctx) {
- xmlSchemaFreeParserCtxt(ctx->parser_ctx);
- }
-
- if (ctx->schema) {
- xmlSchemaFree(ctx->schema);
- }
-
- if (ctx->schema_validation_ctx) {
- xmlSchemaFreeValidCtxt(ctx->schema_validation_ctx);
- }
-
- memset(ctx, 0, sizeof(struct validation_ctx));
-}
-
-static
-int init_validation_ctx(
- struct validation_ctx *ctx, char *xsd_path)
-{
- int ret;
-
- if (!xsd_path) {
- ret = -LTTNG_ERR_NOMEM;
- goto end;
- }
-
- ctx->parser_ctx = xmlSchemaNewParserCtxt(xsd_path);
- if (!ctx->parser_ctx) {
- ret = -LTTNG_ERR_LOAD_INVALID_CONFIG;
- goto end;
- }
- xmlSchemaSetParserErrors(ctx->parser_ctx, xml_error_handler,
- xml_error_handler, NULL);
-
- ctx->schema = xmlSchemaParse(ctx->parser_ctx);
- if (!ctx->schema) {
- ret = -LTTNG_ERR_LOAD_INVALID_CONFIG;
- goto end;
- }
-
- ctx->schema_validation_ctx = xmlSchemaNewValidCtxt(ctx->schema);
- if (!ctx->schema_validation_ctx) {
- ret = -LTTNG_ERR_LOAD_INVALID_CONFIG;
- goto end;
- }
-
- xmlSchemaSetValidErrors(ctx->schema_validation_ctx, xml_error_handler,
- xml_error_handler, NULL);
- ret = 0;
-
-end:
- if (ret) {
- fini_validation_ctx(ctx);
- }
- return ret;
-}
-
-static int validate_xml(const char *xml_file_path, struct validation_ctx *ctx)
-{
- int ret;
- xmlDocPtr doc = NULL;
-
- LTTNG_ASSERT(xml_file_path);
- LTTNG_ASSERT(ctx);
-
- /* Open the document */
- doc = xmlParseFile(xml_file_path);
- if (!doc) {
- ret = LTTNG_ERR_MI_IO_FAIL;
- goto end;
- }
-
- /* Validate against the validation ctx (xsd) */
- ret = xmlSchemaValidateDoc(ctx->schema_validation_ctx, doc);
- if (ret) {
- fprintf(stderr, "ERR: %s\n", "XML is not valid againt provided XSD");
- ret = CMD_ERROR;
- goto end;
- }
-
- ret = CMD_SUCCESS;
-end:
- return ret;
-
-
-}
-int main(int argc, char **argv, char *env[])
-{
- int ret;
- struct validation_ctx ctx = { 0 };
-
- /* Check if we have all argument */
- if (argc < 3) {
- fprintf(stderr, "ERR: %s\n", "Missing arguments");
- ret = CMD_ERROR;
- goto end;
- }
-
- /* Check if xsd file exist */
- ret = access(argv[1], F_OK);
- if (ret < 0) {
- fprintf(stderr, "ERR: %s\n", "Xsd path not valid");
- goto end;
- }
-
- /* Check if xml to validate exist */
- ret = access(argv[2], F_OK);
- if (ret < 0) {
- fprintf(stderr, "ERR: %s\n", "XML path not valid");
- goto end;
- }
-
- /* initialize the validation ctx */
- ret = init_validation_ctx(&ctx, argv[1]);
- if (ret) {
- goto end;
- }
-
- ret = validate_xml(argv[2], &ctx);
-
- fini_validation_ctx(&ctx);
-
-end:
- return ret;
-}
--- /dev/null
+/*
+ * Copyright (C) 2014 Jonathan Rajotte <jonathan.r.julien@gmail.com>
+ *
+ * SPDX-License-Identifier: LGPL-2.1-only
+ *
+ */
+
+ /*
+ * This script validate and xml from an xsd.
+ * argv[1] Path of the xsd
+ * argv[2] Path to the XML to be validated
+ */
+
+#include <ctype.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <inttypes.h>
+#include <dirent.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include <libxml/xmlschemas.h>
+#include <libxml/parser.h>
+
+#include <lttng/lttng-error.h>
+#include <common/macros.h>
+
+struct validation_ctx {
+ xmlSchemaParserCtxtPtr parser_ctx;
+ xmlSchemaPtr schema;
+ xmlSchemaValidCtxtPtr schema_validation_ctx;
+};
+
+enum command_err_code {
+ CMD_SUCCESS = 0,
+ CMD_ERROR
+};
+
+static
+void xml_error_handler(void *ctx, const char *format, ...)
+{
+ char *err_msg;
+ va_list args;
+ int ret;
+
+ va_start(args, format);
+ ret = vasprintf(&err_msg, format, args);
+ va_end(args);
+ if (ret == -1) {
+ fprintf(stderr, "ERR: %s\n",
+ "String allocation failed in xml error handle");
+ return;
+ }
+
+ fprintf(stderr, "XML Error: %s\n", err_msg);
+ free(err_msg);
+}
+
+static
+void fini_validation_ctx(
+ struct validation_ctx *ctx)
+{
+ if (ctx->parser_ctx) {
+ xmlSchemaFreeParserCtxt(ctx->parser_ctx);
+ }
+
+ if (ctx->schema) {
+ xmlSchemaFree(ctx->schema);
+ }
+
+ if (ctx->schema_validation_ctx) {
+ xmlSchemaFreeValidCtxt(ctx->schema_validation_ctx);
+ }
+
+ memset(ctx, 0, sizeof(struct validation_ctx));
+}
+
+static
+int init_validation_ctx(
+ struct validation_ctx *ctx, char *xsd_path)
+{
+ int ret;
+
+ if (!xsd_path) {
+ ret = -LTTNG_ERR_NOMEM;
+ goto end;
+ }
+
+ ctx->parser_ctx = xmlSchemaNewParserCtxt(xsd_path);
+ if (!ctx->parser_ctx) {
+ ret = -LTTNG_ERR_LOAD_INVALID_CONFIG;
+ goto end;
+ }
+ xmlSchemaSetParserErrors(ctx->parser_ctx, xml_error_handler,
+ xml_error_handler, NULL);
+
+ ctx->schema = xmlSchemaParse(ctx->parser_ctx);
+ if (!ctx->schema) {
+ ret = -LTTNG_ERR_LOAD_INVALID_CONFIG;
+ goto end;
+ }
+
+ ctx->schema_validation_ctx = xmlSchemaNewValidCtxt(ctx->schema);
+ if (!ctx->schema_validation_ctx) {
+ ret = -LTTNG_ERR_LOAD_INVALID_CONFIG;
+ goto end;
+ }
+
+ xmlSchemaSetValidErrors(ctx->schema_validation_ctx, xml_error_handler,
+ xml_error_handler, NULL);
+ ret = 0;
+
+end:
+ if (ret) {
+ fini_validation_ctx(ctx);
+ }
+ return ret;
+}
+
+static int validate_xml(const char *xml_file_path, struct validation_ctx *ctx)
+{
+ int ret;
+ xmlDocPtr doc = NULL;
+
+ LTTNG_ASSERT(xml_file_path);
+ LTTNG_ASSERT(ctx);
+
+ /* Open the document */
+ doc = xmlParseFile(xml_file_path);
+ if (!doc) {
+ ret = LTTNG_ERR_MI_IO_FAIL;
+ goto end;
+ }
+
+ /* Validate against the validation ctx (xsd) */
+ ret = xmlSchemaValidateDoc(ctx->schema_validation_ctx, doc);
+ if (ret) {
+ fprintf(stderr, "ERR: %s\n", "XML is not valid againt provided XSD");
+ ret = CMD_ERROR;
+ goto end;
+ }
+
+ ret = CMD_SUCCESS;
+end:
+ return ret;
+
+
+}
+int main(int argc, char **argv, char *env[])
+{
+ int ret;
+ struct validation_ctx ctx = { 0 };
+
+ /* Check if we have all argument */
+ if (argc < 3) {
+ fprintf(stderr, "ERR: %s\n", "Missing arguments");
+ ret = CMD_ERROR;
+ goto end;
+ }
+
+ /* Check if xsd file exist */
+ ret = access(argv[1], F_OK);
+ if (ret < 0) {
+ fprintf(stderr, "ERR: %s\n", "Xsd path not valid");
+ goto end;
+ }
+
+ /* Check if xml to validate exist */
+ ret = access(argv[2], F_OK);
+ if (ret < 0) {
+ fprintf(stderr, "ERR: %s\n", "XML path not valid");
+ goto end;
+ }
+
+ /* initialize the validation ctx */
+ ret = init_validation_ctx(&ctx, argv[1]);
+ if (ret) {
+ goto end;
+ }
+
+ ret = validate_xml(argv[2], &ctx);
+
+ fini_validation_ctx(&ctx);
+
+end:
+ return ret;
+}