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
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/** Spawn a new program loader.
49 *
50 * Spawn a new program loader task. The loader then independetly
51 * connects to the naming service.
52 *
53 * @param name Symbolic name to set on the newly created task.
54 *
55 * @return Error code.
56 *
57 */
58errno_t loader_spawn(const char *name)
59{
60 return (errno_t) __SYSCALL2(SYS_PROGRAM_SPAWN_LOADER,
61 (sysarg_t) name, str_size(name));
62}
63
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)
72{
73 loader_t *ldr = malloc(sizeof(loader_t));
74 if (ldr == NULL)
75 return NULL;
76
77 async_sess_t *sess =
78 service_connect_blocking(SERVICE_LOADER, INTERFACE_LOADER, 0, rc);
79 if (sess == NULL) {
80 free(ldr);
81 return NULL;
82 }
83
84 ldr->sess = sess;
85 return ldr;
86}
87
88/** Get ID of the new task.
89 *
90 * Retrieves the ID of the new task from the loader.
91 *
92 * @param ldr Loader connection structure.
93 * @param task_id Points to a variable where the ID should be stored.
94 *
95 * @return Zero on success or an error code.
96 *
97 */
98errno_t loader_get_task_id(loader_t *ldr, task_id_t *task_id)
99{
100 /* Get task ID. */
101 async_exch_t *exch = async_exchange_begin(ldr->sess);
102
103 ipc_call_t answer;
104 aid_t req = async_send_0(exch, LOADER_GET_TASKID, &answer);
105 errno_t rc = async_data_read_start(exch, task_id, sizeof(task_id_t));
106
107 async_exchange_end(exch);
108
109 if (rc != EOK) {
110 async_forget(req);
111 return (errno_t) rc;
112 }
113
114 async_wait_for(req, &rc);
115 return (errno_t) rc;
116}
117
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 *
124 * @return Zero on success or an error code.
125 *
126 */
127errno_t loader_set_cwd(loader_t *ldr)
128{
129 char *cwd = (char *) malloc(MAX_PATH_LEN + 1);
130 if (!cwd)
131 return ENOMEM;
132
133 if (vfs_cwd_get(cwd, MAX_PATH_LEN + 1) != EOK)
134 str_cpy(cwd, MAX_PATH_LEN + 1, "/");
135
136 size_t len = str_length(cwd);
137
138 async_exch_t *exch = async_exchange_begin(ldr->sess);
139
140 ipc_call_t answer;
141 aid_t req = async_send_0(exch, LOADER_SET_CWD, &answer);
142 errno_t rc = async_data_write_start(exch, cwd, len);
143
144 async_exchange_end(exch);
145 free(cwd);
146
147 if (rc != EOK) {
148 async_forget(req);
149 return (errno_t) rc;
150 }
151
152 async_wait_for(req, &rc);
153 return (errno_t) rc;
154}
155
156/** Set the program to load.
157 *
158 * @param ldr Loader connection structure.
159 * @param name Name to set for the spawned program.
160 * @param file Program file.
161 *
162 * @return Zero on success or an error code.
163 *
164 */
165errno_t loader_set_program(loader_t *ldr, const char *name, int file)
166{
167 async_exch_t *exch = async_exchange_begin(ldr->sess);
168
169 ipc_call_t answer;
170 aid_t req = async_send_0(exch, LOADER_SET_PROGRAM, &answer);
171
172 errno_t rc = async_data_write_start(exch, name, str_size(name) + 1);
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
179 async_exchange_end(exch);
180
181 if (rc != EOK) {
182 async_forget(req);
183 return (errno_t) rc;
184 }
185
186 async_wait_for(req, &rc);
187 return (errno_t) rc;
188}
189
190/** Set the program to load by path.
191 *
192 * @param ldr Loader connection structure.
193 * @param path Program path.
194 *
195 * @return Zero on success or an error code.
196 *
197 */
198errno_t loader_set_program_path(loader_t *ldr, const char *path)
199{
200 size_t abslen;
201 char *abspath = vfs_absolutize(path, &abslen);
202 if (!abspath)
203 return ENOMEM;
204
205 int fd;
206 errno_t rc = vfs_lookup(path, 0, &fd);
207 if (rc != EOK) {
208 return rc;
209 }
210
211 rc = loader_set_program(ldr, abspath, fd);
212 vfs_put(fd);
213 return rc;
214}
215
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 *
222 * @param ldr Loader connection structure.
223 * @param argv NULL-terminated array of pointers to arguments.
224 *
225 * @return Zero on success or an error code.
226 *
227 */
228errno_t loader_set_args(loader_t *ldr, const char *const argv[])
229{
230 /*
231 * Serialize the arguments into a single array. First
232 * compute size of the buffer needed.
233 */
234 const char *const *ap = argv;
235 size_t buffer_size = 0;
236 while (*ap != NULL) {
237 buffer_size += str_size(*ap) + 1;
238 ap++;
239 }
240
241 char *arg_buf = malloc(buffer_size);
242 if (arg_buf == NULL)
243 return ENOMEM;
244
245 /* Now fill the buffer with null-terminated argument strings */
246 ap = argv;
247 char *dp = arg_buf;
248
249 while (*ap != NULL) {
250 str_cpy(dp, buffer_size - (dp - arg_buf), *ap);
251 dp += str_size(*ap) + 1;
252 ap++;
253 }
254
255 /* Send serialized arguments to the loader */
256 async_exch_t *exch = async_exchange_begin(ldr->sess);
257
258 ipc_call_t answer;
259 aid_t req = async_send_0(exch, LOADER_SET_ARGS, &answer);
260 errno_t rc = async_data_write_start(exch, (void *) arg_buf,
261 buffer_size);
262
263 async_exchange_end(exch);
264 free(arg_buf);
265
266 if (rc != EOK) {
267 async_forget(req);
268 return (errno_t) rc;
269 }
270
271 async_wait_for(req, &rc);
272 return (errno_t) rc;
273}
274
275/** Add a file to the task's inbox.
276 *
277 * @param ldr Loader connection structure.
278 * @param name Identification of the file.
279 * @param file The file's descriptor.
280 *
281 * @return Zero on success or an error code.
282 *
283 */
284errno_t loader_add_inbox(loader_t *ldr, const char *name, int file)
285{
286 async_exch_t *exch = async_exchange_begin(ldr->sess);
287 async_exch_t *vfs_exch = vfs_exchange_begin();
288
289 aid_t req = async_send_0(exch, LOADER_ADD_INBOX, NULL);
290
291 errno_t rc = async_data_write_start(exch, name, str_size(name) + 1);
292 if (rc == EOK) {
293 rc = vfs_pass_handle(vfs_exch, file, exch);
294 }
295
296 async_exchange_end(vfs_exch);
297 async_exchange_end(exch);
298
299 if (rc == EOK) {
300 async_wait_for(req, &rc);
301 } else {
302 async_forget(req);
303 }
304
305 return (errno_t) rc;
306}
307
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 *
313 * @param ldr Loader connection structure.
314 *
315 * @return Zero on success or an error code.
316 *
317 */
318errno_t loader_load_program(loader_t *ldr)
319{
320 async_exch_t *exch = async_exchange_begin(ldr->sess);
321 errno_t rc = async_req_0_0(exch, LOADER_LOAD);
322 async_exchange_end(exch);
323
324 return rc;
325}
326
327/** Instruct loader to execute the program.
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.
332 *
333 * After using this function, no further operations can be performed
334 * on the loader structure and it is deallocated.
335 *
336 * @param ldr Loader connection structure.
337 *
338 * @return Zero on success or an error code.
339 *
340 */
341errno_t loader_run(loader_t *ldr)
342{
343 async_exch_t *exch = async_exchange_begin(ldr->sess);
344 errno_t rc = async_req_0_0(exch, LOADER_RUN);
345 async_exchange_end(exch);
346
347 if (rc != EOK)
348 return rc;
349
350 async_hangup(ldr->sess);
351 free(ldr);
352
353 return EOK;
354}
355
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
379/** Cancel the loader session.
380 *
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.
384 *
385 * @param ldr Loader connection structure.
386 *
387 * @return Zero on success or an error code.
388 *
389 */
390void loader_abort(loader_t *ldr)
391{
392 async_hangup(ldr->sess);
393 free(ldr);
394}
395
396/** @}
397 */
Note: See TracBrowser for help on using the repository browser.