summaryrefslogtreecommitdiffstats
path: root/login-utils/simpleinit.c
diff options
context:
space:
mode:
Diffstat (limited to 'login-utils/simpleinit.c')
-rw-r--r--login-utils/simpleinit.c563
1 files changed, 408 insertions, 155 deletions
diff --git a/login-utils/simpleinit.c b/login-utils/simpleinit.c
index 1baf50cd7..9c4b63a5f 100644
--- a/login-utils/simpleinit.c
+++ b/login-utils/simpleinit.c
@@ -64,8 +64,10 @@ struct initline {
struct initline inittab[NUMCMD];
int numcmd;
int stopped = 0; /* are we stopped */
-static char boot_script[PATH_SIZE] = _PATH_RC;
+static char boot_prog[PATH_SIZE] = _PATH_RC;
static char script_prefix[PATH_SIZE] = "\0";
+static char final_prog[PATH_SIZE] = "\0";
+static char init_path[PATH_SIZE] = "\0";
static int caught_sigint = 0;
static const char *initctl_name = "/dev/initctl";
static int initctl_fd = -1;
@@ -73,23 +75,27 @@ static volatile int do_longjmp = 0;
static sigjmp_buf jmp_env;
-static void do_single ();
+static void do_single (void);
static int do_rc_tty (const char *path);
static int process_path ( const char *path, int (*func) (const char *path) );
static int preload_file (const char *path);
static int run_file (const char *path);
-void spawn(), hup_handler(), read_inittab();
-void tstp_handler ();
-void int_handler ();
+static void spawn (int i), read_inittab (void);
+static void hup_handler (int sig);
+static void sigtstp_handler (int sig);
+static void int_handler (int sig);
static void sigchild_handler (int sig);
static void sigquit_handler (int sig);
-void set_tz(), write_wtmp();
-static pid_t mywaitpid (pid_t pid, int *status, int *rc_status);
-static int run_command (const char *path, const char *name, pid_t pid);
-static void forget_those_not_present ();
+static void sigterm_handler (int sig);
+#ifdef SET_TZ
+static void set_tz (void);
+#endif
+static void write_wtmp (void);
+static pid_t mywaitpid (pid_t pid, int *status);
+static int run_command (const char *file, const char *name, pid_t pid);
-void err(char *s)
+static void err (char *s)
{
int fd;
@@ -100,8 +106,7 @@ void err(char *s)
close(fd);
}
-void
-enter_single()
+static void enter_single (void)
{
pid_t pid;
int i;
@@ -130,10 +135,13 @@ int main(int argc, char *argv[])
#ifdef SET_TZ
set_tz();
#endif
+ signal (SIGINT, int_handler);
sigemptyset (&sa.sa_mask);
sa.sa_flags = 0;
- signal (SIGTSTP, tstp_handler);
- signal (SIGINT, int_handler);
+ sa.sa_handler = sigtstp_handler;
+ sigaction (SIGTSTP, &sa, NULL);
+ sa.sa_handler = sigterm_handler;
+ sigaction (SIGTERM, &sa, NULL);
sa.sa_handler = sigchild_handler;
sigaction (SIGCHLD, &sa, NULL);
sa.sa_handler = sigquit_handler;
@@ -156,7 +164,7 @@ int main(int argc, char *argv[])
strcpy (path, script_prefix);
strcat (path, argv[i]);
if (access (path, R_OK | X_OK) == 0)
- strcpy (boot_script, path);
+ strcpy (boot_prog, path);
}
}
@@ -172,7 +180,7 @@ int main(int argc, char *argv[])
while(stopped)
pause();
- if ( do_rc_tty (boot_script) ) do_single ();
+ if ( do_rc_tty (boot_prog) ) do_single ();
while(stopped) /*Also if /etc/rc fails & we get SIGTSTP*/
pause();
@@ -195,10 +203,26 @@ int main(int argc, char *argv[])
for(i = 0; i < numcmd; i++)
spawn(i);
-
+
+ if (final_prog[0] != '\0') {
+ switch ( fork () )
+ {
+ case 0: /* Child */
+ execl (final_prog, final_prog, "start", NULL);
+ err ( _("error running finalprog\n") );
+ _exit (1);
+ break;
+ case -1: /* Error */
+ err ( _("error forking finalprog\n") );
+ break;
+ default: /* Parent */
+ break;
+ }
+ }
+
for ever {
- pid = mywaitpid (-1, &vec, NULL);
- if (pid == 0) continue;
+ pid = mywaitpid (-1, &vec);
+ if (pid < 1) continue;
/* clear utmp entry, and append to wtmp if possible */
{
@@ -249,7 +273,7 @@ int main(int argc, char *argv[])
* return true if singleuser mode is allowed.
* If /etc/securesingle exists ask for root password, otherwise always OK.
*/
-static int check_single_ok ()
+static int check_single_ok (void)
{
char *pass, *rootpass = NULL;
struct passwd *pwd;
@@ -273,7 +297,7 @@ static int check_single_ok ()
return 0;
}
-static void do_single ()
+static void do_single (void)
{
char path[PATH_SIZE];
@@ -293,15 +317,15 @@ static void do_single ()
*/
static int do_rc_tty (const char *path)
{
- int status, rc_status = 0;
- pid_t pid;
+ int status;
+ pid_t pid, child;
sigset_t ss;
if (caught_sigint) return 0;
process_path (path, preload_file);
/* Launch off a subprocess to start a new session (required for frobbing
the TTY) and capture control-C */
- switch ( pid = fork () )
+ switch ( child = fork () )
{
case 0: /* Child */
for (status = 1; status < NSIG; status++) signal (status, SIG_DFL);
@@ -312,7 +336,7 @@ static int do_rc_tty (const char *path)
setsid ();
ioctl (0, TIOCSCTTY, 0); /* I want my control-C */
sigsuspend (&ss); /* Should never return, should just be killed */
- break; /* No-one is controlled by this TTY now */
+ break; /* No-one else is controlled by this TTY now */
case -1: /* Error */
return (1);
/*break;*/
@@ -321,13 +345,15 @@ static int do_rc_tty (const char *path)
}
/* Parent */
process_path (path, run_file);
- while (rc_status == 0)
- if (mywaitpid (-1, &status, &rc_status) == pid)
+ while (1)
+ {
+ if ( ( pid = mywaitpid (-1, &status) ) == child )
return (WTERMSIG (status) == SIGINT) ? 0 : 1;
- forget_those_not_present ();
- kill (pid, SIGKILL);
- while (waitpid (pid, NULL, 0) != pid) /* Nothing */;
- return (rc_status < 0) ? 1 : 0;
+ if (pid < 0) break;
+ }
+ kill (child, SIGKILL);
+ while (waitpid (child, NULL, 0) != child) /* Nothing */;
+ return 0;
} /* End Function do_rc_tty */
static int process_path ( const char *path, int (*func) (const char *path) )
@@ -368,7 +394,7 @@ static int preload_file (const char *path)
char ch;
if ( ( fd = open (path, O_RDONLY, 0) ) < 0) return 0;
- while (read (fd, &ch, 1) == 1) lseek (fd, 1023, SEEK_CUR);
+ while (read (fd, &ch, 1) == 1) lseek (fd, 1024, SEEK_CUR);
close (fd);
return 0;
} /* End Function preload_file */
@@ -380,9 +406,9 @@ static int run_file (const char *path)
if ( ( ptr = strrchr ( (char *) path, '/' ) ) == NULL ) ptr = path;
else ++ptr;
return (run_command (path, ptr, 0) == SIG_FAILED) ? 1 : 0;
-} /* End Function preload_file */
+} /* End Function run_file */
-void spawn(int i)
+static void spawn (int i)
{
pid_t pid;
int j;
@@ -419,6 +445,7 @@ void spawn(int i)
/* this is the parent */
inittab[i].pid = pid;
inittab[i].last_start = ct;
+ sched_yield ();
return;
} else {
/* this is the child */
@@ -448,7 +475,7 @@ void spawn(int i)
}
}
-void read_inittab()
+static void read_inittab (void)
{
FILE *f;
char buf[CMDSIZ];
@@ -460,7 +487,7 @@ void read_inittab()
char tty[50];
struct stat stb;
#endif
- char *termenv, *getenv();
+ char *termenv;
termenv = getenv("TERM"); /* set by kernel */
/* termenv = "vt100"; */
@@ -502,6 +529,16 @@ void read_inittab()
setenv ("PATH", ptr, 1);
continue;
}
+ if ( !strncmp (buf, "INIT_PATH", 9) ) {
+ while ( isspace (*ptr) ) ++ptr;
+ strcpy (init_path, ptr);
+ continue;
+ }
+ if ( !strncmp (buf, "finalprog", 8) ) {
+ while ( isspace (*ptr) ) ++ptr;
+ strcpy (final_prog, ptr);
+ continue;
+ }
}
@@ -549,11 +586,11 @@ void read_inittab()
len = strlen (path);
if (path[len - 1] == '/') path[len - 1] = '\0';
if (access (path, R_OK | X_OK) == 0)
- strcpy (boot_script, path);
+ strcpy (boot_prog, path);
}
}
-void hup_handler()
+static void hup_handler (int sig)
{
int i,j;
int oldnum;
@@ -564,7 +601,7 @@ void hup_handler()
memcpy(savetab, inittab, NUMCMD * sizeof(struct initline));
oldnum = numcmd;
- read_inittab();
+ read_inittab ();
for(i = 0; i < numcmd; i++) {
had_already = 0;
@@ -581,15 +618,21 @@ void hup_handler()
(void) signal(SIGHUP, hup_handler);
}
-void tstp_handler()
+static void sigtstp_handler (int sig)
{
- stopped = ~stopped;
- if(!stopped) hup_handler();
+ stopped = ~stopped;
+ if (!stopped) hup_handler (sig);
+} /* End Function sigtstp_handler */
- signal(SIGTSTP, tstp_handler);
-}
+static void sigterm_handler (int sig)
+{
+ int i;
+
+ for (i = 0; i < numcmd; i++)
+ if (inittab[i].pid > 0) kill (inittab[i].pid, SIGTERM);
+} /* End Function sigterm_handler */
-void int_handler()
+static void int_handler (int sig)
{
pid_t pid;
@@ -617,7 +660,8 @@ static void sigquit_handler (int sig)
execl (_PATH_REBOOT, _PATH_REBOOT, NULL); /* It knows pid=1 must sleep */
}
-void set_tz()
+#ifdef SET_TZ
+static void set_tz (void)
{
FILE *f;
int len;
@@ -629,8 +673,9 @@ void set_tz()
tzone[len-1] = 0; /* get rid of the '\n' */
setenv("TZ", tzone, 0);
}
+#endif
-void write_wtmp()
+static void write_wtmp (void)
{
int fd, lf;
struct utmp ut;
@@ -653,44 +698,66 @@ void write_wtmp()
}
-struct waiter_struct
+struct needer_struct
{
- struct waiter_struct *next;
+ struct needer_struct *next;
pid_t pid;
};
+struct service_struct
+{
+ struct service_struct *prev, *next; /* Script services chain */
+ struct needer_struct *needers; /* Needers waiting for service */
+ struct script_struct *attempting_providers;
+ int failed; /* TRUE if attempting provider failed badly */
+ char name[1];
+};
+
struct script_struct
{
pid_t pid;
- struct script_struct *prev, *next;
- struct waiter_struct *first_waiter;
- char name[1];
+ struct script_struct *prev, *next; /* For the list */
+ struct service_struct *first_service, *last_service; /*First is true name*/
+ struct script_struct *next_attempting_provider; /* Provider chain */
};
struct list_head
{
struct script_struct *first, *last;
+ unsigned int num_entries;
};
-static struct list_head available_list = {NULL, NULL};
-static struct list_head starting_list = {NULL, NULL};
-static struct list_head failed_list = {NULL, NULL};
-static struct list_head unavailable_list = {NULL, NULL};
+static struct list_head available_list = {NULL, NULL, 0};
+static struct list_head starting_list = {NULL, NULL, 0};
+static struct service_struct *unavailable_services = NULL; /* For needers */
+static int num_needers = 0;
-static void process_pidstat (pid_t pid, int status, int *rc_status);
-static struct script_struct *find_script (const char *name,
- struct list_head *head);
+static int process_pidstat (pid_t pid, int status);
+static void process_command (const struct command_struct *command);
+static struct service_struct *find_service_in_list (const char *name,
+ struct service_struct *sv);
+static struct script_struct *find_script_byname
+ (const char *name,struct list_head *head, struct service_struct **service);
+static struct script_struct *find_script_bypid (pid_t pid,
+ struct list_head *head);
static void insert_entry (struct list_head *head, struct script_struct *entry);
static void remove_entry (struct list_head *head, struct script_struct *entry);
-static void signal_waiters (struct script_struct *script, int sig);
-
-
-static pid_t mywaitpid (pid_t pid, int *status, int *rc_status)
+static void signal_needers (struct service_struct *service, int sig);
+static void handle_nonworking (struct script_struct *script);
+static int force_progress (void);
+static void show_scripts (FILE *fp, const struct script_struct *script,
+ const char *type);
+static const char *get_path (const char *file);
+
+
+static pid_t mywaitpid (pid_t pid, int *status)
+/* [RETURNS] The pid for a process to be reaped, 0 if no process is to be
+ reaped, and less than 0 if the boot scripts appear to have finished.
+*/
{
int ival;
- struct script_struct *script;
sigset_t ss_new, ss_old;
long buffer[COMMAND_SIZE / sizeof (long)];
struct command_struct *command = (struct command_struct *) buffer;
@@ -699,8 +766,7 @@ static pid_t mywaitpid (pid_t pid, int *status, int *rc_status)
if (status == NULL) status = &ival;
if ( ( pid = waitpid (pid, status, WNOHANG) ) > 0 )
{
- process_pidstat (pid, *status, rc_status);
- return pid;
+ return process_pidstat (pid, *status);
}
/* Some magic to avoid races */
command->command = -1;
@@ -717,23 +783,76 @@ static pid_t mywaitpid (pid_t pid, int *status, int *rc_status)
}
if (command->command < 0) read (initctl_fd, buffer, COMMAND_SIZE);
do_longjmp = 0;
+ process_command (command);
+ return 0;
+} /* End Function mywaitpid */
+
+static pid_t process_pidstat (pid_t pid, int status)
+/* [RETURNS] The pid for a process to be reaped, 0 if no process is to be
+ reaped, and less than 0 if the boot scripts appear to have finished.
+*/
+{
+ int failed;
+ struct script_struct *script;
+ struct service_struct *service;
+
+ if ( ( script = find_script_bypid (pid, &starting_list) ) == NULL )
+ return pid;
+ remove_entry (&starting_list, script);
+ if ( WIFEXITED (status) && (WEXITSTATUS (status) == 0) )
+ {
+ struct script_struct *provider;
+
+ /* Notify needers and other providers */
+ for (service = script->first_service; service != NULL;
+ service = service->next)
+ {
+ signal_needers (service, SIG_PRESENT);
+ for (provider = service->attempting_providers; provider != NULL;
+ provider = provider->next_attempting_provider)
+ kill (provider->pid, SIG_PRESENT);
+ service->attempting_providers = NULL;
+ }
+ insert_entry (&available_list, script);
+ return force_progress ();
+ }
+ failed = ( WIFEXITED (status) && (WEXITSTATUS (status) == 2) ) ? 0 : 1;
+ for (service = script->first_service; service != NULL;
+ service = service->next)
+ service->failed = failed;
+ handle_nonworking (script);
+ return force_progress ();
+} /* End Function process_pidstat */
+
+static void process_command (const struct command_struct *command)
+{
+ int ival;
+ struct script_struct *script;
+ struct service_struct *service;
+
switch (command->command)
{
case COMMAND_TEST:
kill (command->pid,
- (find_script (command->name, &available_list) == NULL) ?
+ (find_script_byname (command->name, &available_list,
+ NULL) == NULL) ?
SIG_NOT_PRESENT : SIG_PRESENT);
break;
case COMMAND_NEED:
ival = run_command (command->name, command->name, command->pid);
- if (ival != 0) kill (command->pid, ival);
+ if (ival == 0)
+ {
+ ++num_needers;
+ force_progress ();
+ }
+ else kill (command->pid, ival);
break;
case COMMAND_ROLLBACK:
if (command->name[0] == '\0') script = NULL;
else
{
- if ( ( script = find_script (command->name, &available_list) )
- == NULL )
+ if ( ( script = find_script_byname (command->name, &available_list,
+ NULL) ) == NULL )
{
kill (command->pid, SIG_NOT_PRESENT);
break;
@@ -741,7 +860,9 @@ static pid_t mywaitpid (pid_t pid, int *status, int *rc_status)
}
while (script != available_list.first)
{
+ pid_t pid;
struct script_struct *victim = available_list.first;
+ char txt[256];
if ( ( pid = fork () ) == 0 ) /* Child */
{
@@ -749,7 +870,8 @@ static pid_t mywaitpid (pid_t pid, int *status, int *rc_status)
open ("/dev/console", O_RDONLY, 0);
open ("/dev/console", O_RDWR, 0);
dup2 (1, 2);
- execlp (victim->name, victim->name, "stop", NULL);
+ execlp (get_path (victim->first_service->name),
+ victim->first_service->name, "stop", NULL);
err ( _("error running programme\n") );
_exit (SIG_NOT_STOPPED);
}
@@ -759,8 +881,11 @@ static pid_t mywaitpid (pid_t pid, int *status, int *rc_status)
while (waitpid (pid, &ival, 0) != pid) /* Nothing */;
if ( WIFEXITED (ival) && (WEXITSTATUS (ival) == 0) )
{
+ sprintf (txt, "Stopped service: %s\n",
+ victim->first_service->name);
remove_entry (&available_list, victim);
free (victim);
+ err (txt);
}
else break;
}
@@ -769,119 +894,187 @@ static pid_t mywaitpid (pid_t pid, int *status, int *rc_status)
(script ==available_list.first) ? SIG_STOPPED : SIG_NOT_STOPPED);
break;
case COMMAND_DUMP_LIST:
- if (fork () == 0)
+ if (fork () == 0) /* Do it in a child process so pid=1 doesn't block */
{
FILE *fp;
if ( ( fp = fopen (command->name, "w") ) == NULL ) _exit (1);
- fputs ("AVAILABLE SERVICES:\n", fp);
- for (script = available_list.first; script != NULL;
- script = script->next) fprintf (fp, "%s\n", script->name);
- fputs ("FAILED SERVICES:\n", fp);
- for (script = failed_list.first; script != NULL;
- script = script->next) fprintf (fp, "%s\n", script->name);
+ show_scripts (fp, available_list.first, "AVAILABLE");
+ show_scripts (fp, starting_list.first, "STARTING");
+ fputs ("UNAVAILABLE SERVICES:\n", fp);
+ for (service = unavailable_services; service != NULL;
+ service = service->next)
+ fprintf (fp, "%s (%s)\n", service->name,
+ service->failed ? "FAILED" : "not configured");
fclose (fp);
_exit (0);
}
break;
+ case COMMAND_PROVIDE:
+ /* Sanity check */
+ if ( ( script = find_script_bypid (command->ppid, &starting_list) )
+ == NULL )
+ {
+ kill (command->pid, SIG_NOT_CHILD);
+ break;
+ }
+ if (find_script_byname (command->name, &available_list, NULL) != NULL)
+ {
+ kill (command->pid, SIG_PRESENT);
+ break;
+ }
+ if (find_script_byname (command->name, &starting_list, &service)
+ != NULL)
+ { /* Someone else is trying to provide */
+ script->next_attempting_provider = service->attempting_providers;
+ service->attempting_providers = script;
+ break;
+ }
+ if ( ( service = find_service_in_list (command->name,
+ unavailable_services) )
+ == NULL )
+ { /* We're the first to try and provide: create it */
+ if ( ( service =
+ calloc (1, strlen (command->name) + sizeof *service) )
+ == NULL )
+ {
+ kill (command->pid, SIG_NOT_CHILD);
+ break;
+ }
+ strcpy (service->name, command->name);
+ }
+ else
+ { /* Orphaned service: unhook and grab it */
+ if (service->prev == NULL) unavailable_services = service->next;
+ else service->prev->next = service->next;
+ if (service->next != NULL) service->next->prev = service->prev;
+ service->next = NULL;
+ }
+ service->prev = script->last_service;
+ script->last_service->next = service;
+ script->last_service = service;
+ kill (command->pid, SIG_NOT_PRESENT);
+ break;
case -1:
default:
break;
}
- return 0;
-} /* End Function mywaitpid */
-
-static void process_pidstat (pid_t pid, int status, int *rc_status)
-{
- struct script_struct *script;
-
- if (initctl_fd < 0) return;
- if (pid < 1) return;
- for (script = starting_list.first; script != NULL; script = script->next)
- if (script->pid == pid) break;
- if (script == NULL) return;
- remove_entry (&starting_list, script);
- if ( WIFEXITED (status) && (WEXITSTATUS (status) == 0) )
- {
- signal_waiters (script, SIG_PRESENT);
- insert_entry (&available_list, script);
- }
- else if ( WIFEXITED (status) && (WEXITSTATUS (status) == 2) )
- {
- signal_waiters (script, SIG_NOT_PRESENT);
- insert_entry (&unavailable_list, script);
- }
- else
- {
- signal_waiters (script, SIG_FAILED);
- insert_entry (&failed_list, script);
- }
- if ( (rc_status == NULL) || (starting_list.first != NULL) ) return;
- *rc_status = (failed_list.first == NULL) ? 1 : -1;
-} /* End Function process_pidstat */
+} /* End Function process_command */
-static int run_command (const char *path, const char *name, pid_t pid)
+static int run_command (const char *file, const char *name, pid_t pid)
{
struct script_struct *script;
- struct waiter_struct *waiter = NULL;
+ struct needer_struct *needer = NULL;
+ struct service_struct *service;
- if (find_script (name, &available_list) != NULL) return SIG_PRESENT;
- if (find_script (name, &failed_list) != NULL) return SIG_FAILED;
- if (find_script (name, &unavailable_list) != NULL) return SIG_NOT_PRESENT;
+ if (find_script_byname (name, &available_list, NULL) != NULL)
+ return SIG_PRESENT;
if (pid != 0)
{
- waiter = calloc (1, sizeof *waiter);
- if (waiter == NULL) return SIG_FAILED;
- waiter->pid = pid;
+ needer = calloc (1, sizeof *needer);
+ if (needer == NULL) return SIG_FAILED;
+ needer->pid = pid;
}
- script = find_script (name, &starting_list);
+ script = find_script_byname (name, &starting_list, &service);
+ if (script == NULL)
+ service = find_service_in_list (name, unavailable_services);
if (script == NULL)
{
int i;
+ char txt[1024];
- script = calloc (1, strlen (name) + sizeof *script);
- if (script == NULL)
+ if ( ( script = calloc (1, sizeof *script) ) == NULL )
{
- if (waiter != NULL) free (waiter);
+ if (needer != NULL) free (needer);
return SIG_FAILED;
}
- strcpy (script->name, name);
+ if (service == NULL)
+ {
+ service = calloc (1, strlen (name) + sizeof *service);
+ if (service == NULL)
+ {
+ free (script);
+ return SIG_FAILED;
+ }
+ strcpy (service->name, name);
+ }
+ else /* Unhook service from unavailable list */
+ {
+ if (service->prev == NULL) unavailable_services = service->next;
+ else service->prev->next = service->next;
+ if (service->next != NULL) service->next->prev = service->prev;
+ service->prev = NULL;
+ service->next = NULL;
+ }
switch ( script->pid = fork () )
{
case 0: /* Child */
for (i = 1; i < NSIG; i++) signal (i, SIG_DFL);
- execlp (path, script->name, "start", NULL);
- err ( _("error running programme\n") );
+ execlp (get_path (file), service->name, "start", NULL);
+ sprintf (txt, "error running programme: \"%s\"\n", service->name);
+ err ( _(txt) );
_exit (SIG_FAILED);
break;
case -1: /* Error */
+ service->next = unavailable_services;
+ if (unavailable_services != NULL)
+ unavailable_services->prev = service;
+ unavailable_services = service;
free (script);
- if (waiter != NULL) free (waiter);
+ if (needer != NULL) free (needer);
return SIG_FAILED;
/*break;*/
default: /* Parent */
+ script->first_service = service;
+ script->last_service = service;
insert_entry (&starting_list, script);
sched_yield ();
break;
}
}
- if (waiter == NULL) return 0;
- waiter->next = script->first_waiter;
- script->first_waiter = waiter;
+ if (needer == NULL) return 0;
+ needer->next = service->needers;
+ service->needers = needer;
return 0;
} /* End Function run_command */
-static struct script_struct *find_script (const char *name,
- struct list_head *head)
+static struct service_struct *find_service_in_list (const char *name,
+ struct service_struct *sv)
+{
+ for (; sv != NULL; sv = sv->next)
+ if (strcmp (sv->name, name) == 0) return (sv);
+ return NULL;
+} /* End Function find_service_in_list */
+
+static struct script_struct *find_script_byname (const char *name,
+ struct list_head *head,
+ struct service_struct **service)
{
- struct script_struct *entry;
+ struct script_struct *script;
- for (entry = head->first; entry != NULL; entry = entry->next)
+ for (script = head->first; script != NULL; script = script->next)
{
- if (strcmp (entry->name, name) == 0) return (entry);
+ struct service_struct *sv;
+
+ if ( ( sv = find_service_in_list (name, script->first_service) )
+ != NULL )
+ {
+ if (service != NULL) *service = sv;
+ return (script);
+ }
}
return NULL;
-} /* End Function find_script */
+} /* End Function find_script_byname */
+
+static struct script_struct *find_script_bypid (pid_t pid,
+ struct list_head *head)
+{
+ struct script_struct *script;
+
+ for (script = head->first; script != NULL; script = script->next)
+ if (script->pid == pid) return (script);
+ return NULL;
+} /* End Function find_script_bypid */
static void insert_entry (struct list_head *head, struct script_struct *entry)
{
@@ -891,6 +1084,7 @@ static void insert_entry (struct list_head *head, struct script_struct *entry)
if (head->first != NULL) head->first->prev = entry;
head->first = entry;
if (head->last == NULL) head->last = entry;
+ ++head->num_entries;
} /* End Function insert_entry */
static void remove_entry (struct list_head *head, struct script_struct *entry)
@@ -899,37 +1093,96 @@ static void remove_entry (struct list_head *head, struct script_struct *entry)
else entry->prev->next = entry->next;
if (entry->next == NULL) head->last = entry->prev;
else entry->next->prev = entry->prev;
+ --head->num_entries;
} /* End Function remove_entry */
-static void signal_waiters (struct script_struct *script, int sig)
+static void signal_needers (struct service_struct *service, int sig)
{
- struct waiter_struct *waiter, *next_waiter;
+ struct needer_struct *needer, *next_needer;
- for (waiter = script->first_waiter; waiter != NULL; waiter = next_waiter)
+ for (needer = service->needers; needer != NULL; needer = next_needer)
{
- kill (waiter->pid, sig);
- next_waiter = waiter->next;
- free (waiter);
+ kill (needer->pid, sig);
+ next_needer = needer->next;
+ free (needer);
+ --num_needers;
}
- script->first_waiter = NULL;
-} /* End Function signal_waiters */
+ service->needers = NULL;
+} /* End Function signal_needers */
-static void forget_those_not_present ()
+static void handle_nonworking (struct script_struct *script)
{
- struct script_struct *curr, *next;
+ struct service_struct *service, *next;
- for (curr = failed_list.first; curr != NULL; curr = next)
+ for (service = script->first_service; service != NULL; service = next)
{
- next = curr->next;
- free (curr);
+ struct script_struct *provider = service->attempting_providers;
+
+ next = service->next;
+ if (provider == NULL)
+ {
+ service->next = unavailable_services;
+ if (unavailable_services != NULL)
+ unavailable_services->prev = service;
+ unavailable_services = service;
+ continue;
+ }
+ service->attempting_providers = provider->next_attempting_provider;
+ provider->last_service->next = service;
+ service->prev = provider->last_service;
+ provider->last_service = service;
+ service->next = NULL;
+ kill (provider->pid, SIG_NOT_PRESENT);
}
- failed_list.first = NULL;
- failed_list.last = NULL;
- for (curr = unavailable_list.first; curr != NULL; curr = next)
+ free (script);
+} /* End Function handle_nonworking */
+
+static int force_progress (void)
+/* [RETURNS] 0 if boot scripts are still running, else -1.
+*/
+{
+ struct service_struct *service;
+
+ if (starting_list.num_entries > num_needers) return 0;
+ /* No progress can be made: signal needers */
+ for (service = unavailable_services; service != NULL;
+ service = service->next)
+ signal_needers (service,
+ service->failed ? SIG_FAILED : SIG_NOT_PRESENT);
+ return (starting_list.num_entries < 1) ? -1 : 0;
+} /* End Function force_progress */
+
+static void show_scripts (FILE *fp, const struct script_struct *script,
+ const char *type)
+{
+ fprintf (fp, "%s SERVICES:\n", type);
+ for (; script != NULL; script = script->next)
+ {
+ struct service_struct *service = script->first_service;
+
+ fputs (service->name, fp);
+ for (service = service->next; service != NULL; service = service->next)
+ fprintf (fp, " (%s)", service->name);
+ putc ('\n', fp);
+ }
+} /* End Function show_scripts */
+
+static const char *get_path (const char *file)
+{
+ char *p1, *p2;
+ static char path[PATH_SIZE];
+
+ if (file[0] == '/') return file;
+ if (init_path[0] == '\0') return file;
+ for (p1 = init_path; *p1 != '\0'; p1 = p2)
{
- next = curr->next;
- free (curr);
+ if ( ( p2 = strchr (p1, ':') ) == NULL )
+ p2 = p1 + strlen (p1);
+ strncpy (path, p1, p2 - p1);
+ path[p2 - p1] = '/';
+ strcat (path + (p2 - p1) + 1, file);
+ if (*p2 == ':') ++p2;
+ if (access (path, X_OK) == 0) return path;
}
- unavailable_list.first = NULL;
- unavailable_list.last = NULL;
-} /* End Function forget_those_not_present */
+ return file;
+} /* End Function get_path */