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
count_arguments(va_list list,const char * arg,char *** _env)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
copy_arguments(va_list list,const char ** args,const char * arg)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
do_exec(const char * path,char * const args[],char * const environment[],bool useDefaultInterpreter)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
execve(const char * path,char * const args[],char * const environment[])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
execv(const char * path,char * const argv[])138 execv(const char* path, char* const argv[])
139 {
140 return do_exec(path, argv, environ, false);
141 }
142
143
144 int
execvp(const char * file,char * const argv[])145 execvp(const char* file, char* const argv[])
146 {
147 return execvpe(file, argv, environ);
148 }
149
150
151 int
execvpe(const char * file,char * const argv[],char * const environment[])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
execl(const char * path,const char * arg,...)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
execlp(const char * file,const char * arg,...)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
execle(const char * path,const char * arg,...)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
exect(const char * path,char * const * argv)247 exect(const char* path, char* const* argv)
248 {
249 return execv(path, argv);
250 }
251