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
RevLine 
[45454e9b]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
[937aeee]33 */
[45454e9b]34
35#include <ipc/loader.h>
[bfd1546]36#include <ipc/services.h>
[79ae36dd]37#include <ns.h>
[45454e9b]38#include <libc.h>
[0993087]39#include <task.h>
[19f857a]40#include <str.h>
[45454e9b]41#include <stdlib.h>
42#include <async.h>
43#include <errno.h>
44#include <vfs/vfs.h>
45#include <loader/loader.h>
[79ae36dd]46#include "private/loader.h"
[45454e9b]47
48/** Connect to a new program loader.
49 *
50 * Spawns a new program loader task and returns the connection structure.
[937aeee]51 *
52 * @param name Symbolic name to set on the newly created task.
53 *
[f77c1c9]54 * @return Error code.
[45454e9b]55 */
[b7fd2a0]56errno_t loader_spawn(const char *name)
[45454e9b]57{
[b7fd2a0]58 return (errno_t) __SYSCALL2(SYS_PROGRAM_SPAWN_LOADER,
[9eb3623]59 (sysarg_t) name, str_size(name));
[bfd1546]60}
[45454e9b]61
[bfd1546]62loader_t *loader_connect(void)
63{
[937aeee]64 loader_t *ldr = malloc(sizeof(loader_t));
[45454e9b]65 if (ldr == NULL)
66 return NULL;
[a35b458]67
[79ae36dd]68 async_sess_t *sess =
[f9b2cb4c]69 service_connect_blocking(SERVICE_LOADER, INTERFACE_LOADER, 0);
[79ae36dd]70 if (sess == NULL) {
71 free(ldr);
72 return NULL;
73 }
[a35b458]74
[79ae36dd]75 ldr->sess = sess;
[937aeee]76 return ldr;
[45454e9b]77}
78
79/** Get ID of the new task.
80 *
81 * Retrieves the ID of the new task from the loader.
82 *
[937aeee]83 * @param ldr Loader connection structure.
84 * @param task_id Points to a variable where the ID should be stored.
85 *
[cde999a]86 * @return Zero on success or an error code.
[937aeee]87 *
[45454e9b]88 */
[b7fd2a0]89errno_t loader_get_task_id(loader_t *ldr, task_id_t *task_id)
[45454e9b]90{
91 /* Get task ID. */
[79ae36dd]92 async_exch_t *exch = async_exchange_begin(ldr->sess);
[a35b458]93
[937aeee]94 ipc_call_t answer;
[79ae36dd]95 aid_t req = async_send_0(exch, LOADER_GET_TASKID, &answer);
[b7fd2a0]96 errno_t rc = async_data_read_start(exch, task_id, sizeof(task_id_t));
[a35b458]97
[79ae36dd]98 async_exchange_end(exch);
[a35b458]99
[45454e9b]100 if (rc != EOK) {
[50b581d]101 async_forget(req);
[b7fd2a0]102 return (errno_t) rc;
[45454e9b]103 }
[a35b458]104
[79ae36dd]105 async_wait_for(req, &rc);
[b7fd2a0]106 return (errno_t) rc;
[45454e9b]107}
108
[622cdbe]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 *
[cde999a]115 * @return Zero on success or an error code.
[622cdbe]116 *
117 */
[b7fd2a0]118errno_t loader_set_cwd(loader_t *ldr)
[622cdbe]119{
[79ae36dd]120 char *cwd = (char *) malloc(MAX_PATH_LEN + 1);
[622cdbe]121 if (!cwd)
122 return ENOMEM;
[a35b458]123
[d96d9bc]124 if (vfs_cwd_get(cwd, MAX_PATH_LEN + 1) != EOK)
[79ae36dd]125 str_cpy(cwd, MAX_PATH_LEN + 1, "/");
[a35b458]126
[79ae36dd]127 size_t len = str_length(cwd);
[a35b458]128
[79ae36dd]129 async_exch_t *exch = async_exchange_begin(ldr->sess);
[a35b458]130
[622cdbe]131 ipc_call_t answer;
[79ae36dd]132 aid_t req = async_send_0(exch, LOADER_SET_CWD, &answer);
[b7fd2a0]133 errno_t rc = async_data_write_start(exch, cwd, len);
[a35b458]134
[79ae36dd]135 async_exchange_end(exch);
[622cdbe]136 free(cwd);
[a35b458]137
[622cdbe]138 if (rc != EOK) {
[50b581d]139 async_forget(req);
[b7fd2a0]140 return (errno_t) rc;
[622cdbe]141 }
[a35b458]142
[79ae36dd]143 async_wait_for(req, &rc);
[b7fd2a0]144 return (errno_t) rc;
[622cdbe]145}
146
[bb9ec2d]147/** Set the program to load.
[45454e9b]148 *
[937aeee]149 * @param ldr Loader connection structure.
[bb9ec2d]150 * @param name Name to set for the spawned program.
151 * @param file Program file.
[937aeee]152 *
[cde999a]153 * @return Zero on success or an error code.
[937aeee]154 *
[45454e9b]155 */
[b7fd2a0]156errno_t loader_set_program(loader_t *ldr, const char *name, int file)
[45454e9b]157{
[79ae36dd]158 async_exch_t *exch = async_exchange_begin(ldr->sess);
[bb9ec2d]159
[937aeee]160 ipc_call_t answer;
[bb9ec2d]161 aid_t req = async_send_0(exch, LOADER_SET_PROGRAM, &answer);
162
[b7fd2a0]163 errno_t rc = async_data_write_start(exch, name, str_size(name) + 1);
[bb9ec2d]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
[79ae36dd]170 async_exchange_end(exch);
[bb9ec2d]171
[45454e9b]172 if (rc != EOK) {
[50b581d]173 async_forget(req);
[b7fd2a0]174 return (errno_t) rc;
[45454e9b]175 }
[bb9ec2d]176
[79ae36dd]177 async_wait_for(req, &rc);
[b7fd2a0]178 return (errno_t) rc;
[45454e9b]179}
180
[bb9ec2d]181/** Set the program to load by path.
182 *
183 * @param ldr Loader connection structure.
184 * @param path Program path.
185 *
[cde999a]186 * @return Zero on success or an error code.
[bb9ec2d]187 *
188 */
[b7fd2a0]189errno_t loader_set_program_path(loader_t *ldr, const char *path)
[bb9ec2d]190{
[9286475]191 size_t abslen;
192 char *abspath = vfs_absolutize(path, &abslen);
193 if (!abspath)
194 return ENOMEM;
[a35b458]195
[f77c1c9]196 int fd;
[b7fd2a0]197 errno_t rc = vfs_lookup(path, 0, &fd);
[f77c1c9]198 if (rc != EOK) {
199 return rc;
[bb9ec2d]200 }
[a35b458]201
[21d3201]202 rc = loader_set_program(ldr, abspath, fd);
[9c4cf0d]203 vfs_put(fd);
[bb9ec2d]204 return rc;
205}
206
[45454e9b]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 *
[937aeee]213 * @param ldr Loader connection structure.
214 * @param argv NULL-terminated array of pointers to arguments.
215 *
[cde999a]216 * @return Zero on success or an error code.
[937aeee]217 *
[45454e9b]218 */
[b7fd2a0]219errno_t loader_set_args(loader_t *ldr, const char *const argv[])
[45454e9b]220{
[937aeee]221 /*
[45454e9b]222 * Serialize the arguments into a single array. First
223 * compute size of the buffer needed.
224 */
[a000878c]225 const char *const *ap = argv;
[937aeee]226 size_t buffer_size = 0;
[45454e9b]227 while (*ap != NULL) {
[9eb3623]228 buffer_size += str_size(*ap) + 1;
[937aeee]229 ap++;
[45454e9b]230 }
[a35b458]231
[937aeee]232 char *arg_buf = malloc(buffer_size);
233 if (arg_buf == NULL)
234 return ENOMEM;
[a35b458]235
[45454e9b]236 /* Now fill the buffer with null-terminated argument strings */
237 ap = argv;
[937aeee]238 char *dp = arg_buf;
[a35b458]239
[45454e9b]240 while (*ap != NULL) {
[6eb2e96]241 str_cpy(dp, buffer_size - (dp - arg_buf), *ap);
[9eb3623]242 dp += str_size(*ap) + 1;
[937aeee]243 ap++;
[45454e9b]244 }
[a35b458]245
[45454e9b]246 /* Send serialized arguments to the loader */
[79ae36dd]247 async_exch_t *exch = async_exchange_begin(ldr->sess);
[a35b458]248
[937aeee]249 ipc_call_t answer;
[79ae36dd]250 aid_t req = async_send_0(exch, LOADER_SET_ARGS, &answer);
[b7fd2a0]251 errno_t rc = async_data_write_start(exch, (void *) arg_buf,
[79ae36dd]252 buffer_size);
[a35b458]253
[79ae36dd]254 async_exchange_end(exch);
255 free(arg_buf);
[a35b458]256
[45454e9b]257 if (rc != EOK) {
[50b581d]258 async_forget(req);
[b7fd2a0]259 return (errno_t) rc;
[45454e9b]260 }
[a35b458]261
[45454e9b]262 async_wait_for(req, &rc);
[b7fd2a0]263 return (errno_t) rc;
[937aeee]264}
[45454e9b]265
[bb9ec2d]266/** Add a file to the task's inbox.
[937aeee]267 *
[bb9ec2d]268 * @param ldr Loader connection structure.
269 * @param name Identification of the file.
270 * @param file The file's descriptor.
[937aeee]271 *
[cde999a]272 * @return Zero on success or an error code.
[937aeee]273 *
274 */
[b7fd2a0]275errno_t loader_add_inbox(loader_t *ldr, const char *name, int file)
[937aeee]276{
[79ae36dd]277 async_exch_t *exch = async_exchange_begin(ldr->sess);
[7171760]278 async_exch_t *vfs_exch = vfs_exchange_begin();
[a35b458]279
[bb9ec2d]280 aid_t req = async_send_0(exch, LOADER_ADD_INBOX, NULL);
[a35b458]281
[b7fd2a0]282 errno_t rc = async_data_write_start(exch, name, str_size(name) + 1);
[bb9ec2d]283 if (rc == EOK) {
284 rc = vfs_pass_handle(vfs_exch, file, exch);
[7171760]285 }
[a35b458]286
[bb9ec2d]287 async_exchange_end(vfs_exch);
[7171760]288 async_exchange_end(exch);
[a35b458]289
[bb9ec2d]290 if (rc == EOK) {
291 async_wait_for(req, &rc);
292 } else {
[50b581d]293 async_forget(req);
[937aeee]294 }
[a35b458]295
[b7fd2a0]296 return (errno_t) rc;
[45454e9b]297}
298
[4470e26]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 *
[937aeee]304 * @param ldr Loader connection structure.
305 *
[cde999a]306 * @return Zero on success or an error code.
[937aeee]307 *
[4470e26]308 */
[b7fd2a0]309errno_t loader_load_program(loader_t *ldr)
[4470e26]310{
[79ae36dd]311 async_exch_t *exch = async_exchange_begin(ldr->sess);
[b7fd2a0]312 errno_t rc = async_req_0_0(exch, LOADER_LOAD);
[79ae36dd]313 async_exchange_end(exch);
[a35b458]314
[79ae36dd]315 return rc;
[4470e26]316}
317
[45454e9b]318/** Instruct loader to execute the program.
[4470e26]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.
[45454e9b]323 *
[79ae36dd]324 * After using this function, no further operations can be performed
325 * on the loader structure and it is deallocated.
[45454e9b]326 *
[937aeee]327 * @param ldr Loader connection structure.
328 *
[cde999a]329 * @return Zero on success or an error code.
[937aeee]330 *
[45454e9b]331 */
[b7fd2a0]332errno_t loader_run(loader_t *ldr)
[45454e9b]333{
[79ae36dd]334 async_exch_t *exch = async_exchange_begin(ldr->sess);
[b7fd2a0]335 errno_t rc = async_req_0_0(exch, LOADER_RUN);
[79ae36dd]336 async_exchange_end(exch);
[a35b458]337
[45454e9b]338 if (rc != EOK)
339 return rc;
[a35b458]340
[79ae36dd]341 async_hangup(ldr->sess);
342 free(ldr);
[a35b458]343
[45454e9b]344 return EOK;
345}
346
[2443ad8]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
[45454e9b]370/** Cancel the loader session.
371 *
[79ae36dd]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.
[45454e9b]375 *
[937aeee]376 * @param ldr Loader connection structure.
377 *
[cde999a]378 * @return Zero on success or an error code.
[937aeee]379 *
[45454e9b]380 */
381void loader_abort(loader_t *ldr)
382{
[79ae36dd]383 async_hangup(ldr->sess);
384 free(ldr);
[45454e9b]385}
386
387/** @}
388 */
Note: See TracBrowser for help on using the repository browser.