Commit | Line | Data |
---|---|---|
9a6eb889 NW |
1 | /* |
2 | * Copyright (c) 1993 Christoph M. Robitschko | |
800ffe89 NW |
3 | * All rights reserved. |
4 | * | |
800ffe89 NW |
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. All advertising materials mentioning features or use of this software | |
14 | * must display the following acknowledgement: | |
9a6eb889 NW |
15 | * This product includes software developed by Christoph M. Robitschko |
16 | * 4. The name of the author may not be used to endorse or promote products | |
17 | * derived from this software withough specific prior written permission | |
800ffe89 | 18 | * |
9a6eb889 NW |
19 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR |
20 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES | |
21 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. | |
22 | * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, | |
23 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT | |
24 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | |
25 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | |
26 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |
27 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF | |
28 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
800ffe89 NW |
29 | */ |
30 | ||
31 | /* | |
32 | * init.c | |
33 | * Main program for init. | |
34 | * Also contains definitions for global variables etc. | |
35 | */ | |
36 | ||
37 | #include <unistd.h> | |
38 | #include <stdlib.h> | |
39 | #include <sys/types.h> | |
40 | #include <sys/signal.h> | |
41 | #include <sys/wait.h> | |
42 | #include <sys/errno.h> | |
43 | #include <setjmp.h> | |
44 | #include <syslog.h> | |
45 | #include <ttyent.h> | |
46 | #include <string.h> | |
47 | ||
48 | #include "init.h" | |
49 | #include "prototypes.h" | |
9a6eb889 | 50 | #include "libutil.h" |
800ffe89 NW |
51 | |
52 | ||
53 | /* global variables, preset to their defaults */ | |
800ffe89 NW |
54 | int timeout_m2s_TERM = INIT_M2S_TERMTO; |
55 | int timeout_m2s_KILL = INIT_M2S_KILLTO; | |
56 | int retrytime = RETRYTIME; | |
57 | int startup_single = 0; | |
58 | int checkonly = 0; | |
800ffe89 | 59 | int force_single = -1; |
9a6eb889 NW |
60 | #ifdef DEBUG |
61 | int force_debug = -1; | |
62 | int debug = DEBUG_LEVEL; | |
63 | #endif | |
800ffe89 NW |
64 | #ifdef CONFIGURE |
65 | char *config_file = INIT_CONFIG; | |
66 | #endif | |
67 | ||
68 | static ttytab_t *ttytab = (ttytab_t *)0; | |
69 | static callout_t *callout_tab = (callout_t *)0; | |
70 | static callout_t *callout_free = (callout_t *)0; | |
71 | static int callout_nfree = 0; | |
72 | sigset_t block_set; | |
73 | jmp_buf boing_singleuser, | |
74 | boing_single2multi, | |
75 | boing_multiuser, | |
76 | boing_multi2single, | |
77 | boing_waitforboot, | |
78 | *boing_m2stimeout; | |
79 | ||
80 | static enum { SINGLEUSER, MULTIUSER, SINGLE2MULTI, MULTI2SINGLE } | |
81 | State; | |
82 | ||
83 | struct ttyent RCent_auto = { | |
84 | "console", | |
85 | "/bin/sh sh /etc/rc autoboot", | |
86 | "dumb", | |
87 | TTY_ON | TTY_SECURE, | |
88 | 0, | |
89 | 0 | |
90 | }; | |
91 | struct ttyent RCent_fast = { | |
92 | "console", | |
93 | "/bin/sh sh /etc/rc", | |
94 | "dumb", | |
95 | TTY_ON | TTY_SECURE, | |
96 | 0, | |
97 | 0 | |
98 | }; | |
99 | struct ttyent Single_ent = { | |
100 | "console", | |
101 | "/bin/sh -", | |
102 | "pc3", | |
103 | TTY_ON | TTY_SECURE, | |
104 | 0, | |
105 | 0 | |
106 | }; | |
107 | static struct ttyent *RCent = &RCent_auto; | |
108 | static struct ttyent *Singlesh = &Single_ent; | |
109 | ||
110 | ||
111 | ||
112 | ||
113 | /********************************************************** | |
114 | * Main * | |
115 | **********************************************************/ | |
116 | void | |
117 | main(argc, argv) | |
118 | int argc; | |
119 | char **argv; | |
120 | { | |
121 | ||
122 | ||
123 | /* make it a session leader */ | |
124 | (void) setsid(); | |
125 | ||
126 | /* initialize syslog */ | |
127 | openlog("init", LOG_CONS | LOG_PID, LOG_DAEMON); | |
128 | ||
129 | ||
130 | /* parse command line */ | |
131 | while(argc > 1) { | |
132 | if(!strcmp(argv[1], "-s")) /* Singleuser */ | |
133 | force_single = startup_single = 1; | |
134 | ||
135 | else if(!strcmp(argv[1], "-f")) /* Fastboot */ | |
136 | RCent = &RCent_fast; | |
137 | ||
9a6eb889 | 138 | #ifdef DEBUG |
800ffe89 NW |
139 | else if (!strcmp(argv[1], "-d")) /* Debug level */ |
140 | if (argc > 2) { | |
141 | if ((force_debug = str2u(argv[2])) >= 0) { | |
142 | debug = force_debug; | |
143 | argc --; argv++; | |
144 | } else | |
145 | syslog(LOG_ERR, "option -d needs positive integer argument"); | |
146 | } else | |
147 | syslog(LOG_ERR, "option -d needs an argument"); | |
9a6eb889 | 148 | #endif |
800ffe89 NW |
149 | #ifdef CONFIGURE |
150 | else if (!strcmp(argv[1], "-C")) /* Configuration file */ | |
151 | if (argc > 2) { | |
152 | config_file = argv[2]; | |
153 | argc--; argv++; | |
154 | } else | |
155 | syslog(LOG_ERR, "option -C needs an argument"); | |
156 | ||
157 | else if (!strcmp(argv[1], "-S")) /* Syntaxcheck only */ | |
158 | checkonly = 1; | |
159 | #endif | |
160 | else if (!strcmp(argv[1], "-")) /* ignore this */ | |
161 | ; | |
9ea48534 NW |
162 | else if (!strcmp(argv[1], "--")) /* ... and this */ |
163 | ; | |
800ffe89 NW |
164 | else |
165 | syslog(LOG_ERR, "unknown option \"%s\"", argv[1]); | |
166 | argc--; argv++; | |
167 | } | |
168 | ||
169 | ||
170 | #ifndef TESTRUN | |
171 | /* did some idiot try to run init ? */ | |
172 | if((getpid() != 1) && !checkonly) { | |
173 | const char errmsg[] = "init: system daemon, not runnable by user\r\n"; | |
174 | write(2, errmsg, strlen(errmsg)); | |
175 | exit(0xff); | |
176 | } | |
177 | #endif /* ! TESTRUN */ | |
178 | ||
179 | ||
180 | #ifdef CONFIGURE | |
181 | /* read the default configuration (limits etc) */ | |
182 | getconf(); | |
183 | /* read configuration file */ | |
184 | configure(config_file); | |
185 | /* set global configuration parameters */ | |
186 | checkconf(); | |
187 | if (checkonly) | |
188 | exit(0); | |
800ffe89 NW |
189 | |
190 | /* values configured by command-line arguments take precedence */ | |
191 | /* over values in the config file */ | |
9a6eb889 | 192 | # ifdef DEBUG |
800ffe89 NW |
193 | if (force_debug >= 0) |
194 | debug = force_debug; | |
9a6eb889 | 195 | # endif |
800ffe89 NW |
196 | if (force_single >= 0) |
197 | startup_single = force_single; | |
9a6eb889 | 198 | #endif |
800ffe89 NW |
199 | |
200 | /* | |
201 | * initialize callout table | |
202 | */ | |
203 | allocate_callout(); | |
204 | ||
205 | /* | |
206 | * initialize the longjmp buffers; | |
207 | * after a longjmp(), the appropriate function is called and | |
208 | * does not return. | |
209 | */ | |
210 | if (setjmp(boing_singleuser)) | |
211 | singleuser(); | |
212 | if (setjmp(boing_single2multi)) | |
213 | single2multi(); | |
214 | if (setjmp(boing_multiuser)) | |
215 | multiuser(); | |
216 | if (setjmp(boing_multi2single)) | |
217 | multi2single(); | |
218 | if (setjmp(boing_waitforboot)) | |
219 | waitforboot(); | |
220 | ||
221 | /* install signal handlers for catched signals */ | |
222 | signal(SIGTSTP, sig_tstp); | |
223 | signal(SIGTERM, sig_term); | |
224 | signal(SIGHUP, sig_hup); | |
225 | signal(SIGALRM, sig_alrm); | |
226 | #ifdef DEBUG | |
227 | signal(SIGUSR1, sig_usr1); | |
228 | signal(SIGUSR2, sig_usr2); | |
229 | #endif | |
230 | #ifdef CONFIGURE | |
231 | signal(SIGTTIN, sig_ttin); | |
232 | #endif | |
233 | #if defined (UNTRUSTED) && !defined (TESTRUN) | |
234 | signal(SIGINT, sig_int); | |
235 | #endif | |
236 | ||
237 | /* define Set of signals to be blocked for critical parts */ | |
238 | (void) sigemptyset (&block_set); | |
239 | (void) sigaddset (&block_set, SIGTSTP); | |
240 | (void) sigaddset (&block_set, SIGTERM); | |
241 | (void) sigaddset (&block_set, SIGHUP); | |
242 | (void) sigaddset (&block_set, SIGUSR1); | |
243 | (void) sigaddset (&block_set, SIGUSR2); | |
244 | (void) sigaddset (&block_set, SIGALRM); | |
245 | ||
246 | /* Action ! */ | |
247 | if (startup_single) | |
248 | longjmp(boing_singleuser, 1); | |
249 | else | |
250 | longjmp(boing_single2multi, 1); | |
251 | ||
252 | /* NOTREACHED */ | |
253 | } | |
254 | ||
255 | ||
256 | ||
257 | /********************************************************** | |
258 | * Signal Handlers * | |
259 | **********************************************************/ | |
260 | ||
261 | /* TSTP -- wait for children, but don't spawn new ones */ | |
262 | void | |
263 | sig_tstp(sig) | |
264 | int sig; | |
265 | { | |
266 | Debug(3, "TSTP Signal received"); | |
267 | longjmp(boing_waitforboot, 2); | |
268 | } | |
269 | ||
270 | ||
271 | /* TERM -- Go to singleuser mode */ | |
272 | void | |
273 | sig_term(sig) | |
274 | int sig; | |
275 | { | |
276 | Debug(3, "Terminate Signal received"); | |
277 | longjmp(boing_multi2single, 2); | |
278 | } | |
279 | ||
280 | ||
281 | /* HUP -- Reread /etc/ttys file */ | |
282 | void | |
283 | sig_hup(sig) | |
284 | int sig; | |
285 | { | |
286 | Debug(3, "Hangup Signal received"); | |
287 | if (State == MULTIUSER) | |
288 | longjmp(boing_multiuser, 2); | |
289 | } | |
290 | ||
291 | ||
292 | /* ALRM -- Timeout Signal */ | |
293 | void | |
294 | sig_alrm(sig) | |
295 | int sig; | |
296 | { | |
297 | Debug(3, "Alarm Signal received"); | |
298 | if (callout_tab) | |
299 | do_callout(); | |
300 | } | |
301 | ||
302 | ||
303 | #ifdef DEBUG | |
304 | /* USR1 -- Increment debugging level */ | |
305 | void | |
306 | sig_usr1(sig) | |
307 | int sig; | |
308 | { | |
309 | debug++; | |
310 | if (debug == 1) | |
311 | Debug(0, "I will chat like a gossip"); | |
312 | else | |
313 | Debug(0, "I will chat like %d gossips", debug); | |
314 | } | |
315 | ||
316 | /* USR2 -- switch off debugging */ | |
317 | void | |
318 | sig_usr2(sig) | |
319 | int sig; | |
320 | { | |
321 | Debug(0, "OK, I will shut up now."); | |
322 | debug = 0; | |
323 | } | |
324 | #endif | |
325 | ||
326 | #if defined (UNTRUSTED) && !defined (TESTRUN) | |
327 | /* INT -- execute original init (Signal can be generated from the kernel | |
328 | debugger with 'call pfind(1)' and then 'call psignal(XXXXX, 2)' | |
329 | where XXXXX is the return value of the pfind call). | |
330 | This isn't very pretty, but it saved me from booting from floppy | |
331 | disk many times. */ | |
332 | void | |
333 | sig_int(sig) | |
334 | int sig; | |
335 | { | |
336 | Debug(0, "Interrupt signal received; trying to execute /sbin/init.ori"); | |
337 | Debug(0, "(Are you not satisfied with me ?)"); | |
338 | kill (-1, SIGKILL); | |
339 | execl("/sbin/init.ori", "init", "-s", 0); | |
340 | Debug(0, "Could not execute /sbin/init.ori (%m)"); | |
341 | longjmp(boing_multi2single, 1); | |
342 | } | |
343 | #endif /* UNTRUSTED */ | |
344 | ||
345 | ||
346 | #ifdef CONFIGURE | |
347 | /* TTIN -- reread configuration file; only valid when in singleuser mode */ | |
348 | void | |
349 | sig_ttin(sig) | |
350 | int sig; | |
351 | { | |
352 | if (State == SINGLEUSER) { | |
353 | blocksig(); | |
354 | Debug(0, "TTIN signal received, re-reading configuration file"); | |
355 | setconf(); | |
356 | configure(config_file); | |
357 | checkconf(); | |
358 | unblocksig(); | |
359 | } else | |
360 | syslog(LOG_NOTICE, "TTIN signal received, but not in singleuser mode"); | |
361 | } | |
362 | #endif | |
363 | ||
364 | ||
365 | ||
366 | /********************************************************** | |
367 | * SingleUserMode * | |
368 | **********************************************************/ | |
369 | ||
370 | void | |
371 | singleuser(void) | |
372 | { | |
373 | int status; | |
374 | ||
375 | ||
376 | State = SINGLEUSER; | |
377 | clear_callout(); | |
378 | Debug(1, "Entered State singleuser"); | |
379 | ||
380 | if (ttytab) { | |
381 | syslog(LOG_ERR, "internal error: multiple users in singleusermode"); | |
382 | longjmp(boing_multi2single, 1); | |
383 | } | |
384 | ||
385 | ||
386 | RCent = &RCent_fast; | |
387 | blocksig(); | |
388 | ttytab = ent_to_tab(Singlesh, (ttytab_t *)0, ttytab, INIT_NODEV | INIT_OPEN | INIT_ARG0); | |
389 | unblocksig(); | |
390 | if (do_getty(ttytab, 0) < 0) { | |
391 | syslog(LOG_EMERG, "Unable to start singleuser shell"); | |
392 | sync(); sleep(1); | |
393 | _exit(1); /* What else should we do about this ? */ | |
394 | } | |
395 | ||
396 | #ifndef TESTRUN | |
397 | while(wait(&status) != ttytab->pid); | |
398 | #else | |
399 | scanf("%d\n", &status); /* XXX */ | |
400 | #endif | |
401 | Debug(1, "Singleusershell exited with status %d", status); | |
402 | ||
403 | ||
404 | blocksig(); | |
405 | ttytab = free_tty(ttytab, ttytab); | |
406 | unblocksig(); | |
407 | ||
408 | longjmp(boing_single2multi, 1); | |
409 | /* NOTREACHED */ | |
410 | } | |
411 | ||
412 | ||
413 | ||
414 | /********************************************************** | |
415 | * Single 2 Multi * | |
416 | **********************************************************/ | |
417 | ||
418 | void | |
419 | single2multi(void) | |
420 | { | |
421 | int status; | |
422 | ||
423 | ||
424 | State = SINGLE2MULTI; | |
425 | clear_callout(); | |
426 | Debug(1, "Entered State single2multi"); | |
427 | ||
428 | if (ttytab) { | |
429 | syslog(LOG_ERR, "internal error: users in single2multi"); | |
430 | longjmp(boing_multi2single, 1); | |
431 | } | |
432 | ||
433 | ||
434 | blocksig(); | |
435 | ttytab = ent_to_tab(RCent, (ttytab_t *)0, ttytab, INIT_NODEV | INIT_OPEN | INIT_ARG0); | |
436 | unblocksig(); | |
437 | if (do_getty(ttytab, 0) < 0) { | |
438 | syslog(LOG_ERR, "Unable to execute /etc/rc"); | |
439 | ttytab = free_tty(ttytab, ttytab); | |
440 | longjmp(boing_singleuser, 2); | |
441 | } | |
442 | ||
443 | #ifndef TESTRUN | |
444 | while(wait(&status) != ttytab->pid); | |
445 | #else | |
446 | scanf("%d\n", &status); | |
447 | #endif | |
448 | Debug(1, "/etc/rc exited with status %d", status); | |
449 | ||
450 | ||
451 | blocksig(); | |
452 | ttytab = free_tty(ttytab, ttytab); | |
453 | unblocksig(); | |
454 | ||
455 | if (status) | |
456 | longjmp(boing_singleuser, 1); | |
9a6eb889 NW |
457 | else { |
458 | logwtmp("~", "reboot", ""); | |
800ffe89 | 459 | longjmp(boing_multiuser, 1); |
9a6eb889 | 460 | } |
800ffe89 NW |
461 | /* NOTREACHED */ |
462 | } | |
463 | ||
464 | ||
465 | ||
466 | /********************************************************** | |
467 | * WaitForBoot * | |
468 | **********************************************************/ | |
469 | ||
470 | void | |
471 | waitforboot(void) | |
472 | { | |
473 | int status; | |
474 | pid_t pid; | |
475 | ttytab_t *tt; | |
476 | ||
477 | ||
478 | ||
479 | /* Note that the State variable is not set here */ | |
480 | clear_callout(); | |
481 | Debug(1, "Entered State waitforboot"); | |
482 | ||
483 | while (1) { | |
484 | pid = wait(&status); | |
485 | if (pid < 0) | |
486 | pause(); | |
487 | else { | |
488 | Debug(4, "Process %d exited with status %d", pid, status); | |
489 | for (tt=ttytab; tt; tt = tt->next) | |
490 | if (tt->pid == pid) { | |
491 | blocksig(); | |
492 | ttytab = free_tty(ttytab, tt); | |
493 | unblocksig(); | |
494 | break; | |
495 | } | |
496 | } | |
497 | } | |
498 | /* NOTREACHED */ | |
499 | } | |
500 | ||
501 | ||
502 | ||
503 | /********************************************************** | |
504 | * MultiUser * | |
505 | **********************************************************/ | |
506 | ||
507 | void | |
508 | multiuser(void) | |
509 | { | |
510 | ttytab_t *tt; | |
511 | struct ttyent *tent; | |
512 | int pid; | |
513 | int status; | |
514 | ||
515 | ||
516 | ||
517 | State = MULTIUSER; | |
518 | clear_callout(); | |
519 | Debug(1, "Entered State multiuser"); | |
520 | ||
521 | /* First, (re)build ttytab based on what is in /etc/ttys */ | |
522 | blocksig(); | |
523 | setttyent(); | |
524 | ||
525 | for (tt = ttytab; tt; tt = tt->next) | |
526 | tt->intflags &= ~(INIT_SEEN | INIT_CHANGED | INIT_NEW); | |
527 | ||
528 | while ((tent = getttyent())) | |
529 | if (tent->ty_status & TTY_ON) { | |
530 | for (tt = ttytab; tt; tt = tt->next) | |
531 | if (!strcmp(tent->ty_name, tt->name)) | |
532 | break; | |
533 | ttytab = ent_to_tab(tent, tt, ttytab, 0); | |
534 | } | |
535 | ||
536 | unblocksig(); | |
537 | ||
538 | /* Kill the processes whose entries are deleted or changed */ | |
539 | /* Also start the getty process on the lines that were just added */ | |
540 | for (tt = ttytab; tt; tt = tt->next) | |
541 | if (!(tt->intflags & INIT_SEEN)) { | |
542 | Debug(5, "killing %s (PID %d): Not seen", tt->name, tt->pid); | |
543 | kill (tt->pid, SIGKILL); | |
544 | tt->intflags |= INIT_DONTSPAWN; | |
545 | } | |
546 | else if (tt->intflags & INIT_NEW) | |
547 | (void)do_getty(tt, 0); | |
548 | else if (tt->intflags & INIT_CHANGED) { | |
549 | Debug(5, "killing %s (PID %d): Changed", tt->name, tt->pid); | |
550 | kill (tt->pid, SIGKILL); | |
551 | } | |
552 | else if (tt->intflags & INIT_FAILSLEEP) { | |
553 | Debug(5, "continuing %s (PID %d)", tt->name, tt->pid); | |
554 | #define UNSLEEP(a) | |
555 | UNSLEEP(tt->pid); | |
556 | tt->intflags &= ~INIT_FAILED | INIT_FAILSLEEP; | |
557 | do_getty(tt, 0); | |
558 | } | |
559 | ||
560 | ||
561 | /* Now handle terminating children and respawn gettys for lines */ | |
562 | while (1) { | |
563 | pid = wait(&status); | |
564 | if (pid < 0) { | |
565 | switch (errno) { | |
566 | case EINTR: break; | |
567 | case ECHILD: | |
568 | syslog(LOG_ERR, "wait() found no child processes -- going singleuser."); | |
569 | longjmp(boing_multi2single, 2); | |
570 | default: | |
571 | syslog(LOG_ERR, "wait() failed: %m"); | |
572 | sleep(5); | |
573 | } | |
574 | } else { | |
575 | Debug(4, "Process %d terminated with status %d", pid, status); | |
576 | for (tt = ttytab; tt; tt = tt->next) | |
577 | if (pid == tt->pid) | |
578 | if (tt->intflags & INIT_DONTSPAWN) { | |
579 | blocksig(); | |
580 | ttytab = free_tty(ttytab, tt); | |
581 | unblocksig(); | |
582 | } | |
583 | else | |
584 | (void)do_getty(tt, 0); | |
585 | } | |
586 | } | |
587 | /* NOTREACHED */ | |
588 | } | |
589 | ||
590 | ||
591 | ||
592 | /********************************************************** | |
593 | * Multi2Single * | |
594 | **********************************************************/ | |
595 | ||
596 | void | |
597 | multi2single(void) | |
598 | { | |
599 | static jmp_buf boing_timeout; | |
600 | pid_t pid; | |
601 | int status; | |
602 | volatile int round; | |
603 | ||
604 | ||
605 | State = MULTI2SINGLE; | |
606 | clear_callout(); | |
607 | Debug(1, "Entering State multi2single"); | |
608 | ||
609 | /* forget about the gettys */ | |
610 | blocksig(); | |
611 | while (ttytab) | |
612 | ttytab = free_tty(ttytab, ttytab); | |
613 | unblocksig(); | |
614 | ||
615 | /* | |
616 | * round = 1: TERMinate children, then wait for them (default 10 seconds) | |
617 | * round = 2: KILL children, then wait for them (default 30 seconds) | |
618 | * round = 3: timeout expired; go to singleuser mode | |
619 | */ | |
620 | round = 0; | |
621 | setjmp(boing_timeout); | |
622 | boing_m2stimeout = &boing_timeout; | |
623 | round ++; | |
624 | if (round < 3) { | |
625 | if (round == 1){ | |
626 | Debug(3, "TERMinating processes"); | |
627 | kill (-1, SIGTERM); | |
628 | kill (-1, SIGCONT); | |
629 | callout (timeout_m2s_TERM, CO_MUL2SIN, (void *)0); | |
630 | } | |
631 | else { | |
632 | Debug(3, "KILLing processes"); | |
633 | kill (-1, SIGKILL); | |
634 | kill (-1, SIGCONT); | |
635 | callout (timeout_m2s_KILL, CO_MUL2SIN, (void *)0); | |
636 | } | |
637 | while ((pid = wait(&status)) >= 0) | |
638 | Debug(4, "Process %d exited with status %d", pid, status); | |
639 | Debug(2, "Wait returned error: %m"); | |
640 | } | |
641 | else | |
642 | syslog(LOG_NOTICE, "There are still some (hung) processes."); | |
643 | ||
644 | /* We don't need no steenkin timeout any more... */ | |
645 | boing_m2stimeout = (jmp_buf *)0; | |
646 | ||
647 | /* Jump ! (Rein ins Vergnuegen) */ | |
648 | longjmp(boing_singleuser, 2); | |
649 | /* NOTREACHED */ | |
650 | } | |
651 | ||
652 | ||
653 | ||
654 | /********************************************************** | |
655 | * Callout * | |
656 | * Schedule a retry operation for a later time * | |
657 | **********************************************************/ | |
658 | void | |
659 | callout(when, type, arg) | |
660 | unsigned int when; | |
661 | retr_t type; | |
662 | void *arg; | |
663 | { | |
664 | callout_t *ntp, | |
665 | *ctp, | |
666 | *octp; | |
667 | ||
668 | ||
669 | Debug(3, "Scheduling callout in %d seconds.", when); | |
670 | blocksig(); | |
671 | ||
672 | /* find a free callout entry */ | |
673 | if (callout_nfree <= CALLOUT_MINFREE) | |
674 | allocate_callout(); | |
675 | ntp = callout_free; | |
676 | if (!ntp) { | |
677 | syslog(LOG_WARNING, "Callout table is full !"); | |
678 | return; | |
679 | } | |
680 | callout_free = ntp->next; | |
681 | callout_nfree --; | |
682 | ||
683 | /* look at which point we put it in the callout list */ | |
684 | when += (unsigned int)time(NULL); | |
685 | for (octp = NULL, ctp = callout_tab; ctp; octp = ctp, ctp = ctp->next) | |
686 | if (when < ctp->sleept) | |
687 | break; | |
688 | else | |
689 | when -= ctp->sleept; | |
690 | ||
691 | ||
692 | if (octp) | |
693 | octp->next = ntp; | |
694 | else | |
695 | callout_tab = ntp; | |
696 | ntp->next = ctp; | |
697 | ntp->sleept = when; | |
698 | if (ctp) ctp->sleept -= when; | |
699 | ntp->what = type; | |
700 | ntp->arg = arg; | |
701 | ||
702 | /* schedule alarm */ | |
703 | when = callout_tab->sleept - (unsigned int)time(NULL); | |
704 | if (when <= 0) { | |
705 | Debug(4, "Next callout: NOW !"); | |
706 | alarm(0); | |
707 | kill (getpid(), SIGALRM); | |
708 | } else | |
709 | Debug(4, "Next callout in %d seconds.", when); | |
710 | alarm(when); | |
711 | ||
712 | unblocksig(); | |
713 | } | |
714 | ||
715 | ||
716 | /********************************************************** | |
717 | * Allocate_Callout * | |
718 | * allocate (further) elements to the callout table * | |
719 | *********************************************************/ | |
720 | void | |
721 | allocate_callout(void) | |
722 | { | |
723 | callout_t *ntp; | |
724 | int i; | |
725 | ||
726 | ||
727 | ntp = malloc(sizeof(callout_t) * CALLOUT_CHUNK); | |
728 | if (ntp) { | |
729 | for (i=1; i< CALLOUT_CHUNK; i++) | |
730 | ntp[i].next = &ntp[i-1]; | |
731 | ntp->next = callout_free; | |
732 | callout_free = &ntp[i-1]; | |
733 | callout_nfree += CALLOUT_CHUNK; | |
734 | } | |
735 | } | |
736 | ||
737 | ||
738 | /********************************************************** | |
739 | * Clear_Callout * | |
740 | * Removes all callout entries * | |
741 | *********************************************************/ | |
742 | void | |
743 | clear_callout(void) | |
744 | { | |
745 | callout_t *ctp, | |
746 | *nctp; | |
747 | ||
748 | ||
749 | if (callout_tab) | |
750 | Debug(4, "All callouts for today cancelled."); | |
751 | blocksig(); | |
752 | alarm(0); | |
753 | for (ctp = callout_tab; ctp; ctp = nctp) { | |
754 | nctp = ctp->next; | |
755 | ctp->next = callout_free; | |
756 | callout_free = ctp; | |
757 | callout_nfree ++; | |
758 | } | |
9ea48534 | 759 | callout_tab = (callout_t *)0; |
800ffe89 NW |
760 | unblocksig(); |
761 | } | |
762 | ||
763 | ||
764 | ||
765 | /********************************************************** | |
766 | * Do_Callout * | |
767 | * calls the callback routines when the time has expired * | |
768 | *********************************************************/ | |
769 | void | |
770 | do_callout(void) | |
771 | { | |
772 | callout_t *ctp; | |
773 | unsigned int now; | |
774 | ||
775 | ||
776 | now = (unsigned int) time(NULL); | |
777 | for (ctp = callout_tab; ctp;) { | |
778 | if (ctp->sleept > now) | |
779 | break; | |
780 | ctp = ctp->next; | |
781 | if (ctp) | |
782 | ctp->sleept += callout_tab->sleept; | |
783 | callout_tab->next = callout_free; | |
784 | callout_free = callout_tab; | |
785 | callout_tab = ctp; | |
786 | callout_nfree ++; | |
787 | ||
788 | switch (callout_free->what) { | |
789 | case CO_ENT2TAB: | |
790 | Debug(3, "Callout -> Multiuser"); | |
791 | longjmp(boing_multiuser, 2); | |
792 | case CO_FORK: | |
793 | case CO_GETTY: | |
794 | Debug(3, "Callout -> do_getty()"); | |
795 | (void)do_getty((ttytab_t *)callout_free->arg, 0); | |
796 | break; | |
797 | case CO_MUL2SIN: | |
798 | Debug(3, "Callout -> M2S timeout"); | |
799 | if (boing_m2stimeout) | |
800 | longjmp(*boing_m2stimeout, 2); | |
801 | } | |
802 | } | |
803 | ||
804 | /* schedule next alarm */ | |
805 | if (callout_tab) { | |
806 | Debug(4, "Next callout in %d seconds.", callout_tab->sleept - now); | |
807 | alarm(callout_tab->sleept - now); | |
808 | } | |
809 | } | |
810 | ||
811 | ||
812 | /********************************************************** | |
813 | * SignalsForChile * | |
814 | * Set up signals for the child processes * | |
815 | *********************************************************/ | |
816 | void | |
817 | signalsforchile(void) | |
818 | { | |
819 | signal(SIGTSTP, SIG_DFL); | |
820 | signal(SIGTERM, SIG_DFL); | |
821 | signal(SIGHUP , SIG_DFL); | |
822 | signal(SIGUSR1, SIG_DFL); | |
823 | signal(SIGUSR2, SIG_DFL); | |
824 | signal(SIGALRM, SIG_DFL); | |
825 | signal(SIGINT, SIG_DFL); | |
826 | signal(SIGTTIN, SIG_DFL); | |
827 | unblocksig(); | |
828 | } |