1#include "cache.h" 2#include "exec_cmd.h" 3#include "quote.h" 4 5#include <string.h> 6 7#define MAX_ARGS 32 8 9static const char *argv_exec_path; 10static const char *argv0_path; 11 12const char *system_path(const char *path) 13{ 14#ifdef RUNTIME_PREFIX 15 static const char *prefix; 16#else 17 static const char *prefix = PREFIX; 18#endif 19 struct strbuf d = STRBUF_INIT; 20 21 if (is_absolute_path(path)) 22 return path; 23 24#ifdef RUNTIME_PREFIX 25 assert(argv0_path); 26 assert(is_absolute_path(argv0_path)); 27 28 if (!prefix && 29 !(prefix = strip_path_suffix(argv0_path, PERF_EXEC_PATH)) && 30 !(prefix = strip_path_suffix(argv0_path, BINDIR)) && 31 !(prefix = strip_path_suffix(argv0_path, "perf"))) { 32 prefix = PREFIX; 33 fprintf(stderr, "RUNTIME_PREFIX requested, " 34 "but prefix computation failed. " 35 "Using static fallback '%s'.\n", prefix); 36 } 37#endif 38 39 strbuf_addf(&d, "%s/%s", prefix, path); 40 path = strbuf_detach(&d, NULL); 41 return path; 42} 43 44const char *perf_extract_argv0_path(const char *argv0) 45{ 46 const char *slash; 47 48 if (!argv0 || !*argv0) 49 return NULL; 50 slash = argv0 + strlen(argv0); 51 52 while (argv0 <= slash && !is_dir_sep(*slash)) 53 slash--; 54 55 if (slash >= argv0) { 56 argv0_path = strndup(argv0, slash - argv0); 57 return argv0_path ? slash + 1 : NULL; 58 } 59 60 return argv0; 61} 62 63void perf_set_argv_exec_path(const char *exec_path) 64{ 65 argv_exec_path = exec_path; 66 /* 67 * Propagate this setting to external programs. 68 */ 69 setenv(EXEC_PATH_ENVIRONMENT, exec_path, 1); 70} 71 72 73/* Returns the highest-priority, location to look for perf programs. */ 74const char *perf_exec_path(void) 75{ 76 const char *env; 77 78 if (argv_exec_path) 79 return argv_exec_path; 80 81 env = getenv(EXEC_PATH_ENVIRONMENT); 82 if (env && *env) { 83 return env; 84 } 85 86 return system_path(PERF_EXEC_PATH); 87} 88 89static void add_path(struct strbuf *out, const char *path) 90{ 91 if (path && *path) { 92 if (is_absolute_path(path)) 93 strbuf_addstr(out, path); 94 else 95 strbuf_addstr(out, make_nonrelative_path(path)); 96 97 strbuf_addch(out, PATH_SEP); 98 } 99} 100 101void setup_path(void) 102{ 103 const char *old_path = getenv("PATH"); 104 struct strbuf new_path = STRBUF_INIT; 105 106 add_path(&new_path, perf_exec_path()); 107 add_path(&new_path, argv0_path); 108 109 if (old_path) 110 strbuf_addstr(&new_path, old_path); 111 else 112 strbuf_addstr(&new_path, "/usr/local/bin:/usr/bin:/bin"); 113 114 setenv("PATH", new_path.buf, 1); 115 116 strbuf_release(&new_path); 117} 118 119static const char **prepare_perf_cmd(const char **argv) 120{ 121 int argc; 122 const char **nargv; 123 124 for (argc = 0; argv[argc]; argc++) 125 ; /* just counting */ 126 nargv = malloc(sizeof(*nargv) * (argc + 2)); 127 128 nargv[0] = "perf"; 129 for (argc = 0; argv[argc]; argc++) 130 nargv[argc + 1] = argv[argc]; 131 nargv[argc + 1] = NULL; 132 return nargv; 133} 134 135int execv_perf_cmd(const char **argv) { 136 const char **nargv = prepare_perf_cmd(argv); 137 138 /* execvp() can only ever return if it fails */ 139 execvp("perf", (char **)nargv); 140 141 free(nargv); 142 return -1; 143} 144 145 146int execl_perf_cmd(const char *cmd,...) 147{ 148 int argc; 149 const char *argv[MAX_ARGS + 1]; 150 const char *arg; 151 va_list param; 152 153 va_start(param, cmd); 154 argv[0] = cmd; 155 argc = 1; 156 while (argc < MAX_ARGS) { 157 arg = argv[argc++] = va_arg(param, char *); 158 if (!arg) 159 break; 160 } 161 va_end(param); 162 if (MAX_ARGS <= argc) 163 return error("too many args to run %s", cmd); 164 165 argv[argc] = NULL; 166 return execv_perf_cmd(argv); 167} 168