1 // SPDX-License-Identifier: GPL-2.0 << 2 #include <linux/compiler.h> 1 #include <linux/compiler.h> 3 #include <linux/string.h> 2 #include <linux/string.h> 4 #include <sys/types.h> 3 #include <sys/types.h> 5 #include <sys/stat.h> 4 #include <sys/stat.h> 6 #include <unistd.h> 5 #include <unistd.h> 7 #include <string.h> 6 #include <string.h> 8 #include <stdlib.h> 7 #include <stdlib.h> 9 #include <stdio.h> 8 #include <stdio.h> 10 #include "subcmd-util.h" 9 #include "subcmd-util.h" 11 #include "exec-cmd.h" 10 #include "exec-cmd.h" 12 #include "subcmd-config.h" 11 #include "subcmd-config.h" 13 12 14 #define MAX_ARGS 32 13 #define MAX_ARGS 32 15 #define PATH_MAX 4096 14 #define PATH_MAX 4096 16 15 17 static const char *argv_exec_path; 16 static const char *argv_exec_path; 18 static const char *argv0_path; 17 static const char *argv0_path; 19 18 20 void exec_cmd_init(const char *exec_name, cons 19 void exec_cmd_init(const char *exec_name, const char *prefix, 21 const char *exec_path, cons 20 const char *exec_path, const char *exec_path_env) 22 { 21 { 23 subcmd_config.exec_name = exec 22 subcmd_config.exec_name = exec_name; 24 subcmd_config.prefix = pref 23 subcmd_config.prefix = prefix; 25 subcmd_config.exec_path = exec 24 subcmd_config.exec_path = exec_path; 26 subcmd_config.exec_path_env = exec 25 subcmd_config.exec_path_env = exec_path_env; 27 << 28 /* Setup environment variable for invo << 29 setenv("PREFIX", prefix, 1); << 30 } 26 } 31 27 32 #define is_dir_sep(c) ((c) == '/') 28 #define is_dir_sep(c) ((c) == '/') 33 29 34 static int is_absolute_path(const char *path) 30 static int is_absolute_path(const char *path) 35 { 31 { 36 return path[0] == '/'; 32 return path[0] == '/'; 37 } 33 } 38 34 39 static const char *get_pwd_cwd(char *buf, size !! 35 static const char *get_pwd_cwd(void) 40 { 36 { >> 37 static char cwd[PATH_MAX + 1]; 41 char *pwd; 38 char *pwd; 42 struct stat cwd_stat, pwd_stat; 39 struct stat cwd_stat, pwd_stat; 43 if (getcwd(buf, sz) == NULL) !! 40 if (getcwd(cwd, PATH_MAX) == NULL) 44 return NULL; 41 return NULL; 45 pwd = getenv("PWD"); 42 pwd = getenv("PWD"); 46 if (pwd && strcmp(pwd, buf)) { !! 43 if (pwd && strcmp(pwd, cwd)) { 47 stat(buf, &cwd_stat); !! 44 stat(cwd, &cwd_stat); 48 if (!stat(pwd, &pwd_stat) && 45 if (!stat(pwd, &pwd_stat) && 49 pwd_stat.st_dev == cwd_sta 46 pwd_stat.st_dev == cwd_stat.st_dev && 50 pwd_stat.st_ino == cwd_sta 47 pwd_stat.st_ino == cwd_stat.st_ino) { 51 strlcpy(buf, pwd, sz); !! 48 strlcpy(cwd, pwd, PATH_MAX); 52 } 49 } 53 } 50 } 54 return buf; !! 51 return cwd; 55 } 52 } 56 53 57 static const char *make_nonrelative_path(char !! 54 static const char *make_nonrelative_path(const char *path) 58 { 55 { >> 56 static char buf[PATH_MAX + 1]; >> 57 59 if (is_absolute_path(path)) { 58 if (is_absolute_path(path)) { 60 if (strlcpy(buf, path, sz) >= !! 59 if (strlcpy(buf, path, PATH_MAX) >= PATH_MAX) 61 die("Too long path: %. 60 die("Too long path: %.*s", 60, path); 62 } else { 61 } else { 63 const char *cwd = get_pwd_cwd( !! 62 const char *cwd = get_pwd_cwd(); 64 << 65 if (!cwd) 63 if (!cwd) 66 die("Cannot determine 64 die("Cannot determine the current working directory"); 67 !! 65 if (snprintf(buf, PATH_MAX, "%s/%s", cwd, path) >= PATH_MAX) 68 if (strlen(cwd) + strlen(path) << 69 die("Too long path: %. 66 die("Too long path: %.*s", 60, path); 70 << 71 strcat(buf, "/"); << 72 strcat(buf, path); << 73 } 67 } 74 return buf; 68 return buf; 75 } 69 } 76 70 77 char *system_path(const char *path) 71 char *system_path(const char *path) 78 { 72 { 79 char *buf = NULL; 73 char *buf = NULL; 80 74 81 if (is_absolute_path(path)) 75 if (is_absolute_path(path)) 82 return strdup(path); 76 return strdup(path); 83 77 84 astrcatf(&buf, "%s/%s", subcmd_config. 78 astrcatf(&buf, "%s/%s", subcmd_config.prefix, path); 85 79 86 return buf; 80 return buf; 87 } 81 } 88 82 89 const char *extract_argv0_path(const char *arg 83 const char *extract_argv0_path(const char *argv0) 90 { 84 { 91 const char *slash; 85 const char *slash; 92 86 93 if (!argv0 || !*argv0) 87 if (!argv0 || !*argv0) 94 return NULL; 88 return NULL; 95 slash = argv0 + strlen(argv0); 89 slash = argv0 + strlen(argv0); 96 90 97 while (argv0 <= slash && !is_dir_sep(* 91 while (argv0 <= slash && !is_dir_sep(*slash)) 98 slash--; 92 slash--; 99 93 100 if (slash >= argv0) { 94 if (slash >= argv0) { 101 argv0_path = strndup(argv0, sl 95 argv0_path = strndup(argv0, slash - argv0); 102 return argv0_path ? slash + 1 96 return argv0_path ? slash + 1 : NULL; 103 } 97 } 104 98 105 return argv0; 99 return argv0; 106 } 100 } 107 101 108 void set_argv_exec_path(const char *exec_path) 102 void set_argv_exec_path(const char *exec_path) 109 { 103 { 110 argv_exec_path = exec_path; 104 argv_exec_path = exec_path; 111 /* 105 /* 112 * Propagate this setting to external 106 * Propagate this setting to external programs. 113 */ 107 */ 114 setenv(subcmd_config.exec_path_env, ex 108 setenv(subcmd_config.exec_path_env, exec_path, 1); 115 } 109 } 116 110 117 111 118 /* Returns the highest-priority location to lo 112 /* Returns the highest-priority location to look for subprograms. */ 119 char *get_argv_exec_path(void) 113 char *get_argv_exec_path(void) 120 { 114 { 121 char *env; 115 char *env; 122 116 123 if (argv_exec_path) 117 if (argv_exec_path) 124 return strdup(argv_exec_path); 118 return strdup(argv_exec_path); 125 119 126 env = getenv(subcmd_config.exec_path_e 120 env = getenv(subcmd_config.exec_path_env); 127 if (env && *env) 121 if (env && *env) 128 return strdup(env); 122 return strdup(env); 129 123 130 return system_path(subcmd_config.exec_ 124 return system_path(subcmd_config.exec_path); 131 } 125 } 132 126 133 static void add_path(char **out, const char *p 127 static void add_path(char **out, const char *path) 134 { 128 { 135 if (path && *path) { 129 if (path && *path) { 136 if (is_absolute_path(path)) 130 if (is_absolute_path(path)) 137 astrcat(out, path); 131 astrcat(out, path); 138 else { !! 132 else 139 char buf[PATH_MAX]; !! 133 astrcat(out, make_nonrelative_path(path)); 140 << 141 astrcat(out, make_nonr << 142 } << 143 134 144 astrcat(out, ":"); 135 astrcat(out, ":"); 145 } 136 } 146 } 137 } 147 138 148 void setup_path(void) 139 void setup_path(void) 149 { 140 { 150 const char *old_path = getenv("PATH"); 141 const char *old_path = getenv("PATH"); 151 char *new_path = NULL; 142 char *new_path = NULL; 152 char *tmp = get_argv_exec_path(); 143 char *tmp = get_argv_exec_path(); 153 144 154 add_path(&new_path, tmp); 145 add_path(&new_path, tmp); 155 add_path(&new_path, argv0_path); 146 add_path(&new_path, argv0_path); 156 free(tmp); 147 free(tmp); 157 148 158 if (old_path) 149 if (old_path) 159 astrcat(&new_path, old_path); 150 astrcat(&new_path, old_path); 160 else 151 else 161 astrcat(&new_path, "/usr/local 152 astrcat(&new_path, "/usr/local/bin:/usr/bin:/bin"); 162 153 163 setenv("PATH", new_path, 1); 154 setenv("PATH", new_path, 1); 164 155 165 free(new_path); 156 free(new_path); 166 } 157 } 167 158 168 static const char **prepare_exec_cmd(const cha 159 static const char **prepare_exec_cmd(const char **argv) 169 { 160 { 170 int argc; 161 int argc; 171 const char **nargv; 162 const char **nargv; 172 163 173 for (argc = 0; argv[argc]; argc++) 164 for (argc = 0; argv[argc]; argc++) 174 ; /* just counting */ 165 ; /* just counting */ 175 nargv = malloc(sizeof(*nargv) * (argc 166 nargv = malloc(sizeof(*nargv) * (argc + 2)); 176 167 177 nargv[0] = subcmd_config.exec_name; 168 nargv[0] = subcmd_config.exec_name; 178 for (argc = 0; argv[argc]; argc++) 169 for (argc = 0; argv[argc]; argc++) 179 nargv[argc + 1] = argv[argc]; 170 nargv[argc + 1] = argv[argc]; 180 nargv[argc + 1] = NULL; 171 nargv[argc + 1] = NULL; 181 return nargv; 172 return nargv; 182 } 173 } 183 174 184 int execv_cmd(const char **argv) { 175 int execv_cmd(const char **argv) { 185 const char **nargv = prepare_exec_cmd( 176 const char **nargv = prepare_exec_cmd(argv); 186 177 187 /* execvp() can only ever return if it 178 /* execvp() can only ever return if it fails */ 188 execvp(subcmd_config.exec_name, (char 179 execvp(subcmd_config.exec_name, (char **)nargv); 189 180 190 free(nargv); 181 free(nargv); 191 return -1; 182 return -1; 192 } 183 } 193 184 194 185 195 int execl_cmd(const char *cmd,...) 186 int execl_cmd(const char *cmd,...) 196 { 187 { 197 int argc; 188 int argc; 198 const char *argv[MAX_ARGS + 1]; 189 const char *argv[MAX_ARGS + 1]; 199 const char *arg; 190 const char *arg; 200 va_list param; 191 va_list param; 201 192 202 va_start(param, cmd); 193 va_start(param, cmd); 203 argv[0] = cmd; 194 argv[0] = cmd; 204 argc = 1; 195 argc = 1; 205 while (argc < MAX_ARGS) { 196 while (argc < MAX_ARGS) { 206 arg = argv[argc++] = va_arg(pa 197 arg = argv[argc++] = va_arg(param, char *); 207 if (!arg) 198 if (!arg) 208 break; 199 break; 209 } 200 } 210 va_end(param); 201 va_end(param); 211 if (MAX_ARGS <= argc) { 202 if (MAX_ARGS <= argc) { 212 fprintf(stderr, " Error: too m 203 fprintf(stderr, " Error: too many args to run %s\n", cmd); 213 return -1; 204 return -1; 214 } 205 } 215 206 216 argv[argc] = NULL; 207 argv[argc] = NULL; 217 return execv_cmd(argv); 208 return execv_cmd(argv); 218 } 209 } 219 210
Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.