5248d67344acb2441b875d805f708e34bd86fa84
[barrelfish] / usr / kaluga / boot_modules.c
1 #define _USE_XOPEN /* for strdup() */
2 #include <stdio.h>
3 #include <string.h>
4
5 #include <barrelfish/barrelfish.h>
6 #include <barrelfish/cpu_arch.h> // for CURRENT_CPU_TYPE
7 #include <barrelfish/spawn_client.h>
8
9 #include <spawndomain/spawndomain.h>
10 #include <vfs/vfs.h>
11
12 #include "kaluga.h"
13 #include "debug.h"
14
15 #define MAX_DRIVER_MODULES 128
16
17 static struct module_info modules[MAX_DRIVER_MODULES];
18
19 inline bool is_auto_driver(struct module_info* mi) {
20     return mi->argc > 1 && strcmp(mi->argv[1], "auto") == 0;
21 }
22
23 inline bool is_started(struct module_info* mi)
24 {
25     return (mi->num_started);
26 }
27
28 inline bool can_start(struct module_info* mi)
29 {
30     return (mi->allow_multi || (mi->num_started == 0));
31 }
32
33 void set_start_function(char* binary, module_start_fn start_fn)
34 {
35     struct module_info* mi = find_module(binary);
36     if (mi != NULL) {
37         mi->start_function = start_fn;
38     }
39 }
40
41 void set_started(struct module_info* mi)
42 {
43     mi->num_started += 1;
44     assert(mi->allow_multi || (mi->num_started == 1));
45 }
46
47 void set_multi_instance(struct module_info* mi, uint8_t is_multi)
48 {
49     mi->allow_multi = (is_multi != 0);
50 }
51
52 void set_core_id_offset(struct module_info* mi, coreid_t offset)
53 {
54     mi->coreoffset = offset;
55 }
56
57 domainid_t *get_did_ptr(struct module_info *mi)
58 {
59     return (mi->did + mi->num_started);
60 }
61
62 coreid_t get_core_id_offset(struct module_info* mi)
63 {
64     return mi->coreoffset * mi->num_started;
65 }
66
67 struct module_info* find_module(char *binary)
68 {
69     assert(binary != NULL);
70     bool found = false;
71     struct module_info* si = NULL;
72
73     for (size_t i=0; i< MAX_DRIVER_MODULES; i++) {
74         si = &modules[i];
75         if (si->binary != NULL && strcmp(si->binary, binary) == 0) {
76             found = true;
77             break;
78         }
79     }
80
81     return (found) ? si : NULL;
82 }
83
84 static void parse_module(char* line, struct module_info* si)
85 {
86     si->complete_line = strdup(line);
87
88     char* path_end = strchr(line, ' ');
89     if (path_end == NULL) {
90         path_end = line + strlen(line);
91     }
92     size_t path_size = path_end-line;
93     si->path = malloc(path_size+1);
94     strncpy(si->path, line, path_size);
95     si->path[path_size] = '\0';
96
97     char* binary_start = strrchr(si->path, '/');
98     si->binary = strdup(binary_start+1); // exclude /
99     memset(si->did, 0, sizeof(si->did));
100     si->start_function = default_start_function;
101     si->num_started = 0;
102     char* cmdstart = line + path_size - strlen(si->binary);
103     si->args = strdup(line + path_size);
104
105     // cmdargs will be tagged with \0
106     si->cmdargs = strdup(cmdstart);
107     si->argc = spawn_tokenize_cmdargs(si->cmdargs, si->argv,
108                                       ARRAY_LENGTH(si->argv));
109 }
110
111 /**
112  * \brief Parses bootmodules and stores info in
113  * boot_modules.
114  */
115 static errval_t parse_modules(char* bootmodules)
116 {
117     assert(bootmodules != NULL);
118
119     size_t entry = 0;
120     char* bm = strdup(bootmodules);
121
122     static const char* delim = "\n";
123     char* line = strtok(bm, delim);
124
125     while (line != NULL && entry < MAX_DRIVER_MODULES) {
126         struct module_info* si = &modules[entry++];
127         parse_module(line, si);
128         KALUGA_DEBUG("found boot module:\n%s\n%s\n%s (%d)\n", si->binary, si->path, si->cmdargs, si->argc);
129
130         line = strtok(NULL, delim);
131     }
132     free(bm);
133
134     if (line == NULL) {
135         return SYS_ERR_OK;
136     }
137     else {
138         return KALUGA_ERR_PARSE_MODULES;
139     }
140 }
141
142 /**
143  * \brief Open bootmodules file and read it in
144  */
145 static char* get_bootmodules(void)
146 {
147     errval_t err;
148
149     // open bootmodules file and read it in
150     vfs_handle_t vh;
151     err = vfs_open("/bootmodules", &vh);
152     if (err_is_fail(err)) {
153         USER_PANIC_ERR(err, "unable to open /bootmodules");
154     }
155
156     struct vfs_fileinfo info;
157     err = vfs_stat(vh, &info);
158     if (err_is_fail(err)) {
159         USER_PANIC_ERR(err, "unable to stat /bootmodules");
160     }
161
162     char *bootmodules = malloc(info.size + 1);
163     if (bootmodules == NULL) {
164         USER_PANIC_ERR(LIB_ERR_MALLOC_FAIL,
165                        "failed to allocate memory for bootmodules");
166     }
167     size_t bootmodules_len;
168     err = vfs_read(vh, bootmodules, info.size, &bootmodules_len);
169     if (err_is_fail(err)) {
170         USER_PANIC_ERR(err, "unable to read /bootmodules");
171     } else if (bootmodules_len == 0) {
172         USER_PANIC_ERR(err, "/bootmodules is empty");
173     } else if (bootmodules_len != info.size) {
174         USER_PANIC_ERR(err, "unexpected short read of /bootmodules");
175     }
176
177     err = vfs_close(vh);
178     if (err_is_fail(err)) {
179         DEBUG_ERR(err, "could not close bottmodules file");
180     }
181
182     // terminate as a string
183     bootmodules[bootmodules_len] = '\0';
184     return bootmodules;
185 }
186
187 /**
188  * \brief Set an initial default environment for our boot-time children
189  */
190 void init_environ(void)
191 {
192     int r;
193
194     /* PATH=/arch/sbin */
195     char pathstr[64];
196     snprintf(pathstr, sizeof(pathstr), "/%s/sbin",
197              cpu_type_to_archstr(CURRENT_CPU_TYPE));
198     pathstr[sizeof(pathstr) - 1] = '\0';
199     r = setenv("PATH", pathstr, 0);
200     if (r != 0) {
201         USER_PANIC("failed to set PATH");
202     }
203
204     /* HOME=/ */
205     r = setenv("HOME", "/", 0);
206     if (r != 0) {
207         USER_PANIC("failed to set HOME");
208     }
209 }
210
211 errval_t init_boot_modules(void)
212 {
213     char* bootmodules = get_bootmodules();
214     errval_t err = parse_modules(bootmodules);
215     free(bootmodules);
216
217     return err;
218 }