X-Git-Url: https://git.lttng.org/?p=lttng-tools.git;a=blobdiff_plain;f=src%2Fbin%2Flttng%2Fcommands%2Ftrack-untrack.c;h=c54b6407802ed7cd0e342c057f9d3c460c05a351;hp=59bf53d94a4a57476e7526768a1bb97277a3fdcf;hb=2d97a0067600335f07eecb2c1d9ba68fc164583e;hpb=4fc83d948cea6b10484e65f004a6c167e71ac440 diff --git a/src/bin/lttng/commands/track-untrack.c b/src/bin/lttng/commands/track-untrack.c index 59bf53d94..c54b64078 100644 --- a/src/bin/lttng/commands/track-untrack.c +++ b/src/bin/lttng/commands/track-untrack.c @@ -38,18 +38,46 @@ enum cmd_type { 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 int opt_all; -static char *opt_pid_string; -static int opt_pid; + +static struct opt_type opt_pid, opt_vpid, opt_uid, opt_vuid, opt_gid, opt_vgid; + +static enum tracker_type_state type_state; enum { OPT_HELP = 1, OPT_LIST_OPTIONS, OPT_SESSION, OPT_PID, + OPT_VPID, + OPT_UID, + OPT_VUID, + OPT_GID, + OPT_VGID, + OPT_ALL, }; static struct poptOption long_options[] = { @@ -58,162 +86,314 @@ static struct poptOption long_options[] = { { "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, }, - { "all", 'a', POPT_ARG_VAL, &opt_all, 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, }, + { "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 -int parse_pid_string(const char *_pid_string, - int all, int **_pid_list, int *nr_pids) +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 void free_id_list(struct id_list *list) +{ + 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); +} + +static int parse_id_string(const char *_id_string, + int all, + struct id_list **_id_list, + enum lttng_tracker_type tracker_type) { - const char *one_pid_str; + const char *one_id_str; char *iter; int retval = CMD_SUCCESS; int count = 0; - int *pid_list = NULL; - char *pid_string = NULL; + struct id_list *id_list = NULL; + char *id_string = NULL; char *endptr; - if (all && _pid_string) { - ERR("An empty PID string is expected with --all"); + if (all && _id_string) { + ERR("An empty ID string is expected with --all"); retval = CMD_ERROR; goto error; } - if (!all && !_pid_string) { - ERR("Please specify --all with an empty PID string"); + if (!all && !_id_string) { + ERR("An ID string is expected"); retval = CMD_ERROR; goto error; } if (all) { - pid_list = zmalloc(sizeof(*pid_list)); - if (!pid_list) { + 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; } - /* Empty PID string means all PIDs */ - count = 1; - pid_list[0] = -1; + + 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; } - pid_string = strdup(_pid_string); - if (!pid_string) { + id_string = strdup(_id_string); + if (!id_string) { ERR("Out of memory"); retval = CMD_ERROR; goto error; } /* Count */ - one_pid_str = strtok_r(pid_string, ",", &iter); - while (one_pid_str != NULL) { + one_id_str = strtok_r(id_string, ",", &iter); + while (one_id_str != NULL) { unsigned long v; - errno = 0; - v = strtoul(one_pid_str, &endptr, 10); - if ((v == 0 && errno == EINVAL) - || (v == ULONG_MAX && errno == ERANGE) - || (*one_pid_str != '\0' && *endptr != '\0')){ - ERR("Error parsing PID %s", one_pid_str); - retval = CMD_ERROR; - goto error; - } + 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 PID value %ld", (long) v); - 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_pid_str = strtok_r(NULL, ",", &iter); + one_id_str = strtok_r(NULL, ",", &iter); + } + if (count == 0) { + ERR("Fatal error occurred when parsing pid string"); + retval = CMD_ERROR; + goto error; } - free(pid_string); + free(id_string); /* Identity of delimiter has been lost in first pass. */ - pid_string = strdup(_pid_string); - if (!pid_string) { + id_string = strdup(_id_string); + if (!id_string) { ERR("Out of memory"); retval = CMD_ERROR; goto error; } /* Allocate */ - pid_list = zmalloc(count * sizeof(*pid_list)); - if (!pid_list) { + id_list = alloc_id_list(count); + if (!id_list) { ERR("Out of memory"); retval = CMD_ERROR; goto error; } - /* Reparse string and populate the pid list. */ + /* Reparse string and populate the id list. */ count = 0; - one_pid_str = strtok_r(pid_string, ",", &iter); - while (one_pid_str != NULL) { - unsigned long v; + 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; + } - v = strtoul(one_pid_str, NULL, 10); - pid_list[count++] = (int) v; + 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_pid_str = strtok_r(NULL, ",", &iter); + one_id_str = strtok_r(NULL, ",", &iter); } assign: - *nr_pids = count; - *_pid_list = pid_list; - goto end; /* SUCCESS */ + /* SUCCESS */ + *_id_list = id_list; + goto end; - /* ERROR */ error: - free(pid_list); + /* ERROR */ + free_id_list(id_list); end: - free(pid_string); + free(id_string); return retval; } -static -enum cmd_error_code track_untrack_pid(enum cmd_type cmd_type, const char *cmd_str, - const char *session_name, const char *pid_string, - int all, struct mi_writer *writer) +static const char *get_tracker_str(enum lttng_tracker_type tracker_type) +{ + 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"; + default: + return NULL; + } + return NULL; +} + +static int ust_tracker_type_support(enum lttng_tracker_type *tracker_type) +{ + 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; + break; + default: + ret = -1; + break; + } + + return ret; +} + +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) { int ret, success = 1 , i; enum cmd_error_code retval = CMD_SUCCESS; - int *pid_list = NULL; - int nr_pids; + struct id_list *id_list = NULL; struct lttng_domain dom; struct lttng_handle *handle = NULL; - int (*cmd_func)(struct lttng_handle *handle, int pid); + 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_pid; + cmd_func = lttng_track_id; break; case CMD_UNTRACK: - cmd_func = lttng_untrack_pid; + cmd_func = lttng_untrack_id; break; default: ERR("Unknown command"); retval = CMD_ERROR; goto end; } - 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); + if (ret) { + ERR("Invalid parameter"); + retval = CMD_ERROR; + goto end; + } } else { /* Checked by the caller. */ assert(0); } - - ret = parse_pid_string(pid_string, all, &pid_list, &nr_pids); + 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 PID string"); + ERR("Error parsing %s string", tracker_str); retval = CMD_ERROR; goto end; } @@ -225,28 +405,71 @@ enum cmd_error_code track_untrack_pid(enum cmd_type cmd_type, const char *cmd_st } if (writer) { - /* Open process element */ - ret = mi_lttng_targets_open(writer); + /* Open tracker_id and targets elements */ + ret = mi_lttng_id_tracker_open(writer, tracker_type); if (ret) { - retval = CMD_ERROR; goto end; } } - for (i = 0; i < nr_pids; i++) { - DBG("%s PID %d", cmd_str, pid_list[i]); - ret = cmd_func(handle, pid_list[i]); + 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 (status != LTTNG_TRACKER_ID_STATUS_OK) { + ERR("Tracker id object is in an invalid state"); + retval = CMD_ERROR; + 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; + } + + ret = cmd_func(handle, tracker_type, item); if (ret) { + char *msg = NULL; + switch (-ret) { - case LTTNG_ERR_PID_TRACKED: - WARN("PID %i already tracked in session %s", - pid_list[i], session_name); + case LTTNG_ERR_ID_TRACKED: + msg = "already tracked"; success = 1; retval = CMD_SUCCESS; break; - case LTTNG_ERR_PID_NOT_TRACKED: - WARN("PID %i not tracked in session %s", - pid_list[i], session_name); + case LTTNG_ERR_ID_NOT_TRACKED: + msg = "already not tracked"; success = 1; retval = CMD_SUCCESS; break; @@ -256,15 +479,54 @@ enum cmd_error_code track_untrack_pid(enum cmd_type cmd_type, const char *cmd_st retval = CMD_ERROR; break; } + 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; + goto end; + } + } } else { - MSG("PID %i %sed in session %s", - pid_list[i], cmd_str, session_name); + switch (type) { + case LTTNG_ID_ALL: + MSG("All %ss %sed in session %s", tracker_str, + cmd_str, session_name); + break; + case LTTNG_ID_VALUE: + MSG("%s %i %sed in session %s", tracker_str, + value, cmd_str, session_name); + break; + case LTTNG_ID_STRING: + MSG("%s '%s' %sed in session %s", tracker_str, + value_string, cmd_str, + session_name); + break; + default: + retval = CMD_ERROR; + goto end; + } success = 1; } /* Mi */ if (writer) { - ret = mi_lttng_pid_target(writer, pid_list[i], 1); + ret = mi_lttng_id_target(writer, tracker_type, item, 1); if (ret) { retval = CMD_ERROR; goto end; @@ -286,8 +548,8 @@ enum cmd_error_code track_untrack_pid(enum cmd_type cmd_type, const char *cmd_st } if (writer) { - /* Close targets element */ - ret = mi_lttng_writer_close_element(writer); + /* Close targets and tracker_id elements */ + ret = mi_lttng_close_multi_element(writer, 2); if (ret) { retval = CMD_ERROR; goto end; @@ -298,7 +560,7 @@ end: if (handle) { lttng_destroy_handle(handle); } - free(pid_list); + free_id_list(id_list); return retval; } @@ -315,6 +577,12 @@ const char *get_mi_element_command(enum cmd_type cmd_type) } } +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); +} + /* * Add/remove tracker to/from session. */ @@ -346,8 +614,85 @@ int cmd_track_untrack(enum cmd_type cmd_type, const char *cmd_str, list_cmd_options(stdout, long_options); goto end; case OPT_SESSION: + break; case OPT_PID: - opt_pid = 1; + 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"); + command_ret = CMD_ERROR; + goto end; + } + opt_vgid.used = 1; + type_state = STATE_VGID; + break; + case OPT_ALL: + 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; + } break; default: command_ret = CMD_UNDEFINED; @@ -357,7 +702,7 @@ int cmd_track_untrack(enum cmd_type cmd_type, const char *cmd_str, ret = print_missing_or_multiple_domains(opt_kernel + opt_userspace); if (ret) { - ret = CMD_ERROR; + command_ret = CMD_ERROR; goto end; } @@ -371,13 +716,6 @@ int cmd_track_untrack(enum cmd_type cmd_type, const char *cmd_str, session_name = opt_session_name; } - /* Currently only PID tracker is supported */ - if (!opt_pid) { - ERR("Please specify at least one tracker with its expected arguments"); - command_ret = CMD_ERROR; - goto end; - } - /* Mi check */ if (lttng_opt_mi) { writer = mi_lttng_writer_create(fileno(stdout), lttng_opt_mi); @@ -403,19 +741,66 @@ int cmd_track_untrack(enum cmd_type cmd_type, const char *cmd_str, command_ret = CMD_ERROR; goto end; } + + ret = mi_lttng_trackers_open(writer); + if (ret) { + goto end; + } } - command_ret = track_untrack_pid(cmd_type, - cmd_str, session_name, opt_pid_string, - opt_all, writer); - if (command_ret != CMD_SUCCESS) { - success = 0; + 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; + } + } + 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; + } } /* Mi closing */ if (writer) { - /* Close output element */ - ret = mi_lttng_writer_close_element(writer); + /* Close trackers and output elements */ + ret = mi_lttng_close_multi_element(writer, 2); if (ret) { command_ret = CMD_ERROR; goto end;