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
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	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
130int
131execve(const char* path, char* const args[], char* const environment[])
132{
133	return do_exec(path, args, environment, false);
134}
135
136
137int
138execv(const char* path, char* const argv[])
139{
140	return do_exec(path, argv, environ, false);
141}
142
143
144int
145execvp(const char* file, char* const argv[])
146{
147	return execvpe(file, argv, environ);
148}
149
150
151int
152execvpe(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
171int
172execl(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
195int
196execlp(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
219int
220execle(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
244extern int exect(const char *path, char *const *argv);
245
246int
247exect(const char* path, char* const* argv)
248{
249	return execv(path, argv);
250}
251