xref: /haiku/src/system/libroot/posix/unistd/exec.cpp (revision b46615c55ad2c8fe6de54412055a0713da3d610a)
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 
21 static int
22 count_arguments(va_list list, const char *arg, char ***_env)
23 {
24 	int count = 0;
25 
26 	while (arg != NULL) {
27 		count++;
28 		arg = va_arg(list, const char *);
29 	}
30 
31 	if (_env)
32 		*_env = va_arg(list, char **);
33 
34 	return count;
35 }
36 
37 
38 static void
39 copy_arguments(va_list list, const char **args, const char *arg)
40 {
41 	int count = 0;
42 
43 	while (arg != NULL) {
44 		args[count++] = arg;
45 		arg = va_arg(list, const char *);
46 	}
47 
48 	args[count] = NULL;
49 		// terminate list
50 }
51 
52 
53 static int
54 do_exec(const char *path, char * const args[], char * const environment[],
55 	bool useDefaultInterpreter)
56 {
57 	int32 argCount = 0, envCount = 0;
58 	char invoker[B_FILE_NAME_LENGTH];
59 	char **newArgs = NULL;
60 
61 	if (path == NULL) {
62 		errno = B_BAD_VALUE;
63 		return -1;
64 	}
65 
66 	// count argument/environment list entries here, we don't want
67 	// to do this in the kernel
68 	while (args[argCount] != NULL)
69 		argCount++;
70 	while (environment[envCount] != NULL)
71 		envCount++;
72 
73 	if (argCount == 0) {
74 		// we need some more info on what to do...
75 		errno = B_BAD_VALUE;
76 		return -1;
77 	}
78 
79 	// test validity of executable + support for scripts
80 	status_t status = __test_executable(path, invoker);
81 	if (status < B_OK) {
82 		if (status == B_NOT_AN_EXECUTABLE && useDefaultInterpreter) {
83 			strcpy(invoker, "/bin/sh");
84 			status = B_OK;
85 		} else {
86 			errno = status;
87 			return -1;
88 		}
89 	}
90 
91 	if (invoker[0] != '\0') {
92 		status = __parse_invoke_line(invoker, &newArgs, &args, &argCount, path);
93 		if (status < B_OK) {
94 			errno = status;
95 			return -1;
96 		}
97 
98 		path = newArgs[0];
99 	}
100 
101 	char** flatArgs = NULL;
102 	size_t flatArgsSize;
103 	status = __flatten_process_args(newArgs ? newArgs : args, argCount,
104 		environment, envCount, &flatArgs, &flatArgsSize);
105 
106 	if (status == B_OK) {
107 		errno = _kern_exec(path, flatArgs, flatArgsSize, argCount, envCount,
108 			__gUmask);
109 			// if this call returns, something definitely went wrong
110 
111 		free(flatArgs);
112 	} else
113 		errno = status;
114 
115 	free(newArgs);
116 	return -1;
117 }
118 
119 
120 //	#pragma mark -
121 
122 
123 int
124 execve(const char *path, char* const args[], char* const environment[])
125 {
126 	return do_exec(path, args, environment, false);
127 }
128 
129 
130 int
131 execv(const char *path, char * const *argv)
132 {
133 	return do_exec(path, argv, environ, false);
134 }
135 
136 
137 int
138 execvp(const char *file, char* const* argv)
139 {
140 	// let do_exec() handle cases where file is a path (or invalid)
141 	if (file == NULL || strchr(file, '/') != NULL)
142 		return do_exec(file, argv, environ, true);
143 
144 	// file is just a leaf name, so we have to look it up in the path
145 
146 	// get the PATH
147 	const char* paths = getenv("PATH");
148 	if (paths == NULL) {
149 		errno = B_ENTRY_NOT_FOUND;
150 		return -1;
151 	}
152 
153 	int fileNameLen = strlen(file);
154 
155 	// iterate through the paths
156 	const char* pathEnd = paths - 1;
157 	while (pathEnd != NULL) {
158 		paths = pathEnd + 1;
159 		pathEnd = strchr(paths, ':');
160 		int pathLen = (pathEnd ? pathEnd - paths : strlen(paths));
161 
162 		// We skip empty paths and those that would become too long.
163 		// The latter is not really correct, but practically irrelevant.
164 		if (pathLen == 0
165 			|| pathLen + 1 + fileNameLen >= B_PATH_NAME_LENGTH) {
166 			continue;
167 		}
168 
169 		// concatinate the program path
170 		char path[B_PATH_NAME_LENGTH];
171 		memcpy(path, paths, pathLen);
172 		path[pathLen] = '\0';
173 
174 		if (path[pathLen - 1] != '/')
175 			strcat(path, "/");
176 		strcat(path, file);
177 
178 		// check whether it is a file
179 		struct stat st;
180 		if (stat(path, &st) != 0 || !S_ISREG(st.st_mode))
181 			continue;
182 
183 		// if executable, execute it
184 		if (access(path, X_OK) == 0)
185 			return do_exec(path, argv, environ, true);
186 	}
187 
188 	errno = B_ENTRY_NOT_FOUND;
189 	return -1;
190 }
191 
192 
193 int
194 execl(const char *path, const char *arg, ...)
195 {
196 	const char **args;
197 	va_list list;
198 	int count;
199 
200 	// count arguments
201 
202 	va_start(list, arg);
203 	count = count_arguments(list, arg, NULL);
204 	va_end(list);
205 
206 	// copy arguments
207 
208 	args = (const char**)alloca((count + 1) * sizeof(char *));
209 	va_start(list, arg);
210 	copy_arguments(list, args, arg);
211 	va_end(list);
212 
213 	return do_exec(path, (char * const *)args, environ, false);
214 }
215 
216 
217 int
218 execlp(const char *file, const char *arg, ...)
219 {
220 	const char **args;
221 	va_list list;
222 	int count;
223 
224 	// count arguments
225 
226 	va_start(list, arg);
227 	count = count_arguments(list, arg, NULL);
228 	va_end(list);
229 
230 	// copy arguments
231 
232 	args = (const char**)alloca((count + 1) * sizeof(char *));
233 	va_start(list, arg);
234 	copy_arguments(list, args, arg);
235 	va_end(list);
236 
237 	return execvp(file, (char * const *)args);
238 }
239 
240 
241 int
242 execle(const char *path, const char *arg, ... /*, char **env */)
243 {
244 	const char **args;
245 	char **env;
246 	va_list list;
247 	int count;
248 
249 	// count arguments
250 
251 	va_start(list, arg);
252 	count = count_arguments(list, arg, &env);
253 	va_end(list);
254 
255 	// copy arguments
256 
257 	args = (const char**)alloca((count + 1) * sizeof(char *));
258 	va_start(list, arg);
259 	copy_arguments(list, args, arg);
260 	va_end(list);
261 
262 	return do_exec(path, (char * const *)args, env, false);
263 }
264 
265 
266 int
267 exect(const char *path, char * const *argv)
268 {
269 	// ToDo: is this any different?
270 	return execv(path, argv);
271 }
272 
273