Clean-up: lttng: fix -Wshadow error in run_command_string
[lttng-tools.git] / src / bin / lttng / commands / track-untrack.c
index f503c35617b7633e8d32f57b33e2dc42a57a1c5b..e796aa97c448da5ebde65f908b4456a56dbb680a 100644 (file)
@@ -1,19 +1,10 @@
 /*
- * Copyright (C) 2011 - David Goulet <david.goulet@polymtl.ca>
- * Copyright (C) 2015 - Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
+ * 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>
  *
- * 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
 
 #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;
+}
+
+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);
 }
This page took 0.038017 seconds and 4 git commands to generate.