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