source: mainline/uspace/srv/loader/main.c@ 99272a3

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 99272a3 was 99272a3, checked in by Jakub Jermar <jakub@…>, 16 years ago

inode_t → fdi_node_t

  • Property mode set to 100644
File size: 9.5 KB
RevLine 
[c98e6ee]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
[2f57690]30 * @brief Loads and runs programs from VFS.
[c98e6ee]31 * @{
[2f57690]32 */
[c98e6ee]33/**
34 * @file
[2f57690]35 * @brief Loads and runs programs from VFS.
[c98e6ee]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>
[4470e26]49#include <bool.h>
[c98e6ee]50#include <fcntl.h>
51#include <sys/types.h>
52#include <ipc/ipc.h>
[bfd1546]53#include <ipc/services.h>
[c98e6ee]54#include <ipc/loader.h>
55#include <loader/pcb.h>
56#include <errno.h>
57#include <async.h>
[bbdbf86]58#include <string.h>
[c98e6ee]59#include <as.h>
60
61#include <elf.h>
62#include <elf_load.h>
63
[06b2b7f]64#define DPRINTF(...)
65
[c98e6ee]66/** Pathname of the file that will be loaded */
67static char *pathname = NULL;
68
69/** The Program control block */
70static pcb_t pcb;
71
72/** Number of arguments */
73static int argc = 0;
74/** Argument vector */
75static char **argv = NULL;
76/** Buffer holding all arguments */
77static char *arg_buf = NULL;
78
[bbdbf86]79/** Number of preset files */
80static int filc = 0;
81/** Preset files vector */
82static char **filv = NULL;
83/** Buffer holding all preset files */
[99272a3]84static fdi_node_t *fil_buf = NULL;
[bbdbf86]85
[4470e26]86static elf_info_t prog_info;
87static elf_info_t interp_info;
88
89static bool is_dyn_linked;
90
[bfd1546]91/** Used to limit number of connections to one. */
92static bool connected;
[4470e26]93
[bbdbf86]94static void ldr_get_taskid(ipc_callid_t rid, ipc_call_t *request)
[47e0a05b]95{
96 ipc_callid_t callid;
97 task_id_t task_id;
98 size_t len;
[2f57690]99
[47e0a05b]100 task_id = task_get_id();
[2f57690]101
[47e0a05b]102 if (!ipc_data_read_receive(&callid, &len)) {
103 ipc_answer_0(callid, EINVAL);
104 ipc_answer_0(rid, EINVAL);
105 return;
106 }
[2f57690]107
108 if (len > sizeof(task_id))
109 len = sizeof(task_id);
110
[0993087]111 ipc_data_read_finalize(callid, &task_id, len);
[47e0a05b]112 ipc_answer_0(rid, EOK);
113}
114
115
[c98e6ee]116/** Receive a call setting pathname of the program to execute.
117 *
118 * @param rid
119 * @param request
120 */
[bbdbf86]121static void ldr_set_pathname(ipc_callid_t rid, ipc_call_t *request)
[c98e6ee]122{
123 ipc_callid_t callid;
124 size_t len;
125 char *name_buf;
[2f57690]126
[c98e6ee]127 if (!ipc_data_write_receive(&callid, &len)) {
128 ipc_answer_0(callid, EINVAL);
129 ipc_answer_0(rid, EINVAL);
130 return;
131 }
[2f57690]132
[c98e6ee]133 name_buf = malloc(len + 1);
134 if (!name_buf) {
135 ipc_answer_0(callid, ENOMEM);
136 ipc_answer_0(rid, ENOMEM);
137 return;
138 }
[2f57690]139
[c98e6ee]140 ipc_data_write_finalize(callid, name_buf, len);
141 ipc_answer_0(rid, EOK);
[2f57690]142
[c98e6ee]143 if (pathname != NULL) {
144 free(pathname);
145 pathname = NULL;
146 }
[2f57690]147
[c98e6ee]148 name_buf[len] = '\0';
149 pathname = name_buf;
150}
151
152/** Receive a call setting arguments of the program to execute.
153 *
154 * @param rid
155 * @param request
156 */
[bbdbf86]157static void ldr_set_args(ipc_callid_t rid, ipc_call_t *request)
[c98e6ee]158{
159 ipc_callid_t callid;
[92fd52d7]160 size_t buf_size, arg_size;
[c98e6ee]161 char *p;
162 int n;
[2f57690]163
[92fd52d7]164 if (!ipc_data_write_receive(&callid, &buf_size)) {
[c98e6ee]165 ipc_answer_0(callid, EINVAL);
166 ipc_answer_0(rid, EINVAL);
167 return;
168 }
[2f57690]169
[c98e6ee]170 if (arg_buf != NULL) {
171 free(arg_buf);
172 arg_buf = NULL;
173 }
[2f57690]174
[c98e6ee]175 if (argv != NULL) {
176 free(argv);
177 argv = NULL;
178 }
[2f57690]179
[92fd52d7]180 arg_buf = malloc(buf_size + 1);
[c98e6ee]181 if (!arg_buf) {
182 ipc_answer_0(callid, ENOMEM);
183 ipc_answer_0(rid, ENOMEM);
184 return;
185 }
[2f57690]186
[92fd52d7]187 ipc_data_write_finalize(callid, arg_buf, buf_size);
[2f57690]188
[92fd52d7]189 arg_buf[buf_size] = '\0';
[2f57690]190
[c98e6ee]191 /*
192 * Count number of arguments
193 */
194 p = arg_buf;
195 n = 0;
[92fd52d7]196 while (p < arg_buf + buf_size) {
197 arg_size = str_size(p);
198 p = p + arg_size + 1;
[c98e6ee]199 ++n;
200 }
[2f57690]201
[c98e6ee]202 /* Allocate argv */
203 argv = malloc((n + 1) * sizeof(char *));
[2f57690]204
[c98e6ee]205 if (argv == NULL) {
206 free(arg_buf);
207 ipc_answer_0(rid, ENOMEM);
208 return;
209 }
[482c86f]210
[c98e6ee]211 /*
212 * Fill argv with argument pointers
213 */
214 p = arg_buf;
215 n = 0;
[92fd52d7]216 while (p < arg_buf + buf_size) {
[c98e6ee]217 argv[n] = p;
[2f57690]218
[92fd52d7]219 arg_size = str_size(p);
220 p = p + arg_size + 1;
[c98e6ee]221 ++n;
222 }
[2f57690]223
[c98e6ee]224 argc = n;
225 argv[n] = NULL;
[482c86f]226
227 ipc_answer_0(rid, EOK);
[c98e6ee]228}
229
[bbdbf86]230/** Receive a call setting preset files of the program to execute.
231 *
232 * @param rid
233 * @param request
234 */
235static void ldr_set_files(ipc_callid_t rid, ipc_call_t *request)
236{
237 ipc_callid_t callid;
238 size_t buf_size;
239 if (!ipc_data_write_receive(&callid, &buf_size)) {
240 ipc_answer_0(callid, EINVAL);
241 ipc_answer_0(rid, EINVAL);
242 return;
243 }
244
[99272a3]245 if ((buf_size % sizeof(fdi_node_t)) != 0) {
[bbdbf86]246 ipc_answer_0(callid, EINVAL);
247 ipc_answer_0(rid, EINVAL);
248 return;
249 }
250
251 if (fil_buf != NULL) {
252 free(fil_buf);
253 fil_buf = NULL;
254 }
255
256 if (filv != NULL) {
257 free(filv);
258 filv = NULL;
259 }
260
261 fil_buf = malloc(buf_size);
262 if (!fil_buf) {
263 ipc_answer_0(callid, ENOMEM);
264 ipc_answer_0(rid, ENOMEM);
265 return;
266 }
267
268 ipc_data_write_finalize(callid, fil_buf, buf_size);
269
[99272a3]270 int count = buf_size / sizeof(fdi_node_t);
[bbdbf86]271
272 /* Allocate filvv */
[99272a3]273 filv = malloc((count + 1) * sizeof(fdi_node_t *));
[bbdbf86]274
275 if (filv == NULL) {
276 free(fil_buf);
277 ipc_answer_0(rid, ENOMEM);
278 return;
279 }
280
281 /*
282 * Fill filv with argument pointers
283 */
284 int i;
285 for (i = 0; i < count; i++)
286 filv[i] = &fil_buf[i];
287
288 filc = count;
289 filv[count] = NULL;
290
291 ipc_answer_0(rid, EOK);
292}
293
[4470e26]294/** Load the previously selected program.
[c98e6ee]295 *
296 * @param rid
297 * @param request
298 * @return 0 on success, !0 on error.
299 */
[bbdbf86]300static int ldr_load(ipc_callid_t rid, ipc_call_t *request)
[c98e6ee]301{
302 int rc;
[2f57690]303
[c98e6ee]304 rc = elf_load_file(pathname, 0, &prog_info);
[409b0d6]305 if (rc != EE_OK) {
[06b2b7f]306 DPRINTF("Failed to load executable '%s'.\n", pathname);
[c98e6ee]307 ipc_answer_0(rid, EINVAL);
308 return 1;
309 }
[2f57690]310
[c98e6ee]311 elf_create_pcb(&prog_info, &pcb);
[2f57690]312
[c98e6ee]313 pcb.argc = argc;
314 pcb.argv = argv;
[2f57690]315
[bbdbf86]316 pcb.filc = filc;
317 pcb.filv = filv;
318
[c98e6ee]319 if (prog_info.interp == NULL) {
320 /* Statically linked program */
[4470e26]321 is_dyn_linked = false;
[c98e6ee]322 ipc_answer_0(rid, EOK);
323 return 0;
324 }
[2f57690]325
[49093a4]326 rc = elf_load_file(prog_info.interp, 0, &interp_info);
[409b0d6]327 if (rc != EE_OK) {
[06b2b7f]328 DPRINTF("Failed to load interpreter '%s.'\n",
329 prog_info.interp);
[c98e6ee]330 ipc_answer_0(rid, EINVAL);
331 return 1;
332 }
[2f57690]333
[4470e26]334 is_dyn_linked = true;
[c98e6ee]335 ipc_answer_0(rid, EOK);
[2f57690]336
[c98e6ee]337 return 0;
338}
339
[4470e26]340
341/** Run the previously loaded program.
342 *
343 * @param rid
344 * @param request
345 * @return 0 on success, !0 on error.
346 */
[bbdbf86]347static void ldr_run(ipc_callid_t rid, ipc_call_t *request)
[4470e26]348{
[20f1597]349 const char *cp;
[2f57690]350
[bc18d63]351 /* Set the task name. */
[7afb4a5]352 cp = str_rchr(pathname, '/');
[20f1597]353 cp = (cp == NULL) ? pathname : (cp + 1);
354 task_set_name(cp);
[2f57690]355
[4470e26]356 if (is_dyn_linked == true) {
357 /* Dynamically linked program */
[06b2b7f]358 DPRINTF("Run ELF interpreter.\n");
359 DPRINTF("Entry point: 0x%lx\n", interp_info.entry);
[2f57690]360
[4470e26]361 ipc_answer_0(rid, EOK);
362 elf_run(&interp_info, &pcb);
363 } else {
364 /* Statically linked program */
365 ipc_answer_0(rid, EOK);
366 elf_run(&prog_info, &pcb);
[bbdbf86]367 }
368
[4470e26]369 /* Not reached */
370}
371
[c98e6ee]372/** Handle loader connection.
373 *
374 * Receive and carry out commands (of which the last one should be
375 * to execute the loaded program).
376 */
[bbdbf86]377static void ldr_connection(ipc_callid_t iid, ipc_call_t *icall)
[c98e6ee]378{
379 ipc_callid_t callid;
380 ipc_call_t call;
381 int retval;
[2f57690]382
[bfd1546]383 /* Already have a connection? */
384 if (connected) {
385 ipc_answer_0(iid, ELIMIT);
386 return;
387 }
[2f57690]388
[bfd1546]389 connected = true;
390
391 /* Accept the connection */
392 ipc_answer_0(iid, EOK);
[2f57690]393
[c98e6ee]394 /* Ignore parameters, the connection is already open */
[2f57690]395 (void) iid;
396 (void) icall;
397
[c98e6ee]398 while (1) {
399 callid = async_get_call(&call);
[2f57690]400
[c98e6ee]401 switch (IPC_GET_METHOD(call)) {
[86e3d62]402 case IPC_M_PHONE_HUNGUP:
403 exit(0);
[47e0a05b]404 case LOADER_GET_TASKID:
[bbdbf86]405 ldr_get_taskid(callid, &call);
[47e0a05b]406 continue;
[c98e6ee]407 case LOADER_SET_PATHNAME:
[bbdbf86]408 ldr_set_pathname(callid, &call);
[c98e6ee]409 continue;
410 case LOADER_SET_ARGS:
[bbdbf86]411 ldr_set_args(callid, &call);
412 continue;
413 case LOADER_SET_FILES:
414 ldr_set_files(callid, &call);
[4470e26]415 continue;
416 case LOADER_LOAD:
[bbdbf86]417 ldr_load(callid, &call);
[4470e26]418 continue;
[c98e6ee]419 case LOADER_RUN:
[bbdbf86]420 ldr_run(callid, &call);
[4470e26]421 /* Not reached */
[c98e6ee]422 default:
423 retval = ENOENT;
424 break;
425 }
426 if ((callid & IPC_CALLID_NOTIFICATION) == 0 &&
427 IPC_GET_METHOD(call) != IPC_M_PHONE_HUNGUP) {
[06b2b7f]428 DPRINTF("Responding EINVAL to method %d.\n",
[c98e6ee]429 IPC_GET_METHOD(call));
430 ipc_answer_0(callid, EINVAL);
431 }
432 }
433}
434
435/** Program loader main function.
436 */
437int main(int argc, char *argv[])
438{
[bfd1546]439 ipcarg_t phonead;
[2f57690]440
[bfd1546]441 connected = false;
442
443 /* Set a handler of incomming connections. */
[bbdbf86]444 async_set_client_connection(ldr_connection);
[2f57690]445
[bfd1546]446 /* Register at naming service. */
447 if (ipc_connect_to_me(PHONE_NS, SERVICE_LOAD, 0, 0, &phonead) != 0)
448 return -1;
449
[c98e6ee]450 async_manager();
[2f57690]451
[bfd1546]452 /* Never reached */
[c98e6ee]453 return 0;
454}
455
456/** @}
457 */
Note: See TracBrowser for help on using the repository browser.