source: mainline/uspace/srv/loader/main.c@ 06b2b7f

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

Disable message displaying in loader.

  • Property mode set to 100644
File size: 8.0 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
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>
[4470e26]49#include <bool.h>
[c98e6ee]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
[06b2b7f]62#define DPRINTF(...)
63
[c98e6ee]64/** Pathname of the file that will be loaded */
65static char *pathname = NULL;
66
67/** The Program control block */
68static pcb_t pcb;
69
70/** Number of arguments */
71static int argc = 0;
72/** Argument vector */
73static char **argv = NULL;
74/** Buffer holding all arguments */
75static char *arg_buf = NULL;
76
[4470e26]77static elf_info_t prog_info;
78static elf_info_t interp_info;
79
80static bool is_dyn_linked;
81
82
83static void loader_get_taskid(ipc_callid_t rid, ipc_call_t *request)
[47e0a05b]84{
85 ipc_callid_t callid;
86 task_id_t task_id;
87 size_t len;
88
89 task_id = task_get_id();
90
91 if (!ipc_data_read_receive(&callid, &len)) {
92 ipc_answer_0(callid, EINVAL);
93 ipc_answer_0(rid, EINVAL);
94 return;
95 }
96
97 if (len > sizeof(task_id)) len = sizeof(task_id);
98
[0993087]99 ipc_data_read_finalize(callid, &task_id, len);
[47e0a05b]100 ipc_answer_0(rid, EOK);
101}
102
103
[c98e6ee]104/** Receive a call setting pathname of the program to execute.
105 *
106 * @param rid
107 * @param request
108 */
109static void loader_set_pathname(ipc_callid_t rid, ipc_call_t *request)
110{
111 ipc_callid_t callid;
112 size_t len;
113 char *name_buf;
114
115 if (!ipc_data_write_receive(&callid, &len)) {
116 ipc_answer_0(callid, EINVAL);
117 ipc_answer_0(rid, EINVAL);
118 return;
119 }
120
121 name_buf = malloc(len + 1);
122 if (!name_buf) {
123 ipc_answer_0(callid, ENOMEM);
124 ipc_answer_0(rid, ENOMEM);
125 return;
126 }
127
128 ipc_data_write_finalize(callid, name_buf, len);
129 ipc_answer_0(rid, EOK);
130
131 if (pathname != NULL) {
132 free(pathname);
133 pathname = NULL;
134 }
135
136 name_buf[len] = '\0';
137 pathname = name_buf;
138}
139
140/** Receive a call setting arguments of the program to execute.
141 *
142 * @param rid
143 * @param request
144 */
145static void loader_set_args(ipc_callid_t rid, ipc_call_t *request)
146{
147 ipc_callid_t callid;
148 size_t buf_len, arg_len;
149 char *p;
150 int n;
151
152 if (!ipc_data_write_receive(&callid, &buf_len)) {
153 ipc_answer_0(callid, EINVAL);
154 ipc_answer_0(rid, EINVAL);
155 return;
156 }
157
158 if (arg_buf != NULL) {
159 free(arg_buf);
160 arg_buf = NULL;
161 }
162
163 if (argv != NULL) {
164 free(argv);
165 argv = NULL;
166 }
167
168 arg_buf = malloc(buf_len + 1);
169 if (!arg_buf) {
170 ipc_answer_0(callid, ENOMEM);
171 ipc_answer_0(rid, ENOMEM);
172 return;
173 }
174
175 ipc_data_write_finalize(callid, arg_buf, buf_len);
176 ipc_answer_0(rid, EOK);
177
178 arg_buf[buf_len] = '\0';
179
180 /*
181 * Count number of arguments
182 */
183 p = arg_buf;
184 n = 0;
185 while (p < arg_buf + buf_len) {
186 arg_len = strlen(p);
187 p = p + arg_len + 1;
188 ++n;
189 }
190
191 /* Allocate argv */
192 argv = malloc((n + 1) * sizeof(char *));
193
194 if (argv == NULL) {
195 free(arg_buf);
196 ipc_answer_0(callid, ENOMEM);
197 ipc_answer_0(rid, ENOMEM);
198 return;
199 }
200
201 /*
202 * Fill argv with argument pointers
203 */
204 p = arg_buf;
205 n = 0;
206 while (p < arg_buf + buf_len) {
207 argv[n] = p;
208
209 arg_len = strlen(p);
210 p = p + arg_len + 1;
211 ++n;
212 }
213
214 argc = n;
215 argv[n] = NULL;
216}
217
[4470e26]218/** Load the previously selected program.
[c98e6ee]219 *
220 * @param rid
221 * @param request
222 * @return 0 on success, !0 on error.
223 */
[4470e26]224static int loader_load(ipc_callid_t rid, ipc_call_t *request)
[c98e6ee]225{
226 int rc;
227
228 rc = elf_load_file(pathname, 0, &prog_info);
229 if (rc < 0) {
[06b2b7f]230 DPRINTF("Failed to load executable '%s'.\n", pathname);
[c98e6ee]231 ipc_answer_0(rid, EINVAL);
232 return 1;
233 }
234
235 elf_create_pcb(&prog_info, &pcb);
236
237 pcb.argc = argc;
238 pcb.argv = argv;
239
240 if (prog_info.interp == NULL) {
241 /* Statically linked program */
[4470e26]242 is_dyn_linked = false;
[c98e6ee]243 ipc_answer_0(rid, EOK);
244 return 0;
245 }
246
[49093a4]247 rc = elf_load_file(prog_info.interp, 0, &interp_info);
[c98e6ee]248 if (rc < 0) {
[06b2b7f]249 DPRINTF("Failed to load interpreter '%s.'\n",
250 prog_info.interp);
[c98e6ee]251 ipc_answer_0(rid, EINVAL);
252 return 1;
253 }
254
[4470e26]255 is_dyn_linked = true;
[c98e6ee]256 ipc_answer_0(rid, EOK);
257
258 return 0;
259}
260
[4470e26]261
262/** Run the previously loaded program.
263 *
264 * @param rid
265 * @param request
266 * @return 0 on success, !0 on error.
267 */
268static void loader_run(ipc_callid_t rid, ipc_call_t *request)
269{
270 if (is_dyn_linked == true) {
271 /* Dynamically linked program */
[06b2b7f]272 DPRINTF("Run ELF interpreter.\n");
273 DPRINTF("Entry point: 0x%lx\n", interp_info.entry);
[4470e26]274 close_console();
275
276 ipc_answer_0(rid, EOK);
277 elf_run(&interp_info, &pcb);
278
279 } else {
280 /* Statically linked program */
281 close_console();
282 ipc_answer_0(rid, EOK);
283 elf_run(&prog_info, &pcb);
284 }
285
286 /* Not reached */
287}
288
[c98e6ee]289/** Handle loader connection.
290 *
291 * Receive and carry out commands (of which the last one should be
292 * to execute the loaded program).
293 */
294static void loader_connection(ipc_callid_t iid, ipc_call_t *icall)
295{
296 ipc_callid_t callid;
297 ipc_call_t call;
298 int retval;
299
300 /* Ignore parameters, the connection is already open */
301 (void)iid; (void)icall;
302
303 while (1) {
304 callid = async_get_call(&call);
[4470e26]305
[c98e6ee]306 switch (IPC_GET_METHOD(call)) {
[86e3d62]307 case IPC_M_PHONE_HUNGUP:
308 exit(0);
[47e0a05b]309 case LOADER_GET_TASKID:
310 loader_get_taskid(callid, &call);
311 continue;
[c98e6ee]312 case LOADER_SET_PATHNAME:
313 loader_set_pathname(callid, &call);
314 continue;
315 case LOADER_SET_ARGS:
316 loader_set_args(callid, &call);
[4470e26]317 continue;
318 case LOADER_LOAD:
319 loader_load(callid, &call);
320 continue;
[c98e6ee]321 case LOADER_RUN:
322 loader_run(callid, &call);
[4470e26]323 /* Not reached */
[c98e6ee]324 default:
325 retval = ENOENT;
326 break;
327 }
328 if ((callid & IPC_CALLID_NOTIFICATION) == 0 &&
329 IPC_GET_METHOD(call) != IPC_M_PHONE_HUNGUP) {
[06b2b7f]330 DPRINTF("Responding EINVAL to method %d.\n",
[c98e6ee]331 IPC_GET_METHOD(call));
332 ipc_answer_0(callid, EINVAL);
333 }
334 }
335}
336
337/** Program loader main function.
338 */
339int main(int argc, char *argv[])
340{
341 ipc_callid_t callid;
342 ipc_call_t call;
343 ipcarg_t phone_hash;
344
345 /* The first call only communicates the incoming phone hash */
346 callid = ipc_wait_for_call(&call);
347
348 if (IPC_GET_METHOD(call) != LOADER_HELLO) {
349 if (IPC_GET_METHOD(call) != IPC_M_PHONE_HUNGUP)
350 ipc_answer_0(callid, EINVAL);
351 return 1;
352 }
353
354 ipc_answer_0(callid, EOK);
355 phone_hash = call.in_phone_hash;
356
357 /*
358 * Up until now async must not be used as it couldn't
359 * handle incoming requests. (Which means e.g. printf()
360 * cannot be used)
361 */
362 async_new_connection(phone_hash, 0, NULL, loader_connection);
363 async_manager();
364
365 /* not reached */
366 return 0;
367}
368
369/** @}
370 */
Note: See TracBrowser for help on using the repository browser.