1/*
2 * Copyright 2003-2007, Axel Dörfler, axeld@pinc-software.de. All rights reserved.
3 * Distributed under the terms of the MIT License.
4 */
5
6#include <image.h>
7#include <image_private.h>
8
9#include <stdlib.h>
10#include <string.h>
11
12#include <OS.h>
13
14#include <libroot_private.h>
15#include <runtime_loader.h>
16#include <syscalls.h>
17#include <user_runtime.h>
18
19
20thread_id
21load_image(int32 argCount, const char **args, const char **environ)
22{
23	char invoker[B_FILE_NAME_LENGTH];
24	char **newArgs = NULL;
25	int32 envCount = 0;
26	thread_id thread;
27
28	if (argCount < 1 || environ == NULL)
29		return B_BAD_VALUE;
30
31	// test validity of executable + support for scripts
32	{
33		status_t status = __test_executable(args[0], invoker);
34		if (status < B_OK)
35			return status;
36
37		if (invoker[0]) {
38			status = __parse_invoke_line(invoker, &newArgs,
39				(char * const **)&args, &argCount, args[0]);
40			if (status < B_OK)
41				return status;
42		}
43	}
44
45	// count environment variables
46	while (environ[envCount] != NULL)
47		envCount++;
48
49	char** flatArgs = NULL;
50	size_t flatArgsSize;
51	status_t status = __flatten_process_args(args, argCount, environ, envCount,
52		&flatArgs, &flatArgsSize);
53
54	if (status == B_OK) {
55		thread = _kern_load_image(flatArgs, flatArgsSize, argCount, envCount,
56			B_NORMAL_PRIORITY, B_WAIT_TILL_LOADED, -1, 0);
57
58		free(flatArgs);
59	} else
60		thread = status;
61
62	free(newArgs);
63	return thread;
64}
65
66
67image_id
68load_add_on(char const *name)
69{
70	if (name == NULL)
71		return B_BAD_VALUE;
72
73	return __gRuntimeLoader->load_add_on(name, 0);
74}
75
76
77status_t
78unload_add_on(image_id id)
79{
80	return __gRuntimeLoader->unload_add_on(id);
81}
82
83
84status_t
85get_image_symbol(image_id id, char const *symbolName, int32 symbolType,
86	void **_location)
87{
88	return __gRuntimeLoader->get_image_symbol(id, symbolName, symbolType,
89		false, NULL, _location);
90}
91
92
93status_t
94get_image_symbol_etc(image_id id, char const *symbolName, int32 symbolType,
95	bool recursive, image_id *_inImage, void **_location)
96{
97	return __gRuntimeLoader->get_image_symbol(id, symbolName, symbolType,
98		recursive, _inImage, _location);
99}
100
101
102status_t
103get_nth_image_symbol(image_id id, int32 num, char *nameBuffer, int32 *_nameLength,
104	int32 *_symbolType, void **_location)
105{
106	return __gRuntimeLoader->get_nth_image_symbol(id, num, nameBuffer, _nameLength, _symbolType, _location);
107}
108
109
110status_t
111_get_image_info(image_id id, image_info *info, size_t infoSize)
112{
113	return _kern_get_image_info(id, info, infoSize);
114}
115
116
117status_t
118_get_next_image_info(team_id team, int32 *cookie, image_info *info, size_t infoSize)
119{
120	return _kern_get_next_image_info(team, cookie, info, infoSize);
121}
122
123
124void
125clear_caches(void *address, size_t length, uint32 flags)
126{
127	_kern_clear_caches(address, length, flags);
128}
129
130
131//	#pragma mark -
132
133
134static char *
135next_argument(char **_start, bool separate)
136{
137	char *line = *_start;
138	char quote = 0;
139	int32 i;
140
141	// eliminate leading spaces
142	while (line[0] == ' ')
143		line++;
144
145	if (line[0] == '"' || line[0] == '\'') {
146		quote = line[0];
147		line++;
148	}
149
150	if (!line[0])
151		return NULL;
152
153	for (i = 0;; i++) {
154		if (line[i] == '\\' && line[i + 1] != '\0')
155			continue;
156
157		if (line[i] == '\0') {
158			*_start = &line[i];
159			return line;
160		}
161		if ((!quote && line[i] == ' ') || line[i] == quote) {
162			// argument separator!
163			if (separate)
164				line[i] = '\0';
165			*_start = &line[i + 1];
166			return line;
167		}
168	}
169
170	return NULL;
171}
172
173
174status_t
175__parse_invoke_line(char *invoker, char ***_newArgs,
176	char * const **_oldArgs, int32 *_argCount, const char *arg0)
177{
178	int32 i, count = 0;
179	char *arg = invoker;
180	char **newArgs;
181
182	// count arguments in the line
183
184	while (next_argument(&arg, false)) {
185		count++;
186	}
187
188	// this is a shell script and requires special treatment
189	newArgs = (char**)malloc((*_argCount + count + 1) * sizeof(void *));
190	if (newArgs == NULL)
191		return B_NO_MEMORY;
192
193	// copy invoker and old arguments and to newArgs
194
195	for (i = 0; (arg = next_argument(&invoker, true)) != NULL; i++) {
196		newArgs[i] = arg;
197	}
198	for (i = 0; i < *_argCount; i++) {
199		if (i == 0)
200			newArgs[i + count] = (char*)arg0;
201		else
202			newArgs[i + count] = (char *)(*_oldArgs)[i];
203	}
204
205	newArgs[i + count] = NULL;
206
207	*_newArgs = newArgs;
208	*_oldArgs = (char * const *)newArgs;
209	*_argCount += count;
210
211	return B_OK;
212}
213
214
215status_t
216__get_next_image_dependency(image_id id, uint32 *cookie, const char **_name)
217{
218	return __gRuntimeLoader->get_next_image_dependency(id, cookie, _name);
219}
220
221
222status_t
223__test_executable(const char *path, char *invoker)
224{
225	return __gRuntimeLoader->test_executable(path, invoker);
226}
227
228
229/*!	Allocates a flat buffer and copies the argument and environment strings
230	into it. The buffer starts with a char* array which contains pointers to
231	the strings of the arguments and environment, followed by the strings. Both
232	arguments and environment arrays are NULL-terminated.
233*/
234status_t
235__flatten_process_args(const char* const* args, int32 argCount,
236	const char* const* env, int32 envCount, char*** _flatArgs,
237	size_t* _flatSize)
238{
239	if (args == NULL || env == NULL)
240		return B_BAD_VALUE;
241
242	// determine total needed size
243	int32 argSize = 0;
244	for (int32 i = 0; i < argCount; i++) {
245		if (args[i] == NULL)
246			return B_BAD_VALUE;
247		argSize += strlen(args[i]) + 1;
248	}
249
250	int32 envSize = 0;
251	for (int32 i = 0; i < envCount; i++) {
252		if (env[i] == NULL)
253			return B_BAD_VALUE;
254		envSize += strlen(env[i]) + 1;
255	}
256
257	int32 size = (argCount + envCount + 2) * sizeof(char*) + argSize + envSize;
258	if (size > MAX_PROCESS_ARGS_SIZE)
259		return B_TOO_MANY_ARGS;
260
261	// allocate space
262	char** flatArgs = (char**)malloc(size);
263	if (flatArgs == NULL)
264		return B_NO_MEMORY;
265
266	char** slot = flatArgs;
267	char* stringSpace = (char*)(flatArgs + argCount + envCount + 2);
268
269	// copy arguments and environment
270	for (int32 i = 0; i < argCount; i++) {
271		int32 argSize = strlen(args[i]) + 1;
272		memcpy(stringSpace, args[i], argSize);
273		*slot++ = stringSpace;
274		stringSpace += argSize;
275	}
276
277	*slot++ = NULL;
278
279	for (int32 i = 0; i < envCount; i++) {
280		int32 envSize = strlen(env[i]) + 1;
281		memcpy(stringSpace, env[i], envSize);
282		*slot++ = stringSpace;
283		stringSpace += envSize;
284	}
285
286	*slot++ = NULL;
287
288	*_flatArgs = flatArgs;
289	*_flatSize = size;
290	return B_OK;
291}
292
293
294extern "C" void _call_init_routines_(void);
295void
296_call_init_routines_(void)
297{
298	// This is called by the original BeOS startup code.
299	// We don't need it, because our loader already does the job, right?
300}
301
302