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
23static int
24count_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
40static void
41copy_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
55static int
56do_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
125int
126execve(const char *path, char* const args[], char* const environment[])
127{
128	return do_exec(path, args, environment, false);
129}
130
131
132int
133execv(const char *path, char * const *argv)
134{
135	return do_exec(path, argv, environ, false);
136}
137
138
139int
140execvp(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
195int
196execl(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
219int
220execlp(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
243int
244execle(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
268int
269exect(const char *path, char * const *argv)
270{
271	// ToDo: is this any different?
272	return execv(path, argv);
273}
274
275