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