source: mainline/uspace/lib/c/generic/loader.c@ 2443ad8

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 2443ad8 was 2443ad8, checked in by Jiri Svoboda <jiri@…>, 6 years ago

Let trace not use the loader API directly

This fixes traced binaries crashing due to missing working directory
in PCB. It should also prevent similar problems in the future.

  • Property mode set to 100644
File size: 9.3 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 libc
30 * @{
31 */
32/** @file
33 */
34
35#include <ipc/loader.h>
36#include <ipc/services.h>
37#include <ns.h>
38#include <libc.h>
39#include <task.h>
40#include <str.h>
41#include <stdlib.h>
42#include <async.h>
43#include <errno.h>
44#include <vfs/vfs.h>
45#include <loader/loader.h>
46#include "private/loader.h"
47
48/** Connect to a new program loader.
49 *
50 * Spawns a new program loader task and returns the connection structure.
51 *
52 * @param name Symbolic name to set on the newly created task.
53 *
54 * @return Error code.
55 */
56errno_t loader_spawn(const char *name)
57{
58 return (errno_t) __SYSCALL2(SYS_PROGRAM_SPAWN_LOADER,
59 (sysarg_t) name, str_size(name));
60}
61
62loader_t *loader_connect(void)
63{
64 loader_t *ldr = malloc(sizeof(loader_t));
65 if (ldr == NULL)
66 return NULL;
67
68 async_sess_t *sess =
69 service_connect_blocking(SERVICE_LOADER, INTERFACE_LOADER, 0);
70 if (sess == NULL) {
71 free(ldr);
72 return NULL;
73 }
74
75 ldr->sess = sess;
76 return ldr;
77}
78
79/** Get ID of the new task.
80 *
81 * Retrieves the ID of the new task from the loader.
82 *
83 * @param ldr Loader connection structure.
84 * @param task_id Points to a variable where the ID should be stored.
85 *
86 * @return Zero on success or an error code.
87 *
88 */
89errno_t loader_get_task_id(loader_t *ldr, task_id_t *task_id)
90{
91 /* Get task ID. */
92 async_exch_t *exch = async_exchange_begin(ldr->sess);
93
94 ipc_call_t answer;
95 aid_t req = async_send_0(exch, LOADER_GET_TASKID, &answer);
96 errno_t rc = async_data_read_start(exch, task_id, sizeof(task_id_t));
97
98 async_exchange_end(exch);
99
100 if (rc != EOK) {
101 async_forget(req);
102 return (errno_t) rc;
103 }
104
105 async_wait_for(req, &rc);
106 return (errno_t) rc;
107}
108
109/** Set current working directory for the loaded task.
110 *
111 * Sets the current working directory for the loaded task.
112 *
113 * @param ldr Loader connection structure.
114 *
115 * @return Zero on success or an error code.
116 *
117 */
118errno_t loader_set_cwd(loader_t *ldr)
119{
120 char *cwd = (char *) malloc(MAX_PATH_LEN + 1);
121 if (!cwd)
122 return ENOMEM;
123
124 if (vfs_cwd_get(cwd, MAX_PATH_LEN + 1) != EOK)
125 str_cpy(cwd, MAX_PATH_LEN + 1, "/");
126
127 size_t len = str_length(cwd);
128
129 async_exch_t *exch = async_exchange_begin(ldr->sess);
130
131 ipc_call_t answer;
132 aid_t req = async_send_0(exch, LOADER_SET_CWD, &answer);
133 errno_t rc = async_data_write_start(exch, cwd, len);
134
135 async_exchange_end(exch);
136 free(cwd);
137
138 if (rc != EOK) {
139 async_forget(req);
140 return (errno_t) rc;
141 }
142
143 async_wait_for(req, &rc);
144 return (errno_t) rc;
145}
146
147/** Set the program to load.
148 *
149 * @param ldr Loader connection structure.
150 * @param name Name to set for the spawned program.
151 * @param file Program file.
152 *
153 * @return Zero on success or an error code.
154 *
155 */
156errno_t loader_set_program(loader_t *ldr, const char *name, int file)
157{
158 async_exch_t *exch = async_exchange_begin(ldr->sess);
159
160 ipc_call_t answer;
161 aid_t req = async_send_0(exch, LOADER_SET_PROGRAM, &answer);
162
163 errno_t rc = async_data_write_start(exch, name, str_size(name) + 1);
164 if (rc == EOK) {
165 async_exch_t *vfs_exch = vfs_exchange_begin();
166 rc = vfs_pass_handle(vfs_exch, file, exch);
167 vfs_exchange_end(vfs_exch);
168 }
169
170 async_exchange_end(exch);
171
172 if (rc != EOK) {
173 async_forget(req);
174 return (errno_t) rc;
175 }
176
177 async_wait_for(req, &rc);
178 return (errno_t) rc;
179}
180
181/** Set the program to load by path.
182 *
183 * @param ldr Loader connection structure.
184 * @param path Program path.
185 *
186 * @return Zero on success or an error code.
187 *
188 */
189errno_t loader_set_program_path(loader_t *ldr, const char *path)
190{
191 size_t abslen;
192 char *abspath = vfs_absolutize(path, &abslen);
193 if (!abspath)
194 return ENOMEM;
195
196 int fd;
197 errno_t rc = vfs_lookup(path, 0, &fd);
198 if (rc != EOK) {
199 return rc;
200 }
201
202 rc = loader_set_program(ldr, abspath, fd);
203 vfs_put(fd);
204 return rc;
205}
206
207/** Set command-line arguments for the program.
208 *
209 * Sets the vector of command-line arguments to be passed to the loaded
210 * program. By convention, the very first argument is typically the same as
211 * the command used to execute the program.
212 *
213 * @param ldr Loader connection structure.
214 * @param argv NULL-terminated array of pointers to arguments.
215 *
216 * @return Zero on success or an error code.
217 *
218 */
219errno_t loader_set_args(loader_t *ldr, const char *const argv[])
220{
221 /*
222 * Serialize the arguments into a single array. First
223 * compute size of the buffer needed.
224 */
225 const char *const *ap = argv;
226 size_t buffer_size = 0;
227 while (*ap != NULL) {
228 buffer_size += str_size(*ap) + 1;
229 ap++;
230 }
231
232 char *arg_buf = malloc(buffer_size);
233 if (arg_buf == NULL)
234 return ENOMEM;
235
236 /* Now fill the buffer with null-terminated argument strings */
237 ap = argv;
238 char *dp = arg_buf;
239
240 while (*ap != NULL) {
241 str_cpy(dp, buffer_size - (dp - arg_buf), *ap);
242 dp += str_size(*ap) + 1;
243 ap++;
244 }
245
246 /* Send serialized arguments to the loader */
247 async_exch_t *exch = async_exchange_begin(ldr->sess);
248
249 ipc_call_t answer;
250 aid_t req = async_send_0(exch, LOADER_SET_ARGS, &answer);
251 errno_t rc = async_data_write_start(exch, (void *) arg_buf,
252 buffer_size);
253
254 async_exchange_end(exch);
255 free(arg_buf);
256
257 if (rc != EOK) {
258 async_forget(req);
259 return (errno_t) rc;
260 }
261
262 async_wait_for(req, &rc);
263 return (errno_t) rc;
264}
265
266/** Add a file to the task's inbox.
267 *
268 * @param ldr Loader connection structure.
269 * @param name Identification of the file.
270 * @param file The file's descriptor.
271 *
272 * @return Zero on success or an error code.
273 *
274 */
275errno_t loader_add_inbox(loader_t *ldr, const char *name, int file)
276{
277 async_exch_t *exch = async_exchange_begin(ldr->sess);
278 async_exch_t *vfs_exch = vfs_exchange_begin();
279
280 aid_t req = async_send_0(exch, LOADER_ADD_INBOX, NULL);
281
282 errno_t rc = async_data_write_start(exch, name, str_size(name) + 1);
283 if (rc == EOK) {
284 rc = vfs_pass_handle(vfs_exch, file, exch);
285 }
286
287 async_exchange_end(vfs_exch);
288 async_exchange_end(exch);
289
290 if (rc == EOK) {
291 async_wait_for(req, &rc);
292 } else {
293 async_forget(req);
294 }
295
296 return (errno_t) rc;
297}
298
299/** Instruct loader to load the program.
300 *
301 * If this function succeeds, the program has been successfully loaded
302 * and is ready to be executed.
303 *
304 * @param ldr Loader connection structure.
305 *
306 * @return Zero on success or an error code.
307 *
308 */
309errno_t loader_load_program(loader_t *ldr)
310{
311 async_exch_t *exch = async_exchange_begin(ldr->sess);
312 errno_t rc = async_req_0_0(exch, LOADER_LOAD);
313 async_exchange_end(exch);
314
315 return rc;
316}
317
318/** Instruct loader to execute the program.
319 *
320 * Note that this function blocks until the loader actually replies
321 * so you cannot expect this function to return if you are debugging
322 * the task and its thread is stopped.
323 *
324 * After using this function, no further operations can be performed
325 * on the loader structure and it is deallocated.
326 *
327 * @param ldr Loader connection structure.
328 *
329 * @return Zero on success or an error code.
330 *
331 */
332errno_t loader_run(loader_t *ldr)
333{
334 async_exch_t *exch = async_exchange_begin(ldr->sess);
335 errno_t rc = async_req_0_0(exch, LOADER_RUN);
336 async_exchange_end(exch);
337
338 if (rc != EOK)
339 return rc;
340
341 async_hangup(ldr->sess);
342 free(ldr);
343
344 return EOK;
345}
346
347/** Instruct loader to execute the program and do not wait for reply.
348 *
349 * This function does not block even if the loaded task is stopped
350 * for debugging.
351 *
352 * After using this function, no further operations can be performed
353 * on the loader structure and it is deallocated.
354 *
355 * @param ldr Loader connection structure.
356 *
357 * @return Zero on success or an error code.
358 *
359 */
360void loader_run_nowait(loader_t *ldr)
361{
362 async_exch_t *exch = async_exchange_begin(ldr->sess);
363 async_msg_0(exch, LOADER_RUN);
364 async_exchange_end(exch);
365
366 async_hangup(ldr->sess);
367 free(ldr);
368}
369
370/** Cancel the loader session.
371 *
372 * Tell the loader not to load any program and terminate.
373 * After using this function, no further operations can be performed
374 * on the loader structure and it is deallocated.
375 *
376 * @param ldr Loader connection structure.
377 *
378 * @return Zero on success or an error code.
379 *
380 */
381void loader_abort(loader_t *ldr)
382{
383 async_hangup(ldr->sess);
384 free(ldr);
385}
386
387/** @}
388 */
Note: See TracBrowser for help on using the repository browser.