headers/bsd: Add sys/queue.h.
[haiku.git] / src / system / libroot / posix / unistd / exec.cpp
blobbbc74466555e06364a343ed5bd6a6089b11d13d3
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 */
8 #include <libroot_private.h>
9 #include <syscalls.h>
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>
20 #include <errno_private.h>
23 static int
24 count_arguments(va_list list, const char* arg, char*** _env)
26 int count = 0;
28 while (arg != NULL) {
29 count++;
30 arg = va_arg(list, const char*);
33 if (_env)
34 *_env = va_arg(list, char**);
36 return count;
40 static void
41 copy_arguments(va_list list, const char** args, const char* arg)
43 int count = 0;
45 while (arg != NULL) {
46 args[count++] = arg;
47 arg = va_arg(list, const char*);
50 args[count] = NULL;
51 // terminate list
55 static int
56 do_exec(const char* path, char* const args[], char* const environment[],
57 bool useDefaultInterpreter)
59 if (path == NULL || args == NULL) {
60 __set_errno(B_BAD_VALUE);
61 return -1;
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++;
71 int32 envCount = 0;
72 if (environment != NULL) {
73 while (environment[envCount] != NULL) {
74 envCount++;
78 if (argCount == 0) {
79 // we need some more info on what to do...
80 __set_errno(B_BAD_VALUE);
81 return -1;
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;
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;
105 path = newArgs[0];
108 char** flatArgs = NULL;
109 size_t flatArgsSize;
110 status = __flatten_process_args(newArgs ? newArgs : args, argCount,
111 environment, &envCount, path, &flatArgs, &flatArgsSize);
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
118 free(flatArgs);
119 } else
120 __set_errno(status);
122 free(newArgs);
123 return -1;
127 // #pragma mark -
131 execve(const char* path, char* const args[], char* const environment[])
133 return do_exec(path, args, environment, false);
138 execv(const char* path, char* const argv[])
140 return do_exec(path, argv, environ, false);
145 execvp(const char* file, char* const argv[])
147 return execvpe(file, argv, environ);
152 execvpe(const char* file, char* const argv[], char* const environment[])
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);
158 // file is just a leaf name, so we have to look it up in the path
160 // get the PATH
161 const char* paths = getenv("PATH");
162 if (paths == NULL) {
163 __set_errno(B_ENTRY_NOT_FOUND);
164 return -1;
167 int fileNameLen = strlen(file);
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));
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;
183 // concatinate the program path
184 char path[B_PATH_NAME_LENGTH];
185 memcpy(path, paths, pathLen);
186 path[pathLen] = '\0';
188 if (path[pathLen - 1] != '/')
189 strcat(path, "/");
190 strcat(path, file);
192 // check whether it is a file
193 struct stat st;
194 if (stat(path, &st) != 0 || !S_ISREG(st.st_mode))
195 continue;
197 // if executable, execute it
198 if (access(path, X_OK) == 0)
199 return do_exec(path, argv, environment, true);
202 __set_errno(B_ENTRY_NOT_FOUND);
203 return -1;
208 execl(const char* path, const char* arg, ...)
210 const char** args;
211 va_list list;
212 int count;
214 // count arguments
216 va_start(list, arg);
217 count = count_arguments(list, arg, NULL);
218 va_end(list);
220 // copy arguments
222 args = (const char**)alloca((count + 1) * sizeof(char*));
223 va_start(list, arg);
224 copy_arguments(list, args, arg);
225 va_end(list);
227 return do_exec(path, (char* const*)args, environ, false);
232 execlp(const char* file, const char* arg, ...)
234 const char** args;
235 va_list list;
236 int count;
238 // count arguments
240 va_start(list, arg);
241 count = count_arguments(list, arg, NULL);
242 va_end(list);
244 // copy arguments
246 args = (const char**)alloca((count + 1) * sizeof(char*));
247 va_start(list, arg);
248 copy_arguments(list, args, arg);
249 va_end(list);
251 return execvp(file, (char* const*)args);
256 execle(const char* path, const char* arg, ... /*, char** env */)
258 const char** args;
259 char** env;
260 va_list list;
261 int count;
263 // count arguments
265 va_start(list, arg);
266 count = count_arguments(list, arg, &env);
267 va_end(list);
269 // copy arguments
271 args = (const char**)alloca((count + 1) * sizeof(char*));
272 va_start(list, arg);
273 copy_arguments(list, args, arg);
274 va_end(list);
276 return do_exec(path, (char* const*)args, env, false);
279 // TODO: remove this again if possible
280 extern int exect(const char *path, char *const *argv);
283 exect(const char* path, char* const* argv)
285 return execv(path, argv);