xref: /haiku/src/system/libroot/posix/unistd/exec.cpp (revision 9e54316c528c34ee76f4d0d21150ceadd031c4de)
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