1 /* 2 * Copyright 2008, Ingo Weinhold, ingo_weinhold@gmx.de. 3 * Copyright 2004-2015, Axel Dörfler, axeld@pinc-software.de. 4 * Distributed under the terms of the MIT License. 5 */ 6 7 8 #include <libroot_private.h> 9 #include <syscalls.h> 10 11 #include <alloca.h> 12 #include <errno.h> 13 #include <stdarg.h> 14 #include <stdio.h> 15 #include <stdlib.h> 16 #include <string.h> 17 #include <umask.h> 18 #include <unistd.h> 19 20 #include <errno_private.h> 21 22 23 static int 24 count_arguments(va_list list, const char* arg, char*** _env) 25 { 26 int count = 0; 27 28 while (arg != NULL) { 29 count++; 30 arg = va_arg(list, const char*); 31 } 32 33 if (_env) 34 *_env = va_arg(list, char**); 35 36 return count; 37 } 38 39 40 static void 41 copy_arguments(va_list list, const char** args, const char* arg) 42 { 43 int count = 0; 44 45 while (arg != NULL) { 46 args[count++] = arg; 47 arg = va_arg(list, const char*); 48 } 49 50 args[count] = NULL; 51 // terminate list 52 } 53 54 55 static int 56 do_exec(const char* path, char* const args[], char* const environment[], 57 bool useDefaultInterpreter) 58 { 59 if (path == NULL || args == NULL) { 60 __set_errno(B_BAD_VALUE); 61 return -1; 62 } 63 64 // Count argument/environment list entries here, we don't want 65 // to do this in the kernel 66 int32 argCount = 0; 67 while (args[argCount] != NULL) { 68 argCount++; 69 } 70 71 int32 envCount = 0; 72 if (environment != NULL) { 73 while (environment[envCount] != NULL) { 74 envCount++; 75 } 76 } 77 78 if (argCount == 0) { 79 // we need some more info on what to do... 80 __set_errno(B_BAD_VALUE); 81 return -1; 82 } 83 84 // Test validity of executable + support for scripts 85 char invoker[B_FILE_NAME_LENGTH]; 86 status_t status = __test_executable(path, invoker); 87 if (status < B_OK) { 88 if (status == B_NOT_AN_EXECUTABLE && useDefaultInterpreter) { 89 strcpy(invoker, "/bin/sh"); 90 status = B_OK; 91 } else { 92 __set_errno(status); 93 return -1; 94 } 95 } 96 97 char** newArgs = NULL; 98 if (invoker[0] != '\0') { 99 status = __parse_invoke_line(invoker, &newArgs, &args, &argCount, path); 100 if (status < B_OK) { 101 __set_errno(status); 102 return -1; 103 } 104 105 path = newArgs[0]; 106 } 107 108 char** flatArgs = NULL; 109 size_t flatArgsSize; 110 status = __flatten_process_args(newArgs ? newArgs : args, argCount, 111 environment, &envCount, path, &flatArgs, &flatArgsSize); 112 113 if (status == B_OK) { 114 __set_errno(_kern_exec(path, flatArgs, flatArgsSize, argCount, envCount, 115 __gUmask)); 116 // if this call returns, something definitely went wrong 117 118 free(flatArgs); 119 } else 120 __set_errno(status); 121 122 free(newArgs); 123 return -1; 124 } 125 126 127 // #pragma mark - 128 129 130 int 131 execve(const char* path, char* const args[], char* const environment[]) 132 { 133 return do_exec(path, args, environment, false); 134 } 135 136 137 int 138 execv(const char* path, char* const argv[]) 139 { 140 return do_exec(path, argv, environ, false); 141 } 142 143 144 int 145 execvp(const char* file, char* const argv[]) 146 { 147 return execvpe(file, argv, environ); 148 } 149 150 151 int 152 execvpe(const char* file, char* const argv[], char* const environment[]) 153 { 154 // let do_exec() handle cases where file is a path (or invalid) 155 if (file == NULL || strchr(file, '/') != NULL) 156 return do_exec(file, argv, environment, true); 157 158 // file is just a leaf name, so we have to look it up in the path 159 160 // get the PATH 161 const char* paths = getenv("PATH"); 162 if (paths == NULL) { 163 __set_errno(B_ENTRY_NOT_FOUND); 164 return -1; 165 } 166 167 int fileNameLen = strlen(file); 168 169 // iterate through the paths 170 const char* pathEnd = paths - 1; 171 while (pathEnd != NULL) { 172 paths = pathEnd + 1; 173 pathEnd = strchr(paths, ':'); 174 int pathLen = (pathEnd ? pathEnd - paths : strlen(paths)); 175 176 // We skip empty paths and those that would become too long. 177 // The latter is not really correct, but practically irrelevant. 178 if (pathLen == 0 179 || pathLen + 1 + fileNameLen >= B_PATH_NAME_LENGTH) { 180 continue; 181 } 182 183 // concatinate the program path 184 char path[B_PATH_NAME_LENGTH]; 185 memcpy(path, paths, pathLen); 186 path[pathLen] = '\0'; 187 188 if (path[pathLen - 1] != '/') 189 strcat(path, "/"); 190 strcat(path, file); 191 192 // check whether it is a file 193 struct stat st; 194 if (stat(path, &st) != 0 || !S_ISREG(st.st_mode)) 195 continue; 196 197 // if executable, execute it 198 if (access(path, X_OK) == 0) 199 return do_exec(path, argv, environment, true); 200 } 201 202 __set_errno(B_ENTRY_NOT_FOUND); 203 return -1; 204 } 205 206 207 int 208 execl(const char* path, const char* arg, ...) 209 { 210 const char** args; 211 va_list list; 212 int count; 213 214 // count arguments 215 216 va_start(list, arg); 217 count = count_arguments(list, arg, NULL); 218 va_end(list); 219 220 // copy arguments 221 222 args = (const char**)alloca((count + 1) * sizeof(char*)); 223 va_start(list, arg); 224 copy_arguments(list, args, arg); 225 va_end(list); 226 227 return do_exec(path, (char* const*)args, environ, false); 228 } 229 230 231 int 232 execlp(const char* file, const char* arg, ...) 233 { 234 const char** args; 235 va_list list; 236 int count; 237 238 // count arguments 239 240 va_start(list, arg); 241 count = count_arguments(list, arg, NULL); 242 va_end(list); 243 244 // copy arguments 245 246 args = (const char**)alloca((count + 1) * sizeof(char*)); 247 va_start(list, arg); 248 copy_arguments(list, args, arg); 249 va_end(list); 250 251 return execvp(file, (char* const*)args); 252 } 253 254 255 int 256 execle(const char* path, const char* arg, ... /*, char** env */) 257 { 258 const char** args; 259 char** env; 260 va_list list; 261 int count; 262 263 // count arguments 264 265 va_start(list, arg); 266 count = count_arguments(list, arg, &env); 267 va_end(list); 268 269 // copy arguments 270 271 args = (const char**)alloca((count + 1) * sizeof(char*)); 272 va_start(list, arg); 273 copy_arguments(list, args, arg); 274 va_end(list); 275 276 return do_exec(path, (char* const*)args, env, false); 277 } 278 279 // TODO: remove this again if possible 280 extern int exect(const char *path, char *const *argv); 281 282 int 283 exect(const char* path, char* const* argv) 284 { 285 return execv(path, argv); 286 } 287