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 char path[B_PATH_NAME_LENGTH]; 161 status_t status = __look_up_in_path(file, path); 162 if (status != B_OK) { 163 __set_errno(status); 164 return -1; 165 } 166 167 return do_exec(path, argv, environment, true); 168 } 169 170 171 int 172 execl(const char* path, const char* arg, ...) 173 { 174 const char** args; 175 va_list list; 176 int count; 177 178 // count arguments 179 180 va_start(list, arg); 181 count = count_arguments(list, arg, NULL); 182 va_end(list); 183 184 // copy arguments 185 186 args = (const char**)alloca((count + 1) * sizeof(char*)); 187 va_start(list, arg); 188 copy_arguments(list, args, arg); 189 va_end(list); 190 191 return do_exec(path, (char* const*)args, environ, false); 192 } 193 194 195 int 196 execlp(const char* file, 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 execvp(file, (char* const*)args); 216 } 217 218 219 int 220 execle(const char* path, const char* arg, ... /*, char** env */) 221 { 222 const char** args; 223 char** env; 224 va_list list; 225 int count; 226 227 // count arguments 228 229 va_start(list, arg); 230 count = count_arguments(list, arg, &env); 231 va_end(list); 232 233 // copy arguments 234 235 args = (const char**)alloca((count + 1) * sizeof(char*)); 236 va_start(list, arg); 237 copy_arguments(list, args, arg); 238 va_end(list); 239 240 return do_exec(path, (char* const*)args, env, false); 241 } 242 243 // TODO: remove this again if possible 244 extern int exect(const char *path, char *const *argv); 245 246 int 247 exect(const char* path, char* const* argv) 248 { 249 return execv(path, argv); 250 } 251