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