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