]>
git.ipfire.org Git - thirdparty/util-linux.git/blob - login-utils/simpleinit.c
1 /* simpleinit.c - poe@daimi.aau.dk */
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
14 #include <sys/types.h>
26 #include <sys/sysmacros.h>
28 #include <sys/ioctl.h>
38 #include "pathnames.h"
39 #include "linux_reboot.h"
42 #include "simpleinit.h"
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)
49 #define MAX_RESPAWN_RATE 5 /* number of respawns per 100 seconds */
51 #define TZFILE "/etc/TZ"
53 /* #define DEBUGGING */
55 /* Define this if you want init to ignore the termcap field in inittab for
57 /* #define SPECIAL_CONSOLE_TERM */
67 struct timeval last_start
;
71 struct initline inittab
[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
;
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
);
99 static void set_tz (void);
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
);
106 static void err (char *s
)
110 if((fd
= open("/dev/console", O_WRONLY
)) < 0) return;
112 write(fd
, "init: ", 6);
113 write(fd
, s
, strlen(s
));
117 static void enter_single (void)
122 err(_("Booting to single user mode.\n"));
123 if((pid
= fork()) == 0) {
125 execl(_PATH_BSHELL
, _PATH_BSHELL
, NULL
);
126 err(_("exec of single user shell failed\n"));
128 while (waitpid (pid
, &i
, 0) != pid
) /* Nothing */;
130 err(_("fork of single user shell failed\n"));
132 unlink(_PATH_SINGLE
);
135 int main(int argc
, char *argv
[])
146 signal (SIGINT
, int_handler
);
147 sigemptyset (&sa
.sa_mask
);
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
);
158 setlocale(LC_ALL
, "");
159 bindtextdomain(PACKAGE
, LOCALEDIR
);
162 my_reboot (LINUX_REBOOT_CMD_CAD_OFF
);
163 /* Find script to run. Command-line overrides config file overrides
165 for (i
= 0; i
< NUMCMD
; i
++) inittab
[i
].pid
= -1;
167 for (i
= 1; i
< argc
; i
++) {
168 if (strcmp (argv
[i
], "single") == 0) want_single
= 1;
170 char path
[PATH_SIZE
];
172 strcpy (path
, script_prefix
);
173 strcat (path
, argv
[i
]);
174 if (access (path
, R_OK
| X_OK
) == 0)
175 strcpy (boot_prog
, path
);
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") );
185 if ( want_single
|| (access (_PATH_SINGLE
, R_OK
) == 0) ) do_single ();
187 /*If we get a SIGTSTP before multi-user mode, do nothing*/
191 if ( do_rc_tty (boot_prog
) ) do_single ();
193 while(stopped
) /*Also if /etc/rc fails & we get SIGTSTP*/
196 write_wtmp(); /* write boottime record */
198 for(i
= 0; i
< numcmd
; i
++) {
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
);
207 signal(SIGHUP
, hup_handler
);
209 for (i
= 0; i
< getdtablesize (); i
++)
210 if (i
!= initctl_fd
) close (i
);
212 for(i
= 0; i
< numcmd
; i
++)
215 if (final_prog
[0] != '\0') {
219 execl (final_prog
, final_prog
, "start", NULL
);
220 err ( _("error running finalprog\n") );
224 err ( _("error forking finalprog\n") );
226 default: /* Parent */
233 if (pid
< 1) continue;
235 /* clear utmp entry, and append to wtmp if possible */
240 utmpname(_PATH_UTMP
);
242 while((ut
= getutent())) {
243 if(ut
->ut_pid
== pid
) {
245 memset(&ut
->ut_user
, 0, UT_NAMESIZE
);
246 memset(&ut
->ut_host
, 0, sizeof(ut
->ut_host
));
247 ut
->ut_type
= DEAD_PROCESS
;
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
));
259 flock(lf
, LOCK_UN
|LOCK_NB
);
268 for(i
= 0; i
< numcmd
; i
++) {
269 if(pid
== inittab
[i
].pid
|| inittab
[i
].pid
< 0) {
270 if(stopped
) inittab
[i
].pid
= -1;
278 #define MAXTRIES 3 /* number of tries allowed when giving the password */
281 * return true if singleuser mode is allowed.
282 * If /etc/securesingle exists ask for root password, otherwise always OK.
284 static int check_single_ok (void)
286 char *pass
, *rootpass
= NULL
;
290 if (access (_PATH_SECURE
, R_OK
) != 0) return 1;
291 if ( ( pwd
= getpwnam ("root") ) || ( pwd
= getpwuid (0) ) )
292 rootpass
= pwd
->pw_passwd
;
294 return 1; /* a bad /etc/passwd should not lock out */
296 for (i
= 0; i
< MAXTRIES
; i
++)
298 pass
= getpass (_ ("Password: ") );
299 if (pass
== NULL
) continue;
301 if ( !strcmp (crypt (pass
, rootpass
), rootpass
) ) return 1;
303 puts (_ ("\nWrong password.\n") );
308 static void do_single (void)
310 char path
[PATH_SIZE
];
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 */
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.
326 static int do_rc_tty (const char *path
)
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 () )
339 for (status
= 1; status
< NSIG
; status
++) signal (status
, SIG_DFL
);
341 sigprocmask (SIG_UNBLOCK
, &ss
, NULL
);
342 sigdelset (&ss
, SIGINT
);
343 sigdelset (&ss
, SIGQUIT
);
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 */
351 default: /* Parent */
355 process_path (path
, run_file
, 0);
358 if ( ( pid
= mywait (&status
) ) == child
)
359 return (WTERMSIG (status
) == SIGINT
) ? 0 : 1;
362 kill (child
, SIGKILL
);
363 while (waitpid (child
, NULL
, 0) != child
) /* Nothing */;
365 } /* End Function do_rc_tty */
367 static int process_path (const char *path
, int (*func
) (const char *path
),
368 int ignore_dangling_symlink
)
374 if (lstat (path
, &statbuf
) != 0)
376 err (_ ("lstat of path failed\n") );
379 if ( S_ISLNK (statbuf
.st_mode
) )
381 if (stat (path
, &statbuf
) != 0)
383 if ( (errno
== ENOENT
) && ignore_dangling_symlink
) return 0;
384 err (_ ("stat of path failed\n") );
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
)
392 err (_ ("open of directory failed\n") );
395 while ( ( de
= readdir (dp
) ) != NULL
)
398 char newpath
[PATH_SIZE
];
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
;
407 } /* End Function process_path */
409 static int preload_file (const char *path
)
414 if ( ( fd
= open (path
, O_RDONLY
, 0) ) < 0) return 0;
415 while (read (fd
, &ch
, 1) == 1) lseek (fd
, 1024, SEEK_CUR
);
418 } /* End Function preload_file */
420 static int run_file (const char *path
)
424 if ( ( ptr
= strrchr ( (char *) path
, '/' ) ) == NULL
) ptr
= path
;
426 return (run_command (path
, ptr
, 0) == SIG_FAILED
) ? 1 : 0;
427 } /* End Function run_file */
429 static void spawn (int i
)
433 signed long ds_taken
;
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
;
441 ds_taken
+= (ct
.tv_usec
- inittab
[i
].last_start
.tv_usec
) / 100000;
444 inittab
[i
].rate
= (9 * inittab
[i
].rate
+ 1000 / ds_taken
) / 10;
445 if (inittab
[i
].rate
> MAX_RESPAWN_RATE
) {
448 inittab
[i
].toks
[0] = NULL
;
451 sprintf (txt
,"respawning: \"%s\" too fast: quenching entry\n",
457 if((pid
= fork()) < 0) {
459 err(_("fork failed\n"));
463 /* this is the parent */
464 inittab
[i
].pid
= pid
;
465 inittab
[i
].last_start
= ct
;
469 /* this is the child */
477 for(j
= 0; j
< getdtablesize(); j
++)
480 (void) sprintf(term
, "TERM=%s", inittab
[i
].termcap
);
484 (void) sprintf(tz
, "TZ=%s", tzone
);
489 execve(inittab
[i
].toks
[0], inittab
[i
].toks
, env
);
490 err(_("exec failed\n"));
496 static void read_inittab (void)
503 char prog
[PATH_SIZE
];
504 #ifdef SPECIAL_CONSOLE_TERM
510 termenv
= getenv("TERM"); /* set by kernel */
511 /* termenv = "vt100"; */
513 if(!(f
= fopen(_PATH_INITTAB
, "r"))) {
514 err(_("cannot open inittab\n"));
520 while(!feof(f
) && i
< NUMCMD
- 2) {
521 if(fgets(buf
, CMDSIZ
- 1, f
) == 0) break;
524 for(k
= 0; k
< CMDSIZ
&& buf
[k
]; k
++) {
525 if ((buf
[k
] == '#') || (buf
[k
] == '\n')) {
530 if(buf
[0] == 0 || buf
[0] == '\n') continue;
531 ptr
= strchr (buf
, '=');
534 if ( !strncmp (buf
, "bootprog", 8) ) {
535 while ( isspace (*ptr
) ) ++ptr
;
540 if ( !strncmp (buf
, "fileprefix", 10) ) {
541 while ( isspace (*ptr
) ) ++ptr
;
542 strcpy (script_prefix
, ptr
);
545 if ( !strncmp (buf
, "PATH", 4) ) {
546 while ( isspace (*ptr
) ) ++ptr
;
547 setenv ("PATH", ptr
, 1);
550 if ( !strncmp (buf
, "INIT_PATH", 9) ) {
551 while ( isspace (*ptr
) ) ++ptr
;
552 strcpy (init_path
, ptr
);
555 if ( !strncmp (buf
, "finalprog", 8) ) {
556 while ( isspace (*ptr
) ) ++ptr
;
557 strcpy (final_prog
, ptr
);
563 (void) strcpy(inittab
[i
].line
, buf
);
565 (void) strtok(inittab
[i
].line
, ":");
566 xstrncpy(inittab
[i
].tty
, inittab
[i
].line
, 10);
567 xstrncpy(inittab
[i
].termcap
, strtok((char *)0, ":"), 30);
569 getty
= strtok((char *)0, ":");
570 (void) strtok(getty
, " \t\n");
571 inittab
[i
].toks
[0] = getty
;
573 while((ptr
= strtok((char *)0, " \t\n")))
574 inittab
[i
].toks
[j
++] = ptr
;
575 inittab
[i
].toks
[j
] = (char *)0;
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"));
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);
595 char path
[PATH_SIZE
];
597 strcpy (path
, script_prefix
);
600 if (path
[len
- 1] == '/') path
[len
- 1] = '\0';
601 if (access (path
, R_OK
| X_OK
) == 0)
602 strcpy (boot_prog
, path
);
606 static void hup_handler (int sig
)
610 struct initline savetab
[NUMCMD
];
613 (void) signal(SIGHUP
, SIG_IGN
);
615 memcpy(savetab
, inittab
, NUMCMD
* sizeof(struct initline
));
619 for(i
= 0; i
< numcmd
; i
++) {
621 for(j
= 0; j
< oldnum
; j
++) {
622 if(!strcmp(savetab
[j
].tty
, inittab
[i
].tty
)) {
624 if((inittab
[i
].pid
= savetab
[j
].pid
) < 0)
628 if(!had_already
) spawn(i
);
631 (void) signal(SIGHUP
, hup_handler
);
634 static void sigtstp_handler (int sig
)
637 if (!stopped
) hup_handler (sig
);
638 } /* End Function sigtstp_handler */
640 static void sigterm_handler (int sig
)
644 for (i
= 0; i
< numcmd
; i
++)
645 if (inittab
[i
].pid
> 0) kill (inittab
[i
].pid
, SIGTERM
);
646 } /* End Function sigterm_handler */
648 static void int_handler (int sig
)
658 if (pid
== 0) /* reboot properly... */
659 execl(_PATH_REBOOT
, _PATH_REBOOT
, (char *)0);
661 /* fork or exec failed, try the hard way... */
662 my_reboot(LINUX_REBOOT_CMD_RESTART
);
665 static void sigchild_handler (int sig
)
667 if (!do_longjmp
) return;
668 siglongjmp (jmp_env
, 1);
671 static void sigquit_handler (int sig
)
673 execl (_PATH_REBOOT
, _PATH_REBOOT
, NULL
); /* It knows pid=1 must sleep */
677 static void set_tz (void)
682 if((f
=fopen(TZFILE
, "r")) == (FILE *)NULL
) return;
683 fgets(tzone
, CMDSIZ
-2, f
);
685 if((len
=strlen(tzone
)) < 2) return;
686 tzone
[len
-1] = 0; /* get rid of the '\n' */
687 setenv("TZ", tzone
, 0);
691 static void write_wtmp (void)
696 memset((char *)&ut
, 0, sizeof(ut
));
697 strcpy(ut
.ut_line
, "~");
698 memset(ut
.ut_name
, 0, sizeof(ut
.ut_name
));
700 ut
.ut_type
= BOOT_TIME
;
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
));
708 flock(lf
, LOCK_UN
|LOCK_NB
);
716 struct needer_struct
*next
;
720 struct service_struct
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 */
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 */
739 struct script_struct
*first
, *last
;
740 unsigned int num_entries
;
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;
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
,
765 static const char *get_path (const char *file
);
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.
775 long buffer
[COMMAND_SIZE
/ sizeof (long)];
776 struct command_struct
*command
= (struct command_struct
*) buffer
;
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 */
784 process_command (command
);
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 )
792 sigprocmask (SIG_UNBLOCK
, &ss
, NULL
);
793 return process_pidstat (pid
, *status
);
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
);
799 process_command (command
);
801 } /* End Function mywait */
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.
809 struct script_struct
*script
;
810 struct service_struct
*service
;
812 if ( ( script
= find_script_bypid (pid
, &starting_list
) ) == NULL
)
814 remove_entry (&starting_list
, script
);
815 if ( WIFEXITED (status
) && (WEXITSTATUS (status
) == 0) )
817 struct script_struct
*provider
;
819 /* Notify needers and other providers */
820 for (service
= script
->first_service
; service
!= NULL
;
821 service
= service
->next
)
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
;
829 insert_entry (&available_list
, script
);
830 return force_progress ();
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 */
840 static void process_command (const struct command_struct
*command
)
843 struct script_struct
*script
;
844 struct service_struct
*service
;
846 switch (command
->command
)
850 (find_script_byname (command
->name
, &available_list
,
852 SIG_NOT_PRESENT
: SIG_PRESENT
);
855 ival
= run_command (command
->name
, command
->name
, command
->pid
);
861 else kill (command
->pid
, ival
);
863 case COMMAND_ROLLBACK
:
864 if (command
->name
[0] == '\0') script
= NULL
;
867 if ( ( script
= find_script_byname (command
->name
, &available_list
,
870 kill (command
->pid
, SIG_NOT_PRESENT
);
874 while (script
!= available_list
.first
)
877 struct script_struct
*victim
= available_list
.first
;
880 if ( ( pid
= fork () ) == 0 ) /* Child */
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);
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
);
891 else if (pid
== -1) break; /* Error */
894 while (waitpid (pid
, &ival
, 0) != pid
) /* Nothing */;
895 if ( WIFEXITED (ival
) && (WEXITSTATUS (ival
) == 0) )
897 sprintf (txt
, "Stopped service: %s\n",
898 victim
->first_service
->name
);
899 remove_entry (&available_list
, victim
);
907 (script
==available_list
.first
) ? SIG_STOPPED
: SIG_NOT_STOPPED
);
909 case COMMAND_DUMP_LIST
:
910 if (fork () == 0) /* Do it in a child process so pid=1 doesn't block */
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");
926 case COMMAND_PROVIDE
:
928 if ( ( script
= find_script_bypid (command
->ppid
, &starting_list
) )
931 kill (command
->pid
, SIG_NOT_CHILD
);
934 if (find_script_byname (command
->name
, &available_list
, NULL
) != NULL
)
936 kill (command
->pid
, SIG_PRESENT
);
939 if (find_script_byname (command
->name
, &starting_list
, &service
)
941 { /* Someone else is trying to provide */
942 script
->next_attempting_provider
= service
->attempting_providers
;
943 service
->attempting_providers
= script
;
946 if ( ( service
= find_service_in_list (command
->name
,
947 unavailable_services
) )
949 { /* We're the first to try and provide: create it */
951 calloc (1, strlen (command
->name
) + sizeof *service
) )
954 kill (command
->pid
, SIG_NOT_CHILD
);
957 strcpy (service
->name
, command
->name
);
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
;
966 service
->prev
= script
->last_service
;
967 script
->last_service
->next
= service
;
968 script
->last_service
= service
;
969 kill (command
->pid
, SIG_NOT_PRESENT
);
975 } /* End Function process_command */
977 static int run_command (const char *file
, const char *name
, pid_t pid
)
979 struct script_struct
*script
;
980 struct needer_struct
*needer
= NULL
;
981 struct service_struct
*service
;
983 if (find_script_byname (name
, &available_list
, NULL
) != NULL
)
987 needer
= calloc (1, sizeof *needer
);
988 if (needer
== NULL
) return SIG_FAILED
;
991 script
= find_script_byname (name
, &starting_list
, &service
);
993 service
= find_service_in_list (name
, unavailable_services
);
999 if ( ( script
= calloc (1, sizeof *script
) ) == NULL
)
1001 if (needer
!= NULL
) free (needer
);
1004 service
= calloc (1, strlen (name
) + sizeof *service
);
1005 if (service
== NULL
)
1010 strcpy (service
->name
, name
);
1011 switch ( script
->pid
= fork () )
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
);
1020 case -1: /* Error */
1021 service
->next
= unavailable_services
;
1022 if (unavailable_services
!= NULL
)
1023 unavailable_services
->prev
= service
;
1024 unavailable_services
= service
;
1026 if (needer
!= NULL
) free (needer
);
1029 default: /* Parent */
1030 script
->first_service
= service
;
1031 script
->last_service
= service
;
1032 insert_entry (&starting_list
, script
);
1037 if (needer
== NULL
) return 0;
1038 needer
->next
= service
->needers
;
1039 service
->needers
= needer
;
1041 } /* End Function run_command */
1043 static struct service_struct
*find_service_in_list (const char *name
,
1044 struct service_struct
*sv
)
1046 for (; sv
!= NULL
; sv
= sv
->next
)
1047 if (strcmp (sv
->name
, name
) == 0) return (sv
);
1049 } /* End Function find_service_in_list */
1051 static struct script_struct
*find_script_byname (const char *name
,
1052 struct list_head
*head
,
1053 struct service_struct
**service
)
1055 struct script_struct
*script
;
1057 for (script
= head
->first
; script
!= NULL
; script
= script
->next
)
1059 struct service_struct
*sv
;
1061 if ( ( sv
= find_service_in_list (name
, script
->first_service
) )
1064 if (service
!= NULL
) *service
= sv
;
1068 if (service
!= NULL
) *service
= NULL
;
1070 } /* End Function find_script_byname */
1072 static struct script_struct
*find_script_bypid (pid_t pid
,
1073 struct list_head
*head
)
1075 struct script_struct
*script
;
1077 for (script
= head
->first
; script
!= NULL
; script
= script
->next
)
1078 if (script
->pid
== pid
) return (script
);
1080 } /* End Function find_script_bypid */
1082 static void insert_entry (struct list_head
*head
, struct script_struct
*entry
)
1084 if (entry
== NULL
) return;
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 */
1093 static void remove_entry (struct list_head
*head
, struct script_struct
*entry
)
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 */
1102 static void signal_needers (struct service_struct
*service
, int sig
)
1104 struct needer_struct
*needer
, *next_needer
;
1106 for (needer
= service
->needers
; needer
!= NULL
; needer
= next_needer
)
1108 kill (needer
->pid
, sig
);
1109 next_needer
= needer
->next
;
1113 service
->needers
= NULL
;
1114 } /* End Function signal_needers */
1116 static void handle_nonworking (struct script_struct
*script
)
1118 struct service_struct
*service
, *next
;
1120 for (service
= script
->first_service
; service
!= NULL
; service
= next
)
1122 struct script_struct
*provider
= service
->attempting_providers
;
1124 next
= service
->next
;
1125 if (provider
== NULL
)
1127 service
->prev
= NULL
;
1128 service
->next
= unavailable_services
;
1129 if (unavailable_services
!= NULL
)
1130 unavailable_services
->prev
= service
;
1131 unavailable_services
= service
;
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
);
1142 } /* End Function handle_nonworking */
1144 static int force_progress (void)
1145 /* [RETURNS] 0 if boot scripts are still running, else -1.
1148 struct service_struct
*service
;
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 */
1159 static void show_scripts (FILE *fp
, const struct script_struct
*script
,
1162 fprintf (fp
, "%s SERVICES:\n", type
);
1163 for (; script
!= NULL
; script
= script
->next
)
1165 struct service_struct
*service
= script
->first_service
;
1167 fputs (service
->name
, fp
);
1168 for (service
= service
->next
; service
!= NULL
; service
= service
->next
)
1169 fprintf (fp
, " (%s)", service
->name
);
1172 } /* End Function show_scripts */
1174 static const char *get_path (const char *file
)
1177 static char path
[PATH_SIZE
];
1179 if (file
[0] == '/') return file
;
1180 if (init_path
[0] == '\0') return file
;
1181 for (p1
= init_path
; *p1
!= '\0'; p1
= p2
)
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
;
1192 } /* End Function get_path */