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