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