1/**
2 * \file
3 * \brief startd spawn functions
4 */
5
6/*
7 * Copyright (c) 2010-2011, 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, Universitaetstrasse 6, CH-8092 Zurich. Attn: Systems Group.
13 */
14
15#define _USE_XOPEN /* for strdup() in string.h */
16#include <string.h>
17#include <stdio.h>
18
19
20#include <barrelfish/barrelfish.h>
21
22#include <barrelfish/spawn_client.h>
23#include <spawndomain/spawndomain.h>
24#include <dist/barrier.h>
25
26#include "internal.h"
27
28extern char **environ;
29
30static const char *get_shortname(const char *start, const char *nameend,
31                                 size_t *namelen)
32{
33
34    // find the short name by searching back for the last / before the args
35    const char *shortname = nameend;
36    while (shortname >= start && *shortname != '/') {
37        shortname--;
38    }
39    if (shortname != start) {
40        shortname++;
41    }
42
43    // where's the end of the basename? (ie. ignoring beehive's | suffix)
44    const char *basenameend = memchr(shortname, '|', nameend - shortname);
45    if (basenameend == NULL) {
46        basenameend = nameend;
47    }
48
49    *namelen = basenameend - shortname;
50    return shortname;
51}
52
53static void set_local_bindings(void)
54{
55    ram_alloc_set(NULL);
56}
57
58
59struct spawn_info {
60    int argc;
61    char *argv[MAX_CMDLINE_ARGS + 1];
62    char *name;
63    char *shortname;
64    size_t shortnamelen;
65    char *cmdargs;
66};
67
68
69/*
70   read the next line of the bootmodule, and return info about what to
71   spawn in *si
72   return:
73   1: line read succesfully
74   0: end of file reached
75   -1: error
76*/
77static int prepare_spawn(size_t *bmpos, struct spawn_info *si)
78{
79    assert(bmpos != NULL);
80    assert(si != NULL);
81
82    const char *bootmodules = gbootmodules;
83
84    // find the start/end of the next line
85    const char *start = &bootmodules[*bmpos];
86    const char *end = strchr(start, '\n');
87    if (end == NULL) {
88        return 0;
89    } else {
90        *bmpos = end - bootmodules + 1;
91    }
92
93    // ignore arguments for name comparison
94    const char *args = memchr(start, ' ', end - start);
95
96    // where's the end of the full name?
97    const char *nameend = args == NULL ? end : args;
98
99    si->shortname = (char *)get_shortname(start, nameend, &si->shortnamelen);
100
101    si->cmdargs = malloc(end - si->shortname + 1);
102    if (si->cmdargs == NULL) {
103        return -1;
104    }
105    si->name = malloc(nameend - start + 1);
106    if (si->name == NULL) {
107        free(si->cmdargs);
108        return -1;
109    }
110
111    /* Get the command line arguments of the domain: args plus shortname */
112    memcpy(si->cmdargs, si->shortname, end - si->shortname);
113    si->cmdargs[end - si->shortname] = '\0';
114    si->argc = spawn_tokenize_cmdargs(si->cmdargs, si->argv,
115                                      ARRAY_LENGTH(si->argv));
116    if (si->argc >= MAX_CMDLINE_ARGS) {
117        free(si->cmdargs);
118        free(si->name);
119        return -1;
120    }
121
122    /* grab a copy of the full name as a separate string */
123    memcpy(si->name, start, nameend - start);
124    si->name[nameend - start] = '\0';
125
126    return 1;
127}
128
129
130void spawn_dist_domains(void)
131{
132    struct spawn_info si;
133    size_t bmpos = 0;
134    errval_t err;
135    int r;
136
137    coreid_t my_coreid = disp_get_core_id();
138
139    while (true) {
140
141        r = prepare_spawn(&bmpos, &si);
142        if (r == 0) {
143            return;
144        } else if (r == -1) {
145            DEBUG_ERR(STARTD_ERR_BOOTMODULES,
146                      "failed to read bootmodules entry");
147        }
148
149        /* Only spawn special dist-serv modules */
150        if (si.argc >= 2 && strcmp(si.argv[1], "dist-serv") == 0) {
151
152            coreid_t coreid;
153            int extra_args;
154
155            // get core id
156            if (si.argc >= 3 && strncmp(si.argv[2], "core=", 5) == 0) {
157
158                char *p = strchr(si.argv[2], '=');
159                assert(p != NULL);
160                coreid = strtol(p + 1, NULL, 10);
161                extra_args = 2;
162
163            } else {
164                coreid = my_coreid;
165                extra_args = 1;
166            }
167
168            // discard 'dist-serv' and 'core=x' argument
169            for (int i = 1; i <= si.argc - extra_args; i++) {
170                si.argv[i] = si.argv[i+extra_args];
171            }
172            si.argc--;
173
174            debug_printf("starting dist-serv %s on core %d\n", si.name, coreid);
175
176            struct capref new_domain;
177            err = spawn_program(coreid, si.name, si.argv, environ,
178                                0, &new_domain);
179            if (err_is_fail(err)) {
180                DEBUG_ERR(err, "spawn of %s failed", si.name);
181                continue;
182            }
183
184            char c = si.shortname[si.shortnamelen];
185            si.shortname[si.shortnamelen] = '\0';
186
187            // wait until fully started
188            err = nsb_wait_ready(si.shortname);
189            if (err_is_fail(err)) {
190                DEBUG_ERR(err, "nsb_wait_ready on %s failed", si.shortname);
191            }
192
193            si.shortname[si.shortnamelen] = c;
194
195            // HACK:  make sure we use the local versions of a service if
196            // it was started. Really there needs to be a mechanism for that
197            // service to signal us and others to do this once it has started
198            // up.
199            set_local_bindings();
200        }
201
202        free(si.cmdargs);
203        free(si.name);
204    }
205}
206
207void spawn_arrakis_domains(void)
208{
209    struct spawn_info si;
210    size_t bmpos = 0;
211    errval_t err;
212    int r;
213
214    coreid_t my_coreid = disp_get_core_id();
215
216    while (true) {
217
218        r = prepare_spawn(&bmpos, &si);
219        if (r == 0) {
220            return;
221        } else if (r == -1) {
222            DEBUG_ERR(STARTD_ERR_BOOTMODULES,
223                      "failed to read bootmodules entry");
224        }
225
226        /* Only spawn special arrakis modules */
227        if (si.argc >= 2 && strcmp(si.argv[1], "arrakis") == 0) {
228
229            coreid_t coreid;
230            int extra_args;
231
232            // get core id
233            if (si.argc >= 3 && strncmp(si.argv[2], "core=", 5) == 0) {
234
235                char *p = strchr(si.argv[2], '=');
236                assert(p != NULL);
237                coreid = strtol(p + 1, NULL, 10);
238                extra_args = 2;
239
240            } else {
241                coreid = my_coreid;
242                extra_args = 1;
243            }
244
245            // discard 'dist-serv' and 'core=x' argument
246            for (int i = 1; i <= si.argc - extra_args; i++) {
247                si.argv[i] = si.argv[i+extra_args];
248            }
249            si.argc--;
250
251            debug_printf("starting arrakis domain %s on core %d\n", si.name, coreid);
252
253            domainid_t new_domain;
254            err = spawn_arrakis_program(coreid, si.name, si.argv, environ,
255					NULL_CAP, NULL_CAP, 0, &new_domain);
256            if (err_is_fail(err)) {
257                DEBUG_ERR(err, "spawn of %s failed", si.name);
258                continue;
259            }
260        }
261
262        free(si.cmdargs);
263        free(si.name);
264    }
265}
266
267void spawn_app_domains(void)
268{
269    struct spawn_info si;
270    size_t bmpos = 0;
271    errval_t err;
272    int r;
273
274    coreid_t my_coreid = disp_get_core_id();
275
276    while (true) {
277
278        bool spawn_here = true;
279
280        r = prepare_spawn(&bmpos, &si);
281        if (r == 0) {
282            return;
283        } else if (r == -1) {
284            DEBUG_ERR(STARTD_ERR_BOOTMODULES,
285                      "failed to read bootmodules entry");
286        }
287
288        /* Do not spawn special domains */
289        if (strncmp(si.shortname, "init", si.shortnamelen) == 0
290            || strncmp(si.shortname, "cpu", si.shortnamelen) == 0
291                // Adding following condition for cases like "cpu_omap44xx"
292            || strncmp(si.shortname, "cpu", strlen("cpu")) == 0
293            || strncmp(si.shortname, "boot_", strlen("boot_")) == 0
294            || strncmp(si.shortname, "monitor", si.shortnamelen) == 0
295            || strncmp(si.shortname, "mem_serv", si.shortnamelen) == 0
296#ifdef __k1om__
297            || strncmp(si.shortname, "corectrl", si.shortnamelen) == 0
298#endif
299        ) {
300            spawn_here = false;
301        }
302
303        /* Do not spawn special boot modules, dist-serv modules
304           or nospawn modules */
305        if (si.argc >= 2 && (strcmp(si.argv[1], "boot") == 0
306                          || strcmp(si.argv[1], "dist-serv") == 0
307                          || strcmp(si.argv[1], "nospawn") == 0
308                          || strcmp(si.argv[1], "arrakis") == 0
309                          || strcmp(si.argv[1], "auto") == 0)) {
310            spawn_here = false;
311        }
312
313        if (spawn_here) {
314
315            coreid_t coreid;
316
317            uint8_t spawn_flags = 0;
318            uint8_t has_spawn_flags = 0;
319            uint8_t has_core = 0;
320            char *core_ptr = NULL;
321
322            for(int i = 1; i < si.argc && i < 3; ++i) {
323            	if(strncmp(si.argv[i], "spawnflags=", 11) == 0) {
324            	    char *p = strchr(si.argv[i], '=') + 1;
325            	    spawn_flags = (uint8_t)strtol(p, (char **)&p, 10);
326            	    has_spawn_flags = 1;
327            	} else if (strncmp(si.argv[i], "core=", 5)== 0) {
328            	    core_ptr = strchr(si.argv[i], '=') + 1;
329            	    has_core = 1;
330            	} else {
331            		/* ignore */
332            	}
333            }
334
335            if (has_core || has_spawn_flags) {
336                for (int i = 1; i < si.argc; i++) {
337                    if (has_spawn_flags && has_core) {
338                        si.argv[i] = si.argv[i+2];
339                    } else {
340                        si.argv[i] = si.argv[i+1];
341                    }
342                }
343            }
344
345            si.argc -= (has_core + has_spawn_flags);
346
347            if (has_core) {
348                while(*core_ptr != '\0') {
349                    int id_from = strtol(core_ptr, (char **)&core_ptr, 10);
350                    int id_to = id_from;
351                    if(*core_ptr == '-') {
352                        core_ptr++;
353                        id_to = strtol(core_ptr, (char **)&core_ptr, 10);
354                    }
355                    assert(*core_ptr == ',' || *core_ptr == '\0');
356                    if(*core_ptr != '\0') {
357                        core_ptr++;
358                    }
359
360                    /* coreid = strtol(p + 1, NULL, 10); */
361                    // discard 'core=x' argument
362                    for(int i = id_from; i <= id_to; i++) {
363                        debug_printf("starting app %s on core %d\n",
364                                     si.name, i);
365
366                        struct capref ret_domain_cap;
367                        err = spawn_program(i, si.name, si.argv, environ,
368                                            spawn_flags, &ret_domain_cap);
369                        if (err_is_fail(err)) {
370                            DEBUG_ERR(err, "spawn of %s failed", si.name);
371                        }
372                    }
373                }
374
375            } else {
376                coreid = my_coreid;
377
378                debug_printf("starting app %s on core %d\n", si.name, coreid);
379
380                struct capref ret_domain_cap;
381                err = spawn_program(coreid, si.name, si.argv, environ,
382                                    spawn_flags, &ret_domain_cap);
383                if (err_is_fail(err)) {
384                    DEBUG_ERR(err, "spawn of %s failed", si.name);
385                }
386            }
387        }
388
389        free(si.cmdargs);
390        free(si.name);
391    }
392
393}
394
395void spawn_bootscript_domains(void)
396{
397    errval_t err;
398    coreid_t my_coreid = disp_get_core_id();
399    char *argv[256], *name;
400
401    // open bootmodules file and read it in
402    FILE *f = fopen("/bootscript", "r");
403    if(f == NULL) {
404        printf("No bootscript\n");
405        return;
406    }
407    char line[1024];
408    while(fgets(line, 1024, f) != NULL) {
409        int argc;
410
411        // ignore comments (#) and empty lines
412        if (line[0] == '#' || line[0] == '\n') {
413            continue;
414        }
415
416        argv[0] = strtok(line, " \n");
417        name = argv[0];
418        for(argc = 1;; argc++) {
419            argv[argc] = strtok(NULL, " \n");
420            if(argv[argc] == NULL) {
421                break;
422            }
423        }
424
425        // get core id
426        if (argc >= 2 && strncmp(argv[1], "core=", 5) == 0) {
427            char *p = strchr(argv[1], '=');
428            assert(p != NULL);
429
430            p++;
431            while(*p != '\0') {
432                int id_from = strtol(p, (char **)&p, 10), id_to = id_from;
433                if(*p == '-') {
434                    p++;
435                    id_to = strtol(p, (char **)&p, 10);
436                }
437                assert(*p == ',' || *p == '\0');
438                if(*p != '\0') {
439                    p++;
440                }
441
442                /* coreid = strtol(p + 1, NULL, 10); */
443                // discard 'core=x' argument
444                for (int i = 1; i < argc; i++) {
445                    argv[i] = argv[i+1];
446                }
447                argc--;
448
449                for(int i = id_from; i <= id_to; i++) {
450                    debug_printf("starting app %s on core %d\n", name, i);
451
452                    struct capref new_domain;
453                    err = spawn_program(i, name, argv, environ,
454                                        0, &new_domain);
455                    if (err_is_fail(err)) {
456                        DEBUG_ERR(err, "spawn of %s failed", name);
457                    }
458                }
459            }
460        } else {
461            debug_printf("starting app %s on core %d\n", name, my_coreid);
462
463            struct capref new_domain;
464            err = spawn_program(my_coreid, name, argv, environ,
465                                0, &new_domain);
466            if (err_is_fail(err)) {
467                DEBUG_ERR(err, "spawn of %s failed", name);
468            }
469        }
470    }
471
472    fclose(f);
473}
474