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