X-Git-Url: https://git.lttng.org/?p=lttng-tools.git;a=blobdiff_plain;f=src%2Fbin%2Flttng%2Fcommands%2Ftrack-untrack.c;h=e796aa97c448da5ebde65f908b4456a56dbb680a;hp=f503c35617b7633e8d32f57b33e2dc42a57a1c5b;hb=d89dd55ea0f25f8b3fafd064fd887759c9a05af0;hpb=adce7589954ef2c8236be5145e664b4383474d43 diff --git a/src/bin/lttng/commands/track-untrack.c b/src/bin/lttng/commands/track-untrack.c index f503c3561..e796aa97c 100644 --- a/src/bin/lttng/commands/track-untrack.c +++ b/src/bin/lttng/commands/track-untrack.c @@ -1,19 +1,10 @@ /* - * Copyright (C) 2011 - David Goulet - * Copyright (C) 2015 - Mathieu Desnoyers + * Copyright (C) 2011 David Goulet + * Copyright (C) 2015 Mathieu Desnoyers + * Copyright (C) 2020 Jérémie Galarneau * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License, version 2 only, - * as published by the Free Software Foundation. + * SPDX-License-Identifier: GPL-2.0-only * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #define _LGPL_SOURCE @@ -30,574 +21,571 @@ #include +#include #include +#include +#include +#include + +#include #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; +} + +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; + } - 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; - } + if (handle_ret_code != LTTNG_OK) { + ERR("%s", lttng_strerror(-handle_ret_code)); + 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; - } + 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; - 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; + 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_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_VALUE: - MSG("%s %i %sed in session %s", tracker_str, - value, 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_ID_STRING: - MSG("%s '%s' %sed in session %s", tracker_str, - value_string, cmd_str, - session_name); + 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; @@ -618,61 +606,29 @@ int cmd_track_untrack(enum cmd_type cmd_type, const char *cmd_str, 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; @@ -680,39 +636,51 @@ int cmd_track_untrack(enum cmd_type cmd_type, const char *cmd_str, } } - 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; + } } } @@ -729,7 +697,7 @@ int cmd_track_untrack(enum cmd_type cmd_type, const char *cmd_str, leftover = poptGetArg(pc); if (leftover) { ERR("Unknown argument: %s", leftover); - ret = CMD_ERROR; + command_ret = CMD_ERROR; goto end; } @@ -765,52 +733,18 @@ int cmd_track_untrack(enum cmd_type cmd_type, const char *cmd_str, } } - 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; + /* Execute sub-commands. */ + for (i = 0; i < command_count; i++) { + if (!process_attr_commands[i].requested) { + continue; } - } - 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); + command_ret = run_command(cmd_type, session_name, + &process_attr_commands[i], writer); 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; - } - } - 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); - if (command_ret != CMD_SUCCESS) { - success = 0; + sub_command_failed = true; + if (command_ret == CMD_FATAL) { + break; + } } } @@ -825,7 +759,8 @@ int cmd_track_untrack(enum cmd_type cmd_type, const char *cmd_str, /* 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; @@ -850,6 +785,10 @@ 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; } @@ -864,7 +803,7 @@ int cmd_track(int argc, const char **argv) #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) @@ -877,5 +816,5 @@ 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); }