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