source: mainline/uspace/srv/loader/main.c@ 49093a4

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 49093a4 was 49093a4, checked in by Jiri Svoboda <jirik.svoboda@…>, 17 years ago

Remove obsolete dld-related loader fragments.

  • Property mode set to 100644
File size: 7.9 KB
Line 
1/*
2 * Copyright (c) 2008 Jiri Svoboda
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * - Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * - Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * - The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29/** @addtogroup loader
30 * @brief Loads and runs programs from VFS.
31 * @{
32 */
33/**
34 * @file
35 * @brief Loads and runs programs from VFS.
36 *
37 * The program loader is a special init binary. Its image is used
38 * to create a new task upon a @c task_spawn syscall. The syscall
39 * returns the id of a phone connected to the newly created task.
40 *
41 * The caller uses this phone to send the pathname and various other
42 * information to the loader. This is normally done by the C library
43 * and completely hidden from applications.
44 */
45
46#include <stdio.h>
47#include <stdlib.h>
48#include <unistd.h>
49#include <bool.h>
50#include <fcntl.h>
51#include <sys/types.h>
52#include <ipc/ipc.h>
53#include <ipc/loader.h>
54#include <loader/pcb.h>
55#include <errno.h>
56#include <async.h>
57#include <as.h>
58
59#include <elf.h>
60#include <elf_load.h>
61
62/** Pathname of the file that will be loaded */
63static char *pathname = NULL;
64
65/** The Program control block */
66static pcb_t pcb;
67
68/** Number of arguments */
69static int argc = 0;
70/** Argument vector */
71static char **argv = NULL;
72/** Buffer holding all arguments */
73static char *arg_buf = NULL;
74
75static elf_info_t prog_info;
76static elf_info_t interp_info;
77
78static bool is_dyn_linked;
79
80
81static void loader_get_taskid(ipc_callid_t rid, ipc_call_t *request)
82{
83 ipc_callid_t callid;
84 task_id_t task_id;
85 size_t len;
86
87 task_id = task_get_id();
88
89 if (!ipc_data_read_receive(&callid, &len)) {
90 ipc_answer_0(callid, EINVAL);
91 ipc_answer_0(rid, EINVAL);
92 return;
93 }
94
95 if (len > sizeof(task_id)) len = sizeof(task_id);
96
97 ipc_data_read_finalize(callid, &task_id, len);
98 ipc_answer_0(rid, EOK);
99}
100
101
102/** Receive a call setting pathname of the program to execute.
103 *
104 * @param rid
105 * @param request
106 */
107static void loader_set_pathname(ipc_callid_t rid, ipc_call_t *request)
108{
109 ipc_callid_t callid;
110 size_t len;
111 char *name_buf;
112
113 if (!ipc_data_write_receive(&callid, &len)) {
114 ipc_answer_0(callid, EINVAL);
115 ipc_answer_0(rid, EINVAL);
116 return;
117 }
118
119 name_buf = malloc(len + 1);
120 if (!name_buf) {
121 ipc_answer_0(callid, ENOMEM);
122 ipc_answer_0(rid, ENOMEM);
123 return;
124 }
125
126 ipc_data_write_finalize(callid, name_buf, len);
127 ipc_answer_0(rid, EOK);
128
129 if (pathname != NULL) {
130 free(pathname);
131 pathname = NULL;
132 }
133
134 name_buf[len] = '\0';
135 pathname = name_buf;
136}
137
138/** Receive a call setting arguments of the program to execute.
139 *
140 * @param rid
141 * @param request
142 */
143static void loader_set_args(ipc_callid_t rid, ipc_call_t *request)
144{
145 ipc_callid_t callid;
146 size_t buf_len, arg_len;
147 char *p;
148 int n;
149
150 if (!ipc_data_write_receive(&callid, &buf_len)) {
151 ipc_answer_0(callid, EINVAL);
152 ipc_answer_0(rid, EINVAL);
153 return;
154 }
155
156 if (arg_buf != NULL) {
157 free(arg_buf);
158 arg_buf = NULL;
159 }
160
161 if (argv != NULL) {
162 free(argv);
163 argv = NULL;
164 }
165
166 arg_buf = malloc(buf_len + 1);
167 if (!arg_buf) {
168 ipc_answer_0(callid, ENOMEM);
169 ipc_answer_0(rid, ENOMEM);
170 return;
171 }
172
173 ipc_data_write_finalize(callid, arg_buf, buf_len);
174 ipc_answer_0(rid, EOK);
175
176 arg_buf[buf_len] = '\0';
177
178 /*
179 * Count number of arguments
180 */
181 p = arg_buf;
182 n = 0;
183 while (p < arg_buf + buf_len) {
184 arg_len = strlen(p);
185 p = p + arg_len + 1;
186 ++n;
187 }
188
189 /* Allocate argv */
190 argv = malloc((n + 1) * sizeof(char *));
191
192 if (argv == NULL) {
193 free(arg_buf);
194 ipc_answer_0(callid, ENOMEM);
195 ipc_answer_0(rid, ENOMEM);
196 return;
197 }
198
199 /*
200 * Fill argv with argument pointers
201 */
202 p = arg_buf;
203 n = 0;
204 while (p < arg_buf + buf_len) {
205 argv[n] = p;
206
207 arg_len = strlen(p);
208 p = p + arg_len + 1;
209 ++n;
210 }
211
212 argc = n;
213 argv[n] = NULL;
214}
215
216/** Load the previously selected program.
217 *
218 * @param rid
219 * @param request
220 * @return 0 on success, !0 on error.
221 */
222static int loader_load(ipc_callid_t rid, ipc_call_t *request)
223{
224 int rc;
225
226 rc = elf_load_file(pathname, 0, &prog_info);
227 if (rc < 0) {
228 printf("Failed to load executable '%s'.\n", pathname);
229 ipc_answer_0(rid, EINVAL);
230 return 1;
231 }
232
233 elf_create_pcb(&prog_info, &pcb);
234
235 pcb.argc = argc;
236 pcb.argv = argv;
237
238 if (prog_info.interp == NULL) {
239 /* Statically linked program */
240 is_dyn_linked = false;
241 ipc_answer_0(rid, EOK);
242 return 0;
243 }
244
245 rc = elf_load_file(prog_info.interp, 0, &interp_info);
246 if (rc < 0) {
247 printf("Failed to load interpreter '%s.'\n", prog_info.interp);
248 ipc_answer_0(rid, EINVAL);
249 return 1;
250 }
251
252 is_dyn_linked = true;
253 ipc_answer_0(rid, EOK);
254
255 return 0;
256}
257
258
259/** Run the previously loaded program.
260 *
261 * @param rid
262 * @param request
263 * @return 0 on success, !0 on error.
264 */
265static void loader_run(ipc_callid_t rid, ipc_call_t *request)
266{
267 if (is_dyn_linked == true) {
268 /* Dynamically linked program */
269 printf("run dynamic linker\n");
270 printf("entry point: 0x%lx\n", interp_info.entry);
271 close_console();
272
273 ipc_answer_0(rid, EOK);
274 elf_run(&interp_info, &pcb);
275
276 } else {
277 /* Statically linked program */
278 close_console();
279 ipc_answer_0(rid, EOK);
280 elf_run(&prog_info, &pcb);
281 }
282
283 /* Not reached */
284}
285
286/** Handle loader connection.
287 *
288 * Receive and carry out commands (of which the last one should be
289 * to execute the loaded program).
290 */
291static void loader_connection(ipc_callid_t iid, ipc_call_t *icall)
292{
293 ipc_callid_t callid;
294 ipc_call_t call;
295 int retval;
296
297 /* Ignore parameters, the connection is already open */
298 (void)iid; (void)icall;
299
300 while (1) {
301 callid = async_get_call(&call);
302
303 switch (IPC_GET_METHOD(call)) {
304 case IPC_M_PHONE_HUNGUP:
305 exit(0);
306 case LOADER_GET_TASKID:
307 loader_get_taskid(callid, &call);
308 continue;
309 case LOADER_SET_PATHNAME:
310 loader_set_pathname(callid, &call);
311 continue;
312 case LOADER_SET_ARGS:
313 loader_set_args(callid, &call);
314 continue;
315 case LOADER_LOAD:
316 loader_load(callid, &call);
317 continue;
318 case LOADER_RUN:
319 loader_run(callid, &call);
320 /* Not reached */
321 default:
322 retval = ENOENT;
323 break;
324 }
325 if ((callid & IPC_CALLID_NOTIFICATION) == 0 &&
326 IPC_GET_METHOD(call) != IPC_M_PHONE_HUNGUP) {
327 printf("responding EINVAL to method %d\n",
328 IPC_GET_METHOD(call));
329 ipc_answer_0(callid, EINVAL);
330 }
331 }
332}
333
334/** Program loader main function.
335 */
336int main(int argc, char *argv[])
337{
338 ipc_callid_t callid;
339 ipc_call_t call;
340 ipcarg_t phone_hash;
341
342 /* The first call only communicates the incoming phone hash */
343 callid = ipc_wait_for_call(&call);
344
345 if (IPC_GET_METHOD(call) != LOADER_HELLO) {
346 if (IPC_GET_METHOD(call) != IPC_M_PHONE_HUNGUP)
347 ipc_answer_0(callid, EINVAL);
348 return 1;
349 }
350
351 ipc_answer_0(callid, EOK);
352 phone_hash = call.in_phone_hash;
353
354 /*
355 * Up until now async must not be used as it couldn't
356 * handle incoming requests. (Which means e.g. printf()
357 * cannot be used)
358 */
359 async_new_connection(phone_hash, 0, NULL, loader_connection);
360 async_manager();
361
362 /* not reached */
363 return 0;
364}
365
366/** @}
367 */
Note: See TracBrowser for help on using the repository browser.