]>
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@misiek.eu.org>
5 * - added Native Language Support
20 #include <sys/sysmacros.h>
22 #include <sys/ioctl.h>
32 #include "pathnames.h"
33 #include "linux_reboot.h"
35 #include "simpleinit.h"
37 #define CMDSIZ 150 /* max size of a line in inittab */
38 #define NUMCMD 30 /* max number of lines in inittab */
39 #define NUMTOK 20 /* max number of tokens in inittab command */
40 #define PATH_SIZE (CMDSIZ+CMDSIZ+1)
42 #define MAX_RESPAWN_RATE 5 /* number of respawns per 100 seconds */
44 #define TZFILE "/etc/TZ"
46 /* #define DEBUGGING */
48 /* Define this if you want init to ignore the termcap field in inittab for
50 /* #define SPECIAL_CONSOLE_TERM */
60 struct timeval last_start
;
64 struct initline inittab
[NUMCMD
];
66 int stopped
= 0; /* are we stopped */
67 static char boot_prog
[PATH_SIZE
] = _PATH_RC
;
68 static char script_prefix
[PATH_SIZE
] = "\0";
69 static char final_prog
[PATH_SIZE
] = "\0";
70 static char init_path
[PATH_SIZE
] = "\0";
71 static int caught_sigint
= 0;
72 static const char *initctl_name
= "/dev/initctl";
73 static int initctl_fd
= -1;
74 static volatile int do_longjmp
= 0;
75 static sigjmp_buf jmp_env
;
78 static void do_single (void);
79 static int do_rc_tty (const char *path
);
80 static int process_path ( const char *path
, int (*func
) (const char *path
) );
81 static int preload_file (const char *path
);
82 static int run_file (const char *path
);
83 static void spawn (int i
), read_inittab (void);
84 static void hup_handler (int sig
);
85 static void sigtstp_handler (int sig
);
86 static void int_handler (int sig
);
87 static void sigchild_handler (int sig
);
88 static void sigquit_handler (int sig
);
89 static void sigterm_handler (int sig
);
91 static void set_tz (void);
93 static void write_wtmp (void);
94 static pid_t
mywaitpid (pid_t pid
, int *status
);
95 static int run_command (const char *file
, const char *name
, pid_t pid
);
98 static void err (char *s
)
102 if((fd
= open("/dev/console", O_WRONLY
)) < 0) return;
104 write(fd
, "init: ", 6);
105 write(fd
, s
, strlen(s
));
109 static void enter_single (void)
114 err(_("Booting to single user mode.\n"));
115 if((pid
= fork()) == 0) {
117 execl(_PATH_BSHELL
, _PATH_BSHELL
, NULL
);
118 err(_("exec of single user shell failed\n"));
120 while (waitpid (pid
, &i
, 0) != pid
) /* Nothing */;
122 err(_("fork of single user shell failed\n"));
124 unlink(_PATH_SINGLE
);
127 int main(int argc
, char *argv
[])
138 signal (SIGINT
, int_handler
);
139 sigemptyset (&sa
.sa_mask
);
141 sa
.sa_handler
= sigtstp_handler
;
142 sigaction (SIGTSTP
, &sa
, NULL
);
143 sa
.sa_handler
= sigterm_handler
;
144 sigaction (SIGTERM
, &sa
, NULL
);
145 sa
.sa_handler
= sigchild_handler
;
146 sigaction (SIGCHLD
, &sa
, NULL
);
147 sa
.sa_handler
= sigquit_handler
;
148 sigaction (SIGQUIT
, &sa
, NULL
);
150 setlocale(LC_ALL
, "");
151 bindtextdomain(PACKAGE
, LOCALEDIR
);
154 my_reboot (LINUX_REBOOT_CMD_CAD_OFF
);
155 /* Find script to run. Command-line overrides config file overrides
157 for (i
= 0; i
< NUMCMD
; i
++) inittab
[i
].pid
= -1;
159 for (i
= 1; i
< argc
; i
++) {
160 if (strcmp (argv
[i
], "single") == 0) want_single
= 1;
162 char path
[PATH_SIZE
];
164 strcpy (path
, script_prefix
);
165 strcat (path
, argv
[i
]);
166 if (access (path
, R_OK
| X_OK
) == 0)
167 strcpy (boot_prog
, path
);
171 if ( ( initctl_fd
= open (initctl_name
, O_RDWR
, 0) ) < 0 ) {
172 mkfifo (initctl_name
, S_IRUSR
| S_IWUSR
);
173 if ( ( initctl_fd
= open (initctl_name
, O_RDWR
, 0) ) < 0 )
174 err ( _("error opening fifo\n") );
177 if ( want_single
|| (access (_PATH_SINGLE
, R_OK
) == 0) ) do_single ();
179 /*If we get a SIGTSTP before multi-user mode, do nothing*/
183 if ( do_rc_tty (boot_prog
) ) do_single ();
185 while(stopped
) /*Also if /etc/rc fails & we get SIGTSTP*/
188 write_wtmp(); /* write boottime record */
190 for(i
= 0; i
< numcmd
; i
++) {
193 printf("toks= %s %s %s %s\n",p
[0], p
[1], p
[2], p
[3]);
194 printf("tty= %s\n", inittab
[i
].tty
);
195 printf("termcap= %s\n", inittab
[i
].termcap
);
199 signal(SIGHUP
, hup_handler
);
201 for (i
= 0; i
< getdtablesize (); i
++)
202 if (i
!= initctl_fd
) close (i
);
204 for(i
= 0; i
< numcmd
; i
++)
207 if (final_prog
[0] != '\0') {
211 execl (final_prog
, final_prog
, "start", NULL
);
212 err ( _("error running finalprog\n") );
216 err ( _("error forking finalprog\n") );
218 default: /* Parent */
224 pid
= mywaitpid (-1, &vec
);
225 if (pid
< 1) continue;
227 /* clear utmp entry, and append to wtmp if possible */
232 utmpname(_PATH_UTMP
);
234 while((ut
= getutent())) {
235 if(ut
->ut_pid
== pid
) {
237 memset(&ut
->ut_user
, 0, UT_NAMESIZE
);
238 memset(&ut
->ut_host
, 0, sizeof(ut
->ut_host
));
239 ut
->ut_type
= DEAD_PROCESS
;
245 if ((lf
= open(_PATH_WTMPLOCK
, O_CREAT
|O_WRONLY
, 0660)) >= 0) {
246 flock(lf
, LOCK_EX
|LOCK_NB
);
247 if((ut_fd
= open(_PATH_WTMP
, O_APPEND
|O_WRONLY
)) >= 0) {
248 write(ut_fd
, ut
, sizeof(struct utmp
));
251 flock(lf
, LOCK_UN
|LOCK_NB
);
260 for(i
= 0; i
< numcmd
; i
++) {
261 if(pid
== inittab
[i
].pid
|| inittab
[i
].pid
< 0) {
262 if(stopped
) inittab
[i
].pid
= -1;
270 #define MAXTRIES 3 /* number of tries allowed when giving the password */
273 * return true if singleuser mode is allowed.
274 * If /etc/securesingle exists ask for root password, otherwise always OK.
276 static int check_single_ok (void)
278 char *pass
, *rootpass
= NULL
;
282 if (access (_PATH_SECURE
, R_OK
) != 0) return 1;
283 if ( ( pwd
= getpwnam ("root") ) || ( pwd
= getpwuid (0) ) )
284 rootpass
= pwd
->pw_passwd
;
286 return 1; /* a bad /etc/passwd should not lock out */
288 for (i
= 0; i
< MAXTRIES
; i
++)
290 pass
= getpass (_ ("Password: ") );
291 if (pass
== NULL
) continue;
293 if ( !strcmp (crypt (pass
, rootpass
), rootpass
) ) return 1;
295 puts (_ ("\nWrong password.\n") );
300 static void do_single (void)
302 char path
[PATH_SIZE
];
304 if (caught_sigint
) return;
305 strcpy (path
, script_prefix
);
306 strcat (path
, "single");
307 if (access (path
, R_OK
| X_OK
) == 0)
308 if (do_rc_tty (path
) == 0) return;
309 if ( check_single_ok () ) enter_single ();
310 } /* End Function do_single */
313 * run boot script(s). The environment is passed to the script(s), so the RC
314 * environment variable can be used to decide what to do.
315 * RC may be set from LILO.
316 * [RETURNS] 0 on success (exit status convention), otherwise error.
318 static int do_rc_tty (const char *path
)
324 if (caught_sigint
) return 0;
325 process_path (path
, preload_file
);
326 /* Launch off a subprocess to start a new session (required for frobbing
327 the TTY) and capture control-C */
328 switch ( child
= fork () )
331 for (status
= 1; status
< NSIG
; status
++) signal (status
, SIG_DFL
);
333 sigprocmask (SIG_UNBLOCK
, &ss
, NULL
);
334 sigdelset (&ss
, SIGINT
);
335 sigdelset (&ss
, SIGQUIT
);
337 ioctl (0, TIOCSCTTY
, 0); /* I want my control-C */
338 sigsuspend (&ss
); /* Should never return, should just be killed */
339 break; /* No-one else is controlled by this TTY now */
343 default: /* Parent */
347 process_path (path
, run_file
);
350 if ( ( pid
= mywaitpid (-1, &status
) ) == child
)
351 return (WTERMSIG (status
) == SIGINT
) ? 0 : 1;
354 kill (child
, SIGKILL
);
355 while (waitpid (child
, NULL
, 0) != child
) /* Nothing */;
357 } /* End Function do_rc_tty */
359 static int process_path ( const char *path
, int (*func
) (const char *path
) )
365 if (stat (path
, &statbuf
) != 0)
367 err (_ ("stat of path failed\n") );
370 if ( !( statbuf
.st_mode
& (S_IXUSR
| S_IXGRP
| S_IXOTH
) ) ) return 0;
371 if ( !S_ISDIR (statbuf
.st_mode
) ) return (*func
) (path
);
372 if ( ( dp
= opendir (path
) ) == NULL
)
374 err (_ ("open of directory failed\n") );
377 while ( ( de
= readdir (dp
) ) != NULL
)
380 char newpath
[PATH_SIZE
];
382 if (de
->d_name
[0] == '.') continue;
383 retval
= sprintf (newpath
, "%s/%s", path
, de
->d_name
);
384 if (newpath
[retval
- 1] == '~') continue; /* Common mistake */
385 if ( ( retval
= process_path (newpath
, func
) ) ) return retval
;
389 } /* End Function process_path */
391 static int preload_file (const char *path
)
396 if ( ( fd
= open (path
, O_RDONLY
, 0) ) < 0) return 0;
397 while (read (fd
, &ch
, 1) == 1) lseek (fd
, 1024, SEEK_CUR
);
400 } /* End Function preload_file */
402 static int run_file (const char *path
)
406 if ( ( ptr
= strrchr ( (char *) path
, '/' ) ) == NULL
) ptr
= path
;
408 return (run_command (path
, ptr
, 0) == SIG_FAILED
) ? 1 : 0;
409 } /* End Function run_file */
411 static void spawn (int i
)
415 signed long ds_taken
;
418 if (inittab
[i
].toks
[0] == NULL
) return;
419 /* Check if respawning too fast */
420 gettimeofday (&ct
, NULL
);
421 ds_taken
= ct
.tv_sec
- inittab
[i
].last_start
.tv_sec
;
423 ds_taken
+= (ct
.tv_usec
- inittab
[i
].last_start
.tv_usec
) / 100000;
426 inittab
[i
].rate
= (9 * inittab
[i
].rate
+ 1000 / ds_taken
) / 10;
427 if (inittab
[i
].rate
> MAX_RESPAWN_RATE
) {
430 inittab
[i
].toks
[0] = NULL
;
433 sprintf (txt
,"respawning: \"%s\" too fast: quenching entry\n",
439 if((pid
= fork()) < 0) {
441 err(_("fork failed\n"));
445 /* this is the parent */
446 inittab
[i
].pid
= pid
;
447 inittab
[i
].last_start
= ct
;
451 /* this is the child */
459 for(j
= 0; j
< getdtablesize(); j
++)
462 (void) sprintf(term
, "TERM=%s", inittab
[i
].termcap
);
466 (void) sprintf(tz
, "TZ=%s", tzone
);
471 execve(inittab
[i
].toks
[0], inittab
[i
].toks
, env
);
472 err(_("exec failed\n"));
478 static void read_inittab (void)
485 char prog
[PATH_SIZE
];
486 #ifdef SPECIAL_CONSOLE_TERM
492 termenv
= getenv("TERM"); /* set by kernel */
493 /* termenv = "vt100"; */
495 if(!(f
= fopen(_PATH_INITTAB
, "r"))) {
496 err(_("cannot open inittab\n"));
502 while(!feof(f
) && i
< NUMCMD
- 2) {
503 if(fgets(buf
, CMDSIZ
- 1, f
) == 0) break;
506 for(k
= 0; k
< CMDSIZ
&& buf
[k
]; k
++) {
507 if ((buf
[k
] == '#') || (buf
[k
] == '\n')) {
512 if(buf
[0] == 0 || buf
[0] == '\n') continue;
513 ptr
= strchr (buf
, '=');
516 if ( !strncmp (buf
, "bootprog", 8) ) {
517 while ( isspace (*ptr
) ) ++ptr
;
522 if ( !strncmp (buf
, "fileprefix", 10) ) {
523 while ( isspace (*ptr
) ) ++ptr
;
524 strcpy (script_prefix
, ptr
);
527 if ( !strncmp (buf
, "PATH", 4) ) {
528 while ( isspace (*ptr
) ) ++ptr
;
529 setenv ("PATH", ptr
, 1);
532 if ( !strncmp (buf
, "INIT_PATH", 9) ) {
533 while ( isspace (*ptr
) ) ++ptr
;
534 strcpy (init_path
, ptr
);
537 if ( !strncmp (buf
, "finalprog", 8) ) {
538 while ( isspace (*ptr
) ) ++ptr
;
539 strcpy (final_prog
, ptr
);
545 (void) strcpy(inittab
[i
].line
, buf
);
547 (void) strtok(inittab
[i
].line
, ":");
548 (void) strncpy(inittab
[i
].tty
, inittab
[i
].line
, 10);
549 inittab
[i
].tty
[9] = 0;
550 (void) strncpy(inittab
[i
].termcap
,
551 strtok((char *)0, ":"), 30);
552 inittab
[i
].termcap
[29] = 0;
554 getty
= strtok((char *)0, ":");
555 (void) strtok(getty
, " \t\n");
556 inittab
[i
].toks
[0] = getty
;
558 while((ptr
= strtok((char *)0, " \t\n")))
559 inittab
[i
].toks
[j
++] = ptr
;
560 inittab
[i
].toks
[j
] = (char *)0;
562 #ifdef SPECIAL_CONSOLE_TERM
563 /* special-case termcap for the console ttys */
564 (void) sprintf(tty
, "/dev/%s", inittab
[i
].tty
);
565 if(!termenv
|| stat(tty
, &stb
) < 0) {
566 err(_("no TERM or cannot stat tty\n"));
568 /* is it a console tty? */
569 if(major(stb
.st_rdev
) == 4 && minor(stb
.st_rdev
) < 64) {
570 strncpy(inittab
[i
].termcap
, termenv
, 30);
571 inittab
[i
].termcap
[29] = 0;
582 char path
[PATH_SIZE
];
584 strcpy (path
, script_prefix
);
587 if (path
[len
- 1] == '/') path
[len
- 1] = '\0';
588 if (access (path
, R_OK
| X_OK
) == 0)
589 strcpy (boot_prog
, path
);
593 static void hup_handler (int sig
)
597 struct initline savetab
[NUMCMD
];
600 (void) signal(SIGHUP
, SIG_IGN
);
602 memcpy(savetab
, inittab
, NUMCMD
* sizeof(struct initline
));
606 for(i
= 0; i
< numcmd
; i
++) {
608 for(j
= 0; j
< oldnum
; j
++) {
609 if(!strcmp(savetab
[j
].tty
, inittab
[i
].tty
)) {
611 if((inittab
[i
].pid
= savetab
[j
].pid
) < 0)
615 if(!had_already
) spawn(i
);
618 (void) signal(SIGHUP
, hup_handler
);
621 static void sigtstp_handler (int sig
)
624 if (!stopped
) hup_handler (sig
);
625 } /* End Function sigtstp_handler */
627 static void sigterm_handler (int sig
)
631 for (i
= 0; i
< numcmd
; i
++)
632 if (inittab
[i
].pid
> 0) kill (inittab
[i
].pid
, SIGTERM
);
633 } /* End Function sigterm_handler */
635 static void int_handler (int sig
)
645 if (pid
== 0) /* reboot properly... */
646 execl(_PATH_REBOOT
, _PATH_REBOOT
, (char *)0);
648 /* fork or exec failed, try the hard way... */
649 my_reboot(LINUX_REBOOT_CMD_RESTART
);
652 static void sigchild_handler (int sig
)
654 if (!do_longjmp
) return;
655 siglongjmp (jmp_env
, 1);
658 static void sigquit_handler (int sig
)
660 execl (_PATH_REBOOT
, _PATH_REBOOT
, NULL
); /* It knows pid=1 must sleep */
664 static void set_tz (void)
669 if((f
=fopen(TZFILE
, "r")) == (FILE *)NULL
) return;
670 fgets(tzone
, CMDSIZ
-2, f
);
672 if((len
=strlen(tzone
)) < 2) return;
673 tzone
[len
-1] = 0; /* get rid of the '\n' */
674 setenv("TZ", tzone
, 0);
678 static void write_wtmp (void)
683 memset((char *)&ut
, 0, sizeof(ut
));
684 strcpy(ut
.ut_line
, "~");
685 memset(ut
.ut_name
, 0, sizeof(ut
.ut_name
));
687 ut
.ut_type
= BOOT_TIME
;
689 if ((lf
= open(_PATH_WTMPLOCK
, O_CREAT
|O_WRONLY
, 0660)) >= 0) {
690 flock(lf
, LOCK_EX
|LOCK_NB
); /* make sure init won't hang */
691 if((fd
= open(_PATH_WTMP
, O_WRONLY
|O_APPEND
)) >= 0) {
692 write(fd
, (char *)&ut
, sizeof(ut
));
695 flock(lf
, LOCK_UN
|LOCK_NB
);
703 struct needer_struct
*next
;
707 struct service_struct
709 struct service_struct
*prev
, *next
; /* Script services chain */
710 struct needer_struct
*needers
; /* Needers waiting for service */
711 struct script_struct
*attempting_providers
;
712 int failed
; /* TRUE if attempting provider failed badly */
719 struct script_struct
*prev
, *next
; /* For the list */
720 struct service_struct
*first_service
, *last_service
; /*First is true name*/
721 struct script_struct
*next_attempting_provider
; /* Provider chain */
726 struct script_struct
*first
, *last
;
727 unsigned int num_entries
;
731 static struct list_head available_list
= {NULL
, NULL
, 0};
732 static struct list_head starting_list
= {NULL
, NULL
, 0};
733 static struct service_struct
*unavailable_services
= NULL
; /* For needers */
734 static int num_needers
= 0;
737 static int process_pidstat (pid_t pid
, int status
);
738 static void process_command (const struct command_struct
*command
);
739 static struct service_struct
*find_service_in_list (const char *name
,
740 struct service_struct
*sv
);
741 static struct script_struct
*find_script_byname
742 (const char *name
,struct list_head
*head
, struct service_struct
**service
);
743 static struct script_struct
*find_script_bypid (pid_t pid
,
744 struct list_head
*head
);
745 static void insert_entry (struct list_head
*head
, struct script_struct
*entry
);
746 static void remove_entry (struct list_head
*head
, struct script_struct
*entry
);
747 static void signal_needers (struct service_struct
*service
, int sig
);
748 static void handle_nonworking (struct script_struct
*script
);
749 static int force_progress (void);
750 static void show_scripts (FILE *fp
, const struct script_struct
*script
,
752 static const char *get_path (const char *file
);
755 static pid_t
mywaitpid (pid_t pid
, int *status
)
756 /* [RETURNS] The pid for a process to be reaped, 0 if no process is to be
757 reaped, and less than 0 if the boot scripts appear to have finished.
761 sigset_t ss_new
, ss_old
;
762 long buffer
[COMMAND_SIZE
/ sizeof (long)];
763 struct command_struct
*command
= (struct command_struct
*) buffer
;
765 if (initctl_fd
< 0) return waitpid (pid
, status
, 0);
766 if (status
== NULL
) status
= &ival
;
767 if ( ( pid
= waitpid (pid
, status
, WNOHANG
) ) > 0 )
769 return process_pidstat (pid
, *status
);
771 /* Some magic to avoid races */
772 command
->command
= -1;
773 sigemptyset (&ss_new
);
774 sigaddset (&ss_new
, SIGCHLD
);
775 sigprocmask (SIG_BLOCK
, &ss_new
, &ss_old
);
776 ival
= sigsetjmp (jmp_env
, 0);
777 sigprocmask (SIG_SETMASK
, &ss_old
, NULL
);
778 if (ival
== 0) do_longjmp
= 1;
782 if (command
->command
< 0) return 0;
784 if (command
->command
< 0) read (initctl_fd
, buffer
, COMMAND_SIZE
);
786 process_command (command
);
788 } /* End Function mywaitpid */
790 static pid_t
process_pidstat (pid_t pid
, int status
)
791 /* [RETURNS] The pid for a process to be reaped, 0 if no process is to be
792 reaped, and less than 0 if the boot scripts appear to have finished.
796 struct script_struct
*script
;
797 struct service_struct
*service
;
799 if ( ( script
= find_script_bypid (pid
, &starting_list
) ) == NULL
)
801 remove_entry (&starting_list
, script
);
802 if ( WIFEXITED (status
) && (WEXITSTATUS (status
) == 0) )
804 struct script_struct
*provider
;
806 /* Notify needers and other providers */
807 for (service
= script
->first_service
; service
!= NULL
;
808 service
= service
->next
)
810 signal_needers (service
, SIG_PRESENT
);
811 for (provider
= service
->attempting_providers
; provider
!= NULL
;
812 provider
= provider
->next_attempting_provider
)
813 kill (provider
->pid
, SIG_PRESENT
);
814 service
->attempting_providers
= NULL
;
816 insert_entry (&available_list
, script
);
817 return force_progress ();
819 failed
= ( WIFEXITED (status
) && (WEXITSTATUS (status
) == 2) ) ? 0 : 1;
820 for (service
= script
->first_service
; service
!= NULL
;
821 service
= service
->next
)
822 service
->failed
= failed
;
823 handle_nonworking (script
);
824 return force_progress ();
825 } /* End Function process_pidstat */
827 static void process_command (const struct command_struct
*command
)
830 struct script_struct
*script
;
831 struct service_struct
*service
;
833 switch (command
->command
)
837 (find_script_byname (command
->name
, &available_list
,
839 SIG_NOT_PRESENT
: SIG_PRESENT
);
842 ival
= run_command (command
->name
, command
->name
, command
->pid
);
848 else kill (command
->pid
, ival
);
850 case COMMAND_ROLLBACK
:
851 if (command
->name
[0] == '\0') script
= NULL
;
854 if ( ( script
= find_script_byname (command
->name
, &available_list
,
857 kill (command
->pid
, SIG_NOT_PRESENT
);
861 while (script
!= available_list
.first
)
864 struct script_struct
*victim
= available_list
.first
;
867 if ( ( pid
= fork () ) == 0 ) /* Child */
869 for (ival
= 1; ival
< NSIG
; ival
++) signal (ival
, SIG_DFL
);
870 open ("/dev/console", O_RDONLY
, 0);
871 open ("/dev/console", O_RDWR
, 0);
873 execlp (get_path (victim
->first_service
->name
),
874 victim
->first_service
->name
, "stop", NULL
);
875 err ( _("error running programme\n") );
876 _exit (SIG_NOT_STOPPED
);
878 else if (pid
== -1) break; /* Error */
881 while (waitpid (pid
, &ival
, 0) != pid
) /* Nothing */;
882 if ( WIFEXITED (ival
) && (WEXITSTATUS (ival
) == 0) )
884 sprintf (txt
, "Stopped service: %s\n",
885 victim
->first_service
->name
);
886 remove_entry (&available_list
, victim
);
894 (script
==available_list
.first
) ? SIG_STOPPED
: SIG_NOT_STOPPED
);
896 case COMMAND_DUMP_LIST
:
897 if (fork () == 0) /* Do it in a child process so pid=1 doesn't block */
901 if ( ( fp
= fopen (command
->name
, "w") ) == NULL
) _exit (1);
902 show_scripts (fp
, available_list
.first
, "AVAILABLE");
903 show_scripts (fp
, starting_list
.first
, "STARTING");
904 fputs ("UNAVAILABLE SERVICES:\n", fp
);
905 for (service
= unavailable_services
; service
!= NULL
;
906 service
= service
->next
)
907 fprintf (fp
, "%s (%s)\n", service
->name
,
908 service
->failed
? "FAILED" : "not configured");
913 case COMMAND_PROVIDE
:
915 if ( ( script
= find_script_bypid (command
->ppid
, &starting_list
) )
918 kill (command
->pid
, SIG_NOT_CHILD
);
921 if (find_script_byname (command
->name
, &available_list
, NULL
) != NULL
)
923 kill (command
->pid
, SIG_PRESENT
);
926 if (find_script_byname (command
->name
, &starting_list
, &service
)
928 { /* Someone else is trying to provide */
929 script
->next_attempting_provider
= service
->attempting_providers
;
930 service
->attempting_providers
= script
;
933 if ( ( service
= find_service_in_list (command
->name
,
934 unavailable_services
) )
936 { /* We're the first to try and provide: create it */
938 calloc (1, strlen (command
->name
) + sizeof *service
) )
941 kill (command
->pid
, SIG_NOT_CHILD
);
944 strcpy (service
->name
, command
->name
);
947 { /* Orphaned service: unhook and grab it */
948 if (service
->prev
== NULL
) unavailable_services
= service
->next
;
949 else service
->prev
->next
= service
->next
;
950 if (service
->next
!= NULL
) service
->next
->prev
= service
->prev
;
951 service
->next
= NULL
;
953 service
->prev
= script
->last_service
;
954 script
->last_service
->next
= service
;
955 script
->last_service
= service
;
956 kill (command
->pid
, SIG_NOT_PRESENT
);
962 } /* End Function process_command */
964 static int run_command (const char *file
, const char *name
, pid_t pid
)
966 struct script_struct
*script
;
967 struct needer_struct
*needer
= NULL
;
968 struct service_struct
*service
;
970 if (find_script_byname (name
, &available_list
, NULL
) != NULL
)
974 needer
= calloc (1, sizeof *needer
);
975 if (needer
== NULL
) return SIG_FAILED
;
978 script
= find_script_byname (name
, &starting_list
, &service
);
980 service
= find_service_in_list (name
, unavailable_services
);
986 if ( ( script
= calloc (1, sizeof *script
) ) == NULL
)
988 if (needer
!= NULL
) free (needer
);
993 service
= calloc (1, strlen (name
) + sizeof *service
);
999 strcpy (service
->name
, name
);
1001 else /* Unhook service from unavailable list */
1003 if (service
->prev
== NULL
) unavailable_services
= service
->next
;
1004 else service
->prev
->next
= service
->next
;
1005 if (service
->next
!= NULL
) service
->next
->prev
= service
->prev
;
1006 service
->prev
= NULL
;
1007 service
->next
= NULL
;
1009 switch ( script
->pid
= fork () )
1012 for (i
= 1; i
< NSIG
; i
++) signal (i
, SIG_DFL
);
1013 execlp (get_path (file
), service
->name
, "start", NULL
);
1014 sprintf (txt
, "error running programme: \"%s\"\n", service
->name
);
1018 case -1: /* Error */
1019 service
->next
= unavailable_services
;
1020 if (unavailable_services
!= NULL
)
1021 unavailable_services
->prev
= service
;
1022 unavailable_services
= service
;
1024 if (needer
!= NULL
) free (needer
);
1027 default: /* Parent */
1028 script
->first_service
= service
;
1029 script
->last_service
= service
;
1030 insert_entry (&starting_list
, script
);
1035 if (needer
== NULL
) return 0;
1036 needer
->next
= service
->needers
;
1037 service
->needers
= needer
;
1039 } /* End Function run_command */
1041 static struct service_struct
*find_service_in_list (const char *name
,
1042 struct service_struct
*sv
)
1044 for (; sv
!= NULL
; sv
= sv
->next
)
1045 if (strcmp (sv
->name
, name
) == 0) return (sv
);
1047 } /* End Function find_service_in_list */
1049 static struct script_struct
*find_script_byname (const char *name
,
1050 struct list_head
*head
,
1051 struct service_struct
**service
)
1053 struct script_struct
*script
;
1055 for (script
= head
->first
; script
!= NULL
; script
= script
->next
)
1057 struct service_struct
*sv
;
1059 if ( ( sv
= find_service_in_list (name
, script
->first_service
) )
1062 if (service
!= NULL
) *service
= sv
;
1067 } /* End Function find_script_byname */
1069 static struct script_struct
*find_script_bypid (pid_t pid
,
1070 struct list_head
*head
)
1072 struct script_struct
*script
;
1074 for (script
= head
->first
; script
!= NULL
; script
= script
->next
)
1075 if (script
->pid
== pid
) return (script
);
1077 } /* End Function find_script_bypid */
1079 static void insert_entry (struct list_head
*head
, struct script_struct
*entry
)
1081 if (entry
== NULL
) return;
1083 entry
->next
= head
->first
;
1084 if (head
->first
!= NULL
) head
->first
->prev
= entry
;
1085 head
->first
= entry
;
1086 if (head
->last
== NULL
) head
->last
= entry
;
1087 ++head
->num_entries
;
1088 } /* End Function insert_entry */
1090 static void remove_entry (struct list_head
*head
, struct script_struct
*entry
)
1092 if (entry
->prev
== NULL
) head
->first
= entry
->next
;
1093 else entry
->prev
->next
= entry
->next
;
1094 if (entry
->next
== NULL
) head
->last
= entry
->prev
;
1095 else entry
->next
->prev
= entry
->prev
;
1096 --head
->num_entries
;
1097 } /* End Function remove_entry */
1099 static void signal_needers (struct service_struct
*service
, int sig
)
1101 struct needer_struct
*needer
, *next_needer
;
1103 for (needer
= service
->needers
; needer
!= NULL
; needer
= next_needer
)
1105 kill (needer
->pid
, sig
);
1106 next_needer
= needer
->next
;
1110 service
->needers
= NULL
;
1111 } /* End Function signal_needers */
1113 static void handle_nonworking (struct script_struct
*script
)
1115 struct service_struct
*service
, *next
;
1117 for (service
= script
->first_service
; service
!= NULL
; service
= next
)
1119 struct script_struct
*provider
= service
->attempting_providers
;
1121 next
= service
->next
;
1122 if (provider
== NULL
)
1124 service
->next
= unavailable_services
;
1125 if (unavailable_services
!= NULL
)
1126 unavailable_services
->prev
= service
;
1127 unavailable_services
= service
;
1130 service
->attempting_providers
= provider
->next_attempting_provider
;
1131 provider
->last_service
->next
= service
;
1132 service
->prev
= provider
->last_service
;
1133 provider
->last_service
= service
;
1134 service
->next
= NULL
;
1135 kill (provider
->pid
, SIG_NOT_PRESENT
);
1138 } /* End Function handle_nonworking */
1140 static int force_progress (void)
1141 /* [RETURNS] 0 if boot scripts are still running, else -1.
1144 struct service_struct
*service
;
1146 if (starting_list
.num_entries
> num_needers
) return 0;
1147 /* No progress can be made: signal needers */
1148 for (service
= unavailable_services
; service
!= NULL
;
1149 service
= service
->next
)
1150 signal_needers (service
,
1151 service
->failed
? SIG_FAILED
: SIG_NOT_PRESENT
);
1152 return (starting_list
.num_entries
< 1) ? -1 : 0;
1153 } /* End Function force_progress */
1155 static void show_scripts (FILE *fp
, const struct script_struct
*script
,
1158 fprintf (fp
, "%s SERVICES:\n", type
);
1159 for (; script
!= NULL
; script
= script
->next
)
1161 struct service_struct
*service
= script
->first_service
;
1163 fputs (service
->name
, fp
);
1164 for (service
= service
->next
; service
!= NULL
; service
= service
->next
)
1165 fprintf (fp
, " (%s)", service
->name
);
1168 } /* End Function show_scripts */
1170 static const char *get_path (const char *file
)
1173 static char path
[PATH_SIZE
];
1175 if (file
[0] == '/') return file
;
1176 if (init_path
[0] == '\0') return file
;
1177 for (p1
= init_path
; *p1
!= '\0'; p1
= p2
)
1179 if ( ( p2
= strchr (p1
, ':') ) == NULL
)
1180 p2
= p1
+ strlen (p1
);
1181 strncpy (path
, p1
, p2
- p1
);
1182 path
[p2
- p1
] = '/';
1183 strcat (path
+ (p2
- p1
) + 1, file
);
1184 if (*p2
== ':') ++p2
;
1185 if (access (path
, X_OK
) == 0) return path
;
1188 } /* End Function get_path */