1/**
2 * \file
3 * \brief Startup daemon for Barrelfish.
4 * At boot, after spawnd has started, startd decides which domains to spawn.
5 * There are two phases to service startup.
6 * 1) startup distributed services.  This proceeds in lockstep, with
7 *    each service being fully started before the next is started.
8 * 2) startup applications. After all distributed services are started then
9 *    the applications are started.  Here the startd does not wait for a
10 *    previous domain to be started before continuing with the next one.
11 */
12
13/*
14 * Copyright (c) 2010-2012, ETH Zurich.
15 * All rights reserved.
16 *
17 * This file is distributed under the terms in the attached LICENSE file.
18 * If you do not find this file, copies can be found by writing to:
19 * ETH Zurich D-INFK, Universitaetstrasse 6, CH-8092 Zurich. Attn: Systems Group.
20 */
21
22#include <stdio.h>
23#include <string.h>
24
25#include <barrelfish/barrelfish.h>
26#include <barrelfish/nameservice_client.h>
27#include <barrelfish_kpi/cpu.h> // for cpu_type_to_archstr()
28#include <barrelfish/cpu_arch.h> // for CURRENT_CPU_TYPE
29
30#include <vfs/vfs.h>
31
32#include <dist/barrier.h>
33
34#include "internal.h"
35
36#define ALL_SPAWNDS_UP "all_spawnds_up" // this comes from spawnd/internal.h
37
38coreid_t my_core_id;
39bool is_bsp_core;
40const char *gbootmodules;
41
42/* set an initial default environment for our boot-time children */
43static void init_environ(void)
44{
45    int r;
46
47    char pathstr[64];
48    snprintf(pathstr, sizeof(pathstr), "/" BF_BINARY_PREFIX "%s/sbin",
49             cpu_type_to_archstr(CURRENT_CPU_TYPE));
50    pathstr[sizeof(pathstr) - 1] = '\0';
51    r = setenv("PATH", pathstr, 0);
52    if (r != 0) {
53        USER_PANIC("failed to set PATH");
54    }
55
56    /* HOME=/ */
57    r = setenv("HOME", "/", 0);
58    if (r != 0) {
59        USER_PANIC("failed to set HOME");
60    }
61}
62
63
64/* open bootmodules file and read it in */
65static void get_bootmodules(void)
66{
67    errval_t err;
68
69    vfs_handle_t vh;
70    err = vfs_open("/bootmodules", &vh);
71    if (err_is_fail(err)) {
72        USER_PANIC_ERR(err, "unable to open /bootmodules");
73    }
74
75    struct vfs_fileinfo info;
76    err = vfs_stat(vh, &info);
77    if (err_is_fail(err)) {
78        USER_PANIC_ERR(err, "unable to stat /bootmodules");
79    }
80
81    char *bootmodules = malloc(info.size + 1);
82    if (bootmodules == NULL) {
83        USER_PANIC_ERR(LIB_ERR_MALLOC_FAIL,
84                       "failed to allocate memory for bootmodules");
85    }
86
87    size_t bootmodules_len;
88    err = vfs_read(vh, bootmodules, info.size, &bootmodules_len);
89    if (err_is_fail(err)) {
90        USER_PANIC_ERR(err, "unable to read /bootmodules");
91    } else if (bootmodules_len == 0) {
92        USER_PANIC("/bootmodules is empty");
93    } else if (bootmodules_len != info.size) {
94        USER_PANIC("unexpected short read of /bootmodules");
95    }
96
97    vfs_close(vh);
98
99    // terminate as a string
100    bootmodules[bootmodules_len] = '\0';
101    gbootmodules = bootmodules;
102}
103
104int main(int argc, const char *argv[])
105{
106    vfs_init();
107    my_core_id = disp_get_core_id();
108
109    // read in the bootmodules file so that we know what to start
110    get_bootmodules();
111
112    // construct sane inital environment
113    init_environ();
114
115    // wait for spawnd boot to finish
116    errval_t err = nsb_wait(ALL_SPAWNDS_UP);
117    if (err_is_fail(err)) {
118        USER_PANIC_ERR(err, "failed ns barrier wait for %s", ALL_SPAWNDS_UP);
119    }
120
121    // startup distributed services
122    spawn_dist_domains();
123
124    // startup regular apps
125    spawn_app_domains();
126
127    // startup apps listed in bootscript
128    spawn_bootscript_domains();
129
130    spawn_arrakis_domains();
131
132    return EXIT_SUCCESS;
133}
134