source: mainline/uspace/srv/loader/main.c@ 92fd52d7

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

Nuke strcpy() and strcmp().

  • Property mode set to 100644
File size: 8.1 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>
[907bb49]56#include <console.h>
[c98e6ee]57#include <errno.h>
58#include <async.h>
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
[4470e26]79static elf_info_t prog_info;
80static elf_info_t interp_info;
81
82static bool is_dyn_linked;
83
[bfd1546]84/** Used to limit number of connections to one. */
85static bool connected;
[4470e26]86
87static void loader_get_taskid(ipc_callid_t rid, ipc_call_t *request)
[47e0a05b]88{
89 ipc_callid_t callid;
90 task_id_t task_id;
91 size_t len;
[2f57690]92
[47e0a05b]93 task_id = task_get_id();
[2f57690]94
[47e0a05b]95 if (!ipc_data_read_receive(&callid, &len)) {
96 ipc_answer_0(callid, EINVAL);
97 ipc_answer_0(rid, EINVAL);
98 return;
99 }
[2f57690]100
101 if (len > sizeof(task_id))
102 len = sizeof(task_id);
103
[0993087]104 ipc_data_read_finalize(callid, &task_id, len);
[47e0a05b]105 ipc_answer_0(rid, EOK);
106}
107
108
[c98e6ee]109/** Receive a call setting pathname of the program to execute.
110 *
111 * @param rid
112 * @param request
113 */
114static void loader_set_pathname(ipc_callid_t rid, ipc_call_t *request)
115{
116 ipc_callid_t callid;
117 size_t len;
118 char *name_buf;
[2f57690]119
[c98e6ee]120 if (!ipc_data_write_receive(&callid, &len)) {
121 ipc_answer_0(callid, EINVAL);
122 ipc_answer_0(rid, EINVAL);
123 return;
124 }
[2f57690]125
[c98e6ee]126 name_buf = malloc(len + 1);
127 if (!name_buf) {
128 ipc_answer_0(callid, ENOMEM);
129 ipc_answer_0(rid, ENOMEM);
130 return;
131 }
[2f57690]132
[c98e6ee]133 ipc_data_write_finalize(callid, name_buf, len);
134 ipc_answer_0(rid, EOK);
[2f57690]135
[c98e6ee]136 if (pathname != NULL) {
137 free(pathname);
138 pathname = NULL;
139 }
[2f57690]140
[c98e6ee]141 name_buf[len] = '\0';
142 pathname = name_buf;
143}
144
145/** Receive a call setting arguments of the program to execute.
146 *
147 * @param rid
148 * @param request
149 */
150static void loader_set_args(ipc_callid_t rid, ipc_call_t *request)
151{
152 ipc_callid_t callid;
[92fd52d7]153 size_t buf_size, arg_size;
[c98e6ee]154 char *p;
155 int n;
[2f57690]156
[92fd52d7]157 if (!ipc_data_write_receive(&callid, &buf_size)) {
[c98e6ee]158 ipc_answer_0(callid, EINVAL);
159 ipc_answer_0(rid, EINVAL);
160 return;
161 }
[2f57690]162
[c98e6ee]163 if (arg_buf != NULL) {
164 free(arg_buf);
165 arg_buf = NULL;
166 }
[2f57690]167
[c98e6ee]168 if (argv != NULL) {
169 free(argv);
170 argv = NULL;
171 }
[2f57690]172
[92fd52d7]173 arg_buf = malloc(buf_size + 1);
[c98e6ee]174 if (!arg_buf) {
175 ipc_answer_0(callid, ENOMEM);
176 ipc_answer_0(rid, ENOMEM);
177 return;
178 }
[2f57690]179
[92fd52d7]180 ipc_data_write_finalize(callid, arg_buf, buf_size);
[2f57690]181
[92fd52d7]182 arg_buf[buf_size] = '\0';
[2f57690]183
[c98e6ee]184 /*
185 * Count number of arguments
186 */
187 p = arg_buf;
188 n = 0;
[92fd52d7]189 while (p < arg_buf + buf_size) {
190 arg_size = str_size(p);
191 p = p + arg_size + 1;
[c98e6ee]192 ++n;
193 }
[2f57690]194
[c98e6ee]195 /* Allocate argv */
196 argv = malloc((n + 1) * sizeof(char *));
[2f57690]197
[c98e6ee]198 if (argv == NULL) {
199 free(arg_buf);
200 ipc_answer_0(rid, ENOMEM);
201 return;
202 }
[482c86f]203
[c98e6ee]204 /*
205 * Fill argv with argument pointers
206 */
207 p = arg_buf;
208 n = 0;
[92fd52d7]209 while (p < arg_buf + buf_size) {
[c98e6ee]210 argv[n] = p;
[2f57690]211
[92fd52d7]212 arg_size = str_size(p);
213 p = p + arg_size + 1;
[c98e6ee]214 ++n;
215 }
[2f57690]216
[c98e6ee]217 argc = n;
218 argv[n] = NULL;
[482c86f]219
220 ipc_answer_0(rid, EOK);
[c98e6ee]221}
222
[4470e26]223/** Load the previously selected program.
[c98e6ee]224 *
225 * @param rid
226 * @param request
227 * @return 0 on success, !0 on error.
228 */
[4470e26]229static int loader_load(ipc_callid_t rid, ipc_call_t *request)
[c98e6ee]230{
231 int rc;
[2f57690]232
[c98e6ee]233 rc = elf_load_file(pathname, 0, &prog_info);
234 if (rc < 0) {
[06b2b7f]235 DPRINTF("Failed to load executable '%s'.\n", pathname);
[c98e6ee]236 ipc_answer_0(rid, EINVAL);
237 return 1;
238 }
[2f57690]239
[c98e6ee]240 elf_create_pcb(&prog_info, &pcb);
[2f57690]241
[c98e6ee]242 pcb.argc = argc;
243 pcb.argv = argv;
[2f57690]244
[c98e6ee]245 if (prog_info.interp == NULL) {
246 /* Statically linked program */
[4470e26]247 is_dyn_linked = false;
[c98e6ee]248 ipc_answer_0(rid, EOK);
249 return 0;
250 }
[2f57690]251
[49093a4]252 rc = elf_load_file(prog_info.interp, 0, &interp_info);
[c98e6ee]253 if (rc < 0) {
[06b2b7f]254 DPRINTF("Failed to load interpreter '%s.'\n",
255 prog_info.interp);
[c98e6ee]256 ipc_answer_0(rid, EINVAL);
257 return 1;
258 }
[2f57690]259
[4470e26]260 is_dyn_linked = true;
[c98e6ee]261 ipc_answer_0(rid, EOK);
[2f57690]262
[c98e6ee]263 return 0;
264}
265
[4470e26]266
267/** Run the previously loaded program.
268 *
269 * @param rid
270 * @param request
271 * @return 0 on success, !0 on error.
272 */
273static void loader_run(ipc_callid_t rid, ipc_call_t *request)
274{
[20f1597]275 const char *cp;
[2f57690]276
[bc18d63]277 /* Set the task name. */
[20f1597]278 cp = strrchr(pathname, '/');
279 cp = (cp == NULL) ? pathname : (cp + 1);
280 task_set_name(cp);
[2f57690]281
[4470e26]282 if (is_dyn_linked == true) {
283 /* Dynamically linked program */
[06b2b7f]284 DPRINTF("Run ELF interpreter.\n");
285 DPRINTF("Entry point: 0x%lx\n", interp_info.entry);
[907bb49]286 console_close();
[2f57690]287
[4470e26]288 ipc_answer_0(rid, EOK);
289 elf_run(&interp_info, &pcb);
290 } else {
291 /* Statically linked program */
[907bb49]292 console_close();
[4470e26]293 ipc_answer_0(rid, EOK);
294 elf_run(&prog_info, &pcb);
295 }
296
297 /* Not reached */
298}
299
[c98e6ee]300/** Handle loader connection.
301 *
302 * Receive and carry out commands (of which the last one should be
303 * to execute the loaded program).
304 */
305static void loader_connection(ipc_callid_t iid, ipc_call_t *icall)
306{
307 ipc_callid_t callid;
308 ipc_call_t call;
309 int retval;
[2f57690]310
[bfd1546]311 /* Already have a connection? */
312 if (connected) {
313 ipc_answer_0(iid, ELIMIT);
314 return;
315 }
[2f57690]316
[bfd1546]317 connected = true;
318
319 /* Accept the connection */
320 ipc_answer_0(iid, EOK);
[2f57690]321
[c98e6ee]322 /* Ignore parameters, the connection is already open */
[2f57690]323 (void) iid;
324 (void) icall;
325
[c98e6ee]326 while (1) {
327 callid = async_get_call(&call);
[2f57690]328
[c98e6ee]329 switch (IPC_GET_METHOD(call)) {
[86e3d62]330 case IPC_M_PHONE_HUNGUP:
331 exit(0);
[47e0a05b]332 case LOADER_GET_TASKID:
333 loader_get_taskid(callid, &call);
334 continue;
[c98e6ee]335 case LOADER_SET_PATHNAME:
336 loader_set_pathname(callid, &call);
337 continue;
338 case LOADER_SET_ARGS:
339 loader_set_args(callid, &call);
[4470e26]340 continue;
341 case LOADER_LOAD:
342 loader_load(callid, &call);
343 continue;
[c98e6ee]344 case LOADER_RUN:
345 loader_run(callid, &call);
[4470e26]346 /* Not reached */
[c98e6ee]347 default:
348 retval = ENOENT;
349 break;
350 }
351 if ((callid & IPC_CALLID_NOTIFICATION) == 0 &&
352 IPC_GET_METHOD(call) != IPC_M_PHONE_HUNGUP) {
[06b2b7f]353 DPRINTF("Responding EINVAL to method %d.\n",
[c98e6ee]354 IPC_GET_METHOD(call));
355 ipc_answer_0(callid, EINVAL);
356 }
357 }
358}
359
360/** Program loader main function.
361 */
362int main(int argc, char *argv[])
363{
[bfd1546]364 ipcarg_t phonead;
[2f57690]365
[bfd1546]366 connected = false;
367
368 /* Set a handler of incomming connections. */
369 async_set_client_connection(loader_connection);
[2f57690]370
[bfd1546]371 /* Register at naming service. */
372 if (ipc_connect_to_me(PHONE_NS, SERVICE_LOAD, 0, 0, &phonead) != 0)
373 return -1;
374
[c98e6ee]375 async_manager();
[2f57690]376
[bfd1546]377 /* Never reached */
[c98e6ee]378 return 0;
379}
380
381/** @}
382 */
Note: See TracBrowser for help on using the repository browser.