source: mainline/uspace/lib/c/generic/loader.c@ 28a5ebd

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 28a5ebd was 01900b6, checked in by Martin Decky <martin@…>, 5 years ago

Use an optional output argument instead of errno to propagate the error

The use of errno is troublesome in all other than top-level library
functions since the value in errno might get overwritten by subsequent
inner calls on the error path (e.g. cleanup, deallocation, etc.). The
optional output argument makes it possible to explicitly ignore the
error code if it is not needed, but still to pass it reliably back to
the original caller.

This change affecs async_connect_me_to(),
async_connect_me_to_blocking(), async_connect_kbox(), service_connect(),
service_connect_blocking() and loader_connect().

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