File: | obj-scan-build/init/../../init/init.c |
Location: | line 471, column 5 |
Description: | Value stored to 'progname' is never read |
1 | /* Start and maintain hurd core servers and system run state |
2 | |
3 | Copyright (C) 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, |
4 | 2005, 2008, 2013 Free Software Foundation, Inc. |
5 | This file is part of the GNU Hurd. |
6 | |
7 | The GNU Hurd is free software; you can redistribute it and/or modify |
8 | it under the terms of the GNU General Public License as published by |
9 | the Free Software Foundation; either version 2, or (at your option) |
10 | any later version. |
11 | |
12 | The GNU Hurd is distributed in the hope that it will be useful, |
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
15 | GNU General Public License for more details. |
16 | |
17 | You should have received a copy of the GNU General Public License |
18 | along with the GNU Hurd; see the file COPYING. If not, write to |
19 | the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ |
20 | |
21 | /* Written by Michael I. Bushnell and Roland McGrath. */ |
22 | |
23 | /* This is probably more include files than I've ever seen before for |
24 | one file. */ |
25 | #include <hurd.h> |
26 | #include <hurd/fs.h> |
27 | #include <hurd/fsys.h> |
28 | #include <device/device.h> |
29 | #include <stdio.h> |
30 | #include <assert.h> |
31 | #include <hurd/paths.h> |
32 | #include <sys/reboot.h> |
33 | #include <sys/file.h> |
34 | #include <unistd.h> |
35 | #include <string.h> |
36 | #include <mach/notify.h> |
37 | #include <stdlib.h> |
38 | #include <hurd/msg.h> |
39 | #include <hurd/term.h> |
40 | #include <hurd/fshelp.h> |
41 | #include <paths.h> |
42 | #include <sys/mman.h> |
43 | #include <hurd/msg_server.h> |
44 | #include <wire.h> |
45 | #include <sys/wait.h> |
46 | #include <error.h> |
47 | #include <hurd/msg_reply.h> |
48 | #include <argz.h> |
49 | #include <maptime.h> |
50 | #include <version.h> |
51 | #include <argp.h> |
52 | #include <pids.h> |
53 | |
54 | #include "startup_notify_U.h" |
55 | #include "startup_reply_U.h" |
56 | #include "startup_S.h" |
57 | #include "notify_S.h" |
58 | #include "mung_msg_S.h" |
59 | |
60 | /* host_reboot flags for when we crash. */ |
61 | static int crash_flags = RB_AUTOBOOT0; |
62 | |
63 | #define BOOT(flags)((flags & 0x08) ? "halt" : "reboot") ((flags & RB_HALT0x08) ? "halt" : "reboot") |
64 | |
65 | |
66 | const char *argp_program_version = STANDARD_HURD_VERSION (init)"init" " (GNU Hurd) " "0.5"; |
67 | |
68 | static struct argp_option |
69 | options[] = |
70 | { |
71 | {"single-user", 's', 0, 0, "Startup system in single-user mode"}, |
72 | {"query", 'q', 0, 0, "Ask for the names of servers to start"}, |
73 | {"init-name", 'n', 0, 0 }, |
74 | {"crash-debug", 'H', 0, 0, "On system crash, go to kernel debugger"}, |
75 | {"debug", 'd', 0, 0 }, |
76 | {"fake-boot", 'f', 0, 0, "This hurd hasn't been booted on the raw machine"}, |
77 | {0, 'x', 0, OPTION_HIDDEN0x2}, |
78 | {0} |
79 | }; |
80 | |
81 | static char doc[] = "Start and maintain hurd core servers and system run state"; |
82 | |
83 | static int booted; /* Set when the core servers are up. */ |
84 | |
85 | /* This structure keeps track of each notified task. */ |
86 | struct ntfy_task |
87 | { |
88 | mach_port_t notify_port; |
89 | struct ntfy_task *next; |
90 | char *name; |
91 | }; |
92 | |
93 | /* This structure keeps track of each registered essential task. */ |
94 | struct ess_task |
95 | { |
96 | struct ess_task *next; |
97 | task_t task_port; |
98 | char *name; |
99 | }; |
100 | |
101 | /* These are linked lists of all of the registered items. */ |
102 | static struct ess_task *ess_tasks; |
103 | static struct ntfy_task *ntfy_tasks; |
104 | |
105 | |
106 | /* Our receive right */ |
107 | static mach_port_t startup; |
108 | |
109 | /* Ports to the kernel */ |
110 | static mach_port_t host_priv, device_master; |
111 | |
112 | /* Args to bootstrap, expressed as flags */ |
113 | static int bootstrap_args = 0; |
114 | |
115 | /* Stored information for returning proc and auth startup messages. */ |
116 | static mach_port_t procreply, authreply; |
117 | static mach_msg_type_name_t procreplytype, authreplytype; |
118 | |
119 | /* Our ports to auth and proc. */ |
120 | static mach_port_t authserver; |
121 | static mach_port_t procserver; |
122 | |
123 | /* Our bootstrap port, on which we call fsys_getpriv and fsys_init. */ |
124 | static mach_port_t bootport; |
125 | |
126 | /* Set iff we are a `fake' bootstrap. */ |
127 | static int fakeboot; |
128 | |
129 | /* The tasks of auth and proc and the bootstrap filesystem. */ |
130 | static task_t authtask, proctask, fstask; |
131 | |
132 | static mach_port_t default_ports[INIT_PORT_MAX]; |
133 | static mach_port_t default_dtable[3]; |
134 | static int default_ints[INIT_INT_MAX]; |
135 | |
136 | static char **global_argv; |
137 | static char *startup_envz; |
138 | static size_t startup_envz_len; |
139 | |
140 | void launch_system (void); |
141 | void process_signal (int signo); |
142 | |
143 | /** Utility functions **/ |
144 | |
145 | /* Read a string from stdin into BUF. */ |
146 | static int |
147 | getstring (char *buf, size_t bufsize) |
148 | { |
149 | if (fgets (buf, bufsize, stdinstdin) != NULL((void*)0) && buf[0] != '\0') |
150 | { |
151 | size_t len = strlen (buf); |
152 | if (buf[len - 1] == '\n' || buf[len - 1] == '\r') |
153 | buf[len - 1] = '\0'; |
154 | return 1; |
155 | } |
156 | return 0; |
157 | } |
158 | |
159 | |
160 | /** System shutdown **/ |
161 | |
162 | /* Reboot the microkernel. */ |
163 | void |
164 | reboot_mach (int flags) |
165 | { |
166 | if (fakeboot) |
167 | { |
168 | printf ("%s: Would %s Mach with flags %#x\n", |
169 | program_invocation_short_name, BOOT (flags)((flags & 0x08) ? "halt" : "reboot"), flags); |
170 | fflush (stdoutstdout); |
171 | exit (1); |
172 | } |
173 | else |
174 | { |
175 | error_t err; |
176 | printf ("%s: %sing Mach (flags %#x)...\n", |
177 | program_invocation_short_name, BOOT (flags)((flags & 0x08) ? "halt" : "reboot"), flags); |
178 | fflush (stdoutstdout); |
179 | sleep (5); |
180 | while ((err = host_reboot (host_priv, flags))) |
181 | error (0, err, "reboot"); |
182 | for (;;); |
183 | } |
184 | } |
185 | |
186 | /* Reboot the microkernel, specifying that this is a crash. */ |
187 | void |
188 | crash_mach (void) |
189 | { |
190 | reboot_mach (crash_flags); |
191 | } |
192 | |
193 | /* Notify all tasks that have requested shutdown notifications */ |
194 | void |
195 | notify_shutdown (const char *msg) |
196 | { |
197 | struct ntfy_task *n; |
198 | |
199 | for (n = ntfy_tasks; n != NULL((void*)0); n = n->next) |
200 | { |
201 | error_t err; |
202 | printf ("%s: notifying %s of %s...", |
203 | program_invocation_short_name, n->name, msg); |
204 | fflush (stdoutstdout); |
205 | err = startup_dosync (n->notify_port, 60000); /* 1 minute to reply */ |
206 | if (err == MACH_SEND_INVALID_DEST0x10000003) |
207 | puts ("(no longer present)"); |
208 | else if (err) |
209 | puts (strerror (err)); |
210 | else |
211 | puts ("done"); |
212 | fflush (stdoutstdout); |
213 | } |
214 | } |
215 | |
216 | /* Reboot the Hurd. */ |
217 | void |
218 | reboot_system (int flags) |
219 | { |
220 | notify_shutdown ("shutdown"); |
221 | |
222 | if (fakeboot) |
223 | { |
224 | pid_t *pp; |
225 | size_t npids = 0; |
226 | error_t err; |
227 | int ind; |
228 | |
229 | err = proc_getallpids (procserver, &pp, &npids); |
230 | if (err == MACH_SEND_INVALID_DEST0x10000003) |
231 | { |
232 | procbad: |
233 | /* The procserver must have died. Give up. */ |
234 | error (0, 0, "Can't simulate crash; proc has died"); |
235 | reboot_mach (flags); |
236 | } |
237 | for (ind = 0; ind < npids; ind++) |
238 | { |
239 | task_t task; |
240 | |
241 | err = proc_pid2task (procserver, pp[ind], &task); |
242 | if (err == MACH_SEND_INVALID_DEST0x10000003) |
243 | goto procbad; |
244 | else if (err) |
245 | { |
246 | error (0, err, "Getting task for pid %d", pp[ind]); |
247 | continue; |
248 | } |
249 | |
250 | /* Postpone self so we can finish; postpone proc |
251 | so that we can finish. */ |
252 | if (task != mach_task_self ()((__mach_task_self_ + 0)) && task != proctask) |
253 | { |
254 | struct procinfo *pi = 0; |
255 | size_t pisize = 0; |
256 | char *noise; |
257 | size_t noise_len = 0; |
258 | int flags; |
259 | err = proc_getprocinfo (procserver, pp[ind], &flags, |
260 | (int **)&pi, &pisize, |
261 | &noise, &noise_len); |
262 | if (err == MACH_SEND_INVALID_DEST0x10000003) |
263 | goto procbad; |
264 | if (err) |
265 | { |
266 | error (0, err, "Getting procinfo for pid %d", pp[ind]); |
267 | continue; |
268 | } |
269 | if (!(pi->state & PI_NOPARENT0x0000080)) |
270 | { |
271 | printf ("%s: Killing pid %d\n", |
272 | program_invocation_short_name, pp[ind]); |
273 | fflush (stdoutstdout); |
274 | task_terminate (task); |
275 | } |
276 | if (noise_len > 0) |
277 | munmap (noise, noise_len); |
278 | } |
279 | } |
280 | printf ("%s: Killing proc server\n", program_invocation_short_name); |
281 | fflush (stdoutstdout); |
282 | task_terminate (proctask); |
283 | printf ("%s: Exiting", program_invocation_short_name); |
284 | fflush (stdoutstdout); |
285 | } |
286 | reboot_mach (flags); |
287 | } |
288 | |
289 | /* Reboot the Hurd, specifying that this is a crash. */ |
290 | void |
291 | crash_system (void) |
292 | { |
293 | reboot_system (crash_flags); |
294 | } |
295 | |
296 | |
297 | |
298 | /* Request a dead-name notification sent to our port. */ |
299 | static void |
300 | request_dead_name (mach_port_t name) |
301 | { |
302 | mach_port_t prev; |
303 | mach_port_request_notification (mach_task_self ()((__mach_task_self_ + 0)), name, |
304 | MACH_NOTIFY_DEAD_NAME(0100 + 010), 1, startup, |
305 | MACH_MSG_TYPE_MAKE_SEND_ONCE21, &prev); |
306 | if (prev != MACH_PORT_NULL((mach_port_t) 0)) |
307 | mach_port_deallocate (mach_task_self ()((__mach_task_self_ + 0)), prev); |
308 | } |
309 | |
310 | /* Record an essential task in the list. */ |
311 | static error_t |
312 | record_essential_task (const char *name, task_t task) |
313 | { |
314 | struct ess_task *et; |
315 | /* Record this task as essential. */ |
316 | et = malloc (sizeof (struct ess_task)); |
317 | if (et == NULL((void*)0)) |
318 | return ENOMEM((0x10 << 26) | ((12) & 0x3fff)); |
319 | et->task_port = task; |
320 | et->name = strdup (name); |
321 | if (et->name == NULL((void*)0)) |
322 | { |
323 | free (et); |
324 | return ENOMEM((0x10 << 26) | ((12) & 0x3fff)); |
325 | } |
326 | et->next = ess_tasks; |
327 | ess_tasks = et; |
328 | |
329 | /* Dead-name notification on the task port will tell us when it dies. */ |
330 | request_dead_name (task); |
331 | |
332 | #if 0 |
333 | /* Taking over the exception port will give us a better chance |
334 | if the task tries to get wedged on a fault. */ |
335 | task_set_special_port (task, TASK_EXCEPTION_PORT3, startup); |
336 | #endif |
337 | |
338 | return 0; |
339 | } |
340 | |
341 | |
342 | /** Starting programs **/ |
343 | |
344 | /* Run SERVER, giving it INIT_PORT_MAX initial ports from PORTS. |
345 | Set TASK to be the task port of the new image. */ |
346 | void |
347 | run (const char *server, mach_port_t *ports, task_t *task) |
348 | { |
349 | char buf[BUFSIZ8192]; |
350 | const char *prog = server; |
351 | |
352 | if (bootstrap_args & RB_INITNAME0x10) |
353 | { |
354 | printf ("Server file name (default %s): ", server); |
355 | if (getstring (buf, sizeof (buf))) |
356 | prog = buf; |
357 | } |
358 | |
359 | while (1) |
360 | { |
361 | file_t file; |
362 | error_t err; |
363 | |
364 | file = file_name_lookup (prog, O_EXEC0x0004, 0); |
365 | if (file == MACH_PORT_NULL((mach_port_t) 0)) |
366 | error (0, errno(*__errno_location ()), "%s", prog); |
367 | else |
368 | { |
369 | task_create (mach_task_self ()((__mach_task_self_ + 0)), |
370 | #ifdef KERN_INVALID_LEDGER |
371 | NULL((void*)0), 0, /* OSF Mach */ |
372 | #endif |
373 | 0, task); |
374 | if (bootstrap_args & RB_KDB0x04) |
375 | { |
376 | printf ("Pausing for %s\n", prog); |
377 | getchar (); |
378 | } |
379 | err = file_exec (file, *task, 0, |
380 | (char *)prog, strlen (prog) + 1, /* Args. */ |
381 | startup_envz, startup_envz_len, |
382 | default_dtable, MACH_MSG_TYPE_COPY_SEND19, 3, |
383 | ports, MACH_MSG_TYPE_COPY_SEND19, INIT_PORT_MAX, |
384 | default_ints, INIT_INT_MAX, |
385 | NULL((void*)0), 0, NULL((void*)0), 0); |
386 | if (!err) |
387 | break; |
388 | |
389 | error (0, err, "%s", prog); |
390 | } |
391 | |
392 | printf ("File name for server %s (or nothing to reboot): ", server); |
393 | if (getstring (buf, sizeof (buf))) |
394 | prog = buf; |
395 | else |
396 | crash_system (); |
397 | } |
398 | |
399 | #if 0 |
400 | printf ("started %s\n", prog); |
401 | fflush (stdoutstdout); |
402 | #endif |
403 | |
404 | /* Dead-name notification on the task port will tell us when it dies, |
405 | so we can crash if we don't make it to a fully bootstrapped Hurd. */ |
406 | request_dead_name (*task); |
407 | } |
408 | |
409 | /* Run FILENAME as root with ARGS as its argv (length ARGLEN). Return |
410 | the task that we started. If CTTY is set, then make that the |
411 | controlling terminal of the new process and put it in its own login |
412 | collection. If SETSID is set, put it in a new session. Return |
413 | 0 if the task was not created successfully. */ |
414 | pid_t |
415 | run_for_real (char *filename, char *args, int arglen, mach_port_t ctty, |
416 | int setsid) |
417 | { |
418 | file_t file; |
419 | error_t err; |
420 | task_t task; |
421 | char *progname; |
422 | int pid; |
423 | |
424 | #if 0 |
425 | char buf[512]; |
426 | do |
427 | { |
428 | printf ("File name [%s]: ", filename); |
429 | if (getstring (buf, sizeof (buf)) && *buf) |
430 | filename = buf; |
431 | file = file_name_lookup (filename, O_EXEC0x0004, 0); |
432 | if (file == MACH_PORT_NULL((mach_port_t) 0)) |
433 | error (0, errno(*__errno_location ()), "%s", filename); |
434 | } |
435 | while (file == MACH_PORT_NULL((mach_port_t) 0)); |
436 | #else |
437 | file = file_name_lookup (filename, O_EXEC0x0004, 0); |
438 | if (file == MACH_PORT_NULL((mach_port_t) 0)) |
439 | { |
440 | error (0, errno(*__errno_location ()), "%s", filename); |
441 | return 0; |
442 | } |
443 | #endif |
444 | |
445 | task_create (mach_task_self ()((__mach_task_self_ + 0)), |
446 | #ifdef KERN_INVALID_LEDGER |
447 | NULL((void*)0), 0, /* OSF Mach */ |
448 | #endif |
449 | 0, &task); |
450 | proc_child (procserver, task); |
451 | proc_task2pid (procserver, task, &pid); |
452 | proc_task2proc (procserver, task, &default_ports[INIT_PORT_PROC]); |
453 | proc_mark_exec (default_ports[INIT_PORT_PROC]); |
454 | if (setsid) |
455 | proc_setsid (default_ports[INIT_PORT_PROC]); |
456 | if (ctty != MACH_PORT_NULL((mach_port_t) 0)) |
457 | { |
458 | term_getctty (ctty, &default_ports[INIT_PORT_CTTYID]); |
459 | io_mod_owner (ctty, -pid); |
460 | proc_make_login_coll (default_ports[INIT_PORT_PROC]); |
461 | } |
462 | if (bootstrap_args & RB_KDB0x04) |
463 | { |
464 | printf ("Pausing for %s\n", filename); |
465 | getchar (); |
466 | } |
467 | progname = strrchr (filename, '/'); |
468 | if (progname) |
469 | ++progname; |
470 | else |
471 | progname = filename; |
Value stored to 'progname' is never read | |
472 | err = file_exec (file, task, 0, |
473 | args, arglen, |
474 | startup_envz, startup_envz_len, |
475 | default_dtable, MACH_MSG_TYPE_COPY_SEND19, 3, |
476 | default_ports, MACH_MSG_TYPE_COPY_SEND19, |
477 | INIT_PORT_MAX, |
478 | default_ints, INIT_INT_MAX, |
479 | NULL((void*)0), 0, NULL((void*)0), 0); |
480 | mach_port_deallocate (mach_task_self ()((__mach_task_self_ + 0)), default_ports[INIT_PORT_PROC]); |
481 | mach_port_deallocate (mach_task_self ()((__mach_task_self_ + 0)), task); |
482 | if (ctty != MACH_PORT_NULL((mach_port_t) 0)) |
483 | { |
484 | mach_port_deallocate (mach_task_self ()((__mach_task_self_ + 0)), |
485 | default_ports[INIT_PORT_CTTYID]); |
486 | default_ports[INIT_PORT_CTTYID] = MACH_PORT_NULL((mach_port_t) 0); |
487 | } |
488 | mach_port_deallocate (mach_task_self ()((__mach_task_self_ + 0)), file); |
489 | if (err) |
490 | { |
491 | error (0, err, "Cannot execute %s", filename); |
492 | return 0; |
493 | } |
494 | return pid; |
495 | } |
496 | |
497 | |
498 | /** Main program and setup **/ |
499 | |
500 | static int |
501 | demuxer (mach_msg_header_t *inp, |
502 | mach_msg_header_t *outp) |
503 | { |
504 | extern int notify_server (), startup_server (), msg_server (); |
505 | |
506 | return (notify_server (inp, outp) || |
507 | msg_server (inp, outp) || |
508 | startup_server (inp, outp)); |
509 | } |
510 | |
511 | static int |
512 | parse_opt (int key, char *arg, struct argp_state *state) |
513 | { |
514 | switch (key) |
515 | { |
516 | case 'q': bootstrap_args |= RB_ASKNAME0x01; break; |
517 | case 's': bootstrap_args |= RB_SINGLE0x02; break; |
518 | case 'd': bootstrap_args |= RB_KDB0x04; break; |
519 | case 'n': bootstrap_args |= RB_INITNAME0x10; break; |
520 | case 'f': fakeboot = 1; break; |
521 | case 'H': crash_flags = RB_DEBUGGER0x1000; break; |
522 | case 'x': /* NOP */ break; |
523 | default: return ARGP_ERR_UNKNOWN((0x10 << 26) | ((7) & 0x3fff)); |
524 | } |
525 | return 0; |
526 | } |
527 | |
528 | int |
529 | main (int argc, char **argv, char **envp) |
530 | { |
531 | volatile int err; |
532 | int i; |
533 | int flags; |
534 | mach_port_t consdev; |
535 | struct argp argp = { options, parse_opt, 0, doc }; |
536 | |
537 | /* Parse the arguments. We don't want the vector reordered, we |
538 | should pass on to our child the exact arguments we got and just |
539 | ignore any arguments that aren't flags for us. ARGP_NO_ERRS |
540 | suppresses --help and --version, so we only use that option if we |
541 | are booting. */ |
542 | flags = ARGP_IN_ORDER0x08; |
543 | if (getpid () == 0) |
544 | flags |= ARGP_NO_ERRS0x02; |
545 | argp_parse (&argp, argc, argv, flags, 0, 0); |
546 | |
547 | if (getpid () > 0) |
548 | error (2, 0, "can only be run by bootstrap filesystem"); |
549 | |
550 | global_argv = argv; |
551 | |
552 | /* Fetch a port to the bootstrap filesystem, the host priv and |
553 | master device ports, and the console. */ |
554 | if (task_get_bootstrap_port (mach_task_self (), &bootport)(task_get_special_port((((__mach_task_self_ + 0))), 4, (& bootport))) |
555 | || fsys_getpriv (bootport, &host_priv, &device_master, &fstask) |
556 | || device_open (device_master, D_WRITE0x2, "console", &consdev)) |
557 | crash_mach (); |
558 | |
559 | wire_task_self (); |
560 | |
561 | /* Clear our bootstrap port so our children don't inherit it. */ |
562 | task_set_bootstrap_port (mach_task_self (), MACH_PORT_NULL)(task_set_special_port((((__mach_task_self_ + 0))), 4, (((mach_port_t ) 0)))); |
563 | |
564 | stderrstderr = stdoutstdout = mach_open_devstream (consdev, "w"); |
565 | stdinstdin = mach_open_devstream (consdev, "r"); |
566 | if (stdoutstdout == NULL((void*)0) || stdinstdin == NULL((void*)0)) |
567 | crash_mach (); |
568 | setbuf (stdoutstdout, NULL((void*)0)); |
569 | |
570 | err = argz_create (envp, &startup_envz, &startup_envz_len); |
571 | assert_perror (err)(!(err) ? (void) (0) : __assert_perror_fail ((err), "../../init/init.c" , 571, __PRETTY_FUNCTION__)); |
572 | |
573 | /* At this point we can use assert to check for errors. */ |
574 | err = mach_port_allocate (mach_task_self ()((__mach_task_self_ + 0)), |
575 | MACH_PORT_RIGHT_RECEIVE((mach_port_right_t) 1), &startup); |
576 | assert_perror (err)(!(err) ? (void) (0) : __assert_perror_fail ((err), "../../init/init.c" , 576, __PRETTY_FUNCTION__)); |
577 | err = mach_port_insert_right (mach_task_self ()((__mach_task_self_ + 0)), startup, startup, |
578 | MACH_MSG_TYPE_MAKE_SEND20); |
579 | assert_perror (err)(!(err) ? (void) (0) : __assert_perror_fail ((err), "../../init/init.c" , 579, __PRETTY_FUNCTION__)); |
580 | |
581 | /* Crash if the boot filesystem task dies. */ |
582 | request_dead_name (fstask); |
583 | |
584 | /* Set up the set of ports we will pass to the programs we exec. */ |
585 | for (i = 0; i < INIT_PORT_MAX; i++) |
586 | switch (i) |
587 | { |
588 | case INIT_PORT_CRDIR: |
589 | default_ports[i] = getcrdir (); |
590 | break; |
591 | case INIT_PORT_CWDIR: |
592 | default_ports[i] = getcwdir (); |
593 | break; |
594 | default: |
595 | default_ports[i] = MACH_PORT_NULL((mach_port_t) 0); |
596 | break; |
597 | } |
598 | |
599 | default_dtable[0] = getdport (0); |
600 | default_dtable[1] = getdport (1); |
601 | default_dtable[2] = getdport (2); |
602 | |
603 | /* All programs we start should ignore job control stop signals. |
604 | That way Posix.1 B.2.2.2 is satisfied where it says that programs |
605 | not run under job control shells are protected. */ |
606 | default_ints[INIT_SIGIGN] = (sigmask (SIGTSTP)(((__sigset_t) 1) << ((18) - 1)) |
607 | | sigmask (SIGTTIN)(((__sigset_t) 1) << ((21) - 1)) |
608 | | sigmask (SIGTTOU)(((__sigset_t) 1) << ((22) - 1))); |
609 | |
610 | default_ports[INIT_PORT_BOOTSTRAP] = startup; |
611 | run ("/hurd/proc", default_ports, &proctask); |
612 | printf (" proc"); |
613 | fflush (stdoutstdout); |
614 | run ("/hurd/auth", default_ports, &authtask); |
615 | printf (" auth"); |
616 | fflush (stdoutstdout); |
617 | default_ports[INIT_PORT_BOOTSTRAP] = MACH_PORT_NULL((mach_port_t) 0); |
618 | |
619 | /* Wait for messages. When both auth and proc have started, we |
620 | run launch_system which does the rest of the boot. */ |
621 | while (1) |
622 | { |
623 | err = mach_msg_server (demuxer, 0, startup); |
624 | assert_perror (err)(!(err) ? (void) (0) : __assert_perror_fail ((err), "../../init/init.c" , 624, __PRETTY_FUNCTION__)); |
625 | } |
626 | } |
627 | |
628 | void |
629 | launch_core_servers (void) |
630 | { |
631 | mach_port_t old; |
632 | mach_port_t authproc, fsproc, procproc; |
633 | error_t err; |
634 | |
635 | /* Reply to the proc and auth servers. */ |
636 | startup_procinit_reply (procreply, procreplytype, 0, |
637 | mach_task_self ()((__mach_task_self_ + 0)), authserver, |
638 | host_priv, MACH_MSG_TYPE_COPY_SEND19, |
639 | device_master, MACH_MSG_TYPE_COPY_SEND19); |
640 | if (!fakeboot) |
641 | { |
642 | mach_port_deallocate (mach_task_self ()((__mach_task_self_ + 0)), device_master); |
643 | device_master = 0; |
644 | } |
645 | |
646 | /* Mark us as important. */ |
647 | proc_mark_important (procserver); |
648 | proc_mark_exec (procserver); |
649 | |
650 | /* Declare that the filesystem and auth are our children. */ |
651 | proc_child (procserver, fstask); |
652 | proc_child (procserver, authtask); |
653 | |
654 | proc_task2proc (procserver, authtask, &authproc); |
655 | proc_mark_important (authproc); |
656 | proc_mark_exec (authproc); |
657 | startup_authinit_reply (authreply, authreplytype, 0, authproc, |
658 | MACH_MSG_TYPE_COPY_SEND19); |
659 | mach_port_deallocate (mach_task_self ()((__mach_task_self_ + 0)), authproc); |
660 | |
661 | /* Give the library our auth and proc server ports. */ |
662 | _hurd_port_set (&_hurd_ports[INIT_PORT_AUTH], authserver); |
663 | _hurd_port_set (&_hurd_ports[INIT_PORT_PROC], procserver); |
664 | |
665 | /* Do NOT run _hurd_proc_init! That will start signals, which we do not |
666 | want. We listen to our own message port. Tell the proc server where |
667 | our args and environment are. */ |
668 | proc_set_arg_locations (procserver, |
669 | (vm_address_t) global_argv, (vm_address_t) environ); |
670 | |
671 | default_ports[INIT_PORT_AUTH] = authserver; |
672 | |
673 | /* Declare that the proc server is our child. */ |
674 | proc_child (procserver, proctask); |
675 | err = proc_task2proc (procserver, proctask, &procproc); |
676 | if (!err) |
677 | { |
678 | proc_mark_important (procproc); |
679 | proc_mark_exec (procproc); |
680 | mach_port_deallocate (mach_task_self ()((__mach_task_self_ + 0)), procproc); |
681 | } |
682 | |
683 | proc_register_version (procserver, host_priv, "init", "", HURD_VERSION"0.5"); |
684 | |
685 | /* Get the bootstrap filesystem's proc server port. |
686 | We must do this before calling proc_setmsgport below. */ |
687 | proc_task2proc (procserver, fstask, &fsproc); |
688 | proc_mark_important (fsproc); |
689 | proc_mark_exec (fsproc); |
690 | |
691 | #if 0 |
692 | printf ("Init has completed.\n"); |
693 | fflush (stdoutstdout); |
694 | #endif |
695 | printf (".\n"); |
696 | fflush (stdoutstdout); |
697 | |
698 | /* Tell the proc server our msgport. Be sure to do this after we are all |
699 | done making requests of proc. Once we have done this RPC, proc |
700 | assumes it can send us requests, so we cannot block on proc again |
701 | before accepting more RPC requests! However, we must do this before |
702 | calling fsys_init, because fsys_init blocks on exec_init, and |
703 | exec_init will block waiting on our message port. */ |
704 | proc_setmsgport (procserver, startup, &old); |
705 | if (old != MACH_PORT_NULL((mach_port_t) 0)) |
706 | mach_port_deallocate (mach_task_self ()((__mach_task_self_ + 0)), old); |
707 | |
708 | /* Give the bootstrap FS its proc and auth ports. */ |
709 | err = fsys_init (bootport, fsproc, MACH_MSG_TYPE_COPY_SEND19, authserver); |
710 | mach_port_deallocate (mach_task_self ()((__mach_task_self_ + 0)), fsproc); |
711 | if (err) |
712 | error (0, err, "fsys_init"); /* Not necessarily fatal. */ |
713 | } |
714 | |
715 | /* Set up the initial value of the standard exec data. */ |
716 | void |
717 | init_stdarrays () |
718 | { |
719 | auth_t nullauth; |
720 | mach_port_t pt; |
721 | mach_port_t ref; |
722 | mach_port_t *std_port_array; |
723 | int *std_int_array; |
724 | int i; |
725 | |
726 | std_port_array = alloca (sizeof (mach_port_t) * INIT_PORT_MAX)__builtin_alloca (sizeof (mach_port_t) * INIT_PORT_MAX); |
727 | std_int_array = alloca (sizeof (int) * INIT_INT_MAX)__builtin_alloca (sizeof (int) * INIT_INT_MAX); |
728 | |
729 | bzero (std_port_array, sizeof (mach_port_t) * INIT_PORT_MAX); |
730 | bzero (std_int_array, sizeof (int) * INIT_INT_MAX); |
731 | |
732 | __USEPORT (AUTH, auth_makeauth (port, 0, MACH_MSG_TYPE_COPY_SEND, 0,({ struct hurd_port *const __p = (&_hurd_ports[INIT_PORT_AUTH ]); struct hurd_userlink __link; const mach_port_t port = _hurd_port_get (__p, &__link); __typeof((auth_makeauth (port, 0, 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, &nullauth))) __result = ((auth_makeauth (port, 0, 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, &nullauth))); _hurd_port_free (__p, &__link, port); __result; }) |
733 | 0, 0, 0, 0, 0, 0, 0, 0, &nullauth))({ struct hurd_port *const __p = (&_hurd_ports[INIT_PORT_AUTH ]); struct hurd_userlink __link; const mach_port_t port = _hurd_port_get (__p, &__link); __typeof((auth_makeauth (port, 0, 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, &nullauth))) __result = ((auth_makeauth (port, 0, 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, &nullauth))); _hurd_port_free (__p, &__link, port); __result; }); |
734 | |
735 | /* MAKE_SEND is safe in these transactions because we destroy REF |
736 | ourselves each time. */ |
737 | pt = getcwdir (); |
738 | ref = mach_reply_port (); |
739 | io_reauthenticate (pt, ref, MACH_MSG_TYPE_MAKE_SEND20); |
740 | auth_user_authenticate (nullauth, ref, MACH_MSG_TYPE_MAKE_SEND20, |
741 | &std_port_array[INIT_PORT_CWDIR]); |
742 | mach_port_destroy (mach_task_self ()((__mach_task_self_ + 0)), ref); |
743 | mach_port_deallocate (mach_task_self ()((__mach_task_self_ + 0)), pt); |
744 | |
745 | pt = getcrdir (); |
746 | ref = mach_reply_port (); |
747 | io_reauthenticate (pt, ref, MACH_MSG_TYPE_MAKE_SEND20); |
748 | auth_user_authenticate (nullauth, ref, MACH_MSG_TYPE_MAKE_SEND20, |
749 | &std_port_array[INIT_PORT_CRDIR]); |
750 | mach_port_destroy (mach_task_self ()((__mach_task_self_ + 0)), ref); |
751 | mach_port_deallocate (mach_task_self ()((__mach_task_self_ + 0)), pt); |
752 | |
753 | std_port_array[INIT_PORT_AUTH] = nullauth; |
754 | |
755 | std_int_array[INIT_UMASK] = CMASK0022; |
756 | |
757 | __USEPORT (PROC, proc_setexecdata (port, std_port_array,({ struct hurd_port *const __p = (&_hurd_ports[INIT_PORT_PROC ]); struct hurd_userlink __link; const mach_port_t port = _hurd_port_get (__p, &__link); __typeof((proc_setexecdata (port, std_port_array , 19, INIT_PORT_MAX, std_int_array, INIT_INT_MAX))) __result = ((proc_setexecdata (port, std_port_array, 19, INIT_PORT_MAX, std_int_array, INIT_INT_MAX))); _hurd_port_free (__p, &__link , port); __result; }) |
758 | MACH_MSG_TYPE_COPY_SEND, INIT_PORT_MAX,({ struct hurd_port *const __p = (&_hurd_ports[INIT_PORT_PROC ]); struct hurd_userlink __link; const mach_port_t port = _hurd_port_get (__p, &__link); __typeof((proc_setexecdata (port, std_port_array , 19, INIT_PORT_MAX, std_int_array, INIT_INT_MAX))) __result = ((proc_setexecdata (port, std_port_array, 19, INIT_PORT_MAX, std_int_array, INIT_INT_MAX))); _hurd_port_free (__p, &__link , port); __result; }) |
759 | std_int_array, INIT_INT_MAX))({ struct hurd_port *const __p = (&_hurd_ports[INIT_PORT_PROC ]); struct hurd_userlink __link; const mach_port_t port = _hurd_port_get (__p, &__link); __typeof((proc_setexecdata (port, std_port_array , 19, INIT_PORT_MAX, std_int_array, INIT_INT_MAX))) __result = ((proc_setexecdata (port, std_port_array, 19, INIT_PORT_MAX, std_int_array, INIT_INT_MAX))); _hurd_port_free (__p, &__link , port); __result; }); |
760 | for (i = 0; i < INIT_PORT_MAX; i++) |
761 | mach_port_deallocate (mach_task_self ()((__mach_task_self_ + 0)), std_port_array[i]); |
762 | } |
763 | |
764 | /* Frobnicate the kernel task and the proc server's idea of it (PID 2), |
765 | so the kernel command line can be read as for a normal Hurd process. */ |
766 | |
767 | void |
768 | frob_kernel_process (void) |
769 | { |
770 | error_t err; |
771 | int argc, i; |
772 | char *argz, *entry; |
773 | size_t argzlen; |
774 | size_t windowsz; |
775 | vm_address_t mine, his; |
776 | task_t task; |
777 | process_t proc, kbs; |
778 | |
779 | err = proc_pid2task (procserver, HURD_PID_KERNEL2, &task); |
780 | if (err) |
781 | { |
782 | error (0, err, "cannot get kernel task port"); |
783 | return; |
784 | } |
785 | err = proc_task2proc (procserver, task, &proc); |
786 | if (err) |
787 | { |
788 | error (0, err, "cannot get kernel task's proc server port"); |
789 | mach_port_deallocate (mach_task_self ()((__mach_task_self_ + 0)), task); |
790 | return; |
791 | } |
792 | |
793 | /* Mark the kernel task as an essential task so that we or the proc server |
794 | never want to task_terminate it. */ |
795 | proc_mark_important (proc); |
796 | |
797 | err = record_essential_task ("kernel", task); |
798 | assert_perror (err)(!(err) ? (void) (0) : __assert_perror_fail ((err), "../../init/init.c" , 798, __PRETTY_FUNCTION__)); |
799 | |
800 | err = task_get_bootstrap_port (task, &kbs)(task_get_special_port((task), 4, (&kbs))); |
801 | assert_perror (err)(!(err) ? (void) (0) : __assert_perror_fail ((err), "../../init/init.c" , 801, __PRETTY_FUNCTION__)); |
802 | if (kbs == MACH_PORT_NULL((mach_port_t) 0)) |
803 | { |
804 | /* The kernel task has no bootstrap port set, so we are presumably |
805 | the first Hurd to boot. Install the kernel task's proc port from |
806 | this Hurd's proc server as the task bootstrap port. Additional |
807 | Hurds will see this. */ |
808 | |
809 | err = task_set_bootstrap_port (task, proc)(task_set_special_port((task), 4, (proc))); |
810 | if (err) |
811 | error (0, err, "cannot set kernel task's bootstrap port"); |
812 | |
813 | if (fakeboot) |
814 | error (0, 0, "warning: --fake-boot specified but I see no other Hurd"); |
815 | } |
816 | else |
817 | { |
818 | /* The kernel task has a bootstrap port set. Perhaps it is its proc |
819 | server port from another Hurd. If so, propagate the kernel |
820 | argument locations from that Hurd rather than diddling with the |
821 | kernel task ourselves. */ |
822 | |
823 | vm_address_t kargv, kenvp; |
824 | err = proc_get_arg_locations (kbs, &kargv, &kenvp); |
825 | mach_port_deallocate (mach_task_self ()((__mach_task_self_ + 0)), kbs); |
826 | if (err) |
827 | error (0, err, "kernel task bootstrap port (ignoring)"); |
828 | else |
829 | { |
830 | err = proc_set_arg_locations (proc, kargv, kenvp); |
831 | if (err) |
832 | error (0, err, "cannot propagate original kernel command line"); |
833 | else |
834 | { |
835 | mach_port_deallocate (mach_task_self ()((__mach_task_self_ + 0)), proc); |
836 | mach_port_deallocate (mach_task_self ()((__mach_task_self_ + 0)), task); |
837 | if (! fakeboot) |
838 | error (0, 0, "warning: " |
839 | "I see another Hurd, but --fake-boot was not given"); |
840 | return; |
841 | } |
842 | } |
843 | } |
844 | |
845 | /* Our arguments make up the multiboot command line used to boot the |
846 | kernel. We'll write into the kernel task a page containing a |
847 | canonical argv array and argz of those words. */ |
848 | |
849 | err = argz_create (&global_argv[1], &argz, &argzlen); |
850 | assert_perror (err)(!(err) ? (void) (0) : __assert_perror_fail ((err), "../../init/init.c" , 850, __PRETTY_FUNCTION__)); |
851 | argc = argz_count (argz, argzlen); |
852 | |
853 | windowsz = round_page (((argc + 1) * sizeof (char *)) + argzlen)((((vm_offset_t) (((argc + 1) * sizeof (char *)) + argzlen) + __vm_page_size - 1) / __vm_page_size) * __vm_page_size); |
854 | |
855 | mine = (vm_address_t) mmap (0, windowsz, PROT_READ0x04|PROT_WRITE0x02, |
856 | MAP_ANON0x0002, 0, 0); |
857 | assert (mine != -1)((mine != -1) ? (void) (0) : __assert_fail ("mine != -1", "../../init/init.c" , 857, __PRETTY_FUNCTION__)); |
858 | err = vm_allocate (task, &his, windowsz, 1); |
859 | if (err) |
860 | { |
861 | error (0, err, "cannot allocate %Zu bytes in kernel task", windowsz); |
862 | free (argz); |
863 | mach_port_deallocate (mach_task_self ()((__mach_task_self_ + 0)), proc); |
864 | mach_port_deallocate (mach_task_self ()((__mach_task_self_ + 0)), task); |
865 | munmap ((caddr_t) mine, windowsz); |
866 | return; |
867 | } |
868 | |
869 | for (i = 0, entry = argz; entry != NULL((void*)0); |
870 | ++i, entry = argz_next (argz, argzlen, entry)) |
871 | ((char **) mine)[i] = ((char *) &((char **) his)[argc + 1] |
872 | + (entry - argz)); |
873 | ((char **) mine)[argc] = NULL((void*)0); |
874 | memcpy (&((char **) mine)[argc + 1], argz, argzlen); |
875 | |
876 | free (argz); |
877 | |
878 | /* We have the data all set up in our copy, now just write it over. */ |
879 | err = vm_write (task, his, mine, windowsz); |
880 | mach_port_deallocate (mach_task_self ()((__mach_task_self_ + 0)), task); |
881 | munmap ((caddr_t) mine, windowsz); |
882 | if (err) |
883 | { |
884 | error (0, err, "cannot write command line into kernel task"); |
885 | return; |
886 | } |
887 | |
888 | /* The argument vector is set up in the kernel task at address HIS. |
889 | Finally, we can inform the proc server where to find it. */ |
890 | err = proc_set_arg_locations (proc, his, his + (argc * sizeof (char *))); |
891 | mach_port_deallocate (mach_task_self ()((__mach_task_self_ + 0)), proc); |
892 | if (err) |
893 | error (0, err, "proc_set_arg_locations for kernel task"); |
894 | } |
895 | |
896 | /** Running userland. **/ |
897 | |
898 | /* In the "split-init" setup, we just run a single program (usually |
899 | /libexec/runsystem) that is not expected to ever exit (or stop). |
900 | If it does exit (or can't be started), we go to an emergency single-user |
901 | shell as a fallback. */ |
902 | |
903 | |
904 | static pid_t child_pid; /* PID of the child we run */ |
905 | static task_t child_task; /* and its (original) task port */ |
906 | |
907 | error_t send_signal (mach_port_t msgport, int signal, mach_port_t refport, |
908 | mach_msg_timeout_t); |
909 | |
910 | static void launch_something (const char *why); |
911 | |
912 | |
913 | /* SIGNO has arrived and has been validated. Do whatever work it |
914 | implies. */ |
915 | void |
916 | process_signal (int signo) |
917 | { |
918 | if (signo == SIGCHLD20) |
919 | { |
920 | /* A child died. Find its status. */ |
921 | int status; |
922 | pid_t pid; |
923 | |
924 | while (1) |
925 | { |
926 | pid = waitpid (WAIT_ANY(-1), &status, WNOHANG1 | WUNTRACED2); |
927 | if (pid <= 0) |
928 | break; /* No more children. */ |
929 | |
930 | /* Since we are init, orphaned processes get reparented to us and |
931 | alas, all our adopted children eventually die. Woe is us. We |
932 | just need to reap the zombies to relieve the proc server of |
933 | its burden, and then we can forget about the little varmints. */ |
934 | |
935 | if (pid == child_pid) |
936 | { |
937 | /* The big magilla bit the dust. */ |
938 | |
939 | char *desc = 0; |
940 | |
941 | mach_port_deallocate (mach_task_self ()((__mach_task_self_ + 0)), child_task); |
942 | child_task = MACH_PORT_NULL((mach_port_t) 0); |
943 | child_pid = -1; |
944 | |
945 | if (WIFSIGNALED (status)(((signed char) ((((__extension__ (((union { __typeof(status) __in; int __i; }) { .__in = (status) }).__i))) & 0x7f) + 1) >> 1) > 0)) |
946 | asprintf (&desc, "terminated abnormally (%s)", |
947 | strsignal (WTERMSIG (status)(((__extension__ (((union { __typeof(status) __in; int __i; } ) { .__in = (status) }).__i))) & 0x7f))); |
948 | else if (WIFSTOPPED (status)((((__extension__ (((union { __typeof(status) __in; int __i; } ) { .__in = (status) }).__i))) & 0xff) == 0x7f)) |
949 | asprintf (&desc, "stopped abnormally (%s)", |
950 | strsignal (WTERMSIG (status)(((__extension__ (((union { __typeof(status) __in; int __i; } ) { .__in = (status) }).__i))) & 0x7f))); |
951 | else if (WEXITSTATUS (status)((((__extension__ (((union { __typeof(status) __in; int __i; } ) { .__in = (status) }).__i))) & 0xff00) >> 8) == 0) |
952 | desc = strdup ("finished"); |
953 | else |
954 | asprintf (&desc, "exited with status %d", |
955 | WEXITSTATUS (status)((((__extension__ (((union { __typeof(status) __in; int __i; } ) { .__in = (status) }).__i))) & 0xff00) >> 8)); |
956 | |
957 | { |
958 | char buf[40]; |
959 | snprintf (buf, sizeof buf, "%d", status); |
960 | setenv ("STATUS", buf, 1); |
961 | } |
962 | |
963 | launch_something (desc); |
964 | free (desc); |
965 | } |
966 | } |
967 | } |
968 | else |
969 | { |
970 | /* Pass the signal on to the child. */ |
971 | task_t task; |
972 | error_t err; |
973 | |
974 | err = proc_pid2task (procserver, child_pid, &task); |
975 | if (err) |
976 | { |
977 | error (0, err, "proc_pid2task on %d", child_pid); |
978 | task = child_task; |
979 | } |
980 | else |
981 | { |
982 | mach_port_deallocate (mach_task_self ()((__mach_task_self_ + 0)), child_task); |
983 | child_task = task; |
984 | } |
985 | |
986 | if (signo == SIGKILL9) |
987 | { |
988 | err = task_terminate (task); |
989 | if (err != MACH_SEND_INVALID_DEST0x10000003) |
990 | error (0, err, "task_terminate"); |
991 | } |
992 | else |
993 | { |
994 | mach_port_t msgport; |
995 | err = proc_getmsgport (procserver, child_pid, &msgport); |
996 | if (err) |
997 | error (0, err, "proc_getmsgport"); |
998 | else |
999 | { |
1000 | err = send_signal (msgport, signo, task, |
1001 | 500); /* Block only half a second. */ |
1002 | mach_port_deallocate (mach_task_self ()((__mach_task_self_ + 0)), msgport); |
1003 | if (err) |
1004 | { |
1005 | error (0, err, "cannot send %s to child %d", |
1006 | strsignal (signo), child_pid); |
1007 | err = task_terminate (task); |
1008 | if (err != MACH_SEND_INVALID_DEST0x10000003) |
1009 | error (0, err, "task_terminate"); |
1010 | } |
1011 | } |
1012 | } |
1013 | } |
1014 | } |
1015 | |
1016 | /* Start the child program PROG. It is run via /libexec/console-run |
1017 | with the given additional arguments. */ |
1018 | static int |
1019 | start_child (const char *prog, char **progargs) |
1020 | { |
1021 | file_t file; |
1022 | error_t err; |
1023 | char *args; |
1024 | size_t arglen; |
1025 | |
1026 | if (progargs == 0) |
1027 | { |
1028 | const char *argv[] = { "/libexec/console-run", prog, 0 }; |
1029 | err = argz_create ((char **) argv, &args, &arglen); |
1030 | } |
1031 | else |
1032 | { |
1033 | int argc = 0; |
1034 | while (progargs[argc] != 0) |
1035 | ++argc; |
1036 | { |
1037 | const char *argv[2 + argc + 1]; |
1038 | argv[0] = "/libexec/console-run"; |
1039 | argv[1] = prog; |
1040 | argv[2 + argc] = 0; |
1041 | while (argc-- > 0) |
1042 | argv[2 + argc] = progargs[argc]; |
1043 | err = argz_create ((char **) argv, &args, &arglen); |
1044 | } |
1045 | } |
1046 | assert_perror (err)(!(err) ? (void) (0) : __assert_perror_fail ((err), "../../init/init.c" , 1046, __PRETTY_FUNCTION__)); |
1047 | |
1048 | file = file_name_lookup (args, O_EXEC0x0004, 0); |
1049 | if (file == MACH_PORT_NULL((mach_port_t) 0)) |
1050 | { |
1051 | error (0, errno(*__errno_location ()), "%s", args); |
1052 | free (args); |
1053 | return -1; |
1054 | } |
1055 | |
1056 | task_create (mach_task_self ()((__mach_task_self_ + 0)), |
1057 | #ifdef KERN_INVALID_LEDGER |
1058 | NULL((void*)0), 0, /* OSF Mach */ |
1059 | #endif |
1060 | 0, &child_task); |
1061 | proc_child (procserver, child_task); |
1062 | proc_task2pid (procserver, child_task, &child_pid); |
1063 | proc_task2proc (procserver, child_task, &default_ports[INIT_PORT_PROC]); |
1064 | |
1065 | if (bootstrap_args & RB_KDB0x04) |
1066 | { |
1067 | printf ("Pausing for %s\n", args); |
1068 | getchar (); |
1069 | } |
1070 | |
1071 | err = file_exec (file, child_task, 0, |
1072 | args, arglen, |
1073 | startup_envz, startup_envz_len, |
1074 | NULL((void*)0), MACH_MSG_TYPE_COPY_SEND19, 0, /* No fds. */ |
1075 | default_ports, MACH_MSG_TYPE_COPY_SEND19, INIT_PORT_MAX, |
1076 | default_ints, INIT_INT_MAX, |
1077 | NULL((void*)0), 0, NULL((void*)0), 0); |
1078 | proc_mark_important (default_ports[INIT_PORT_PROC]); |
1079 | mach_port_deallocate (mach_task_self ()((__mach_task_self_ + 0)), default_ports[INIT_PORT_PROC]); |
1080 | mach_port_deallocate (mach_task_self ()((__mach_task_self_ + 0)), file); |
1081 | if (err) |
1082 | { |
1083 | error (0, err, "Cannot execute %s", args); |
1084 | free (args); |
1085 | return -1; |
1086 | } |
1087 | free (args); |
1088 | return 0; |
1089 | } |
1090 | |
1091 | static void |
1092 | launch_something (const char *why) |
1093 | { |
1094 | file_t something; |
1095 | static unsigned int try; |
1096 | static const char *const tries[] = |
1097 | { |
1098 | "/libexec/runsystem", |
1099 | _PATH_BSHELL"/bin/sh", |
1100 | "/bin/shd", /* XXX */ |
1101 | }; |
1102 | |
1103 | if (why) |
1104 | error (0, 0, "%s %s", tries[try - 1], why); |
1105 | |
1106 | something = file_name_lookup (tries[try], O_EXEC0x0004, 0); |
1107 | if (something != MACH_PORT_NULL((mach_port_t) 0)) |
1108 | { |
1109 | mach_port_deallocate (mach_task_self ()((__mach_task_self_ + 0)), something); |
1110 | if (try == 0 && start_child (tries[try++], &global_argv[1]) == 0) |
1111 | return; |
1112 | } |
1113 | else |
1114 | try++; |
1115 | |
1116 | while (try < sizeof tries / sizeof tries[0]) |
1117 | { |
1118 | something = file_name_lookup (tries[try], O_EXEC0x0004, 0); |
1119 | if (something != MACH_PORT_NULL((mach_port_t) 0)) |
1120 | { |
1121 | mach_port_deallocate (mach_task_self ()((__mach_task_self_ + 0)), something); |
1122 | if (start_child (tries[try++], NULL((void*)0)) == 0) |
1123 | return; |
1124 | } |
1125 | } |
1126 | |
1127 | crash_system (); |
1128 | } |
1129 | |
1130 | void |
1131 | launch_system (void) |
1132 | { |
1133 | launch_something (0); |
1134 | } |
1135 | |
1136 | /** RPC servers **/ |
1137 | |
1138 | kern_return_t |
1139 | S_startup_procinit (startup_t server, |
1140 | mach_port_t reply, |
1141 | mach_msg_type_name_t reply_porttype, |
1142 | process_t proc, |
1143 | mach_port_t *startuptask, |
1144 | auth_t *auth, |
1145 | mach_port_t *priv, |
1146 | mach_msg_type_name_t *hostprivtype, |
1147 | mach_port_t *dev, |
1148 | mach_msg_type_name_t *devtype) |
1149 | { |
1150 | if (procserver) |
1151 | /* Only one proc server. */ |
1152 | return EPERM((0x10 << 26) | ((1) & 0x3fff)); |
1153 | |
1154 | procserver = proc; |
1155 | |
1156 | procreply = reply; |
1157 | procreplytype = reply_porttype; |
1158 | |
1159 | /* Save the reply port until we get startup_authinit. */ |
1160 | if (authserver) |
1161 | launch_core_servers (); |
1162 | |
1163 | return MIG_NO_REPLY-305; |
1164 | } |
1165 | |
1166 | /* Called by the auth server when it starts up. */ |
1167 | |
1168 | kern_return_t |
1169 | S_startup_authinit (startup_t server, |
1170 | mach_port_t reply, |
1171 | mach_msg_type_name_t reply_porttype, |
1172 | mach_port_t auth, |
1173 | mach_port_t *proc, |
1174 | mach_msg_type_name_t *proctype) |
1175 | { |
1176 | if (authserver) |
1177 | /* Only one auth server. */ |
1178 | return EPERM((0x10 << 26) | ((1) & 0x3fff)); |
1179 | |
1180 | authserver = auth; |
1181 | |
1182 | /* Save the reply port until we get startup_procinit. */ |
1183 | authreply = reply; |
1184 | authreplytype = reply_porttype; |
1185 | |
1186 | if (procserver) |
1187 | launch_core_servers (); |
1188 | |
1189 | return MIG_NO_REPLY-305; |
1190 | } |
1191 | |
1192 | |
1193 | kern_return_t |
1194 | S_startup_essential_task (mach_port_t server, |
1195 | mach_port_t reply, |
1196 | mach_msg_type_name_t replytype, |
1197 | task_t task, |
1198 | mach_port_t excpt, |
1199 | char *name, |
1200 | mach_port_t credential) |
1201 | { |
1202 | static int authinit, procinit, execinit; |
1203 | int fail; |
1204 | |
1205 | /* Always deallocate the extra reference this message carries. */ |
1206 | if (MACH_PORT_VALID (credential)(((credential) != ((mach_port_t) 0)) && ((credential) != ((mach_port_t) ~0)))) |
1207 | mach_port_deallocate (mach_task_self ()((__mach_task_self_ + 0)), credential); |
1208 | |
1209 | if (credential != host_priv) |
1210 | return EPERM((0x10 << 26) | ((1) & 0x3fff)); |
1211 | |
1212 | fail = record_essential_task (name, task); |
1213 | if (fail) |
1214 | return fail; |
1215 | |
1216 | if (!booted) |
1217 | { |
1218 | if (!strcmp (name, "auth")) |
1219 | authinit = 1; |
1220 | else if (!strcmp (name, "exec")) |
1221 | { |
1222 | execinit = 1; |
1223 | mach_port_t execproc; |
1224 | proc_task2proc (procserver, task, &execproc); |
1225 | proc_mark_important (execproc); |
1226 | } |
1227 | else if (!strcmp (name, "proc")) |
1228 | procinit = 1; |
1229 | |
1230 | if (authinit && execinit && procinit) |
1231 | { |
1232 | /* Reply to this RPC, after that everything |
1233 | is ready for real startup to begin. */ |
1234 | startup_essential_task_reply (reply, replytype, 0); |
1235 | |
1236 | init_stdarrays (); |
1237 | frob_kernel_process (); |
1238 | |
1239 | launch_system (); |
1240 | |
1241 | booted = 1; |
1242 | |
1243 | return MIG_NO_REPLY-305; |
1244 | } |
1245 | } |
1246 | |
1247 | return 0; |
1248 | } |
1249 | |
1250 | kern_return_t |
1251 | S_startup_request_notification (mach_port_t server, |
1252 | mach_port_t notify, |
1253 | char *name) |
1254 | { |
1255 | struct ntfy_task *nt; |
1256 | |
1257 | request_dead_name (notify); |
1258 | |
1259 | /* Note that the ntfy_tasks list is kept in inverse order of the |
1260 | calls; this is important. We need later notification requests |
1261 | to get executed first. */ |
1262 | nt = malloc (sizeof (struct ntfy_task)); |
1263 | nt->notify_port = notify; |
1264 | nt->next = ntfy_tasks; |
1265 | ntfy_tasks = nt; |
1266 | nt->name = malloc (strlen (name) + 1); |
1267 | strcpy (nt->name, name); |
1268 | return 0; |
1269 | } |
1270 | |
1271 | kern_return_t |
1272 | do_mach_notify_dead_name (mach_port_t notify, |
1273 | mach_port_t name) |
1274 | { |
1275 | struct ntfy_task *nt, *pnt; |
1276 | struct ess_task *et; |
1277 | |
1278 | assert (notify == startup)((notify == startup) ? (void) (0) : __assert_fail ("notify == startup" , "../../init/init.c", 1278, __PRETTY_FUNCTION__)); |
1279 | |
1280 | /* Deallocate the extra reference the notification carries. */ |
1281 | mach_port_deallocate (mach_task_self ()((__mach_task_self_ + 0)), name); |
1282 | |
1283 | for (et = ess_tasks; et != NULL((void*)0); et = et->next) |
1284 | if (et->task_port == name) |
1285 | /* An essential task has died. */ |
1286 | { |
1287 | error (0, 0, "Crashing system; essential task %s died", et->name); |
1288 | crash_system (); |
1289 | } |
1290 | |
1291 | for (nt = ntfy_tasks, pnt = NULL((void*)0); nt != NULL((void*)0); pnt = nt, nt = nt->next) |
1292 | if (nt->notify_port == name) |
1293 | { |
1294 | /* Someone who wanted to be notified is gone. */ |
1295 | mach_port_deallocate (mach_task_self ()((__mach_task_self_ + 0)), name); |
1296 | if (pnt != NULL((void*)0)) |
1297 | pnt->next = nt->next; |
1298 | else |
1299 | ntfy_tasks = nt->next; |
1300 | free (nt); |
1301 | |
1302 | return 0; |
1303 | } |
1304 | |
1305 | if (! booted) |
1306 | { |
1307 | /* The system has not come up yet, so essential tasks are not yet |
1308 | registered. But the essential servers involved in the bootstrap |
1309 | handshake might crash before completing it, so we have requested |
1310 | dead-name notification on those tasks. */ |
1311 | static const struct { task_t *taskp; const char *name; } boots[] = |
1312 | { |
1313 | {&fstask, "bootstrap filesystem"}, |
1314 | {&authtask, "auth"}, |
1315 | {&proctask, "proc"}, |
1316 | }; |
1317 | size_t i; |
1318 | for (i = 0; i < sizeof boots / sizeof boots[0]; ++i) |
1319 | if (name == *boots[i].taskp) |
1320 | { |
1321 | error (0, 0, "Crashing system; %s server died during bootstrap", |
1322 | boots[i].name); |
1323 | crash_mach (); |
1324 | } |
1325 | error (0, 0, "BUG! Unexpected dead-name notification (name %#zx)", |
1326 | name); |
1327 | crash_mach (); |
1328 | } |
1329 | |
1330 | return 0; |
1331 | } |
1332 | |
1333 | kern_return_t |
1334 | S_startup_reboot (mach_port_t server, |
1335 | mach_port_t refpt, |
1336 | int code) |
1337 | { |
1338 | if (refpt != host_priv) |
1339 | return EPERM((0x10 << 26) | ((1) & 0x3fff)); |
1340 | |
1341 | reboot_system (code); |
1342 | for (;;); |
1343 | } |
1344 | |
1345 | /* Stubs for unused notification RPCs. */ |
1346 | |
1347 | kern_return_t |
1348 | do_mach_notify_port_destroyed (mach_port_t notify, |
1349 | mach_port_t rights) |
1350 | { |
1351 | return EOPNOTSUPP((0x10 << 26) | ((45) & 0x3fff)); |
1352 | } |
1353 | |
1354 | kern_return_t |
1355 | do_mach_notify_send_once (mach_port_t notify) |
1356 | { |
1357 | return EOPNOTSUPP((0x10 << 26) | ((45) & 0x3fff)); |
1358 | } |
1359 | |
1360 | kern_return_t |
1361 | do_mach_notify_no_senders (mach_port_t port, mach_port_mscount_t mscount) |
1362 | { |
1363 | return EOPNOTSUPP((0x10 << 26) | ((45) & 0x3fff)); |
1364 | } |
1365 | |
1366 | kern_return_t |
1367 | do_mach_notify_port_deleted (mach_port_t notify, |
1368 | mach_port_t name) |
1369 | { |
1370 | return EOPNOTSUPP((0x10 << 26) | ((45) & 0x3fff)); |
1371 | } |
1372 | |
1373 | kern_return_t |
1374 | do_mach_notify_msg_accepted (mach_port_t notify, |
1375 | mach_port_t name) |
1376 | { |
1377 | return EOPNOTSUPP((0x10 << 26) | ((45) & 0x3fff)); |
1378 | } |
1379 | |
1380 | /* msg server */ |
1381 | |
1382 | kern_return_t |
1383 | S_msg_sig_post_untraced (mach_port_t msgport, |
1384 | mach_port_t reply, mach_msg_type_name_t reply_type, |
1385 | int signo, natural_t sigcode, mach_port_t refport) |
1386 | { |
1387 | if (refport != mach_task_self ()((__mach_task_self_ + 0))) |
1388 | return EPERM((0x10 << 26) | ((1) & 0x3fff)); |
1389 | mach_port_deallocate (mach_task_self ()((__mach_task_self_ + 0)), refport); |
1390 | |
1391 | /* Reply immediately */ |
1392 | msg_sig_post_untraced_reply (reply, reply_type, 0); |
1393 | |
1394 | process_signal (signo); |
1395 | return MIG_NO_REPLY-305; |
1396 | } |
1397 | |
1398 | kern_return_t |
1399 | S_msg_sig_post (mach_port_t msgport, |
1400 | mach_port_t reply, mach_msg_type_name_t reply_type, |
1401 | int signo, natural_t sigcode, mach_port_t refport) |
1402 | { |
1403 | if (refport != mach_task_self ()((__mach_task_self_ + 0))) |
1404 | return EPERM((0x10 << 26) | ((1) & 0x3fff)); |
1405 | mach_port_deallocate (mach_task_self ()((__mach_task_self_ + 0)), refport); |
1406 | |
1407 | /* Reply immediately */ |
1408 | msg_sig_post_reply (reply, reply_type, 0); |
1409 | |
1410 | process_signal (signo); |
1411 | return MIG_NO_REPLY-305; |
1412 | } |
1413 | |
1414 | |
1415 | /* For the rest of the msg functions, just call the C library's |
1416 | internal server stubs usually run in the signal thread. */ |
1417 | |
1418 | kern_return_t |
1419 | S_msg_proc_newids (mach_port_t process, |
1420 | mach_port_t task, |
1421 | pid_t ppid, |
1422 | pid_t pgrp, |
1423 | int orphaned) |
1424 | { return _S_msg_proc_newids (process, task, ppid, pgrp, orphaned); } |
1425 | |
1426 | |
1427 | kern_return_t |
1428 | S_msg_add_auth (mach_port_t process, |
1429 | auth_t auth) |
1430 | { return _S_msg_add_auth (process, auth); } |
1431 | |
1432 | |
1433 | kern_return_t |
1434 | S_msg_del_auth (mach_port_t process, |
1435 | mach_port_t task, |
1436 | intarray_t uids, |
1437 | mach_msg_type_number_t uidsCnt, |
1438 | intarray_t gids, |
1439 | mach_msg_type_number_t gidsCnt) |
1440 | { return _S_msg_del_auth (process, task, uids, uidsCnt, gids, gidsCnt); } |
1441 | |
1442 | |
1443 | kern_return_t |
1444 | S_msg_get_init_port (mach_port_t process, |
1445 | mach_port_t refport, |
1446 | int which, |
1447 | mach_port_t *port, |
1448 | mach_msg_type_name_t *portPoly) |
1449 | { return _S_msg_get_init_port (process, refport, which, port, portPoly); } |
1450 | |
1451 | |
1452 | kern_return_t |
1453 | S_msg_set_init_port (mach_port_t process, |
1454 | mach_port_t refport, |
1455 | int which, |
1456 | mach_port_t port) |
1457 | { return _S_msg_set_init_port (process, refport, which, port); } |
1458 | |
1459 | |
1460 | kern_return_t |
1461 | S_msg_get_init_ports (mach_port_t process, |
1462 | mach_port_t refport, |
1463 | portarray_t *ports, |
1464 | mach_msg_type_name_t *portsPoly, |
1465 | mach_msg_type_number_t *portsCnt) |
1466 | { return _S_msg_get_init_ports (process, refport, ports, portsPoly, portsCnt); } |
1467 | |
1468 | |
1469 | kern_return_t |
1470 | S_msg_set_init_ports (mach_port_t process, |
1471 | mach_port_t refport, |
1472 | portarray_t ports, |
1473 | mach_msg_type_number_t portsCnt) |
1474 | { return _S_msg_set_init_ports (process, refport, ports, portsCnt); } |
1475 | |
1476 | |
1477 | kern_return_t |
1478 | S_msg_get_init_int (mach_port_t process, |
1479 | mach_port_t refport, |
1480 | int which, |
1481 | int *value) |
1482 | { return _S_msg_get_init_int (process, refport, which, value); } |
1483 | |
1484 | |
1485 | kern_return_t |
1486 | S_msg_set_init_int (mach_port_t process, |
1487 | mach_port_t refport, |
1488 | int which, |
1489 | int value) |
1490 | { return _S_msg_set_init_int (process, refport, which, value); } |
1491 | |
1492 | |
1493 | kern_return_t |
1494 | S_msg_get_init_ints (mach_port_t process, |
1495 | mach_port_t refport, |
1496 | intarray_t *values, |
1497 | mach_msg_type_number_t *valuesCnt) |
1498 | { return _S_msg_get_init_ints (process, refport, values, valuesCnt); } |
1499 | |
1500 | |
1501 | kern_return_t |
1502 | S_msg_set_init_ints (mach_port_t process, |
1503 | mach_port_t refport, |
1504 | intarray_t values, |
1505 | mach_msg_type_number_t valuesCnt) |
1506 | { return _S_msg_set_init_ints (process, refport, values, valuesCnt); } |
1507 | |
1508 | |
1509 | kern_return_t |
1510 | S_msg_get_dtable (mach_port_t process, |
1511 | mach_port_t refport, |
1512 | portarray_t *dtable, |
1513 | mach_msg_type_name_t *dtablePoly, |
1514 | mach_msg_type_number_t *dtableCnt) |
1515 | { return _S_msg_get_dtable (process, refport, dtable, dtablePoly, dtableCnt); } |
1516 | |
1517 | |
1518 | kern_return_t |
1519 | S_msg_set_dtable (mach_port_t process, |
1520 | mach_port_t refport, |
1521 | portarray_t dtable, |
1522 | mach_msg_type_number_t dtableCnt) |
1523 | { return _S_msg_set_dtable (process, refport, dtable, dtableCnt); } |
1524 | |
1525 | |
1526 | kern_return_t |
1527 | S_msg_get_fd (mach_port_t process, |
1528 | mach_port_t refport, |
1529 | int fd, |
1530 | mach_port_t *port, |
1531 | mach_msg_type_name_t *portPoly) |
1532 | { return _S_msg_get_fd (process, refport, fd, port, portPoly); } |
1533 | |
1534 | |
1535 | kern_return_t |
1536 | S_msg_set_fd (mach_port_t process, |
1537 | mach_port_t refport, |
1538 | int fd, |
1539 | mach_port_t port) |
1540 | { return _S_msg_set_fd (process, refport, fd, port); } |
1541 | |
1542 | |
1543 | kern_return_t |
1544 | S_msg_get_environment (mach_port_t process, |
1545 | data_t *value, |
1546 | mach_msg_type_number_t *valueCnt) |
1547 | { return _S_msg_get_environment (process, value, valueCnt); } |
1548 | |
1549 | |
1550 | kern_return_t |
1551 | S_msg_set_environment (mach_port_t process, |
1552 | mach_port_t refport, |
1553 | data_t value, |
1554 | mach_msg_type_number_t valueCnt) |
1555 | { return _S_msg_set_environment (process, refport, value, valueCnt); } |
1556 | |
1557 | |
1558 | kern_return_t |
1559 | S_msg_get_env_variable (mach_port_t process, |
1560 | string_t variable, |
1561 | data_t *value, |
1562 | mach_msg_type_number_t *valueCnt) |
1563 | { return _S_msg_get_env_variable (process, variable, value, valueCnt); } |
1564 | |
1565 | |
1566 | kern_return_t |
1567 | S_msg_set_env_variable (mach_port_t process, |
1568 | mach_port_t refport, |
1569 | string_t variable, |
1570 | string_t value, |
1571 | boolean_t replace) |
1572 | { return _S_msg_set_env_variable (process, refport, variable, value, replace); } |
1573 | |
1574 | error_t |
1575 | S_msg_describe_ports (mach_port_t process, |
1576 | mach_port_t refport, |
1577 | mach_port_array_t names, |
1578 | mach_msg_type_number_t namesCnt, |
1579 | data_t *descriptions, |
1580 | mach_msg_type_number_t *descriptionsCnt) |
1581 | { |
1582 | return _S_msg_describe_ports (process, refport, names, namesCnt, |
1583 | descriptions, descriptionsCnt); |
1584 | } |
1585 | |
1586 | error_t |
1587 | S_msg_report_wait (mach_port_t process, thread_t thread, |
1588 | string_t desc, mach_msg_id_t *rpc) |
1589 | { |
1590 | *desc = 0; |
1591 | *rpc = 0; |
1592 | return 0; |
1593 | } |