-/*
- * Walk the directories in the PATH environment variable to find the target
- * binary passed as parameter.
- *
- * On success, the full path of the binary is copied in binary_full_path out
- * parameter. This buffer is allocated by the caller and must be at least
- * LTTNG_PATH_MAX bytes long.
- * On failure, returns -1;
- */
-static int walk_command_search_path(const char *binary, char *binary_full_path)
-{
- char *tentative_binary_path = NULL;
- char *command_search_path = NULL;
- char *curr_search_dir_end = NULL;
- char *curr_search_dir = NULL;
- struct stat stat_output;
- int ret = 0;
-
- command_search_path = lttng_secure_getenv("PATH");
- if (!command_search_path) {
- ret = -1;
- goto end;
- }
-
- /*
- * Duplicate the $PATH string as the char pointer returned by getenv() should
- * not be modified.
- */
- command_search_path = strdup(command_search_path);
- if (!command_search_path) {
- ret = -1;
- goto end;
- }
-
- /*
- * This char array is used to concatenate path to binary to look for
- * the binary.
- */
- tentative_binary_path = zmalloc(LTTNG_PATH_MAX * sizeof(char));
- if (!tentative_binary_path) {
- ret = -1;
- goto alloc_error;
- }
-
- curr_search_dir = command_search_path;
- do {
- /*
- * Split on ':'. The return value of this call points to the
- * matching character.
- */
- curr_search_dir_end = strchr(curr_search_dir, ':');
- if (curr_search_dir_end != NULL) {
- /*
- * Add a NULL byte to the end of the first token so it
- * can be used as a string.
- */
- curr_search_dir_end[0] = '\0';
- }
-
- /* Empty the tentative path */
- memset(tentative_binary_path, 0, LTTNG_PATH_MAX * sizeof(char));
-
- /*
- * Build the tentative path to the binary using the current
- * search directory and the name of the binary.
- */
- ret = snprintf(tentative_binary_path, LTTNG_PATH_MAX, "%s/%s",
- curr_search_dir, binary);
- if (ret < 0) {
- goto free_binary_path;
- }
- if (ret < LTTNG_PATH_MAX) {
- /*
- * Use STAT(2) to see if the file exists.
- */
- ret = stat(tentative_binary_path, &stat_output);
- if (ret == 0) {
- /*
- * Verify that it is a regular file or a
- * symlink and not a special file (e.g.
- * device).
- */
- if (S_ISREG(stat_output.st_mode)
- || S_ISLNK(stat_output.st_mode)) {
- /*
- * Found a match, set the out parameter
- * and return success.
- */
- ret = lttng_strncpy(binary_full_path,
- tentative_binary_path,
- LTTNG_PATH_MAX);
- if (ret == -1) {
- ERR("Source path does not fit "
- "in destination buffer.");
- }
- goto free_binary_path;
- }
- }
- }
- /* Go to the next entry in the $PATH variable. */
- curr_search_dir = curr_search_dir_end + 1;
- } while (curr_search_dir_end != NULL);
-
-free_binary_path:
- free(tentative_binary_path);
-alloc_error:
- free(command_search_path);
-end:
- return ret;
-}
-
-/*
- * Parse userspace probe options
- * Set the userspace probe fields in the lttng_event struct and set the
- * target_path to the path to the binary.
- */
-static int parse_userspace_probe_opts(struct lttng_event *ev, char *opt)
-{
- int ret = CMD_SUCCESS;
- int num_token;
- char **tokens;
- char *target_path = NULL;
- char *unescaped_target_path = NULL;
- char *real_target_path = NULL;
- char *symbol_name = NULL, *probe_name = NULL, *provider_name = NULL;
- struct lttng_userspace_probe_location *probe_location = NULL;
- struct lttng_userspace_probe_location_lookup_method *lookup_method =
- NULL;
-
- if (opt == NULL) {
- ret = CMD_ERROR;
- goto end;
- }
-
- /*
- * userspace probe fields are separated by ':'.
- */
- tokens = strutils_split(opt, ':', 1);
- num_token = strutils_array_of_strings_len(tokens);
-
- /*
- * Early sanity check that the number of parameter is between 2 and 4
- * inclusively.
- * elf:PATH:SYMBOL
- * std:PATH:PROVIDER_NAME:PROBE_NAME
- * PATH:SYMBOL (same behavior as ELF)
- */
- if (num_token < 2 || num_token > 4) {
- ret = CMD_ERROR;
- goto end_string;
- }
-
- /*
- * Looking up the first parameter will tell the technique to use to
- * interpret the userspace probe/function description.
- */
- switch (num_token) {
- case 2:
- /* When the probe type is omitted we assume ELF for now. */
- case 3:
- if (num_token == 3 && strcmp(tokens[0], "elf") == 0) {
- target_path = tokens[1];
- symbol_name = tokens[2];
- } else if (num_token == 2) {
- target_path = tokens[0];
- symbol_name = tokens[1];
- } else {
- ret = CMD_ERROR;
- goto end_string;
- }
- lookup_method =
- lttng_userspace_probe_location_lookup_method_function_elf_create();
- if (!lookup_method) {
- WARN("Failed to create ELF lookup method");
- ret = CMD_ERROR;
- goto end_string;
- }
- break;
- case 4:
- if (strcmp(tokens[0], "sdt") == 0) {
- target_path = tokens[1];
- provider_name = tokens[2];
- probe_name = tokens[3];
- } else {
- ret = CMD_ERROR;
- goto end_string;
- }
- lookup_method =
- lttng_userspace_probe_location_lookup_method_tracepoint_sdt_create();
- if (!lookup_method) {
- WARN("Failed to create ELF lookup method");
- ret = CMD_ERROR;
- goto end_string;
- }
- break;
- default:
- ret = CMD_ERROR;
- goto end_string;
- }
-
- /* strutils_unescape_string allocates a new char *. */
- unescaped_target_path = strutils_unescape_string(target_path, 0);
- if (!unescaped_target_path) {
- ret = -LTTNG_ERR_INVALID;
- goto end_string;
- }
-
- /*
- * If there is not forward slash in the path. Walk the $PATH else
- * expand.
- */
- if (strchr(target_path, '/') == NULL) {
- /* Walk the $PATH variable to find the targeted binary. */
- real_target_path = zmalloc(LTTNG_PATH_MAX * sizeof(char));
- if (!real_target_path) {
- PERROR("Error allocating path buffer");
- ret = CMD_ERROR;
- goto end_unescaped_string;
- }
- ret = walk_command_search_path(target_path, real_target_path);
- if (ret) {
- ERR("Binary not found.");
- ret = CMD_ERROR;
- goto end_free_path;
- }
- } else {
- /*
- * Expand references to `/./` and `/../`. This function does not check
- * if the file exists.
- */
- real_target_path = utils_expand_path_keep_symlink(target_path);
- if (!real_target_path) {
- ERR("Error expanding the path to binary.");
- ret = CMD_ERROR;
- goto end_free_path;
- }
-
- /*
- * Check if the file exists using access(2). If it does not, walk the
- * $PATH.
- */
- ret = access(real_target_path, F_OK);
- if (ret) {
- ret = CMD_ERROR;
- goto end_free_path;
- }
- }
-
- switch (lttng_userspace_probe_location_lookup_method_get_type(lookup_method)) {
- case LTTNG_USERSPACE_PROBE_LOCATION_LOOKUP_METHOD_TYPE_FUNCTION_ELF:
- probe_location = lttng_userspace_probe_location_function_create(
- real_target_path, symbol_name, lookup_method);
- if (!probe_location) {
- WARN("Failed to create function probe location");
- ret = CMD_ERROR;
- goto end_destroy_lookup_method;
- }
-
- /* Ownership transferred to probe_location. */
- lookup_method = NULL;
-
- ret = lttng_event_set_userspace_probe_location(ev, probe_location);
- if (ret) {
- WARN("Failed to set probe location on event");
- ret = CMD_ERROR;
- goto end_destroy_location;
- }
- break;
- case LTTNG_USERSPACE_PROBE_LOCATION_LOOKUP_METHOD_TYPE_TRACEPOINT_SDT:
- probe_location = lttng_userspace_probe_location_tracepoint_create(
- real_target_path, provider_name, probe_name, lookup_method);
- if (!probe_location) {
- WARN("Failed to create function probe location");
- ret = CMD_ERROR;
- goto end_destroy_lookup_method;
- }
-
- /* Ownership transferred to probe_location. */
- lookup_method = NULL;
-
- ret = lttng_event_set_userspace_probe_location(ev, probe_location);
- if (ret) {
- WARN("Failed to set probe location on event");
- ret = CMD_ERROR;
- goto end_destroy_location;
- }
- break;
- default:
- ret = CMD_ERROR;
- goto end_string;
- }
-
- switch (ev->type) {
- case LTTNG_EVENT_USERSPACE_PROBE:
- break;
- default:
- assert(0);
- }
-
- goto end;
-
-end_destroy_location:
- lttng_userspace_probe_location_destroy(probe_location);
-end_destroy_lookup_method:
- lttng_userspace_probe_location_lookup_method_destroy(lookup_method);
-end_free_path:
- /*
- * Free path that was allocated by the call to realpath() or when walking
- * the PATH.
- */
- free(real_target_path);
-end_unescaped_string:
- free(unescaped_target_path);
-end_string:
- strutils_free_null_terminated_array_of_strings(tokens);
-end:
- return ret;
-}
-