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