xref: /haiku/src/system/libroot/os/image.cpp (revision b55a57da7173b9af0432bd3e148d03f06161d036)
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 
20 thread_id
21 load_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 
67 image_id
68 load_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 
77 status_t
78 unload_add_on(image_id id)
79 {
80 	return __gRuntimeLoader->unload_add_on(id);
81 }
82 
83 
84 status_t
85 get_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 
93 status_t
94 get_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 
102 status_t
103 get_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 
110 status_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 
117 status_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 
124 void
125 clear_caches(void *address, size_t length, uint32 flags)
126 {
127 	_kern_clear_caches(address, length, flags);
128 }
129 
130 
131 //	#pragma mark -
132 
133 
134 static char *
135 next_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 
174 status_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 
215 status_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 
222 status_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 */
234 status_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 
294 extern "C" void _call_init_routines_(void);
295 void
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