root / prex-0.9.0 / usr / server / boot / boot.c @ 03e9c04a
History | View | Annotate | Download (7.23 KB)
1 | 03e9c04a | Brad Neuman | /*-
|
---|---|---|---|
2 | * Copyright (c) 2005-2007, Kohsuke Ohtani
|
||
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 | * 1. Redistributions of source code must retain the above copyright
|
||
9 | * notice, this list of conditions and the following disclaimer.
|
||
10 | * 2. Redistributions in binary form must reproduce the above copyright
|
||
11 | * notice, this list of conditions and the following disclaimer in the
|
||
12 | * documentation and/or other materials provided with the distribution.
|
||
13 | * 3. Neither the name of the author nor the names of any co-contributors
|
||
14 | * may be used to endorse or promote products derived from this software
|
||
15 | * without specific prior written permission.
|
||
16 | *
|
||
17 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||
18 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||
19 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||
20 | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||
21 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||
22 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||
23 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||
24 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||
25 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||
26 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||
27 | * SUCH DAMAGE.
|
||
28 | */
|
||
29 | |||
30 | /*
|
||
31 | * main.c - bootstrap server
|
||
32 | */
|
||
33 | |||
34 | /*
|
||
35 | * A bootstrap server works to setup the POSIX environment for
|
||
36 | * 'init' process. It sends a setup message to other servers in
|
||
37 | * order to let them know that this task becomes 'init' process.
|
||
38 | * The bootstrap server is gone after it launches (exec) the
|
||
39 | * 'init' process.
|
||
40 | */
|
||
41 | |||
42 | #include <sys/prex.h> |
||
43 | #include <sys/mount.h> |
||
44 | #include <sys/stat.h> |
||
45 | #include <sys/fcntl.h> |
||
46 | #include <sys/syslog.h> |
||
47 | |||
48 | #include <ipc/fs.h> |
||
49 | #include <ipc/exec.h> |
||
50 | #include <ipc/proc.h> |
||
51 | #include <ipc/ipc.h> |
||
52 | |||
53 | #include <unistd.h> |
||
54 | #include <string.h> |
||
55 | #include <stdlib.h> |
||
56 | #include <stdio.h> |
||
57 | #include <signal.h> |
||
58 | #include <errno.h> |
||
59 | |||
60 | #ifdef DEBUG
|
||
61 | #define DPRINTF(a) sys_log a
|
||
62 | #else
|
||
63 | #define DPRINTF(a)
|
||
64 | #endif
|
||
65 | |||
66 | static const char *initargs[] = { "1", NULL }; |
||
67 | static const char *initenvs[] = { "TERM=vt100", "USER=root", NULL }; |
||
68 | |||
69 | static char iobuf[BUFSIZ]; |
||
70 | |||
71 | /*
|
||
72 | * Base directories at root.
|
||
73 | */
|
||
74 | static char *base_dir[] = { |
||
75 | "/bin", /* applications */ |
||
76 | "/boot", /* system servers */ |
||
77 | "/dev", /* device files */ |
||
78 | "/etc", /* shareable read-only data */ |
||
79 | "/mnt", /* mount point for file systems */ |
||
80 | "/private", /* user's private data */ |
||
81 | "/tmp", /* temporary files */ |
||
82 | NULL
|
||
83 | }; |
||
84 | |||
85 | static void |
||
86 | wait_server(const char *name, object_t *pobj) |
||
87 | { |
||
88 | int i, error = 0; |
||
89 | |||
90 | /* Give chance to run other servers. */
|
||
91 | thread_yield(); |
||
92 | |||
93 | /*
|
||
94 | * Wait for server loading. timeout is 1 sec.
|
||
95 | */
|
||
96 | for (i = 0; i < 100; i++) { |
||
97 | error = object_lookup((char *)name, pobj);
|
||
98 | if (error == 0) |
||
99 | break;
|
||
100 | |||
101 | /* Wait 10msec */
|
||
102 | timer_sleep(10, 0); |
||
103 | thread_yield(); |
||
104 | } |
||
105 | if (error)
|
||
106 | sys_panic("boot: server not found");
|
||
107 | } |
||
108 | |||
109 | static void |
||
110 | send_bootmsg(object_t obj) |
||
111 | { |
||
112 | struct msg m;
|
||
113 | int error;
|
||
114 | |||
115 | m.hdr.code = STD_BOOT; |
||
116 | error = msg_send(obj, &m, sizeof(m));
|
||
117 | if (error)
|
||
118 | sys_panic("boot: server error");
|
||
119 | } |
||
120 | |||
121 | static void |
||
122 | mount_fs(void)
|
||
123 | { |
||
124 | char line[128]; |
||
125 | FILE *fp; |
||
126 | char *spec, *file, *type, *p;
|
||
127 | char nodev[] = ""; |
||
128 | int i;
|
||
129 | |||
130 | DPRINTF(("boot: mounting file systems\n"));
|
||
131 | |||
132 | /*
|
||
133 | * Mount root.
|
||
134 | */
|
||
135 | if (mount("", "/", "ramfs", 0, NULL) < 0) |
||
136 | sys_panic("boot: mount failed");
|
||
137 | |||
138 | /*
|
||
139 | * Create some default directories.
|
||
140 | */
|
||
141 | i = 0;
|
||
142 | while (base_dir[i] != NULL) { |
||
143 | if (mkdir(base_dir[i], 0) == -1) |
||
144 | sys_panic("boot: mkdir failed");
|
||
145 | i++; |
||
146 | } |
||
147 | |||
148 | /*
|
||
149 | * Mount file system for /boot.
|
||
150 | */
|
||
151 | if (mount("/dev/ram0", "/boot", "arfs", 0, NULL) < 0) |
||
152 | sys_panic("boot: mount failed");
|
||
153 | |||
154 | /*
|
||
155 | * Mount file systems described in fstab.
|
||
156 | */
|
||
157 | if ((fp = fopen("/boot/fstab", "r")) == NULL) |
||
158 | sys_panic("boot: no fstab");
|
||
159 | |||
160 | for (;;) {
|
||
161 | if ((p = fgets(line, sizeof(line), fp)) == NULL) |
||
162 | break;
|
||
163 | spec = strtok(p, " \t\n");
|
||
164 | if (spec == NULL || *spec == '#') |
||
165 | continue;
|
||
166 | file = strtok(NULL, " \t\n"); |
||
167 | type = strtok(NULL, " \t\n"); |
||
168 | if (!strcmp(file, "/") || !strcmp(file, "/boot")) |
||
169 | continue;
|
||
170 | if (!strcmp(spec, "none")) |
||
171 | spec = nodev; |
||
172 | |||
173 | /* We create the mount point automatically */
|
||
174 | mkdir(file, 0);
|
||
175 | mount(spec, file, type, 0, 0); |
||
176 | } |
||
177 | fclose(fp); |
||
178 | } |
||
179 | |||
180 | static int |
||
181 | exec_init(object_t execobj) |
||
182 | { |
||
183 | struct exec_msg msg;
|
||
184 | int error, i, argc, envc;
|
||
185 | size_t bufsz; |
||
186 | char *dest;
|
||
187 | char const *src; |
||
188 | |||
189 | DPRINTF(("boot: execute init\n"));
|
||
190 | |||
191 | /* Get arg/env buffer size */
|
||
192 | bufsz = 0;
|
||
193 | argc = 0;
|
||
194 | while (initargs[argc]) {
|
||
195 | bufsz += (strlen(initargs[argc]) + 1);
|
||
196 | argc++; |
||
197 | } |
||
198 | envc = 0;
|
||
199 | while (initenvs[envc]) {
|
||
200 | bufsz += (strlen(initenvs[envc]) + 1);
|
||
201 | envc++; |
||
202 | } |
||
203 | if (bufsz >= ARG_MAX)
|
||
204 | sys_panic("boot: args too long");
|
||
205 | |||
206 | /*
|
||
207 | * Build exec message.
|
||
208 | */
|
||
209 | dest = msg.buf; |
||
210 | for (i = 0; i < argc; i++) { |
||
211 | src = initargs[i]; |
||
212 | while ((*dest++ = *src++) != 0); |
||
213 | } |
||
214 | for (i = 0; i < envc; i++) { |
||
215 | src = initenvs[i]; |
||
216 | while ((*dest++ = *src++) != 0); |
||
217 | } |
||
218 | msg.hdr.code = EXEC_EXECVE; |
||
219 | msg.argc = argc; |
||
220 | msg.envc = envc; |
||
221 | msg.bufsz = bufsz; |
||
222 | strlcpy(msg.cwd, "/", sizeof(msg.cwd)); |
||
223 | strlcpy(msg.path, "/boot/init", sizeof(msg.path)); |
||
224 | |||
225 | do {
|
||
226 | error = msg_send(execobj, &msg, sizeof(msg));
|
||
227 | /*
|
||
228 | * If exec server can execute new process
|
||
229 | * properly, it will terminate the caller task
|
||
230 | * automatically. So, the control never comes
|
||
231 | * here in that case.
|
||
232 | */
|
||
233 | } while (error == EINTR);
|
||
234 | return -1; |
||
235 | } |
||
236 | |||
237 | static void |
||
238 | copy_file(char *src, char *dest) |
||
239 | { |
||
240 | int fold, fnew, n;
|
||
241 | struct stat stbuf;
|
||
242 | mode_t mode; |
||
243 | |||
244 | if ((fold = open(src, O_RDONLY)) == -1) |
||
245 | return;
|
||
246 | |||
247 | fstat(fold, &stbuf); |
||
248 | mode = stbuf.st_mode; |
||
249 | |||
250 | if ((fnew = creat(dest, mode)) == -1) { |
||
251 | close(fold); |
||
252 | return;
|
||
253 | } |
||
254 | while ((n = read(fold, iobuf, BUFSIZ)) > 0) { |
||
255 | if (write(fnew, iobuf, (size_t)n) != n) {
|
||
256 | close(fold); |
||
257 | close(fnew); |
||
258 | return;
|
||
259 | } |
||
260 | } |
||
261 | close(fold); |
||
262 | close(fnew); |
||
263 | } |
||
264 | |||
265 | int
|
||
266 | main(int argc, char *argv[]) |
||
267 | { |
||
268 | object_t execobj, procobj, fsobj; |
||
269 | struct bind_msg bm;
|
||
270 | struct msg m;
|
||
271 | |||
272 | sys_log("Starting bootstrap server\n");
|
||
273 | |||
274 | thread_setpri(thread_self(), PRI_DEFAULT); |
||
275 | |||
276 | /*
|
||
277 | * Wait until all required system servers
|
||
278 | * become available.
|
||
279 | */
|
||
280 | wait_server("!proc", &procobj);
|
||
281 | wait_server("!fs", &fsobj);
|
||
282 | wait_server("!exec", &execobj);
|
||
283 | |||
284 | /*
|
||
285 | * Send boot message to all servers.
|
||
286 | * This is required to synchronize the server
|
||
287 | * initialization without deadlock.
|
||
288 | */
|
||
289 | send_bootmsg(execobj); |
||
290 | send_bootmsg(procobj); |
||
291 | send_bootmsg(fsobj); |
||
292 | |||
293 | /*
|
||
294 | * Request to bind a new capabilities for us.
|
||
295 | */
|
||
296 | bm.hdr.code = EXEC_BINDCAP; |
||
297 | strlcpy(bm.path, "/boot/boot", sizeof(bm.path)); |
||
298 | msg_send(execobj, &bm, sizeof(bm));
|
||
299 | |||
300 | /*
|
||
301 | * Register this process as 'init'.
|
||
302 | * We will become an init process later.
|
||
303 | */
|
||
304 | m.hdr.code = PS_SETINIT; |
||
305 | msg_send(procobj, &m, sizeof(m));
|
||
306 | |||
307 | /*
|
||
308 | * Initialize a library for file I/O.
|
||
309 | */
|
||
310 | fslib_init(); |
||
311 | |||
312 | /*
|
||
313 | * Mount file systems.
|
||
314 | */
|
||
315 | mount_fs(); |
||
316 | |||
317 | /*
|
||
318 | * Copy some files.
|
||
319 | * Note that almost applications including 'init'
|
||
320 | * does not have an access right to /boot directory...
|
||
321 | */
|
||
322 | copy_file("/boot/rc", "/etc/rc"); |
||
323 | copy_file("/boot/fstab", "/etc/fstab"); |
||
324 | |||
325 | /*
|
||
326 | * Exec first application.
|
||
327 | */
|
||
328 | exec_init(execobj); |
||
329 | |||
330 | sys_panic("boot: failed to exec init");
|
||
331 | |||
332 | /* NOTREACHED */
|
||
333 | return 0; |
||
334 | } |