/*
* Copyright (C) 2011 David Goulet <david.goulet@polymtl.ca>
* Copyright (C) 2015 Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
+ * Copyright (C) 2020 Jérémie Galarneau <jeremie.galarneau@efficios.com>
*
* SPDX-License-Identifier: GPL-2.0-only
*
#include <urcu/list.h>
+#include <common/dynamic-array.h>
#include <common/mi-lttng.h>
+#include <common/optional.h>
+#include <common/dynamic-buffer.h>
+#include <common/tracker.h>
+
+#include <lttng/lttng.h>
#include "../command.h"
+struct process_attr_command_args {
+ enum lttng_process_attr process_attr;
+ /* Present in the user's command. */
+ bool requested;
+ bool all;
+ struct lttng_dynamic_pointer_array string_args;
+};
+
enum cmd_type {
CMD_TRACK,
CMD_UNTRACK,
};
-enum tracker_type_state {
- STATE_NONE = 0,
- STATE_PID,
- STATE_VPID,
- STATE_UID,
- STATE_VUID,
- STATE_GID,
- STATE_VGID,
-};
-
-struct opt_type {
- int used;
- int all;
- char *string;
-};
-
-struct id_list {
- size_t nr;
- struct lttng_tracker_id **array;
-};
-
-static char *opt_session_name;
-static int opt_kernel;
-static int opt_userspace;
-
-static struct opt_type opt_pid, opt_vpid, opt_uid, opt_vuid, opt_gid, opt_vgid;
-
-static enum tracker_type_state type_state;
-
+/* Offset OPT_ values by one since libpopt gives '0' a special meaning. */
enum {
- OPT_HELP = 1,
+ OPT_PID = LTTNG_PROCESS_ATTR_PROCESS_ID + 1,
+ OPT_VPID = LTTNG_PROCESS_ATTR_VIRTUAL_PROCESS_ID + 1,
+ OPT_UID = LTTNG_PROCESS_ATTR_USER_ID + 1,
+ OPT_VUID = LTTNG_PROCESS_ATTR_VIRTUAL_USER_ID + 1,
+ OPT_GID = LTTNG_PROCESS_ATTR_GROUP_ID + 1,
+ OPT_VGID = LTTNG_PROCESS_ATTR_VIRTUAL_GROUP_ID + 1,
+ OPT_HELP,
OPT_LIST_OPTIONS,
OPT_SESSION,
- OPT_PID,
- OPT_VPID,
- OPT_UID,
- OPT_VUID,
- OPT_GID,
- OPT_VGID,
OPT_ALL,
};
+static char *opt_session_name;
+static int opt_kernel;
+static int opt_userspace;
+static char *opt_str_arg;
+
static struct poptOption long_options[] = {
/* { longName, shortName, argInfo, argPtr, value, descrip, argDesc, } */
{ "help", 'h', POPT_ARG_NONE, 0, OPT_HELP, 0, 0, },
{ "session", 's', POPT_ARG_STRING, &opt_session_name, OPT_SESSION, 0, 0, },
{ "kernel", 'k', POPT_ARG_VAL, &opt_kernel, 1, 0, 0, },
{ "userspace", 'u', POPT_ARG_VAL, &opt_userspace, 1, 0, 0, },
- { "pid", 'p', POPT_ARG_STRING | POPT_ARGFLAG_OPTIONAL, &opt_pid.string, OPT_PID, 0, 0, },
- { "vpid", 0, POPT_ARG_STRING | POPT_ARGFLAG_OPTIONAL, &opt_vpid.string, OPT_VPID, 0, 0, },
- { "uid", 0, POPT_ARG_STRING | POPT_ARGFLAG_OPTIONAL, &opt_uid.string, OPT_UID, 0, 0, },
- { "vuid", 0, POPT_ARG_STRING | POPT_ARGFLAG_OPTIONAL, &opt_vuid.string, OPT_VUID, 0, 0, },
- { "gid", 0, POPT_ARG_STRING | POPT_ARGFLAG_OPTIONAL, &opt_gid.string, OPT_GID, 0, 0, },
- { "vgid", 0, POPT_ARG_STRING | POPT_ARGFLAG_OPTIONAL, &opt_vgid.string, OPT_VGID, 0, 0, },
+ { "pid", 'p', POPT_ARG_STRING | POPT_ARGFLAG_OPTIONAL, &opt_str_arg, OPT_PID, 0, 0, },
+ { "vpid", 0, POPT_ARG_STRING | POPT_ARGFLAG_OPTIONAL, &opt_str_arg, OPT_VPID, 0, 0, },
+ { "uid", 0, POPT_ARG_STRING | POPT_ARGFLAG_OPTIONAL, &opt_str_arg, OPT_UID, 0, 0, },
+ { "vuid", 0, POPT_ARG_STRING | POPT_ARGFLAG_OPTIONAL, &opt_str_arg, OPT_VUID, 0, 0, },
+ { "gid", 0, POPT_ARG_STRING | POPT_ARGFLAG_OPTIONAL, &opt_str_arg, OPT_GID, 0, 0, },
+ { "vgid", 0, POPT_ARG_STRING | POPT_ARGFLAG_OPTIONAL, &opt_str_arg, OPT_VGID, 0, 0, },
{ "all", 'a', POPT_ARG_NONE, 0, OPT_ALL, 0, 0, },
{ "list-options", 0, POPT_ARG_NONE, NULL, OPT_LIST_OPTIONS, 0, 0, },
{ 0, 0, 0, 0, 0, 0, 0, },
};
-static struct id_list *alloc_id_list(size_t nr_items)
-{
- struct id_list *id_list;
- struct lttng_tracker_id **items;
-
- id_list = zmalloc(sizeof(*id_list));
- if (!id_list) {
- goto error;
- }
- items = zmalloc(nr_items * sizeof(*items));
- if (!items) {
- goto error;
- }
- id_list->nr = nr_items;
- id_list->array = items;
- return id_list;
-error:
- free(id_list);
- return NULL;
-}
+static struct process_attr_command_args
+ process_attr_commands[LTTNG_PROCESS_ATTR_VIRTUAL_GROUP_ID + 1];
-static void free_id_list(struct id_list *list)
+static void process_attr_command_init(struct process_attr_command_args *cmd,
+ enum lttng_process_attr process_attr)
{
- size_t nr_items;
- int i;
-
- if (!list) {
- return;
- }
- nr_items = list->nr;
- for (i = 0; i < nr_items; i++) {
- struct lttng_tracker_id *item = list->array[i];
- lttng_tracker_id_destroy(item);
- }
- free(list);
+ cmd->process_attr = process_attr;
+ cmd->all = false;
+ lttng_dynamic_pointer_array_init(&cmd->string_args, NULL);
}
-static int parse_id_string(const char *_id_string,
- int all,
- struct id_list **_id_list,
- enum lttng_tracker_type tracker_type)
+static void process_attr_command_fini(struct process_attr_command_args *cmd)
{
- const char *one_id_str;
- char *iter;
- int retval = CMD_SUCCESS;
- int count = 0;
- struct id_list *id_list = NULL;
- char *id_string = NULL;
- char *endptr;
-
- if (all && _id_string) {
- ERR("An empty ID string is expected with --all");
- retval = CMD_ERROR;
- goto error;
- }
- if (!all && !_id_string) {
- ERR("An ID string is expected");
- retval = CMD_ERROR;
- goto error;
- }
- if (all) {
- enum lttng_tracker_id_status status;
- /* Empty `ID string means all IDs */
- id_list = alloc_id_list(1);
- if (!id_list) {
- ERR("Out of memory");
- retval = CMD_ERROR;
- goto error;
- }
-
- id_list->array[0] = lttng_tracker_id_create();
- if (id_list->array[0] == NULL) {
- ERR("Out of memory");
- retval = CMD_ERROR;
- goto error;
- }
-
- status = lttng_tracker_id_set_all(id_list->array[0]);
- if (status != LTTNG_TRACKER_ID_STATUS_OK) {
- ERR("Invalid value for tracker id");
- retval = CMD_ERROR;
- goto error;
- }
- goto assign;
- }
-
- id_string = strdup(_id_string);
- if (!id_string) {
- ERR("Out of memory");
- retval = CMD_ERROR;
- goto error;
- }
-
- /* Count */
- one_id_str = strtok_r(id_string, ",", &iter);
- while (one_id_str != NULL) {
- unsigned long v;
-
- if (isdigit(one_id_str[0])) {
- errno = 0;
- v = strtoul(one_id_str, &endptr, 10);
- if ((v == 0 && errno == EINVAL) ||
- (v == ULONG_MAX && errno == ERANGE) ||
- (*one_id_str != '\0' &&
- *endptr != '\0')) {
- ERR("Error parsing ID %s", one_id_str);
- retval = CMD_ERROR;
- goto error;
- }
-
- if ((long) v > INT_MAX || (int) v < 0) {
- ERR("Invalid ID value %ld", (long) v);
- retval = CMD_ERROR;
- goto error;
- }
- }
- count++;
-
- /* For next loop */
- one_id_str = strtok_r(NULL, ",", &iter);
- }
- if (count == 0) {
- ERR("Fatal error occurred when parsing pid string");
- retval = CMD_ERROR;
- goto error;
- }
-
- free(id_string);
- /* Identity of delimiter has been lost in first pass. */
- id_string = strdup(_id_string);
- if (!id_string) {
- ERR("Out of memory");
- retval = CMD_ERROR;
- goto error;
- }
-
- /* Allocate */
- id_list = alloc_id_list(count);
- if (!id_list) {
- ERR("Out of memory");
- retval = CMD_ERROR;
- goto error;
- }
-
- /* Reparse string and populate the id list. */
- count = 0;
- one_id_str = strtok_r(id_string, ",", &iter);
- while (one_id_str != NULL) {
- enum lttng_tracker_id_status status;
- struct lttng_tracker_id *item;
- item = lttng_tracker_id_create();
- if (item == NULL) {
- ERR("Out of memory");
- retval = CMD_ERROR;
- goto error;
- }
-
- id_list->array[count++] = item;
- if (isdigit(one_id_str[0])) {
- unsigned long v;
-
- v = strtoul(one_id_str, NULL, 10);
- status = lttng_tracker_id_set_value(item, (int) v);
- if (status == LTTNG_TRACKER_ID_STATUS_INVALID) {
- ERR("Invalid value");
- retval = CMD_ERROR;
- goto error;
- }
- } else {
- status = lttng_tracker_id_set_string(item, one_id_str);
- if (status == LTTNG_TRACKER_ID_STATUS_INVALID) {
- ERR("Failed to set ID string");
- retval = CMD_ERROR;
- goto error;
- }
- }
-
- /* For next loop */
- one_id_str = strtok_r(NULL, ",", &iter);
- }
-
-assign:
- /* SUCCESS */
- *_id_list = id_list;
- goto end;
-
-error:
- /* ERROR */
- free_id_list(id_list);
-end:
- free(id_string);
- return retval;
+ lttng_dynamic_pointer_array_reset(&cmd->string_args);
}
-static const char *get_tracker_str(enum lttng_tracker_type tracker_type)
+static const char *get_capitalized_process_attr_str(enum lttng_process_attr process_attr)
{
- switch (tracker_type) {
- case LTTNG_TRACKER_PID:
- return "PID";
- case LTTNG_TRACKER_VPID:
- return "VPID";
- case LTTNG_TRACKER_UID:
- return "UID";
- case LTTNG_TRACKER_VUID:
- return "VUID";
- case LTTNG_TRACKER_GID:
- return "GID";
- case LTTNG_TRACKER_VGID:
- return "VGID";
+ switch (process_attr) {
+ case LTTNG_PROCESS_ATTR_PROCESS_ID:
+ return "Process ID";
+ case LTTNG_PROCESS_ATTR_VIRTUAL_PROCESS_ID:
+ return "Virtual process ID";
+ case LTTNG_PROCESS_ATTR_USER_ID:
+ return "User ID";
+ case LTTNG_PROCESS_ATTR_VIRTUAL_USER_ID:
+ return "Virtual user ID";
+ case LTTNG_PROCESS_ATTR_GROUP_ID:
+ return "Group ID";
+ case LTTNG_PROCESS_ATTR_VIRTUAL_GROUP_ID:
+ return "Virtual group ID";
default:
- return NULL;
+ return "Unknown";
}
return NULL;
}
-static int ust_tracker_type_support(enum lttng_tracker_type *tracker_type)
+static bool ust_process_attr_supported(enum lttng_process_attr *process_attr)
{
- int ret;
-
- switch (*tracker_type) {
- case LTTNG_TRACKER_PID:
- *tracker_type = LTTNG_TRACKER_VPID;
- ret = 0;
- break;
- case LTTNG_TRACKER_VPID:
- case LTTNG_TRACKER_VUID:
- case LTTNG_TRACKER_VGID:
- ret = 0;
- break;
- case LTTNG_TRACKER_UID:
- case LTTNG_TRACKER_GID:
- ERR("The %s tracker is invalid for UST domain.",
- get_tracker_str(*tracker_type));
- ret = -1;
+ bool supported;
+
+ switch (*process_attr) {
+ case LTTNG_PROCESS_ATTR_PROCESS_ID:
+ *process_attr = LTTNG_PROCESS_ATTR_VIRTUAL_PROCESS_ID;
+ /* fall-through. */
+ case LTTNG_PROCESS_ATTR_VIRTUAL_PROCESS_ID:
+ case LTTNG_PROCESS_ATTR_VIRTUAL_USER_ID:
+ case LTTNG_PROCESS_ATTR_VIRTUAL_GROUP_ID:
+ supported = true;
break;
default:
- ret = -1;
+ ERR("The %s process attribute cannot be tracked in the user space domain.",
+ lttng_process_attr_to_string(*process_attr));
+ supported = false;
break;
}
-
- return ret;
+ return supported;
}
-static enum cmd_error_code track_untrack_id(enum cmd_type cmd_type,
- const char *cmd_str,
- const char *session_name,
- const char *id_string,
- int all,
- struct mi_writer *writer,
- enum lttng_tracker_type tracker_type)
+static const char *get_mi_element_command(enum cmd_type cmd_type)
{
- int ret, success = 1 , i;
- enum cmd_error_code retval = CMD_SUCCESS;
- struct id_list *id_list = NULL;
- struct lttng_domain dom;
- struct lttng_handle *handle = NULL;
- int (*cmd_func)(struct lttng_handle *handle,
- enum lttng_tracker_type tracker_type,
- const struct lttng_tracker_id *id);
- const char *tracker_str;
-
switch (cmd_type) {
case CMD_TRACK:
- cmd_func = lttng_track_id;
- break;
+ return mi_lttng_element_command_track;
case CMD_UNTRACK:
- cmd_func = lttng_untrack_id;
- break;
+ return mi_lttng_element_command_untrack;
default:
- ERR("Unknown command");
- retval = CMD_ERROR;
- goto end;
+ abort();
}
- memset(&dom, 0, sizeof(dom));
- if (opt_kernel) {
- dom.type = LTTNG_DOMAIN_KERNEL;
- } else if (opt_userspace) {
- dom.type = LTTNG_DOMAIN_UST;
- ret = ust_tracker_type_support(&tracker_type);
+}
+
+static enum cmd_error_code run_command_all(enum cmd_type cmd_type,
+ const char *session_name,
+ enum lttng_domain_type domain_type,
+ enum lttng_process_attr process_attr,
+ struct mi_writer *writer)
+{
+ struct lttng_process_attr_tracker_handle *tracker_handle = NULL;
+ const enum lttng_error_code handle_ret_code =
+ lttng_session_get_tracker_handle(session_name,
+ domain_type, process_attr,
+ &tracker_handle);
+ enum cmd_error_code cmd_ret = CMD_SUCCESS;
+ enum lttng_process_attr_tracker_handle_status status;
+
+ if (writer) {
+ const int ret = mi_lttng_all_process_attribute_value(
+ writer, process_attr, true);
if (ret) {
- ERR("Invalid parameter");
- retval = CMD_ERROR;
+ cmd_ret = CMD_FATAL;
goto end;
}
- } else {
- /* Checked by the caller. */
- assert(0);
- }
- tracker_str = get_tracker_str(tracker_type);
- if (!tracker_str) {
- ERR("Unknown tracker type");
- retval = CMD_ERROR;
- goto end;
- }
- ret = parse_id_string(id_string, all, &id_list, tracker_type);
- if (ret != CMD_SUCCESS) {
- ERR("Error parsing %s string", tracker_str);
- retval = CMD_ERROR;
- goto end;
}
- handle = lttng_create_handle(session_name, &dom);
- if (handle == NULL) {
- retval = CMD_ERROR;
+ if (handle_ret_code != LTTNG_OK) {
+ ERR("Session `%s` does not exist", session_name);
+ cmd_ret = CMD_FATAL;
goto end;
}
+ status = lttng_process_attr_tracker_handle_set_tracking_policy(
+ tracker_handle,
+ cmd_type == CMD_TRACK ?
+ LTTNG_TRACKING_POLICY_INCLUDE_ALL :
+ LTTNG_TRACKING_POLICY_EXCLUDE_ALL);
+ switch (status) {
+ case LTTNG_PROCESS_ATTR_TRACKER_HANDLE_STATUS_OK:
+ if (cmd_type == CMD_TRACK) {
+ MSG("%s tracking policy set to `include all`",
+ get_capitalized_process_attr_str(process_attr));
+ } else {
+ MSG("%s tracking policy set to `exclude all`",
+ get_capitalized_process_attr_str(process_attr));
+ }
+ break;
+ case LTTNG_PROCESS_ATTR_TRACKER_HANDLE_STATUS_SESSION_DOES_NOT_EXIST:
+ ERR("%s", lttng_strerror(-LTTNG_ERR_SESS_NOT_FOUND));
+ break;
+ default:
+ ERR("Unknown error encountered while setting tracking policy of %s tracker to `%s`",
+ lttng_process_attr_to_string(process_attr),
+ cmd_type == CMD_TRACK ? "include all" :
+ "exclude all");
+ cmd_ret = CMD_FATAL;
+ break;
+ }
+end:
if (writer) {
- /* Open tracker_id and targets elements */
- ret = mi_lttng_id_tracker_open(writer, tracker_type);
+ int ret = mi_lttng_writer_write_element_bool(writer,
+ mi_lttng_element_success,
+ cmd_ret == CMD_SUCCESS);
+
if (ret) {
- goto end;
+ cmd_ret = CMD_FATAL;
+ } else {
+ ret = mi_lttng_writer_close_element(writer);
+ cmd_ret = ret == 0 ? cmd_ret : CMD_FATAL;
}
}
+ lttng_process_attr_tracker_handle_destroy(tracker_handle);
+ return cmd_ret;
+}
- for (i = 0; i < id_list->nr; i++) {
- struct lttng_tracker_id *item = id_list->array[i];
- enum lttng_tracker_id_type type =
- lttng_tracker_id_get_type(item);
- enum lttng_tracker_id_status status =
- LTTNG_TRACKER_ID_STATUS_OK;
- int value;
- const char *value_string;
-
- switch (type) {
- case LTTNG_ID_ALL:
- /* Nothing to check */
- break;
- case LTTNG_ID_VALUE:
- status = lttng_tracker_id_get_value(item, &value);
- break;
- case LTTNG_ID_STRING:
- status = lttng_tracker_id_get_string(
- item, &value_string);
- break;
- default:
- retval = CMD_ERROR;
- goto end;
- }
+static enum cmd_error_code run_command_string(enum cmd_type cmd_type,
+ const char *session_name,
+ enum lttng_domain_type domain_type,
+ enum lttng_process_attr process_attr,
+ const char *_args,
+ struct mi_writer *writer)
+{
+ struct lttng_process_attr_tracker_handle *tracker_handle;
+ const enum lttng_error_code handle_ret_code =
+ lttng_session_get_tracker_handle(session_name,
+ domain_type, process_attr,
+ &tracker_handle);
+ enum cmd_error_code cmd_ret = CMD_SUCCESS;
+ const char *one_value_str;
+ char *args = strdup(_args);
+ char *iter = args;
+ bool policy_set = false;
+
+ if (!args) {
+ ERR("%s", lttng_strerror(-LTTNG_ERR_NOMEM));
+ cmd_ret = CMD_FATAL;
+ goto end;
+ }
- if (status != LTTNG_TRACKER_ID_STATUS_OK) {
- ERR("Tracker id object is in an invalid state");
- retval = CMD_ERROR;
- goto end;
- }
+ if (handle_ret_code != LTTNG_OK) {
+ ERR("%s", lttng_strerror(-handle_ret_code));
+ cmd_ret = CMD_FATAL;
+ goto end;
+ }
- switch (type) {
- case LTTNG_ID_ALL:
- DBG("%s all IDs", cmd_str);
- break;
- case LTTNG_ID_VALUE:
- DBG("%s ID %d", cmd_str, value);
- break;
- case LTTNG_ID_STRING:
- DBG("%s ID '%s'", cmd_str, value_string);
- break;
- default:
- retval = CMD_ERROR;
- goto end;
+ while ((one_value_str = strtok_r(iter, ",", &iter)) != NULL) {
+ const bool is_numerical_argument = isdigit(one_value_str[0]);
+ enum lttng_process_attr_tracker_handle_status status;
+ enum lttng_tracking_policy policy;
+ int ret;
+ char *prettified_arg;
+
+ if (!policy_set) {
+ status = lttng_process_attr_tracker_handle_get_tracking_policy(
+ tracker_handle, &policy);
+ if (status != LTTNG_PROCESS_ATTR_TRACKER_HANDLE_STATUS_OK) {
+ break;
+ }
+
+ if (policy != LTTNG_TRACKING_POLICY_INCLUDE_SET) {
+ status = lttng_process_attr_tracker_handle_set_tracking_policy(
+ tracker_handle,
+ LTTNG_TRACKING_POLICY_INCLUDE_SET);
+ if (status != LTTNG_PROCESS_ATTR_TRACKER_HANDLE_STATUS_OK) {
+ break;
+ }
+ }
+ policy_set = true;
}
- ret = cmd_func(handle, tracker_type, item);
- if (ret) {
- char *msg = NULL;
+ if (is_numerical_argument) {
+ const unsigned long one_value_int =
+ strtoul(one_value_str, NULL, 10);
+
+ if (writer) {
+ ret = mi_lttng_integral_process_attribute_value(
+ writer, process_attr,
+ (int64_t) one_value_int, true);
+ if (ret) {
+ cmd_ret = CMD_FATAL;
+ goto end;
+ }
+ }
- switch (-ret) {
- case LTTNG_ERR_ID_TRACKED:
- msg = "already tracked";
- success = 1;
- retval = CMD_SUCCESS;
+ switch (process_attr) {
+ case LTTNG_PROCESS_ATTR_PROCESS_ID:
+ status = cmd_type == CMD_TRACK ?
+ lttng_process_attr_process_id_tracker_handle_add_pid(
+ tracker_handle,
+ (pid_t) one_value_int) :
+ lttng_process_attr_process_id_tracker_handle_remove_pid(
+ tracker_handle,
+ (pid_t) one_value_int);
break;
- case LTTNG_ERR_ID_NOT_TRACKED:
- msg = "already not tracked";
- success = 1;
- retval = CMD_SUCCESS;
+ case LTTNG_PROCESS_ATTR_VIRTUAL_PROCESS_ID:
+ status = cmd_type == CMD_TRACK ?
+ lttng_process_attr_virtual_process_id_tracker_handle_add_pid(
+ tracker_handle,
+ (pid_t) one_value_int) :
+ lttng_process_attr_virtual_process_id_tracker_handle_remove_pid(
+ tracker_handle,
+ (pid_t) one_value_int);
break;
- default:
- ERR("%s", lttng_strerror(ret));
- success = 0;
- retval = CMD_ERROR;
+ case LTTNG_PROCESS_ATTR_USER_ID:
+ status = cmd_type == CMD_TRACK ?
+ lttng_process_attr_user_id_tracker_handle_add_uid(
+ tracker_handle,
+ (uid_t) one_value_int) :
+ lttng_process_attr_user_id_tracker_handle_remove_uid(
+ tracker_handle,
+ (uid_t) one_value_int);
+ break;
+ case LTTNG_PROCESS_ATTR_VIRTUAL_USER_ID:
+ status = cmd_type == CMD_TRACK ?
+ lttng_process_attr_virtual_user_id_tracker_handle_add_uid(
+ tracker_handle,
+ (uid_t) one_value_int) :
+ lttng_process_attr_virtual_user_id_tracker_handle_remove_uid(
+ tracker_handle,
+ (uid_t) one_value_int);
+ break;
+ case LTTNG_PROCESS_ATTR_GROUP_ID:
+ status = cmd_type == CMD_TRACK ?
+ lttng_process_attr_group_id_tracker_handle_add_gid(
+ tracker_handle,
+ (gid_t) one_value_int) :
+ lttng_process_attr_group_id_tracker_handle_remove_gid(
+ tracker_handle,
+ (gid_t) one_value_int);
break;
+ case LTTNG_PROCESS_ATTR_VIRTUAL_GROUP_ID:
+ status = cmd_type == CMD_TRACK ?
+ lttng_process_attr_virtual_group_id_tracker_handle_add_gid(
+ tracker_handle,
+ (gid_t) one_value_int) :
+ lttng_process_attr_virtual_group_id_tracker_handle_remove_gid(
+ tracker_handle,
+ (gid_t) one_value_int);
+ break;
+ default:
+ abort();
}
- if (msg) {
- switch (type) {
- case LTTNG_ID_ALL:
- WARN("All %ss %s in session %s",
- tracker_str, msg,
- session_name);
- break;
- case LTTNG_ID_VALUE:
- WARN("%s %i %s in session %s",
- tracker_str, value, msg,
- session_name);
- break;
- case LTTNG_ID_STRING:
- WARN("%s '%s' %s in session %s",
- tracker_str,
- value_string, msg,
- session_name);
- break;
- default:
- retval = CMD_ERROR;
+
+ } else {
+ if (writer) {
+ ret = mi_lttng_string_process_attribute_value(
+ writer, process_attr,
+ one_value_str, true);
+ if (ret) {
+ cmd_ret = CMD_FATAL;
goto end;
}
}
- } else {
- switch (type) {
- case LTTNG_ID_ALL:
- MSG("All %ss %sed in session %s", tracker_str,
- cmd_str, session_name);
+
+ switch (process_attr) {
+ case LTTNG_PROCESS_ATTR_USER_ID:
+ status = cmd_type == CMD_TRACK ?
+ lttng_process_attr_user_id_tracker_handle_add_user_name(
+ tracker_handle,
+ one_value_str) :
+ lttng_process_attr_user_id_tracker_handle_remove_user_name(
+ tracker_handle,
+ one_value_str);
break;
- case LTTNG_ID_VALUE:
- MSG("%s %i %sed in session %s", tracker_str,
- value, cmd_str, session_name);
+ case LTTNG_PROCESS_ATTR_VIRTUAL_USER_ID:
+ status = cmd_type == CMD_TRACK ?
+ lttng_process_attr_virtual_user_id_tracker_handle_add_user_name(
+ tracker_handle,
+ one_value_str) :
+ lttng_process_attr_virtual_user_id_tracker_handle_remove_user_name(
+ tracker_handle,
+ one_value_str);
break;
- case LTTNG_ID_STRING:
- MSG("%s '%s' %sed in session %s", tracker_str,
- value_string, cmd_str,
- session_name);
+ case LTTNG_PROCESS_ATTR_GROUP_ID:
+ status = cmd_type == CMD_TRACK ?
+ lttng_process_attr_group_id_tracker_handle_add_group_name(
+ tracker_handle,
+ one_value_str) :
+ lttng_process_attr_group_id_tracker_handle_remove_group_name(
+ tracker_handle,
+ one_value_str);
+ break;
+ case LTTNG_PROCESS_ATTR_VIRTUAL_GROUP_ID:
+ status = cmd_type == CMD_TRACK ?
+ lttng_process_attr_virtual_group_id_tracker_handle_add_group_name(
+ tracker_handle,
+ one_value_str) :
+ lttng_process_attr_virtual_group_id_tracker_handle_remove_group_name(
+ tracker_handle,
+ one_value_str);
break;
default:
- retval = CMD_ERROR;
+ ERR("%s is not a valid %s value; expected an integer",
+ one_value_str,
+ lttng_process_attr_to_string(
+ process_attr));
+ cmd_ret = CMD_FATAL;
goto end;
}
- success = 1;
}
- /* Mi */
- if (writer) {
- ret = mi_lttng_id_target(writer, tracker_type, item, 1);
- if (ret) {
- retval = CMD_ERROR;
- goto end;
+ ret = asprintf(&prettified_arg,
+ is_numerical_argument ? "%s" : "`%s`",
+ one_value_str);
+ if (ret < 0) {
+ PERROR("Failed to format argument `%s`", one_value_str);
+ cmd_ret = CMD_FATAL;
+ goto end;
+ }
+
+ switch (status) {
+ case LTTNG_PROCESS_ATTR_TRACKER_HANDLE_STATUS_OK:
+ if (cmd_type == CMD_TRACK) {
+ MSG("Added %s to the %s tracker inclusion set",
+ one_value_str,
+ lttng_process_attr_to_string(
+ process_attr));
+ } else {
+ MSG("Removed %s from the %s tracker inclusion set",
+ one_value_str,
+ lttng_process_attr_to_string(
+ process_attr));
}
+ break;
+ case LTTNG_PROCESS_ATTR_TRACKER_HANDLE_STATUS_SESSION_DOES_NOT_EXIST:
+ ERR("Session `%s` not found", session_name);
+ break;
+ case LTTNG_PROCESS_ATTR_TRACKER_HANDLE_STATUS_EXISTS:
+ WARN("%s is already in the %s inclusion set",
+ prettified_arg,
+ lttng_process_attr_to_string(
+ process_attr));
+ break;
+ case LTTNG_PROCESS_ATTR_TRACKER_HANDLE_STATUS_MISSING:
+ WARN("%s is not in the %s the inclusion set",
+ prettified_arg,
+ lttng_process_attr_to_string(
+ process_attr));
+ break;
+ case LTTNG_PROCESS_ATTR_TRACKER_HANDLE_STATUS_USER_NOT_FOUND:
+ ERR("User %s was not found", prettified_arg);
+ cmd_ret = CMD_ERROR;
+ break;
+ case LTTNG_PROCESS_ATTR_TRACKER_HANDLE_STATUS_GROUP_NOT_FOUND:
+ ERR("Group %s was not found", prettified_arg);
+ cmd_ret = CMD_ERROR;
+ break;
+ default:
+ ERR("Unknown error encountered while %s %s %s %s tracker's inclusion set",
+ cmd_type == CMD_TRACK ? "adding" :
+ "removing",
+ lttng_process_attr_to_string(
+ process_attr),
+ prettified_arg,
+ cmd_type == CMD_TRACK ? "to" : "from");
+ cmd_ret = CMD_FATAL;
+ break;
+ }
+ free(prettified_arg);
+ if (writer) {
ret = mi_lttng_writer_write_element_bool(writer,
- mi_lttng_element_success, success);
- if (ret) {
- retval = CMD_ERROR;
- goto end;
- }
+ mi_lttng_element_success,
+ cmd_ret == CMD_SUCCESS);
- ret = mi_lttng_writer_close_element(writer);
if (ret) {
- retval = CMD_ERROR;
- goto end;
+ cmd_ret = CMD_FATAL;
+ } else {
+ ret = mi_lttng_writer_close_element(writer);
+ cmd_ret = ret == 0 ? cmd_ret : CMD_FATAL;
}
}
}
+end:
+ free(args);
+ lttng_process_attr_tracker_handle_destroy(tracker_handle);
+ return cmd_ret;
+}
+
+static enum cmd_error_code run_command(enum cmd_type cmd_type,
+ const char *session_name,
+ const struct process_attr_command_args *command_args,
+ struct mi_writer *writer)
+{
+ const enum lttng_domain_type domain_type =
+ opt_kernel ? LTTNG_DOMAIN_KERNEL : LTTNG_DOMAIN_UST;
+ enum cmd_error_code cmd_ret = CMD_SUCCESS;
+ unsigned int i;
+ const unsigned int string_arg_count =
+ lttng_dynamic_pointer_array_get_count(
+ &command_args->string_args);
+ enum lttng_process_attr process_attr = command_args->process_attr;
+
+ if (opt_userspace) {
+ /*
+ * Check that this process attribute can be tracked
+ * in the user space domain. Backward-compatibility
+ * changes are be applied to process_attr as needed.
+ */
+ if (!ust_process_attr_supported(&process_attr)) {
+ cmd_ret = CMD_ERROR;
+ goto end;
+ }
+ }
if (writer) {
- /* Close targets and tracker_id elements */
- ret = mi_lttng_close_multi_element(writer, 2);
+ /* Open tracker and trackers elements */
+ const int ret = mi_lttng_process_attribute_tracker_open(
+ writer, process_attr);
if (ret) {
- retval = CMD_ERROR;
+ cmd_ret = CMD_FATAL;
goto end;
}
}
-end:
- if (handle) {
- lttng_destroy_handle(handle);
- }
- free_id_list(id_list);
- return retval;
-}
+ if (command_args->all) {
+ cmd_ret = run_command_all(cmd_type, session_name, domain_type,
+ process_attr, writer);
+ } else {
+ bool error_occurred = false;
-static
-const char *get_mi_element_command(enum cmd_type cmd_type)
-{
- switch (cmd_type) {
- case CMD_TRACK:
- return mi_lttng_element_command_track;
- case CMD_UNTRACK:
- return mi_lttng_element_command_untrack;
- default:
- return NULL;
+ for (i = 0; i < string_arg_count; i++) {
+ const char *arg = lttng_dynamic_pointer_array_get_pointer(
+ &command_args->string_args, i);
+
+ cmd_ret = run_command_string(cmd_type, session_name,
+ domain_type, process_attr, arg, writer);
+ if (cmd_ret != CMD_SUCCESS) {
+ error_occurred = true;
+ if (cmd_ret == CMD_FATAL) {
+ break;
+ }
+ goto end;
+ }
+ }
+ if (error_occurred) {
+ cmd_ret = CMD_ERROR;
+ }
}
-}
-static void print_err_duplicate(const char *type)
-{
- ERR("The --%s option can only be used once. A list of comma-separated values can be specified.",
- type);
+ if (writer) {
+ /* Close tracker and trackers elements */
+ const int ret = mi_lttng_close_multi_element(
+ writer, 2);
+ if (ret) {
+ cmd_ret = CMD_FATAL;
+ goto end;
+ }
+ }
+end:
+ return cmd_ret;
}
/*
* Add/remove tracker to/from session.
*/
-static
-int cmd_track_untrack(enum cmd_type cmd_type, const char *cmd_str,
- int argc, const char **argv, const char *help_msg)
+static int cmd_track_untrack(enum cmd_type cmd_type,
+ int argc,
+ const char **argv,
+ const char *help_msg)
{
- int opt, ret = 0, success = 1;
- bool opt_all_present = false;
+ int opt, ret = 0;
+ bool sub_command_failed = false;
+ bool opt_all = false;
+ unsigned int selected_process_attr_tracker_count = 0;
+ const unsigned int command_count =
+ sizeof(process_attr_commands) /
+ sizeof(struct process_attr_command_args);
enum cmd_error_code command_ret = CMD_SUCCESS;
static poptContext pc;
char *session_name = NULL;
const char *leftover = NULL;
struct mi_writer *writer = NULL;
+ size_t i;
+
+ for (i = 0; i < command_count; i++) {
+ process_attr_command_init(&process_attr_commands[i], i);
+ }
if (argc < 1) {
command_ret = CMD_ERROR;
case OPT_SESSION:
break;
case OPT_PID:
- if (opt_pid.used) {
- print_err_duplicate("pid");
- command_ret = CMD_ERROR;
- goto end;
- }
- opt_pid.used = 1;
- type_state = STATE_PID;
- break;
case OPT_VPID:
- if (opt_vpid.used) {
- print_err_duplicate("vpid");
- command_ret = CMD_ERROR;
- goto end;
- }
- opt_vpid.used = 1;
- type_state = STATE_VPID;
- break;
case OPT_UID:
- if (opt_uid.used) {
- print_err_duplicate("uid");
- command_ret = CMD_ERROR;
- goto end;
- }
- opt_uid.used = 1;
- type_state = STATE_UID;
- break;
case OPT_VUID:
- if (opt_vuid.used) {
- print_err_duplicate("vuid");
- command_ret = CMD_ERROR;
- goto end;
- }
- opt_vuid.used = 1;
- type_state = STATE_VUID;
- break;
case OPT_GID:
- if (opt_gid.used) {
- print_err_duplicate("gid");
- command_ret = CMD_ERROR;
- goto end;
- }
- opt_gid.used = 1;
- type_state = STATE_GID;
- break;
case OPT_VGID:
- if (opt_vgid.used) {
- print_err_duplicate("vgid");
+ /* See OPT_ enum declaration comment. */
+ opt--;
+ selected_process_attr_tracker_count++;
+ process_attr_commands[opt].requested = true;
+ if (!opt_str_arg) {
+ continue;
+ }
+ ret = lttng_dynamic_pointer_array_add_pointer(
+ &process_attr_commands[opt].string_args,
+ opt_str_arg);
+ if (ret) {
+ ERR("Allocation failed while parsing command arguments");
command_ret = CMD_ERROR;
goto end;
}
- opt_vgid.used = 1;
- type_state = STATE_VGID;
break;
case OPT_ALL:
- opt_all_present = true;
+ opt_all = true;
break;
default:
command_ret = CMD_UNDEFINED;
}
}
- ret = print_missing_or_multiple_domains(opt_kernel + opt_userspace);
+ ret = print_missing_or_multiple_domains(
+ opt_kernel + opt_userspace, false);
if (ret) {
command_ret = CMD_ERROR;
goto end;
}
- /*
- * If the `--all` option is present set the appropriate tracker's `all`
- * field.
- */
- if (opt_all_present) {
- switch (type_state) {
- case STATE_PID:
- opt_pid.all = 1;
- break;
- case STATE_VPID:
- opt_vpid.all = 1;
- break;
- case STATE_UID:
- opt_uid.all = 1;
- break;
- case STATE_VUID:
- opt_vuid.all = 1;
- break;
- case STATE_GID:
- opt_gid.all = 1;
- break;
- case STATE_VGID:
- opt_vgid.all = 1;
- break;
- default:
- command_ret = CMD_ERROR;
- goto end;
+ if (selected_process_attr_tracker_count == 0) {
+ ERR("At least one process attribute must be specified");
+ command_ret = CMD_ERROR;
+ goto end;
+ }
+ if (opt_all) {
+ /*
+ * Only one process attribute tracker was specified; find it
+ * and set it in 'all' mode.
+ */
+ for (i = 0; i < command_count; i++) {
+ if (!process_attr_commands[i].requested) {
+ continue;
+ }
+ process_attr_commands[i].all = true;
+ if (lttng_dynamic_pointer_array_get_count(
+ &process_attr_commands[i]
+ .string_args)) {
+ ERR("The --all option cannot be used with a list of process attribute values");
+ command_ret = CMD_ERROR;
+ goto end;
+ }
+ }
+ } else {
+ for (i = 0; i < command_count; i++) {
+ if (!process_attr_commands[i].requested) {
+ continue;
+ }
+ if (lttng_dynamic_pointer_array_get_count(
+ &process_attr_commands[i]
+ .string_args) == 0) {
+ ERR("No process attribute value specified for %s tracker",
+ get_capitalized_process_attr_str(
+ process_attr_commands[i]
+ .process_attr));
+ command_ret = CMD_ERROR;
+ goto end;
+ }
}
}
leftover = poptGetArg(pc);
if (leftover) {
ERR("Unknown argument: %s", leftover);
- ret = CMD_ERROR;
+ command_ret = CMD_ERROR;
goto end;
}
}
}
- if (opt_pid.used) {
- command_ret = track_untrack_id(cmd_type, cmd_str, session_name,
- opt_pid.string, opt_pid.all, writer,
- LTTNG_TRACKER_PID);
- if (command_ret != CMD_SUCCESS) {
- success = 0;
- }
- }
- if (opt_vpid.used) {
- command_ret = track_untrack_id(cmd_type, cmd_str, session_name,
- opt_vpid.string, opt_vpid.all, writer,
- LTTNG_TRACKER_VPID);
- if (command_ret != CMD_SUCCESS) {
- success = 0;
- }
- }
- if (opt_uid.used) {
- command_ret = track_untrack_id(cmd_type, cmd_str, session_name,
- opt_uid.string, opt_uid.all, writer,
- LTTNG_TRACKER_UID);
- if (command_ret != CMD_SUCCESS) {
- success = 0;
- }
- }
- if (opt_vuid.used) {
- command_ret = track_untrack_id(cmd_type, cmd_str, session_name,
- opt_vuid.string, opt_vuid.all, writer,
- LTTNG_TRACKER_VUID);
- if (command_ret != CMD_SUCCESS) {
- success = 0;
+ /* Execute sub-commands. */
+ for (i = 0; i < command_count; i++) {
+ if (!process_attr_commands[i].requested) {
+ continue;
}
- }
- if (opt_gid.used) {
- command_ret = track_untrack_id(cmd_type, cmd_str, session_name,
- opt_gid.string, opt_gid.all, writer,
- LTTNG_TRACKER_GID);
- if (command_ret != CMD_SUCCESS) {
- success = 0;
- }
- }
- if (opt_vgid.used) {
- command_ret = track_untrack_id(cmd_type, cmd_str, session_name,
- opt_vgid.string, opt_vgid.all, writer,
- LTTNG_TRACKER_VGID);
+ command_ret = run_command(cmd_type, session_name,
+ &process_attr_commands[i], writer);
if (command_ret != CMD_SUCCESS) {
- success = 0;
+ sub_command_failed = true;
+ if (command_ret == CMD_FATAL) {
+ break;
+ }
}
}
/* Success ? */
ret = mi_lttng_writer_write_element_bool(writer,
- mi_lttng_element_command_success, success);
+ mi_lttng_element_command_success,
+ !sub_command_failed);
if (ret) {
command_ret = CMD_ERROR;
goto end;
command_ret = CMD_ERROR;
}
+ for (i = 0; i < command_count; i++) {
+ process_attr_command_fini(&process_attr_commands[i]);
+ }
+
poptFreeContext(pc);
return (int) command_ret;
}
#endif
;
- return cmd_track_untrack(CMD_TRACK, "track", argc, argv, help_msg);
+ return cmd_track_untrack(CMD_TRACK, argc, argv, help_msg);
}
int cmd_untrack(int argc, const char **argv)
#endif
;
- return cmd_track_untrack(CMD_UNTRACK, "untrack", argc, argv, help_msg);
+ return cmd_track_untrack(CMD_UNTRACK, argc, argv, help_msg);
}