proc_mgmt: implementation spawn_wait() with nohang flag
[barrelfish] / lib / barrelfish / spawn_client.c
1 /**
2  * \file
3  * \brief Client for interacting with the process management server.
4  */
5
6 /*
7  * Copyright (c) 2017, ETH Zurich.
8  * All rights reserved.
9  *
10  * This file is distributed under the terms in the attached LICENSE file.
11  * If you do not find this file, copies can be found by writing to:
12  * ETH Zurich D-INFK, Haldeneggsteig 4, CH-8092 Zurich. Attn: Systems Group.
13  */
14
15 #include <barrelfish/barrelfish.h>
16 #include <barrelfish/nameservice_client.h>
17 #include <barrelfish/spawn_client.h>
18 #include <if/octopus_defs.h>
19 #include <if/proc_mgmt_defs.h>
20 #include <if/arrakis_defs.h>
21 #include <if/monitor_defs.h>
22 #include <if/spawn_defs.h>
23 #include <vfs/vfs_path.h>
24
25 // For spawn_program_on_all_cores
26 #include <octopus/getset.h> // for oct_read TODO
27 #include <octopus/trigger.h> // for NOP_TRIGGER
28
29
30 struct proc_mgmt_bind_retst {
31     errval_t err;
32     struct proc_mgmt_binding *b;
33     bool present;
34 };
35
36 struct spawn_bind_retst {
37     errval_t err;
38     struct spawn_binding *b;
39     bool present;
40 };
41
42 struct arrakis_bind_retst {
43     errval_t err;
44     struct arrakis_binding *b;
45     bool present;
46 };
47
48 extern char **environ;
49
50 static void spawn_bind_cont(void *st, errval_t err, struct spawn_binding *b)
51 {
52     struct spawn_bind_retst *retst = st;
53     assert(retst != NULL);
54     assert(!retst->present);
55     retst->err = err;
56     retst->b = b;
57     retst->present = true;
58 }
59
60 static void arrakis_bind_cont(void *st, errval_t err, struct arrakis_binding *b)
61 {
62     struct arrakis_bind_retst *retst = st;
63     assert(retst != NULL);
64     assert(!retst->present);
65     retst->err = err;
66     retst->b = b;
67     retst->present = true;
68 }
69
70 static struct spawn_binding *spawn_b = NULL;
71
72 static errval_t bind_client(coreid_t coreid)
73 {
74     struct spawn_binding *cl;
75     errval_t err = SYS_ERR_OK;
76
77     // do we have a spawn client connection for this core?
78     assert(coreid < MAX_CPUS);
79     cl = get_spawn_binding(coreid);
80     if (cl == NULL) {
81         char namebuf[16];
82         snprintf(namebuf, sizeof(namebuf), "spawn.%u", coreid);
83         namebuf[sizeof(namebuf) - 1] = '\0';
84
85         iref_t iref;
86         err = nameservice_blocking_lookup(namebuf, &iref);
87         if (err_is_fail(err)) {
88             //DEBUG_ERR(err, "spawn daemon on core %u not found\n", coreid);
89             return err;
90         }
91
92         // initiate bind
93         struct spawn_bind_retst bindst = { .present = false };
94         err = spawn_bind(iref, spawn_bind_cont, &bindst, get_default_waitset(),
95                          IDC_BIND_FLAGS_DEFAULT);
96         if (err_is_fail(err)) {
97             DEBUG_ERR(err, "spawn_bind failed");
98             return err;
99         }
100
101         // XXX: block for bind completion
102         while (!bindst.present) {
103             messages_wait_and_handle_next();
104         }
105
106         if (err_is_fail(bindst.err)) {
107             return bindst.err;
108         }
109
110         spawn_b = bindst.b;
111
112         spawn_rpc_client_init(bindst.b);
113         set_spawn_binding(coreid, bindst.b);
114     }
115
116     return err;
117 }
118
119 errval_t spawn_bind_iref(iref_t iref, struct spawn_binding **ret_client)
120 {
121     assert(ret_client != NULL);
122
123     struct spawn_bind_retst bindst = { .present = false };
124     errval_t err = spawn_bind(iref, spawn_bind_cont, &bindst,
125                               get_default_waitset(), IDC_BIND_FLAGS_DEFAULT);
126     if (err_is_fail(err)) {
127         DEBUG_ERR(err, "spawn_bind failed");
128         return err;
129     }
130
131     // XXX: block for bind completion
132     while (!bindst.present) {
133         messages_wait_and_handle_next();
134     }
135
136     if (err_is_fail(bindst.err)) {
137         return bindst.err;
138     }
139
140     spawn_rpc_client_init(bindst.b);
141     *ret_client = bindst.b;
142     // set_spawn_binding(coreid, bindst.b);
143
144     return err;
145 }
146
147
148 static void error_handler(struct proc_mgmt_binding *b, errval_t err)
149 {
150 #if defined(__x86_64__) || defined(__i386__)
151     debug_printf("%p \n",  __builtin_return_address(0));
152 #endif
153     debug_err(__FILE__, __func__, __LINE__, err,
154               "asynchronous error in proc_mgmt binding");
155     abort();
156 }
157
158 static void proc_mgmt_bind_cont(void *st, errval_t err,
159         struct proc_mgmt_binding *b)
160 {
161     struct proc_mgmt_bind_retst *retst = (struct proc_mgmt_bind_retst*) st;
162     assert(retst != NULL);
163     assert(!retst->present);
164     retst->err = err;
165     retst->b = b;
166     retst->present = true;
167     b->st = retst;
168 }
169
170 static void proc_mgmt_accept_recv_handler(void *arg)
171 {
172     struct proc_mgmt_lmp_binding *b = arg;
173     struct lmp_recv_msg msg = LMP_RECV_MSG_INIT;
174     struct capref cap;
175     errval_t err;
176
177     // try to retrieve a message from the channel
178     err = lmp_chan_recv(&b->chan, &msg, &cap);
179     if (err_is_fail(err)) {
180         if (err_no(err) == LIB_ERR_NO_LMP_MSG) {
181             // nothing there, re-register
182             struct event_closure recv_handler = {
183                 .handler = proc_mgmt_accept_recv_handler,
184                 .arg = b,
185             };
186             err = lmp_chan_register_recv(&b->chan, b->b.waitset, recv_handler);
187             b->b.error_handler(&b->b, err_push(err, LIB_ERR_CHAN_REGISTER_RECV));
188         } else {
189             // real error, report to user
190             b->b.error_handler(&b->b, err_push(err, LIB_ERR_LMP_CHAN_RECV));
191         }
192         return;
193     }
194
195     // TODO(razvan): LMP_PROC_MGMT_ACCEPT ?
196     assert(b->chan.connstate == LMP_MONITOR_ACCEPT);
197     assert(!capref_is_null(cap));
198     b->chan.remote_cap = cap;
199     b->chan.connstate = LMP_CONNECTED;
200
201     /* allocate a new receive slot */
202     err = lmp_chan_alloc_recv_slot(&b->chan);
203     if (err_is_fail(err)) {
204         // XXX: report the error, but continue
205         b->b.error_handler(&b->b, err_push(err, LIB_ERR_LMP_ALLOC_RECV_SLOT));
206     }
207
208     /* Run the RX handler; has a side-effect of registering for receive events */
209     proc_mgmt_lmp_rx_handler(b);
210 }
211
212 static errval_t init_lmp_binding(struct proc_mgmt_lmp_binding *lmpb,
213                                  struct waitset *ws,
214                                  size_t buflen_words)
215 {
216     errval_t err;
217
218     proc_mgmt_lmp_init(lmpb, ws);
219
220     /* allocate a cap slot for the new endpoint cap */
221     err = slot_alloc(&lmpb->chan.local_cap);
222     if (err_is_fail(err)) {
223         return err_push(err, LIB_ERR_SLOT_ALLOC);
224     }
225
226     /* allocate a local endpoint */
227     err = lmp_endpoint_create_in_slot(buflen_words, lmpb->chan.local_cap,
228                                       &lmpb->chan.endpoint);
229     if (err_is_fail(err)) {
230         // TODO(razvan): Free cap slot.
231         return err_push(err, LIB_ERR_ENDPOINT_CREATE);
232     }
233
234     /* allocate an initial receive slot */
235     err = lmp_chan_alloc_recv_slot(&lmpb->chan);
236     if (err_is_fail(err)) {
237         return err;
238     }
239
240     /* setup error handler */
241     lmpb->b.error_handler = error_handler;
242
243     /* setup initial receive handlers */
244     // TODO(razvan): Don't think this is needed, but dunno for sure yet.
245     // lmpb->b.rx_vtbl = monitor_rx_vtbl;
246
247     // connect handlers
248     lmpb->b.change_waitset(&lmpb->b, lmpb->b.waitset);
249     return SYS_ERR_OK;
250 }
251
252 /**
253  * \brief Accept a new LMP binding to a proc mgmt client.
254  *
255  * Should only be used in the process manager.
256  *
257  * \param lmpb         Storage for binding state
258  * \param ws           Waitset for handling incoming messages
259  * \param buflen_words Size of incoming buffer, in number of words
260  */
261 errval_t proc_mgmt_client_lmp_accept(struct proc_mgmt_lmp_binding *lmpb,
262                                      struct waitset *ws,
263                                      size_t lmp_buflen_words)
264 {
265     errval_t err = init_lmp_binding(lmpb, ws, lmp_buflen_words);
266     if (err_is_fail(err)) {
267         return err;
268     }
269
270     lmpb->chan.connstate = LMP_MONITOR_ACCEPT;  // TODO(razvan): LMP_PROC_MGMT_ACCEPT?
271     lmpb->chan.remote_cap = NULL_CAP; // will be sent to us by the client
272
273     /* Register for receive notification on our special handler */
274     struct event_closure receive_handler = {
275         .handler = proc_mgmt_accept_recv_handler,
276         .arg = lmpb,
277     };
278     err = lmp_chan_register_recv(&lmpb->chan, ws, receive_handler);
279     if (err_is_fail(err)) {
280         return err;  // TODO(razvan): cleanup?
281     }
282
283     return SYS_ERR_OK;
284 }
285
286
287 /**
288  * \brief Initiate a new LMP binding to the process manager
289  *
290  * To be used by the monitor for setting up the privileged channel used for
291  * spawnd discovery.
292  * Requires an explicit remote endpoint cap allocated by the process manager.
293  *
294  * \param lmpb         Storage for binding state
295  * \param ep           Remote endpoint of the process manager
296  * \param ws           Waitset for handling incoming messages
297  * \param cont         Continuation for when binding completes or fails
298  * \param st           State passed to continuation function
299  * \param buflen_words Size of incoming buffer, in number of words
300  */
301 errval_t proc_mgmt_client_lmp_bind(struct proc_mgmt_lmp_binding *lmpb,
302                                    struct capref ep,
303                                    proc_mgmt_bind_continuation_fn *cont,
304                                    void *st,
305                                    struct waitset *ws,
306                                    size_t lmp_buflen_words)
307 {
308     errval_t err = init_lmp_binding(lmpb, ws, lmp_buflen_words);
309     if (err_is_fail(err)) {
310         return err;
311     }
312
313     lmpb->chan.remote_cap = ep;
314
315     // Send the local endpoint cap to the process manager.
316     lmpb->chan.connstate = LMP_CONNECTED; /* pre-established */
317     err = lmp_chan_send0(&lmpb->chan, 0, lmpb->chan.local_cap);
318     if (err_is_fail(err)) {
319         // TODO(razvan): This, below.
320         /* XXX: I'm lazily assuming this can never fail with a transient error,
321          * since we only do it once at dispatcher startup. If not, we need to
322          * register and retry here */
323         assert(!lmp_err_is_transient(err));
324         return err;
325     }
326
327     /* Run the RX handler; has a side-effect of registering for receive events */
328     proc_mgmt_lmp_rx_handler(lmpb);
329
330     /* Run the continuation */
331     cont(st, SYS_ERR_OK, &lmpb->b);
332
333     return SYS_ERR_OK;
334 }
335
336 errval_t proc_mgmt_bind_client(void)
337 {
338     struct proc_mgmt_binding *b = get_proc_mgmt_binding();
339     if (b != NULL) {
340         return SYS_ERR_OK;
341     }
342
343     errval_t err;
344     iref_t iref;
345     // Try using nameserver to retrievew the proc mgmt iref.
346     err = nameservice_blocking_lookup("proc_mgmt", &iref);
347     if (err_is_fail(err)) {
348         return err;
349     }
350     
351     // Initiate bind.
352     struct proc_mgmt_bind_retst bindst = {
353         .present = false
354     };
355
356     err = proc_mgmt_bind(iref, proc_mgmt_bind_cont, &bindst,
357             get_default_waitset(), /*IDC_BIND_FLAG_RPC_CAP_TRANSFER*/IDC_BIND_FLAGS_DEFAULT);
358     if (err_is_fail(err)) {
359         USER_PANIC_ERR(err, "proc_mgmt_bind");
360     }
361
362     // Wait for bind completion.
363     while (!bindst.present) {
364         messages_wait_and_handle_next();
365     }
366
367     if (err_is_fail(bindst.err)) {
368         return bindst.err;
369     }
370
371     proc_mgmt_rpc_client_init(bindst.b);
372
373     set_proc_mgmt_binding(bindst.b);
374
375     return SYS_ERR_OK;
376 }
377
378 errval_t proc_mgmt_add_spawnd(iref_t iref, coreid_t core_id)
379 {
380     errval_t err = proc_mgmt_bind_client();
381     if (err_is_fail(err)) {
382         DEBUG_ERR(err, "proc_mgmt_bind_client");
383         return err;
384     }
385
386     struct proc_mgmt_binding *b = get_proc_mgmt_binding();
387     assert(b != NULL);
388
389     err = b->tx_vtbl.add_spawnd(b, NOP_CONT, core_id, iref);
390     if (err_is_fail(err)) {
391         DEBUG_ERR(err, "add_spawnd");
392     }
393
394     return err;
395 }
396
397 /**
398  * \brief Request the process manager to spawn a program on a specific core
399  *
400  * \param coreid          Core ID on which to spawn the program
401  * \param path            Absolute path in the file system to an executable
402  *                        image suitable for the given core
403  * \param argv            Command-line arguments, NULL-terminated
404  * \param envp            Optional environment, NULL-terminated
405  *                        (pass NULL to inherit)
406  * \param inheritcn_cap   Cap to a CNode containing capabilities to be inherited
407  * \param argcn_cap       Cap to a CNode containing capabilities passed as
408  *                        arguments
409  * \param flags           Flags to spawn
410  * \param ret_domain_cap  If non-NULL, filled in with domain cap of new domain
411  *
412  * \bug flags are currently ignored
413  */
414 errval_t spawn_program_with_caps(coreid_t core_id, const char *path,
415                                  char *const argv[],
416                                  char *const envp[],
417                                  struct capref inheritcn_cap,
418                                  struct capref argcn_cap,
419                                  uint8_t flags,
420                                  struct capref *ret_domain_cap)
421 {
422     errval_t err, msgerr;
423
424     // default to copying our environment
425     if (envp == NULL) {
426         envp = environ;
427     }
428
429     err = proc_mgmt_bind_client();
430     if (err_is_fail(err)) {
431         USER_PANIC_ERR(err, "proc_mgmt_bind_client");
432     }
433
434     struct proc_mgmt_binding *b = get_proc_mgmt_binding();
435     assert(b != NULL);
436
437     // construct argument "string"
438     // \0-separated strings in contiguous character buffer
439     // this is needed, as flounder can't send variable-length arrays of strings
440     size_t argstrlen = 0;
441
442     for (int i = 0; argv[i] != NULL; i++) {
443         argstrlen += strlen(argv[i]) + 1;
444     }
445
446     char argstr[argstrlen];
447     size_t argstrpos = 0;
448     for (int i = 0; argv[i] != NULL; i++) {
449         strcpy(&argstr[argstrpos], argv[i]);
450         argstrpos += strlen(argv[i]);
451         argstr[argstrpos++] = '\0';
452     }
453     assert(argstrpos == argstrlen);
454
455     // repeat for environment
456     size_t envstrlen = 0;
457     for (int i = 0; envp[i] != NULL; i++) {
458         envstrlen += strlen(envp[i]) + 1;
459     }
460
461     char envstr[envstrlen];
462     size_t envstrpos = 0;
463     for (int i = 0; envp[i] != NULL; i++) {
464         strcpy(&envstr[envstrpos], envp[i]);
465         envstrpos += strlen(envp[i]);
466         envstr[envstrpos++] = '\0';
467     }
468     assert(envstrpos == envstrlen);
469
470     // make an unqualified path absolute using the $PATH variable
471     // TODO: implement search (currently assumes PATH is a single directory)
472     char *searchpath = getenv("PATH");
473     if (searchpath == NULL) {
474         searchpath = VFS_PATH_SEP_STR; // XXX: just put it in the root
475     }
476     size_t buflen = strlen(path) + strlen(searchpath) + 2;
477     char pathbuf[buflen];
478     if (path[0] != VFS_PATH_SEP) {
479         snprintf(pathbuf, buflen, "%s%c%s", searchpath, VFS_PATH_SEP, path);
480         pathbuf[buflen - 1] = '\0';
481         //vfs_path_normalise(pathbuf);
482         path = pathbuf;
483     }
484
485     struct capref domain_cap;
486     err = slot_alloc(&domain_cap);
487     if (err_is_fail(err)) {
488         return err;
489     }
490
491     if (capref_is_null(inheritcn_cap) && capref_is_null(argcn_cap)) {
492         err = b->rpc_tx_vtbl.spawn(b, core_id, path, argstr, argstrlen, envstr,
493                                    envstrlen, flags, &msgerr, &domain_cap);
494     } else {
495         err = b->rpc_tx_vtbl.spawn_with_caps(b, core_id, path, argstr,
496                                              argstrlen, envstr, envstrlen,
497                                              inheritcn_cap, argcn_cap, flags,
498                                              &msgerr, &domain_cap);
499     }
500     if (err_is_fail(err)) {
501         USER_PANIC_ERR(err, "error sending spawn request to process manager");
502     } else if (err_is_fail(msgerr)) {
503         goto out;
504     }
505
506     if (ret_domain_cap != NULL) {
507         *ret_domain_cap = domain_cap;
508     }
509
510 out:
511     return msgerr;
512     
513 }
514
515 /**
516  * \brief Request the process manager to spawn a program on a specific core
517  *
518  * \param coreid          Core ID on which to spawn the program
519  * \param path            Absolute path in the file system to an executable
520  *                        image suitable for the given core
521  * \param argv            Command-line arguments, NULL-terminated
522  * \param envp            Optional environment, NULL-terminated
523  *                        (pass NULL to inherit)
524  * \param inheritcn_cap   Cap to a CNode containing capabilities to be inherited
525  * \param argcn_cap       Cap to a CNode containing capabilities passed as
526  *                        arguments
527  * \param flags           Flags to spawn
528  * \param ret_domain_cap  If non-NULL, filled in with domain cap of new domain
529  *
530  * \bug flags are currently ignored
531  */
532 errval_t spawn_program(coreid_t core_id, const char *path,
533                        char *const argv[], char *const envp[],
534                        uint8_t flags, struct capref *ret_domain_cap)
535 {
536     return spawn_program_with_caps(core_id, path, argv, envp,
537                                    NULL_CAP, NULL_CAP, flags,
538                                    ret_domain_cap);
539 }
540
541 errval_t spawn_arrakis_program(coreid_t coreid, const char *path,
542                                char *const argv[], char *const envp[],
543                                struct capref inheritcn_cap,
544                                struct capref argcn_cap, spawn_flags_t flags,
545                                domainid_t *ret_domainid)
546 {
547     struct arrakis_binding *cl;
548     errval_t err, msgerr;
549
550     // default to copying our environment
551     if (envp == NULL) {
552         envp = environ;
553     }
554
555     // do we have a arrakis client connection for this core?
556     assert(coreid < MAX_CPUS);
557     cl = get_arrakis_binding(coreid);
558     if (cl == NULL) {
559         char namebuf[16];
560         snprintf(namebuf, sizeof(namebuf), "arrakis.%u", coreid);
561         namebuf[sizeof(namebuf) - 1] = '\0';
562
563         iref_t iref;
564         err = nameservice_blocking_lookup(namebuf, &iref);
565         if (err_is_fail(err)) {
566             //DEBUG_ERR(err, "arrakis daemon on core %u not found\n", coreid);
567             return err;
568         }
569
570         // initiate bind
571         struct arrakis_bind_retst bindst = { .present = false };
572         err = arrakis_bind(iref, arrakis_bind_cont, &bindst, get_default_waitset(),
573                            IDC_BIND_FLAGS_DEFAULT);
574         if (err_is_fail(err)) {
575             USER_PANIC_ERR(err, "arrakis_bind failed");
576         }
577
578         // XXX: block for bind completion
579         while (!bindst.present) {
580             messages_wait_and_handle_next();
581         }
582
583         if(err_is_fail(bindst.err)) {
584             USER_PANIC_ERR(bindst.err, "asynchronous error during arrakis_bind");
585         }
586         assert(bindst.b != NULL);
587
588         arrakis_rpc_client_init(bindst.b);
589         set_arrakis_binding(coreid, bindst.b);
590     }
591
592     // construct argument "string"
593     // \0-separated strings in contiguous character buffer
594     // this is needed, as flounder can't send variable-length arrays of strings
595     size_t argstrlen = 0;
596     for (int i = 0; argv[i] != NULL; i++) {
597         argstrlen += strlen(argv[i]) + 1;
598     }
599
600     char argstr[argstrlen];
601     size_t argstrpos = 0;
602     for (int i = 0; argv[i] != NULL; i++) {
603         strcpy(&argstr[argstrpos], argv[i]);
604         argstrpos += strlen(argv[i]);
605         argstr[argstrpos++] = '\0';
606     }
607     assert(argstrpos == argstrlen);
608
609     // repeat for environment
610     size_t envstrlen = 0;
611     for (int i = 0; envp[i] != NULL; i++) {
612         envstrlen += strlen(envp[i]) + 1;
613     }
614
615     char envstr[envstrlen];
616     size_t envstrpos = 0;
617     for (int i = 0; envp[i] != NULL; i++) {
618         strcpy(&envstr[envstrpos], envp[i]);
619         envstrpos += strlen(envp[i]);
620         envstr[envstrpos++] = '\0';
621     }
622     assert(envstrpos == envstrlen);
623
624
625     domainid_t domain_id;
626
627     // make an unqualified path absolute using the $PATH variable
628     // TODO: implement search (currently assumes PATH is a single directory)
629     char *searchpath = getenv("PATH");
630     if (searchpath == NULL) {
631         searchpath = VFS_PATH_SEP_STR; // XXX: just put it in the root
632     }
633     size_t buflen = strlen(path) + strlen(searchpath) + 2;
634     char pathbuf[buflen];
635     if (path[0] != VFS_PATH_SEP) {
636         snprintf(pathbuf, buflen, "%s%c%s", searchpath, VFS_PATH_SEP, path);
637         pathbuf[buflen - 1] = '\0';
638         //vfs_path_normalise(pathbuf);
639         path = pathbuf;
640     }
641
642     err = cl->rpc_tx_vtbl.spawn_arrakis_domain(cl, path, argstr, argstrlen,
643                                         envstr, envstrlen, &msgerr, &domain_id);
644     if (err_is_fail(err)) {
645         USER_PANIC_ERR(err, "error sending arrakis request");
646     } else if (err_is_fail(msgerr)) {
647         return msgerr;
648     }
649
650     if (ret_domainid != NULL) {
651         *ret_domainid = domain_id;
652     }
653
654     return msgerr;
655 }
656
657 /**
658  * \brief Request a program be spawned on all cores in the system
659  *
660  * \param same_core Iff false, don't spawn on the same core as the caller
661  * \param path   Absolute path in the file system to an executable image
662  *                        suitable for the given core
663  * \param argv   Command-line arguments, NULL-terminated
664  * \param envp   Optional environment, NULL-terminated (pass NULL to inherit)
665  * \param flags  Flags to spawn
666  * \param ret_domainid If non-NULL, filled in with domain ID of program
667  * \param count How much programs it spawned
668  *
669  * \note This function is for legacy compatibility with existing benchmark/test
670  *    code, and SHOULD NOT BE USED IN NEW CODE UNLESS YOU HAVE A GOOD REASON!
671  *    It doesn't make much sense from a scalability perspective, and is
672  *    probably useless on a heterogeneous system.
673  */
674 errval_t spawn_program_on_all_cores(bool same_core, const char *path,
675                                     char *const argv[], char *const envp[],
676                                     spawn_flags_t flags, struct capref *ret_domain_cap,
677                                     coreid_t* spawn_count)
678 {
679     // TODO: handle flags, domain ID
680     errval_t err = SYS_ERR_OK;
681
682     struct octopus_binding *r = get_octopus_binding();
683     if (r == NULL) {
684         return LIB_ERR_NAMESERVICE_NOT_BOUND;
685     }
686
687     // FIXME: world's most (kinda less now) broken implementation...
688     char** names = NULL;
689     size_t count = 0;
690
691     static char* spawnds = "r'spawn.[0-9]+' { iref: _ }";
692     struct octopus_get_names_response__rx_args reply;
693     err = r->rpc_tx_vtbl.get_names(r, spawnds, NOP_TRIGGER, reply.output, &reply.tid,
694                             &reply.error_code);
695     if (err_is_fail(err) || err_is_fail(reply.error_code)) {
696         err = err_push(err, SPAWN_ERR_FIND_SPAWNDS);
697         goto out;
698     }
699
700     err = oct_parse_names(reply.output, &names, &count);
701     if (err_is_fail(err)) {
702         goto out;
703     }
704
705     for (size_t c = 0; c < count; c++) {
706         coreid_t coreid;
707         int ret = sscanf(names[c], "spawn.%hhu", &coreid);
708         if (ret != 1) {
709             err = SPAWN_ERR_MALFORMED_SPAWND_RECORD;
710             goto out;
711         }
712
713         if (!same_core && coreid == disp_get_core_id()) {
714             continue;
715         }
716
717         err = spawn_program(c, path, argv, envp, flags, NULL);
718         if (err_is_ok(err) && spawn_count != NULL) {
719             *spawn_count += 1;
720         }
721
722         if (err_is_fail(err)) {
723             DEBUG_ERR(err, "error spawning %s on core %u\n", path, c);
724             goto out;
725         }
726     }
727
728 out:
729     oct_free_names(names, count);
730     return err;
731 }
732
733 errval_t spawn_binding(coreid_t coreid, struct spawn_binding **ret_client)
734 {
735     errval_t err = bind_client(coreid);
736     if (err_is_fail(err)) {
737         return err;
738     }
739
740     *ret_client = get_spawn_binding(coreid);
741     return SYS_ERR_OK;
742 }
743
744 /**
745  * \brief Request the process manager to span onto a new core.
746  *
747  * \param core_id ID of core to span onto.
748  *
749  * Blocks until the new dispatcher has established an interdispatcher connection
750  * to the current one.
751  */
752 errval_t spawn_span(coreid_t core_id)
753 {
754     coreid_t my_core_id = disp_get_core_id();
755     assert (core_id != my_core_id);
756
757     errval_t err, msgerr;
758     err = proc_mgmt_bind_client();
759     if (err_is_fail(err)) {
760         USER_PANIC_ERR(err, "proc_mgmt_bind_client");
761     }
762     
763     struct span_domain_state *st;
764     err = domain_new_dispatcher_setup_only(core_id, &st);
765     if (err_is_fail(err)) {
766         USER_PANIC_ERR(err, "failed to setup new dispatcher");
767     }
768
769     struct proc_mgmt_binding *b = get_proc_mgmt_binding();
770     assert(b != NULL);
771
772     err = b->rpc_tx_vtbl.span(b, cap_domainid, core_id, st->vroot, st->frame,
773                               &msgerr);
774     if (err_is_fail(err)) {
775         USER_PANIC_ERR(err, "error sending span request to process manager");
776     }
777
778     if (err_is_fail(msgerr)) {
779         return msgerr;
780     }
781
782     while(!st->initialized) {
783         event_dispatch(get_default_waitset());
784     }
785     free(st);
786
787     return SYS_ERR_OK;
788 }
789
790 /**
791  * \brief Request the process manager to kill a domain
792  *
793  * \param domain_cap Domain ID cap for the victim
794  */
795 errval_t spawn_kill(struct capref domain_cap)
796 {
797     errval_t err, msgerr;
798     err = proc_mgmt_bind_client();
799     if (err_is_fail(err)) {
800         USER_PANIC_ERR(err, "proc_mgmt_bind_client");
801     }
802
803     struct proc_mgmt_binding *b = get_proc_mgmt_binding();
804     assert(b != NULL);
805
806     err = b->rpc_tx_vtbl.kill(b, domain_cap, &msgerr);
807     if (err_is_fail(err)) {
808         USER_PANIC_ERR(err, "error sending kill request to process manager");
809     }
810
811     return msgerr;
812 }
813
814 /**
815  * \brief Inform the process manager about exiting execution.
816  */
817 errval_t spawn_exit(uint8_t status)
818 {
819     errval_t err = proc_mgmt_bind_client();
820     if (err_is_fail(err)) {
821         return err;
822     }
823
824     struct proc_mgmt_binding *b = get_proc_mgmt_binding();
825     assert(b != NULL);
826
827     err = b->rpc_tx_vtbl.exit(b, cap_domainid, status);
828     if (err_is_fail(err)) {
829         return err;
830     }
831
832     return SYS_ERR_OK;
833 }
834
835 /**
836  * \brief Wait for spawned proccess to exit on core.
837  */
838 errval_t spawn_wait_coreid(coreid_t coreid, struct capref domain_cap,
839                            uint8_t *exitcode, bool nohang)
840 {
841     return spawn_wait_core(disp_get_core_id(), domain_cap, exitcode, nohang);
842 }
843
844
845 /**
846  * \brief Wait for the termination of a domain on a remote core.
847  */
848 errval_t spawn_wait_core(coreid_t coreid, struct capref domain_cap,
849                          uint8_t *exitcode, bool nohang)
850 {
851     return spawn_wait(domain_cap, exitcode, nohang);
852 }
853
854
855 /**
856  * \brief Wait for spawned proccess to exit on current core.
857  */
858 errval_t spawn_wait(struct capref domain_cap, uint8_t *status, bool nohang)
859 {
860     errval_t err, msgerr;
861     err = proc_mgmt_bind_client();
862     if (err_is_fail(err)) {
863         return err;
864     }
865
866     struct proc_mgmt_binding *b = get_proc_mgmt_binding();
867     assert(b != NULL);
868
869     err = b->rpc_tx_vtbl.wait(b, domain_cap, nohang, &msgerr, status);
870     if (err_is_fail(err)) {
871         USER_PANIC_ERR(err, "error sending wait request to process manager");
872     }
873
874     return msgerr;
875 }
876
877 errval_t spawn_wait_compat(uint8_t domainid,
878                            uint8_t *exitcode, bool nohang)
879 {
880     errval_t err, reterr;
881
882     err = bind_client(disp_get_core_id());
883     if (err_is_fail(err)) {
884         return err;
885     }
886     struct spawn_binding *cl = get_spawn_binding(disp_get_core_id());
887     assert(cl != NULL);
888
889     err = cl->rpc_tx_vtbl.wait(cl, domainid, nohang, exitcode, &reterr);
890     if (err_is_fail(err)) {
891         return err;
892     }
893
894     return reterr;
895 }
896
897 /**
898  * \brief Get the list of domains for ps like implementation
899  */
900 errval_t spawn_get_domain_list(uint8_t **domains, size_t *len)
901 {
902     errval_t err;
903     err = proc_mgmt_bind_client();
904     if (err_is_fail(err)) {
905         return err;
906     }
907
908     struct proc_mgmt_binding *b = get_proc_mgmt_binding();
909     assert(b != NULL);
910
911     struct proc_mgmt_get_domainlist_response__rx_args reply;
912     err = b->rpc_tx_vtbl.get_domainlist(b, reply.domains, len);
913     if (err_is_fail(err)) {
914         USER_PANIC_ERR(err, "get_domainlist");
915     }
916
917     *domains = memdup(reply.domains, *len);
918     return SYS_ERR_OK;
919 }
920
921 /**
922  * \brief Get the status of a domain for ps like implementation
923  */
924 errval_t spawn_get_status(domainid_t domain_id, struct spawn_ps_entry *pse,
925                           char **argbuf, size_t *arglen, errval_t *reterr)
926 {
927     /*
928     errval_t err;
929
930     struct spawn_binding *cl;
931     err = spawn_binding(disp_get_core_id(), &cl);
932     if (err_is_fail(err)) {
933         USER_PANIC_ERR(err, "spawn_binding");
934     }
935     assert(cl != NULL);
936
937     struct spawn_status_response__rx_args reply;
938     err = cl->rpc_tx_vtbl.status(cl, domain, (spawn_ps_entry_t *)pse, reply.argv,
939                           arglen, reterr);
940     if (err_is_fail(err)) {
941         USER_PANIC_ERR(err, "status");
942     }
943
944     *argbuf = memdup(reply.argv, *arglen);
945     
946 */
947     return SYS_ERR_OK;
948 }
949
950 /**
951  * \brief Dump capabilities for a given domain
952  */
953 errval_t spawn_dump_capabilities_compat(domainid_t domainid)
954 {
955     errval_t err, reterr;
956
957     err = bind_client(disp_get_core_id());
958     if (err_is_fail(err)) {
959         return err;
960     }
961     struct spawn_binding *cl = get_spawn_binding(disp_get_core_id());
962     assert(cl != NULL);
963
964     err = cl->rpc_tx_vtbl.dump_capabilities(cl, domainid, &reterr);
965     if (err_is_fail(err)) {
966         return err;
967     }
968
969     return reterr;
970 }
971
972 /**
973  * \brief Utility function to create an inherit cnode
974  * and copy caps into it.
975  *
976  * \param inheritcn_capp Pointer to capref, filled-in with location of inheritcn
977  *                       capability.
978  * \param fdcap          fdcap to copy into inherit cnode.
979  * \param sidcap         sidcap to copy into inherit cnode.
980  * \param kernelcap      kernelcap to copy into inherit cnode.
981  *
982  * \retval SYS_ERR_OK inherticn_capp is allocated and contains copies of the
983  * provided caps.
984  */
985 errval_t alloc_inheritcn_with_caps(struct capref *inheritcn_capp,
986                                    struct capref fdcap,
987                                    struct capref sidcap,
988                                    struct capref kernelcap)
989 {
990     errval_t err;
991
992     // construct inherit CNode
993     struct cnoderef inheritcn;
994     err = cnode_create_l2(inheritcn_capp, &inheritcn);
995     if (err_is_fail(err)) {
996         return err;
997     }
998
999     if (!capref_is_null(fdcap)) {
1000         // copy fdcap to inherit Cnode
1001         struct capref dest = {
1002             .cnode = inheritcn,
1003             .slot  = INHERITCN_SLOT_FDSPAGE
1004         };
1005         err = cap_copy(dest, fdcap);
1006         if (err_is_fail(err)) {
1007             return err;
1008         }
1009     }
1010
1011     if (!capref_is_null(sidcap)) {
1012         // copy fdcap to inherit Cnode
1013         struct capref dest = {
1014             .cnode = inheritcn,
1015             .slot  = INHERITCN_SLOT_SESSIONID
1016         };
1017         err = cap_copy(dest, sidcap);
1018         if (err_is_fail(err)) {
1019             return err;
1020         }
1021     }
1022
1023     if (!capref_is_null(kernelcap)) {
1024         // copy fdcap to inherit Cnode
1025         struct capref dest = {
1026             .cnode = inheritcn,
1027             .slot  = INHERITCN_SLOT_KERNELCAP
1028         };
1029         err = cap_copy(dest, kernelcap);
1030         if (err_is_fail(err)) {
1031             return err;
1032         }
1033     }
1034
1035     return SYS_ERR_OK;
1036 }