]> git.ipfire.org Git - thirdparty/util-linux.git/blob - login-utils/simpleinit.c
Imported from util-linux-2.11b tarball.
[thirdparty/util-linux.git] / login-utils / simpleinit.c
1 /* simpleinit.c - poe@daimi.aau.dk */
2 /* Version 2.0.1 */
3
4 /* 1999-02-22 Arkadiusz Mi¶kiewicz <misiek@pld.ORG.PL>
5 * - added Native Language Support
6 * 2001-01-25 Richard Gooch <rgooch@atnf.csiro.au>
7 * - fixed bug with failed services so they may be later "reclaimed"
8 * 2001-02-02 Richard Gooch <rgooch@atnf.csiro.au>
9 * - fixed race when reading from pipe and reaping children
10 * 2001-02-18 sam@quux.dropbear.id.au
11 * - fixed bug in <get_path>: multiple INIT_PATH components did not work
12 */
13
14 #include <sys/types.h>
15 #include <stdlib.h>
16 #include <unistd.h>
17 #include <stdio.h>
18 #include <ctype.h>
19 #include <fcntl.h>
20 #include <string.h>
21 #include <signal.h>
22 #include <pwd.h>
23 #include <sys/file.h>
24 #include <sys/wait.h>
25 #include <sys/stat.h>
26 #include <sys/sysmacros.h>
27 #include <sys/time.h>
28 #include <sys/ioctl.h>
29 #include <dirent.h>
30 #include <termios.h>
31 #include <utmp.h>
32 #include <setjmp.h>
33 #include <sched.h>
34 #ifdef SHADOW_PWD
35 # include <shadow.h>
36 #endif
37 #include "my_crypt.h"
38 #include "pathnames.h"
39 #include "linux_reboot.h"
40 #include "xstrncpy.h"
41 #include "nls.h"
42 #include "simpleinit.h"
43
44 #define CMDSIZ 150 /* max size of a line in inittab */
45 #define NUMCMD 30 /* max number of lines in inittab */
46 #define NUMTOK 20 /* max number of tokens in inittab command */
47 #define PATH_SIZE (CMDSIZ+CMDSIZ+1)
48
49 #define MAX_RESPAWN_RATE 5 /* number of respawns per 100 seconds */
50
51 #define TZFILE "/etc/TZ"
52 char tzone[CMDSIZ];
53 /* #define DEBUGGING */
54
55 /* Define this if you want init to ignore the termcap field in inittab for
56 console ttys. */
57 /* #define SPECIAL_CONSOLE_TERM */
58
59 #define ever (;;)
60
61 struct initline {
62 pid_t pid;
63 char tty[10];
64 char termcap[30];
65 char *toks[NUMTOK];
66 char line[CMDSIZ];
67 struct timeval last_start;
68 signed long rate;
69 };
70
71 struct initline inittab[NUMCMD];
72 int numcmd;
73 int stopped = 0; /* are we stopped */
74 static char boot_prog[PATH_SIZE] = _PATH_RC;
75 static char script_prefix[PATH_SIZE] = "\0";
76 static char final_prog[PATH_SIZE] = "\0";
77 static char init_path[PATH_SIZE] = "\0";
78 static int caught_sigint = 0;
79 static const char *initctl_name = "/dev/initctl";
80 static int initctl_fd = -1;
81 static volatile int do_longjmp = 0;
82 static sigjmp_buf jmp_env;
83
84
85 static void do_single (void);
86 static int do_rc_tty (const char *path);
87 static int process_path (const char *path, int (*func) (const char *path),
88 int ignore_dangling_symlink);
89 static int preload_file (const char *path);
90 static int run_file (const char *path);
91 static void spawn (int i), read_inittab (void);
92 static void hup_handler (int sig);
93 static void sigtstp_handler (int sig);
94 static void int_handler (int sig);
95 static void sigchild_handler (int sig);
96 static void sigquit_handler (int sig);
97 static void sigterm_handler (int sig);
98 #ifdef SET_TZ
99 static void set_tz (void);
100 #endif
101 static void write_wtmp (void);
102 static pid_t mywait (int *status);
103 static int run_command (const char *file, const char *name, pid_t pid);
104
105
106 static void err (char *s)
107 {
108 int fd;
109
110 if((fd = open("/dev/console", O_WRONLY)) < 0) return;
111
112 write(fd, "init: ", 6);
113 write(fd, s, strlen(s));
114 close(fd);
115 }
116
117 static void enter_single (void)
118 {
119 pid_t pid;
120 int i;
121
122 err(_("Booting to single user mode.\n"));
123 if((pid = fork()) == 0) {
124 /* the child */
125 execl(_PATH_BSHELL, _PATH_BSHELL, NULL);
126 err(_("exec of single user shell failed\n"));
127 } else if(pid > 0) {
128 while (waitpid (pid, &i, 0) != pid) /* Nothing */;
129 } else if(pid < 0) {
130 err(_("fork of single user shell failed\n"));
131 }
132 unlink(_PATH_SINGLE);
133 }
134
135 int main(int argc, char *argv[])
136 {
137 int vec,i;
138 int want_single = 0;
139 pid_t pid;
140 struct sigaction sa;
141
142
143 #ifdef SET_TZ
144 set_tz();
145 #endif
146 signal (SIGINT, int_handler);
147 sigemptyset (&sa.sa_mask);
148 sa.sa_flags = 0;
149 sa.sa_handler = sigtstp_handler;
150 sigaction (SIGTSTP, &sa, NULL);
151 sa.sa_handler = sigterm_handler;
152 sigaction (SIGTERM, &sa, NULL);
153 sa.sa_handler = sigchild_handler;
154 sigaction (SIGCHLD, &sa, NULL);
155 sa.sa_handler = sigquit_handler;
156 sigaction (SIGQUIT, &sa, NULL);
157
158 setlocale(LC_ALL, "");
159 bindtextdomain(PACKAGE, LOCALEDIR);
160 textdomain(PACKAGE);
161
162 my_reboot (LINUX_REBOOT_CMD_CAD_OFF);
163 /* Find script to run. Command-line overrides config file overrides
164 built-in default */
165 for (i = 0; i < NUMCMD; i++) inittab[i].pid = -1;
166 read_inittab ();
167 for (i = 1; i < argc; i++) {
168 if (strcmp (argv[i], "single") == 0) want_single = 1;
169 else {
170 char path[PATH_SIZE];
171
172 strcpy (path, script_prefix);
173 strcat (path, argv[i]);
174 if (access (path, R_OK | X_OK) == 0)
175 strcpy (boot_prog, path);
176 }
177 }
178
179 if ( ( initctl_fd = open (initctl_name, O_RDWR, 0) ) < 0 ) {
180 mkfifo (initctl_name, S_IRUSR | S_IWUSR);
181 if ( ( initctl_fd = open (initctl_name, O_RDWR, 0) ) < 0 )
182 err ( _("error opening fifo\n") );
183 }
184
185 if ( want_single || (access (_PATH_SINGLE, R_OK) == 0) ) do_single ();
186
187 /*If we get a SIGTSTP before multi-user mode, do nothing*/
188 while(stopped)
189 pause();
190
191 if ( do_rc_tty (boot_prog) ) do_single ();
192
193 while(stopped) /*Also if /etc/rc fails & we get SIGTSTP*/
194 pause();
195
196 write_wtmp(); /* write boottime record */
197 #ifdef DEBUGGING
198 for(i = 0; i < numcmd; i++) {
199 char **p;
200 p = inittab[i].toks;
201 printf("toks= %s %s %s %s\n",p[0], p[1], p[2], p[3]);
202 printf("tty= %s\n", inittab[i].tty);
203 printf("termcap= %s\n", inittab[i].termcap);
204 }
205 exit(0);
206 #endif
207 signal(SIGHUP, hup_handler);
208
209 for (i = 0; i < getdtablesize (); i++)
210 if (i != initctl_fd) close (i);
211
212 for(i = 0; i < numcmd; i++)
213 spawn(i);
214
215 if (final_prog[0] != '\0') {
216 switch ( fork () )
217 {
218 case 0: /* Child */
219 execl (final_prog, final_prog, "start", NULL);
220 err ( _("error running finalprog\n") );
221 _exit (1);
222 break;
223 case -1: /* Error */
224 err ( _("error forking finalprog\n") );
225 break;
226 default: /* Parent */
227 break;
228 }
229 }
230
231 for ever {
232 pid = mywait (&vec);
233 if (pid < 1) continue;
234
235 /* clear utmp entry, and append to wtmp if possible */
236 {
237 struct utmp *ut;
238 int ut_fd, lf;
239
240 utmpname(_PATH_UTMP);
241 setutent();
242 while((ut = getutent())) {
243 if(ut->ut_pid == pid) {
244 time(&ut->ut_time);
245 memset(&ut->ut_user, 0, UT_NAMESIZE);
246 memset(&ut->ut_host, 0, sizeof(ut->ut_host));
247 ut->ut_type = DEAD_PROCESS;
248 ut->ut_pid = 0;
249 ut->ut_addr = 0;
250 /*endutent();*/
251 pututline(ut);
252
253 if ((lf = open(_PATH_WTMPLOCK, O_CREAT|O_WRONLY, 0660)) >= 0) {
254 flock(lf, LOCK_EX|LOCK_NB);
255 if((ut_fd = open(_PATH_WTMP, O_APPEND|O_WRONLY)) >= 0) {
256 write(ut_fd, ut, sizeof(struct utmp));
257 close(ut_fd);
258 }
259 flock(lf, LOCK_UN|LOCK_NB);
260 close(lf);
261 }
262 break;
263 }
264 }
265 endutent();
266 }
267
268 for(i = 0; i < numcmd; i++) {
269 if(pid == inittab[i].pid || inittab[i].pid < 0) {
270 if(stopped) inittab[i].pid = -1;
271 else spawn(i);
272 break;
273 }
274 }
275 }
276 }
277
278 #define MAXTRIES 3 /* number of tries allowed when giving the password */
279
280 /*
281 * return true if singleuser mode is allowed.
282 * If /etc/securesingle exists ask for root password, otherwise always OK.
283 */
284 static int check_single_ok (void)
285 {
286 char *pass, *rootpass = NULL;
287 struct passwd *pwd;
288 int i;
289
290 if (access (_PATH_SECURE, R_OK) != 0) return 1;
291 if ( ( pwd = getpwnam ("root") ) || ( pwd = getpwuid (0) ) )
292 rootpass = pwd->pw_passwd;
293 else
294 return 1; /* a bad /etc/passwd should not lock out */
295
296 for (i = 0; i < MAXTRIES; i++)
297 {
298 pass = getpass (_ ("Password: ") );
299 if (pass == NULL) continue;
300
301 if ( !strcmp (crypt (pass, rootpass), rootpass) ) return 1;
302
303 puts (_ ("\nWrong password.\n") );
304 }
305 return 0;
306 }
307
308 static void do_single (void)
309 {
310 char path[PATH_SIZE];
311
312 if (caught_sigint) return;
313 strcpy (path, script_prefix);
314 strcat (path, "single");
315 if (access (path, R_OK | X_OK) == 0)
316 if (do_rc_tty (path) == 0) return;
317 if ( check_single_ok () ) enter_single ();
318 } /* End Function do_single */
319
320 /*
321 * run boot script(s). The environment is passed to the script(s), so the RC
322 * environment variable can be used to decide what to do.
323 * RC may be set from LILO.
324 * [RETURNS] 0 on success (exit status convention), otherwise error.
325 */
326 static int do_rc_tty (const char *path)
327 {
328 int status;
329 pid_t pid, child;
330 sigset_t ss;
331
332 if (caught_sigint) return 0;
333 process_path (path, preload_file, 0);
334 /* Launch off a subprocess to start a new session (required for frobbing
335 the TTY) and capture control-C */
336 switch ( child = fork () )
337 {
338 case 0: /* Child */
339 for (status = 1; status < NSIG; status++) signal (status, SIG_DFL);
340 sigfillset (&ss);
341 sigprocmask (SIG_UNBLOCK, &ss, NULL);
342 sigdelset (&ss, SIGINT);
343 sigdelset (&ss, SIGQUIT);
344 setsid ();
345 ioctl (0, TIOCSCTTY, 0); /* I want my control-C */
346 sigsuspend (&ss); /* Should never return, should just be killed */
347 break; /* No-one else is controlled by this TTY now */
348 case -1: /* Error */
349 return (1);
350 /*break;*/
351 default: /* Parent */
352 break;
353 }
354 /* Parent */
355 process_path (path, run_file, 0);
356 while (1)
357 {
358 if ( ( pid = mywait (&status) ) == child )
359 return (WTERMSIG (status) == SIGINT) ? 0 : 1;
360 if (pid < 0) break;
361 }
362 kill (child, SIGKILL);
363 while (waitpid (child, NULL, 0) != child) /* Nothing */;
364 return 0;
365 } /* End Function do_rc_tty */
366
367 static int process_path (const char *path, int (*func) (const char *path),
368 int ignore_dangling_symlink)
369 {
370 struct stat statbuf;
371 DIR *dp;
372 struct dirent *de;
373
374 if (lstat (path, &statbuf) != 0)
375 {
376 err (_ ("lstat of path failed\n") );
377 return 1;
378 }
379 if ( S_ISLNK (statbuf.st_mode) )
380 {
381 if (stat (path, &statbuf) != 0)
382 {
383 if ( (errno == ENOENT) && ignore_dangling_symlink ) return 0;
384 err (_ ("stat of path failed\n") );
385 return 1;
386 }
387 }
388 if ( !( statbuf.st_mode & (S_IXUSR | S_IXGRP | S_IXOTH) ) ) return 0;
389 if ( !S_ISDIR (statbuf.st_mode) ) return (*func) (path);
390 if ( ( dp = opendir (path) ) == NULL )
391 {
392 err (_ ("open of directory failed\n") );
393 return 1;
394 }
395 while ( ( de = readdir (dp) ) != NULL )
396 {
397 int retval;
398 char newpath[PATH_SIZE];
399
400 if (de->d_name[0] == '.') continue;
401 retval = sprintf (newpath, "%s/%s", path, de->d_name);
402 if (newpath[retval - 1] == '~') continue; /* Common mistake */
403 if ( ( retval = process_path (newpath, func, 1) ) ) return retval;
404 }
405 closedir (dp);
406 return 0;
407 } /* End Function process_path */
408
409 static int preload_file (const char *path)
410 {
411 int fd;
412 char ch;
413
414 if ( ( fd = open (path, O_RDONLY, 0) ) < 0) return 0;
415 while (read (fd, &ch, 1) == 1) lseek (fd, 1024, SEEK_CUR);
416 close (fd);
417 return 0;
418 } /* End Function preload_file */
419
420 static int run_file (const char *path)
421 {
422 const char *ptr;
423
424 if ( ( ptr = strrchr ( (char *) path, '/' ) ) == NULL ) ptr = path;
425 else ++ptr;
426 return (run_command (path, ptr, 0) == SIG_FAILED) ? 1 : 0;
427 } /* End Function run_file */
428
429 static void spawn (int i)
430 {
431 pid_t pid;
432 int j;
433 signed long ds_taken;
434 struct timeval ct;
435
436 if (inittab[i].toks[0] == NULL) return;
437 /* Check if respawning too fast */
438 gettimeofday (&ct, NULL);
439 ds_taken = ct.tv_sec - inittab[i].last_start.tv_sec;
440 ds_taken *= 10;
441 ds_taken += (ct.tv_usec - inittab[i].last_start.tv_usec) / 100000;
442 if (ds_taken < 1)
443 ds_taken = 1;
444 inittab[i].rate = (9 * inittab[i].rate + 1000 / ds_taken) / 10;
445 if (inittab[i].rate > MAX_RESPAWN_RATE) {
446 char txt[256];
447
448 inittab[i].toks[0] = NULL;
449 inittab[i].pid = -1;
450 inittab[i].rate = 0;
451 sprintf (txt,"respawning: \"%s\" too fast: quenching entry\n",
452 inittab[i].tty);
453 err (_(txt));
454 return;
455 }
456
457 if((pid = fork()) < 0) {
458 inittab[i].pid = -1;
459 err(_("fork failed\n"));
460 return;
461 }
462 if(pid) {
463 /* this is the parent */
464 inittab[i].pid = pid;
465 inittab[i].last_start = ct;
466 sched_yield ();
467 return;
468 } else {
469 /* this is the child */
470 char term[40];
471 #ifdef SET_TZ
472 char tz[CMDSIZ];
473 #endif
474 char *env[3];
475
476 setsid();
477 for(j = 0; j < getdtablesize(); j++)
478 (void) close(j);
479
480 (void) sprintf(term, "TERM=%s", inittab[i].termcap);
481 env[0] = term;
482 env[1] = (char *)0;
483 #ifdef SET_TZ
484 (void) sprintf(tz, "TZ=%s", tzone);
485 env[1] = tz;
486 #endif
487 env[2] = (char *)0;
488
489 execve(inittab[i].toks[0], inittab[i].toks, env);
490 err(_("exec failed\n"));
491 sleep(5);
492 _exit(1);
493 }
494 }
495
496 static void read_inittab (void)
497 {
498 FILE *f;
499 char buf[CMDSIZ];
500 int i,j,k;
501 int has_prog = 0;
502 char *ptr, *getty;
503 char prog[PATH_SIZE];
504 #ifdef SPECIAL_CONSOLE_TERM
505 char tty[50];
506 struct stat stb;
507 #endif
508 char *termenv;
509
510 termenv = getenv("TERM"); /* set by kernel */
511 /* termenv = "vt100"; */
512
513 if(!(f = fopen(_PATH_INITTAB, "r"))) {
514 err(_("cannot open inittab\n"));
515 return;
516 }
517
518 prog[0] = '\0';
519 i = 0;
520 while(!feof(f) && i < NUMCMD - 2) {
521 if(fgets(buf, CMDSIZ - 1, f) == 0) break;
522 buf[CMDSIZ-1] = 0;
523
524 for(k = 0; k < CMDSIZ && buf[k]; k++) {
525 if ((buf[k] == '#') || (buf[k] == '\n')) {
526 buf[k] = 0; break;
527 }
528 }
529
530 if(buf[0] == 0 || buf[0] == '\n') continue;
531 ptr = strchr (buf, '=');
532 if (ptr) {
533 ptr++;
534 if ( !strncmp (buf, "bootprog", 8) ) {
535 while ( isspace (*ptr) ) ++ptr;
536 strcpy (prog, ptr);
537 has_prog = 1;
538 continue;
539 }
540 if ( !strncmp (buf, "fileprefix", 10) ) {
541 while ( isspace (*ptr) ) ++ptr;
542 strcpy (script_prefix, ptr);
543 continue;
544 }
545 if ( !strncmp (buf, "PATH", 4) ) {
546 while ( isspace (*ptr) ) ++ptr;
547 setenv ("PATH", ptr, 1);
548 continue;
549 }
550 if ( !strncmp (buf, "INIT_PATH", 9) ) {
551 while ( isspace (*ptr) ) ++ptr;
552 strcpy (init_path, ptr);
553 continue;
554 }
555 if ( !strncmp (buf, "finalprog", 8) ) {
556 while ( isspace (*ptr) ) ++ptr;
557 strcpy (final_prog, ptr);
558 continue;
559 }
560 }
561
562
563 (void) strcpy(inittab[i].line, buf);
564
565 (void) strtok(inittab[i].line, ":");
566 xstrncpy(inittab[i].tty, inittab[i].line, 10);
567 xstrncpy(inittab[i].termcap, strtok((char *)0, ":"), 30);
568
569 getty = strtok((char *)0, ":");
570 (void) strtok(getty, " \t\n");
571 inittab[i].toks[0] = getty;
572 j = 1;
573 while((ptr = strtok((char *)0, " \t\n")))
574 inittab[i].toks[j++] = ptr;
575 inittab[i].toks[j] = (char *)0;
576
577 #ifdef SPECIAL_CONSOLE_TERM
578 /* special-case termcap for the console ttys */
579 (void) sprintf(tty, "/dev/%s", inittab[i].tty);
580 if(!termenv || stat(tty, &stb) < 0) {
581 err(_("no TERM or cannot stat tty\n"));
582 } else {
583 /* is it a console tty? */
584 if(major(stb.st_rdev) == 4 && minor(stb.st_rdev) < 64)
585 xstrncpy(inittab[i].termcap, termenv, 30);
586 }
587 #endif
588
589 i++;
590 }
591 fclose(f);
592 numcmd = i;
593 if (has_prog) {
594 int len;
595 char path[PATH_SIZE];
596
597 strcpy (path, script_prefix);
598 strcat (path, prog);
599 len = strlen (path);
600 if (path[len - 1] == '/') path[len - 1] = '\0';
601 if (access (path, R_OK | X_OK) == 0)
602 strcpy (boot_prog, path);
603 }
604 }
605
606 static void hup_handler (int sig)
607 {
608 int i,j;
609 int oldnum;
610 struct initline savetab[NUMCMD];
611 int had_already;
612
613 (void) signal(SIGHUP, SIG_IGN);
614
615 memcpy(savetab, inittab, NUMCMD * sizeof(struct initline));
616 oldnum = numcmd;
617 read_inittab ();
618
619 for(i = 0; i < numcmd; i++) {
620 had_already = 0;
621 for(j = 0; j < oldnum; j++) {
622 if(!strcmp(savetab[j].tty, inittab[i].tty)) {
623 had_already = 1;
624 if((inittab[i].pid = savetab[j].pid) < 0)
625 spawn(i);
626 }
627 }
628 if(!had_already) spawn(i);
629 }
630
631 (void) signal(SIGHUP, hup_handler);
632 }
633
634 static void sigtstp_handler (int sig)
635 {
636 stopped = ~stopped;
637 if (!stopped) hup_handler (sig);
638 } /* End Function sigtstp_handler */
639
640 static void sigterm_handler (int sig)
641 {
642 int i;
643
644 for (i = 0; i < numcmd; i++)
645 if (inittab[i].pid > 0) kill (inittab[i].pid, SIGTERM);
646 } /* End Function sigterm_handler */
647
648 static void int_handler (int sig)
649 {
650 pid_t pid;
651
652 caught_sigint = 1;
653 sync();
654 sync();
655 pid = fork();
656 if (pid > 0)
657 return;
658 if (pid == 0) /* reboot properly... */
659 execl(_PATH_REBOOT, _PATH_REBOOT, (char *)0);
660
661 /* fork or exec failed, try the hard way... */
662 my_reboot(LINUX_REBOOT_CMD_RESTART);
663 }
664
665 static void sigchild_handler (int sig)
666 {
667 if (!do_longjmp) return;
668 siglongjmp (jmp_env, 1);
669 }
670
671 static void sigquit_handler (int sig)
672 {
673 execl (_PATH_REBOOT, _PATH_REBOOT, NULL); /* It knows pid=1 must sleep */
674 }
675
676 #ifdef SET_TZ
677 static void set_tz (void)
678 {
679 FILE *f;
680 int len;
681
682 if((f=fopen(TZFILE, "r")) == (FILE *)NULL) return;
683 fgets(tzone, CMDSIZ-2, f);
684 fclose(f);
685 if((len=strlen(tzone)) < 2) return;
686 tzone[len-1] = 0; /* get rid of the '\n' */
687 setenv("TZ", tzone, 0);
688 }
689 #endif
690
691 static void write_wtmp (void)
692 {
693 int fd, lf;
694 struct utmp ut;
695
696 memset((char *)&ut, 0, sizeof(ut));
697 strcpy(ut.ut_line, "~");
698 memset(ut.ut_name, 0, sizeof(ut.ut_name));
699 time(&ut.ut_time);
700 ut.ut_type = BOOT_TIME;
701
702 if ((lf = open(_PATH_WTMPLOCK, O_CREAT|O_WRONLY, 0660)) >= 0) {
703 flock(lf, LOCK_EX|LOCK_NB); /* make sure init won't hang */
704 if((fd = open(_PATH_WTMP, O_WRONLY|O_APPEND)) >= 0) {
705 write(fd, (char *)&ut, sizeof(ut));
706 close(fd);
707 }
708 flock(lf, LOCK_UN|LOCK_NB);
709 close(lf);
710 }
711 }
712
713
714 struct needer_struct
715 {
716 struct needer_struct *next;
717 pid_t pid;
718 };
719
720 struct service_struct
721 {
722 struct service_struct *prev, *next; /* Script services chain */
723 struct needer_struct *needers; /* Needers waiting for service */
724 struct script_struct *attempting_providers;
725 int failed; /* TRUE if attempting provider failed badly */
726 char name[1];
727 };
728
729 struct script_struct
730 {
731 pid_t pid;
732 struct script_struct *prev, *next; /* For the list */
733 struct service_struct *first_service, *last_service; /*First is true name*/
734 struct script_struct *next_attempting_provider; /* Provider chain */
735 };
736
737 struct list_head
738 {
739 struct script_struct *first, *last;
740 unsigned int num_entries;
741 };
742
743
744 static struct list_head available_list = {NULL, NULL, 0};
745 static struct list_head starting_list = {NULL, NULL, 0};
746 static struct service_struct *unavailable_services = NULL; /* For needers */
747 static int num_needers = 0;
748
749
750 static int process_pidstat (pid_t pid, int status);
751 static void process_command (const struct command_struct *command);
752 static struct service_struct *find_service_in_list (const char *name,
753 struct service_struct *sv);
754 static struct script_struct *find_script_byname
755 (const char *name,struct list_head *head, struct service_struct **service);
756 static struct script_struct *find_script_bypid (pid_t pid,
757 struct list_head *head);
758 static void insert_entry (struct list_head *head, struct script_struct *entry);
759 static void remove_entry (struct list_head *head, struct script_struct *entry);
760 static void signal_needers (struct service_struct *service, int sig);
761 static void handle_nonworking (struct script_struct *script);
762 static int force_progress (void);
763 static void show_scripts (FILE *fp, const struct script_struct *script,
764 const char *type);
765 static const char *get_path (const char *file);
766
767
768 static pid_t mywait (int *status)
769 /* [RETURNS] The pid for a process to be reaped, 0 if no process is to be
770 reaped, and less than 0 if the boot scripts appear to have finished.
771 */
772 {
773 pid_t pid;
774 sigset_t ss;
775 long buffer[COMMAND_SIZE / sizeof (long)];
776 struct command_struct *command = (struct command_struct *) buffer;
777
778 if (initctl_fd < 0) return wait (status);
779 /* Some magic to avoid races which can result in lost signals */
780 command->command = -1;
781 if ( sigsetjmp (jmp_env, 1) )
782 { /* Jump from signal handler */
783 do_longjmp = 0;
784 process_command (command);
785 return 0;
786 }
787 sigemptyset (&ss); /* Block SIGCHLD so wait status cannot be lost */
788 sigaddset (&ss, SIGCHLD);
789 sigprocmask (SIG_BLOCK, &ss, NULL);
790 if ( ( pid = waitpid (-1, status, WNOHANG) ) > 0 )
791 {
792 sigprocmask (SIG_UNBLOCK, &ss, NULL);
793 return process_pidstat (pid, *status);
794 }
795 do_longjmp = 1; /* After this, SIGCHLD will cause a jump backwards */
796 sigprocmask (SIG_UNBLOCK, &ss, NULL);
797 read (initctl_fd, buffer, COMMAND_SIZE);
798 do_longjmp = 0;
799 process_command (command);
800 return 0;
801 } /* End Function mywait */
802
803 static pid_t process_pidstat (pid_t pid, int status)
804 /* [RETURNS] The pid for a process to be reaped, 0 if no process is to be
805 reaped, and less than 0 if the boot scripts appear to have finished.
806 */
807 {
808 int failed;
809 struct script_struct *script;
810 struct service_struct *service;
811
812 if ( ( script = find_script_bypid (pid, &starting_list) ) == NULL )
813 return pid;
814 remove_entry (&starting_list, script);
815 if ( WIFEXITED (status) && (WEXITSTATUS (status) == 0) )
816 {
817 struct script_struct *provider;
818
819 /* Notify needers and other providers */
820 for (service = script->first_service; service != NULL;
821 service = service->next)
822 {
823 signal_needers (service, SIG_PRESENT);
824 for (provider = service->attempting_providers; provider != NULL;
825 provider = provider->next_attempting_provider)
826 kill (provider->pid, SIG_PRESENT);
827 service->attempting_providers = NULL;
828 }
829 insert_entry (&available_list, script);
830 return force_progress ();
831 }
832 failed = ( WIFEXITED (status) && (WEXITSTATUS (status) == 2) ) ? 0 : 1;
833 for (service = script->first_service; service != NULL;
834 service = service->next)
835 service->failed = failed;
836 handle_nonworking (script);
837 return force_progress ();
838 } /* End Function process_pidstat */
839
840 static void process_command (const struct command_struct *command)
841 {
842 int ival;
843 struct script_struct *script;
844 struct service_struct *service;
845
846 switch (command->command)
847 {
848 case COMMAND_TEST:
849 kill (command->pid,
850 (find_script_byname (command->name, &available_list,
851 NULL) == NULL) ?
852 SIG_NOT_PRESENT : SIG_PRESENT);
853 break;
854 case COMMAND_NEED:
855 ival = run_command (command->name, command->name, command->pid);
856 if (ival == 0)
857 {
858 ++num_needers;
859 force_progress ();
860 }
861 else kill (command->pid, ival);
862 break;
863 case COMMAND_ROLLBACK:
864 if (command->name[0] == '\0') script = NULL;
865 else
866 {
867 if ( ( script = find_script_byname (command->name, &available_list,
868 NULL) ) == NULL )
869 {
870 kill (command->pid, SIG_NOT_PRESENT);
871 break;
872 }
873 }
874 while (script != available_list.first)
875 {
876 pid_t pid;
877 struct script_struct *victim = available_list.first;
878 char txt[256];
879
880 if ( ( pid = fork () ) == 0 ) /* Child */
881 {
882 for (ival = 1; ival < NSIG; ival++) signal (ival, SIG_DFL);
883 open ("/dev/console", O_RDONLY, 0);
884 open ("/dev/console", O_RDWR, 0);
885 dup2 (1, 2);
886 execlp (get_path (victim->first_service->name),
887 victim->first_service->name, "stop", NULL);
888 err ( _("error running programme\n") );
889 _exit (SIG_NOT_STOPPED);
890 }
891 else if (pid == -1) break; /* Error */
892 else /* Parent */
893 {
894 while (waitpid (pid, &ival, 0) != pid) /* Nothing */;
895 if ( WIFEXITED (ival) && (WEXITSTATUS (ival) == 0) )
896 {
897 sprintf (txt, "Stopped service: %s\n",
898 victim->first_service->name);
899 remove_entry (&available_list, victim);
900 free (victim);
901 err (txt);
902 }
903 else break;
904 }
905 }
906 kill (command->pid,
907 (script ==available_list.first) ? SIG_STOPPED : SIG_NOT_STOPPED);
908 break;
909 case COMMAND_DUMP_LIST:
910 if (fork () == 0) /* Do it in a child process so pid=1 doesn't block */
911 {
912 FILE *fp;
913
914 if ( ( fp = fopen (command->name, "w") ) == NULL ) _exit (1);
915 show_scripts (fp, available_list.first, "AVAILABLE");
916 show_scripts (fp, starting_list.first, "STARTING");
917 fputs ("UNAVAILABLE SERVICES:\n", fp);
918 for (service = unavailable_services; service != NULL;
919 service = service->next)
920 fprintf (fp, "%s (%s)\n", service->name,
921 service->failed ? "FAILED" : "not configured");
922 fclose (fp);
923 _exit (0);
924 }
925 break;
926 case COMMAND_PROVIDE:
927 /* Sanity check */
928 if ( ( script = find_script_bypid (command->ppid, &starting_list) )
929 == NULL )
930 {
931 kill (command->pid, SIG_NOT_CHILD);
932 break;
933 }
934 if (find_script_byname (command->name, &available_list, NULL) != NULL)
935 {
936 kill (command->pid, SIG_PRESENT);
937 break;
938 }
939 if (find_script_byname (command->name, &starting_list, &service)
940 != NULL)
941 { /* Someone else is trying to provide */
942 script->next_attempting_provider = service->attempting_providers;
943 service->attempting_providers = script;
944 break;
945 }
946 if ( ( service = find_service_in_list (command->name,
947 unavailable_services) )
948 == NULL )
949 { /* We're the first to try and provide: create it */
950 if ( ( service =
951 calloc (1, strlen (command->name) + sizeof *service) )
952 == NULL )
953 {
954 kill (command->pid, SIG_NOT_CHILD);
955 break;
956 }
957 strcpy (service->name, command->name);
958 }
959 else
960 { /* Orphaned service: unhook and grab it */
961 if (service->prev == NULL) unavailable_services = service->next;
962 else service->prev->next = service->next;
963 if (service->next != NULL) service->next->prev = service->prev;
964 service->next = NULL;
965 }
966 service->prev = script->last_service;
967 script->last_service->next = service;
968 script->last_service = service;
969 kill (command->pid, SIG_NOT_PRESENT);
970 break;
971 case -1:
972 default:
973 break;
974 }
975 } /* End Function process_command */
976
977 static int run_command (const char *file, const char *name, pid_t pid)
978 {
979 struct script_struct *script;
980 struct needer_struct *needer = NULL;
981 struct service_struct *service;
982
983 if (find_script_byname (name, &available_list, NULL) != NULL)
984 return SIG_PRESENT;
985 if (pid != 0)
986 {
987 needer = calloc (1, sizeof *needer);
988 if (needer == NULL) return SIG_FAILED;
989 needer->pid = pid;
990 }
991 script = find_script_byname (name, &starting_list, &service);
992 if (script == NULL)
993 service = find_service_in_list (name, unavailable_services);
994 if (service == NULL)
995 {
996 int i;
997 char txt[1024];
998
999 if ( ( script = calloc (1, sizeof *script) ) == NULL )
1000 {
1001 if (needer != NULL) free (needer);
1002 return SIG_FAILED;
1003 }
1004 service = calloc (1, strlen (name) + sizeof *service);
1005 if (service == NULL)
1006 {
1007 free (script);
1008 return SIG_FAILED;
1009 }
1010 strcpy (service->name, name);
1011 switch ( script->pid = fork () )
1012 {
1013 case 0: /* Child */
1014 for (i = 1; i < NSIG; i++) signal (i, SIG_DFL);
1015 execlp (get_path (file), service->name, "start", NULL);
1016 sprintf (txt, "error running programme: \"%s\"\n", service->name);
1017 err ( _(txt) );
1018 _exit (SIG_FAILED);
1019 break;
1020 case -1: /* Error */
1021 service->next = unavailable_services;
1022 if (unavailable_services != NULL)
1023 unavailable_services->prev = service;
1024 unavailable_services = service;
1025 free (script);
1026 if (needer != NULL) free (needer);
1027 return SIG_FAILED;
1028 /*break;*/
1029 default: /* Parent */
1030 script->first_service = service;
1031 script->last_service = service;
1032 insert_entry (&starting_list, script);
1033 sched_yield ();
1034 break;
1035 }
1036 }
1037 if (needer == NULL) return 0;
1038 needer->next = service->needers;
1039 service->needers = needer;
1040 return 0;
1041 } /* End Function run_command */
1042
1043 static struct service_struct *find_service_in_list (const char *name,
1044 struct service_struct *sv)
1045 {
1046 for (; sv != NULL; sv = sv->next)
1047 if (strcmp (sv->name, name) == 0) return (sv);
1048 return NULL;
1049 } /* End Function find_service_in_list */
1050
1051 static struct script_struct *find_script_byname (const char *name,
1052 struct list_head *head,
1053 struct service_struct **service)
1054 {
1055 struct script_struct *script;
1056
1057 for (script = head->first; script != NULL; script = script->next)
1058 {
1059 struct service_struct *sv;
1060
1061 if ( ( sv = find_service_in_list (name, script->first_service) )
1062 != NULL )
1063 {
1064 if (service != NULL) *service = sv;
1065 return (script);
1066 }
1067 }
1068 if (service != NULL) *service = NULL;
1069 return NULL;
1070 } /* End Function find_script_byname */
1071
1072 static struct script_struct *find_script_bypid (pid_t pid,
1073 struct list_head *head)
1074 {
1075 struct script_struct *script;
1076
1077 for (script = head->first; script != NULL; script = script->next)
1078 if (script->pid == pid) return (script);
1079 return NULL;
1080 } /* End Function find_script_bypid */
1081
1082 static void insert_entry (struct list_head *head, struct script_struct *entry)
1083 {
1084 if (entry == NULL) return;
1085 entry->prev = NULL;
1086 entry->next = head->first;
1087 if (head->first != NULL) head->first->prev = entry;
1088 head->first = entry;
1089 if (head->last == NULL) head->last = entry;
1090 ++head->num_entries;
1091 } /* End Function insert_entry */
1092
1093 static void remove_entry (struct list_head *head, struct script_struct *entry)
1094 {
1095 if (entry->prev == NULL) head->first = entry->next;
1096 else entry->prev->next = entry->next;
1097 if (entry->next == NULL) head->last = entry->prev;
1098 else entry->next->prev = entry->prev;
1099 --head->num_entries;
1100 } /* End Function remove_entry */
1101
1102 static void signal_needers (struct service_struct *service, int sig)
1103 {
1104 struct needer_struct *needer, *next_needer;
1105
1106 for (needer = service->needers; needer != NULL; needer = next_needer)
1107 {
1108 kill (needer->pid, sig);
1109 next_needer = needer->next;
1110 free (needer);
1111 --num_needers;
1112 }
1113 service->needers = NULL;
1114 } /* End Function signal_needers */
1115
1116 static void handle_nonworking (struct script_struct *script)
1117 {
1118 struct service_struct *service, *next;
1119
1120 for (service = script->first_service; service != NULL; service = next)
1121 {
1122 struct script_struct *provider = service->attempting_providers;
1123
1124 next = service->next;
1125 if (provider == NULL)
1126 {
1127 service->prev = NULL;
1128 service->next = unavailable_services;
1129 if (unavailable_services != NULL)
1130 unavailable_services->prev = service;
1131 unavailable_services = service;
1132 continue;
1133 }
1134 service->attempting_providers = provider->next_attempting_provider;
1135 provider->last_service->next = service;
1136 service->prev = provider->last_service;
1137 provider->last_service = service;
1138 service->next = NULL;
1139 kill (provider->pid, SIG_NOT_PRESENT);
1140 }
1141 free (script);
1142 } /* End Function handle_nonworking */
1143
1144 static int force_progress (void)
1145 /* [RETURNS] 0 if boot scripts are still running, else -1.
1146 */
1147 {
1148 struct service_struct *service;
1149
1150 if (starting_list.num_entries > num_needers) return 0;
1151 /* No progress can be made: signal needers */
1152 for (service = unavailable_services; service != NULL;
1153 service = service->next)
1154 signal_needers (service,
1155 service->failed ? SIG_FAILED : SIG_NOT_PRESENT);
1156 return (starting_list.num_entries < 1) ? -1 : 0;
1157 } /* End Function force_progress */
1158
1159 static void show_scripts (FILE *fp, const struct script_struct *script,
1160 const char *type)
1161 {
1162 fprintf (fp, "%s SERVICES:\n", type);
1163 for (; script != NULL; script = script->next)
1164 {
1165 struct service_struct *service = script->first_service;
1166
1167 fputs (service->name, fp);
1168 for (service = service->next; service != NULL; service = service->next)
1169 fprintf (fp, " (%s)", service->name);
1170 putc ('\n', fp);
1171 }
1172 } /* End Function show_scripts */
1173
1174 static const char *get_path (const char *file)
1175 {
1176 char *p1, *p2;
1177 static char path[PATH_SIZE];
1178
1179 if (file[0] == '/') return file;
1180 if (init_path[0] == '\0') return file;
1181 for (p1 = init_path; *p1 != '\0'; p1 = p2)
1182 {
1183 if ( ( p2 = strchr (p1, ':') ) == NULL )
1184 p2 = p1 + strlen (p1);
1185 strncpy (path, p1, p2 - p1);
1186 path[p2 - p1] = '/';
1187 strcpy (path + (p2 - p1) + 1, file);
1188 if (*p2 == ':') ++p2;
1189 if (access (path, X_OK) == 0) return path;
1190 }
1191 return file;
1192 } /* End Function get_path */