summaryrefslogtreecommitdiffstats
path: root/login-utils
diff options
context:
space:
mode:
authorKarel Zak2006-12-07 00:25:43 +0100
committerKarel Zak2006-12-07 00:25:43 +0100
commit22853e4a82c6ef7b336527529acb94b14a0b0fd8 (patch)
treeee28e4598c8c449d7e811711d8ce8eb17caecfb6 /login-utils
parentImported from util-linux-2.10f tarball. (diff)
downloadkernel-qcow2-util-linux-22853e4a82c6ef7b336527529acb94b14a0b0fd8.tar.gz
kernel-qcow2-util-linux-22853e4a82c6ef7b336527529acb94b14a0b0fd8.tar.xz
kernel-qcow2-util-linux-22853e4a82c6ef7b336527529acb94b14a0b0fd8.zip
Imported from util-linux-2.10m tarball.
Diffstat (limited to 'login-utils')
-rw-r--r--login-utils/Makefile13
-rw-r--r--login-utils/agetty.c26
-rw-r--r--login-utils/chfn.c12
-rw-r--r--login-utils/chsh.c1
-rw-r--r--login-utils/login.c53
-rw-r--r--login-utils/need.885
-rw-r--r--login-utils/need.c160
-rw-r--r--login-utils/shutdown.88
-rw-r--r--login-utils/shutdown.c14
-rw-r--r--login-utils/simpleinit.872
-rw-r--r--login-utils/simpleinit.c673
-rw-r--r--login-utils/simpleinit.h25
12 files changed, 948 insertions, 194 deletions
diff --git a/login-utils/Makefile b/login-utils/Makefile
index e277d1bad..0960854ec 100644
--- a/login-utils/Makefile
+++ b/login-utils/Makefile
@@ -18,7 +18,8 @@ MAN1.PASSWD= passwd.1
MAN8.GETTY= agetty.8
-MAN8.INIT= fastboot.8 fasthalt.8 halt.8 reboot.8 simpleinit.8 shutdown.8
+MAN8.INIT= fastboot.8 fasthalt.8 halt.8 reboot.8 simpleinit.8 shutdown.8 \
+ need.8
MAN8.PUTILS= vipw.8 vigr.8
@@ -27,7 +28,7 @@ MAN8.PUTILS= vipw.8 vigr.8
SBIN.GETTY= agetty
-SBIN.INIT= simpleinit shutdown
+SBIN.INIT= simpleinit shutdown need
BIN.PUTILS= login
@@ -109,10 +110,15 @@ newgrp: newgrp.o
setpwnam.o: $(LIB)/pathnames.h
shutdown.o: $(LIB)/pathnames.h $(LIB)/linux_reboot.h
shutdown: shutdown.o $(LIB)/my_reboot.o
-simpleinit.o: $(LIB)/pathnames.h $(LIB)/linux_reboot.h
+simpleinit.o: $(LIB)/pathnames.h $(LIB)/linux_reboot.h simpleinit.h
+need.o: simpleinit.h
+
simpleinit: simpleinit.o $(LIB)/my_reboot.o
$(CC) $(LDFLAGS) -o $@ $^ $(CRYPT)
+need: need.o
+ $(CC) $(LDFLAGS) -o $@ $^
+
vipw.o: $(LIB)/pathnames.h
vipw: vipw.o
@@ -177,6 +183,7 @@ install-init: $(SBIN.INIT)
(cd $(SHUTDOWNDIR); ln -sf shutdown fastboot)
(cd $(SHUTDOWNDIR); ln -sf shutdown halt)
(cd $(SHUTDOWNDIR); ln -sf shutdown fasthalt)
+ (cd $(SHUTDOWNDIR); ln -sf need display-services)
install-getty: $(SBIN.GETTY)
diff --git a/login-utils/agetty.c b/login-utils/agetty.c
index 9360be0ae..6ae4e8335 100644
--- a/login-utils/agetty.c
+++ b/login-utils/agetty.c
@@ -24,11 +24,11 @@
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
-#include <varargs.h>
+#include <stdarg.h>
#include <ctype.h>
#include <utmp.h>
#include <getopt.h>
-#include <memory.h>
+#include <time.h>
#include <sys/file.h>
#include "nls.h"
@@ -42,7 +42,6 @@
#ifdef USE_SYSLOG
#include <syslog.h>
-extern void closelog();
#endif
/*
@@ -216,12 +215,13 @@ static struct Speedtab speedtab[] = {
{ 0, 0 },
};
-#define P_(s) ()
+#define P_(s) s
+int main P_((int argc, char **argv));
void parse_args P_((int argc, char **argv, struct options *op));
void parse_speeds P_((struct options *op, char *arg));
void update_utmp P_((char *line));
void open_tty P_((char *tty, struct termio *tp, int local));
-void termio_init P_((struct termio *tp, int speed, int local));
+void termio_init P_((struct termio *tp, int speed, struct options *op));
void auto_baud P_((struct termio *tp));
void do_prompt P_((struct options *op, struct termio *tp));
void next_speed P_((struct termio *tp, struct options *op));
@@ -230,7 +230,7 @@ void termio_final P_((struct options *op, struct termio *tp, struct chardata *cp
int caps_lock P_((char *s));
int bcode P_((char *s));
void usage P_((void));
-void error P_((int va_alist));
+void error P_((const char *, ...));
#undef P_
/* The following is used for understandable diagnostics. */
@@ -499,7 +499,6 @@ parse_speeds(op, arg)
struct options *op;
char *arg;
{
- char *strtok();
char *cp;
debug(_("entered parse_speeds\n"));
@@ -522,8 +521,6 @@ update_utmp(line)
struct utmp ut;
time_t t;
int mypid = getpid();
- long time();
- long lseek();
struct utmp *utp;
/*
@@ -1178,13 +1175,9 @@ usage()
#define str2cpy(b,s1,s2) strcat(strcpy(b,s1),s2)
-/* VARARGS */
void
-error(va_alist)
- va_dcl
-{
+error(const char *fmt, ...) {
va_list ap;
- char *fmt;
#ifndef USE_SYSLOG
int fd;
#endif
@@ -1214,15 +1207,14 @@ error(va_alist)
* vsprintf() like interface.
*/
- va_start(ap);
- fmt = va_arg(ap, char *);
+ va_start(ap, fmt);
while (*fmt) {
if (strncmp(fmt, "%s", 2) == 0) {
(void) strcpy(bp, va_arg(ap, char *));
bp += strlen(bp);
fmt += 2;
} else if (strncmp(fmt, "%m", 2) == 0) {
- (void) strcpy(bp, sys_errlist[errno]);
+ (void) strcpy(bp, strerror(errno));
bp += strlen(bp);
fmt += 2;
} else {
diff --git a/login-utils/chfn.c b/login-utils/chfn.c
index 93e801e0c..73a9b8918 100644
--- a/login-utils/chfn.c
+++ b/login-utils/chfn.c
@@ -86,16 +86,12 @@ extern int setpwnam P((struct passwd *pwd));
/* we do not accept gecos field sizes longer than MAX_FIELD_SIZE */
#define MAX_FIELD_SIZE 256
-int main (argc, argv)
- int argc;
- char *argv[];
-{
+int main (int argc, char **argv) {
char *cp;
uid_t uid;
struct finfo oldf, newf;
boolean interactive;
int status;
- extern int errno;
#if REQUIRE_PASSWORD && USE_PAM
pam_handle_t *pamh = NULL;
int retcode;
@@ -316,13 +312,15 @@ static void parse_passwd (pw, pinfo)
struct passwd *pw;
struct finfo *pinfo;
{
+ char *gecos;
char *cp;
if (pw) {
pinfo->pw = pw;
pinfo->username = pw->pw_name;
- /* use pw_gecos */
- cp = pw->pw_gecos;
+ /* use pw_gecos - we take a copy since PAM destroys the original */
+ gecos = strdup(pw->pw_gecos);
+ cp = (gecos ? gecos : "");
pinfo->full_name = cp;
cp = strchr (cp, ',');
if (cp) { *cp = 0, cp++; } else return;
diff --git a/login-utils/chsh.c b/login-utils/chsh.c
index d1d14d0fa..f17b176fb 100644
--- a/login-utils/chsh.c
+++ b/login-utils/chsh.c
@@ -88,7 +88,6 @@ int main (argc, argv)
uid_t uid;
struct sinfo info;
struct passwd *pw;
- extern int errno;
#if REQUIRE_PASSWORD && USE_PAM
pam_handle_t *pamh = NULL;
int retcode;
diff --git a/login-utils/login.c b/login-utils/login.c
index 399b4aee1..eaaf1a520 100644
--- a/login-utils/login.c
+++ b/login-utils/login.c
@@ -30,7 +30,7 @@
'Lastlog' feature.
- - A lot of nitty gritty details has been adjusted in favour of
+ - A lot of nitty gritty details have been adjusted in favour of
HP-UX, e.g. /etc/securetty, default paths and the environment
variables assigned by 'login'.
@@ -304,7 +304,7 @@ consoletty(int fd)
int
main(int argc, char **argv)
{
- extern int errno, optind;
+ extern int optind;
extern char *optarg, **environ;
struct group *gr;
register int ch;
@@ -414,7 +414,7 @@ main(int argc, char **argv)
*p++ = ' ';
} else
ask = 1;
-
+
#ifndef __linux__
ioctlval = 0;
ioctl(0, TIOCLSET, &ioctlval);
@@ -479,12 +479,12 @@ main(int argc, char **argv)
opentty(ttyn);
tcsetattr(0,TCSAFLUSH,&tt);
}
-
- if ((tty = rindex(ttyn, '/')))
- ++tty;
+
+ if (strncmp(ttyn, "/dev/", 5) == 0)
+ tty = ttyn+5;
else
- tty = ttyn;
-
+ tty = ttyn;
+
openlog("login", LOG_ODELAY, LOG_AUTHPRIV);
#if 0
@@ -494,10 +494,11 @@ main(int argc, char **argv)
#endif
#ifdef USE_PAM
- /* username is initialized to NULL
- and if specified on the command line it is set.
- Therefore, we are safe not setting it to anything
- */
+ /*
+ * username is initialized to NULL
+ * and if specified on the command line it is set.
+ * Therefore, we are safe not setting it to anything
+ */
retcode = pam_start("login",username, &conv, &pamh);
if(retcode != PAM_SUCCESS) {
@@ -513,14 +514,18 @@ main(int argc, char **argv)
retcode = pam_set_item(pamh, PAM_TTY, tty);
PAM_FAIL_CHECK;
- /* Andrew.Taylor@cal.montage.ca: Provide a user prompt to PAM
- so that the "login: " prompt gets localized. Unfortunately,
- PAM doesn't have an interface to specify the "Password: " string (yet). */
+ /*
+ * Andrew.Taylor@cal.montage.ca: Provide a user prompt to PAM
+ * so that the "login: " prompt gets localized. Unfortunately,
+ * PAM doesn't have an interface to specify the "Password: " string
+ * (yet).
+ */
retcode = pam_set_item(pamh, PAM_USER_PROMPT, _("login: "));
PAM_FAIL_CHECK;
#if 0
- /* other than iso-8859-1
+ /*
+ * other than iso-8859-1
* one more time due to reset tty by PAM
*/
printf("\033(K");
@@ -602,12 +607,12 @@ main(int argc, char **argv)
ioctlval = 0;
ioctl(0, TIOCSETD, &ioctlval);
# endif
-
+
if (ask) {
fflag = 0;
getloginname();
}
-
+
/* Dirty patch to fix a gigantic security hole when using
yellow pages. This problem should be solved by the
libraries, and not by programs, but this must be fixed
@@ -672,7 +677,7 @@ main(int argc, char **argv)
pwd->pw_name, tty);
continue;
}
-
+
/*
* If no pre-authentication and a password exists
* for this user, prompt for one and verify it.
@@ -717,6 +722,7 @@ main(int argc, char **argv)
}
# endif /* KERBEROS */
memset(pp, 0, strlen(pp));
+
if (pwd && !strcmp(p, pwd->pw_passwd))
break;
@@ -852,7 +858,6 @@ main(int argc, char **argv)
/* for linux, write entries in utmp and wtmp */
{
struct utmp ut;
- int wtmp;
struct utmp *utp;
pid_t mypid = getpid();
@@ -924,15 +929,19 @@ Michael Riepe <michael@stud.uni-hannover.de>
#if 0
/* The O_APPEND open() flag should be enough to guarantee
atomic writes at end of file. */
- if((wtmp = open(_PATH_WTMP, O_APPEND|O_WRONLY)) >= 0) {
+ {
+ int wtmp;
+
+ if((wtmp = open(_PATH_WTMP, O_APPEND|O_WRONLY)) >= 0) {
write(wtmp, (char *)&ut, sizeof(ut));
close(wtmp);
+ }
}
#else
/* Probably all this locking below is just nonsense,
and the short version is OK as well. */
{
- int lf;
+ int lf, wtmp;
if ((lf = open(_PATH_WTMPLOCK, O_CREAT|O_WRONLY, 0660)) >= 0) {
flock(lf, LOCK_EX);
if ((wtmp = open(_PATH_WTMP, O_APPEND|O_WRONLY)) >= 0) {
diff --git a/login-utils/need.8 b/login-utils/need.8
new file mode 100644
index 000000000..cc3712d74
--- /dev/null
+++ b/login-utils/need.8
@@ -0,0 +1,85 @@
+.\" Copyright (C) 2000 Richard Gooch
+.\"
+.\" This program is free software; you can redistribute it and/or modify
+.\" it under the terms of the GNU General Public License as published by
+.\" the Free Software Foundation; either version 2 of the License, or
+.\" (at your option) any later version.
+.\"
+.\" This program is distributed in the hope that it will be useful,
+.\" but WITHOUT ANY WARRANTY; without even the implied warranty of
+.\" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+.\" GNU General Public License for more details.
+.\"
+.\" You should have received a copy of the GNU General Public License
+.\" along with this program; if not, write to the Free Software
+.\" Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+.\"
+.\" Richard Gooch may be reached by email at rgooch@atnf.csiro.au
+.\" The postal address is:
+.\" Richard Gooch, c/o ATNF, P. O. Box 76, Epping, N.S.W., 2121, Australia.
+.\"
+.\" need.8 Richard Gooch 28-FEB-2000
+.\"
+.TH NEED 8 "28 Feb 2000" "Util-Linux Package"
+.SH NAME
+need \- utility to tell simpleinit(8) to start a service
+.SH SYNOPSIS
+.nf
+\fBneed\fP [\fB-r\fP] [\fBservice\fP]
+.BR display-services
+.fi
+.SH DESCRIPTION
+The \fBneed\fP programme is a utility that tells \fBsimpleinit\fP(8)
+to start a \fIservice\fP (usually a script in \fI/sbin/init.d\fP) and
+will wait for the service to become available. If the service is
+already available, it will not be started again.
+
+When invoked as \fBdisplay-services\fP it will write the list of
+currently available services and the list of failed services to the
+standard output.
+
+The \fB-r\fP option is used to tell \fBsimpleinit\fP(8) to "roll back"
+(stop) services up to (but not including) \fIservice\fP. If
+\fIservice\fP is not specified, all services are stopped. The \fB-r\fP
+option thus allows the system to be partially or wholly shut down in
+an orderly fashion. The \fBshutdown\fP(8) programme still needs to be
+run.
+
+The \fBneed\fP programme is designed to help improve the robustness,
+scalability and readability of system boot scripts. It is now possible
+to write a modularised set of boot scripts without the complex and
+fragile numbered symlink scheme used in SysV-style boot scripts. Each
+script can simply declare, using \fBneed\fP(8), what must run before
+them.
+.SH EXIT CODE
+The exit code from \fBneed\fP is 0 if the service was successfully
+started, 1 if the service failed badly, and 2 if the service is
+unavailable (i.e. disabled in configuration files). These exit codes
+reflect the exit codes from the service startup scripts.
+
+The exit code from \fBneed -r\fP is 0 if the service was successfully
+stopped, 1 if the service could not be stopped, and 2 if the service
+was not available to start with. The service shutdown scripts may only
+return 0 (for success) or 1 (for failure).
+.SH SIGNALS
+\fBneed\fP(8) uses \fBSIGUSR1\fP, \fBSIGUSR2\fP and \fBSIGPOLL\fP for
+communication with \fBsimpleinit\fP(8). Don't send these signals to
+it.
+.SH FILES
+.PD 0
+.TP 20
+.BI /dev/initctl
+This is the control FIFO, created by \fBsimpleinit\fP(8), which
+\fBneed\fP(8) writes commands to.
+.SH SEE ALSO
+.BR simpleinit (8),
+.BR init (8)
+.PP
+A more complete discussion of the new boot script system, based on
+\fBneed\fP(8), is available from:
+http://www.atnf.csiro.au/~rgooch/linux/boot-scripts/
+.SH AUTHOR
+Richard Gooch (rgooch@atnf.csiro.au)
+.SH AVAILABILITY
+The Util-Linux package is available from:
+ftp://ftp.??.kernel.org/pub/linux/utils/util-linux/
diff --git a/login-utils/need.c b/login-utils/need.c
new file mode 100644
index 000000000..97690c461
--- /dev/null
+++ b/login-utils/need.c
@@ -0,0 +1,160 @@
+/* need.c
+
+ Source file for need (init(8) dependency tool).
+
+ Copyright (C) 2000 Richard Gooch
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ Richard Gooch may be reached by email at rgooch@atnf.csiro.au
+ The postal address is:
+ Richard Gooch, c/o ATNF, P. O. Box 76, Epping, N.S.W., 2121, Australia.
+*/
+
+/*
+ This tool will request init(8) to start a service and will wait for that
+ service to be available. If the service is already available, init(8) will
+ not start it again.
+ This tool may also be used to inspect the list of currently available
+ services.
+
+
+ Written by Richard Gooch 28-FEB-2000
+
+ Last updated by Richard Gooch 28-FEB-2000
+
+
+*/
+#include <unistd.h>
+#include <stdio.h>
+#include <limits.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <string.h>
+#include "simpleinit.h"
+
+
+static void signal_handler (int sig);
+
+
+static int caught_signal = 0;
+
+
+int main (int argc, char **argv)
+{
+ int fd, nbytes;
+ struct sigaction sa;
+ sigset_t ss;
+ char *ptr;
+ long buffer[COMMAND_SIZE / sizeof (long)];
+ struct command_struct *command = (struct command_struct *) buffer;
+
+ sigemptyset (&ss);
+ sigaddset (&ss, SIG_PRESENT);
+ sigaddset (&ss, SIG_NOT_PRESENT);
+ sigaddset (&ss, SIG_FAILED);
+ sigprocmask (SIG_BLOCK, &ss, NULL);
+ sigemptyset (&sa.sa_mask);
+ sa.sa_flags = 0;
+ sa.sa_handler = signal_handler;
+ sigaction (SIG_PRESENT, &sa, NULL);
+ sigaction (SIG_NOT_PRESENT, &sa, NULL);
+ sigaction (SIG_FAILED, &sa, NULL);
+ command->pid = getpid ();
+ if ( ( ptr = strrchr (argv[0], '/') ) == NULL ) ptr = argv[0];
+ else ++ptr;
+ if (strcmp (ptr, "display-services") == 0)
+ {
+ command->command = COMMAND_DUMP_LIST;
+ if (tmpnam (command->name) == NULL)
+ {
+ fprintf (stderr, "Unable to create a unique filename\t%s\n",
+ ERRSTRING);
+ exit (1);
+ }
+ if (mkfifo (command->name, S_IRUSR) != 0)
+ {
+ fprintf (stderr, "Unable to create FIFO: \"%s\"\t%s\n",
+ command->name, ERRSTRING);
+ exit (1);
+ }
+ }
+ else
+ {
+ if ( (argc > 1) && (strcmp (argv[1], "-r") == 0) )
+ {
+ command->command = COMMAND_ROLLBACK;
+ --argc;
+ ++argv;
+ }
+ else command->command = COMMAND_NEED;
+ if (argc == 2) strcpy (command->name, argv[1]);
+ else
+ {
+ if (command->command == COMMAND_ROLLBACK) command->name[0] = '\0';
+ else
+ {
+ fprintf (stderr, "Usage:\tneed programme\n");
+ exit (1);
+ }
+ }
+ }
+ if ( ( fd = open ("/dev/initctl", O_WRONLY, 0) ) < 0 )
+ {
+ fprintf (stderr, "Error opening\t%s\n", ERRSTRING);
+ exit (1);
+ }
+ if (write (fd, buffer, COMMAND_SIZE) < COMMAND_SIZE)
+ {
+ fprintf (stderr, "Error writing\t%s\n", ERRSTRING);
+ exit (1);
+ }
+ close (fd);
+ if (command->command != COMMAND_DUMP_LIST)
+ {
+ sigemptyset (&ss);
+ while (caught_signal == 0) sigsuspend (&ss);
+ switch (caught_signal)
+ {
+ case SIG_PRESENT:
+ return 0;
+ case SIG_NOT_PRESENT:
+ return 2;
+ case SIG_FAILED:
+ return 1;
+ }
+ return 3;
+ }
+ /* Read back the data and display it */
+ if ( ( fd = open (command->name, O_RDONLY, 0) ) < 0 )
+ {
+ fprintf (stderr, "Error opening:\"%s\"\t%s\n",
+ command->name, ERRSTRING);
+ exit (1);
+ }
+ unlink (command->name);
+ fflush (stdout);
+ while ( ( nbytes = read (fd, buffer, COMMAND_SIZE) ) > 0 )
+ write (1, buffer, nbytes);
+ close (fd);
+ return (0);
+} /* End Function main */
+
+static void signal_handler (int sig)
+{
+ caught_signal = sig;
+} /* End Function signal_handler */
diff --git a/login-utils/shutdown.8 b/login-utils/shutdown.8
index 961579bdc..492084a2b 100644
--- a/login-utils/shutdown.8
+++ b/login-utils/shutdown.8
@@ -2,7 +2,7 @@
.\" May be distributed under the GNU General Public License
.\"
.\"
-.TH SHUTDOWN 8 "24 July 1998" "Linux 2.0" "Linux Programmer's Manual"
+.TH SHUTDOWN 8 "2 March 2000" "Linux 2.0" "Linux Programmer's Manual"
.SH NAME
shutdown \- close down the system
.SH SYNOPSIS
@@ -66,6 +66,12 @@ unmounts all the disks,
.BR sync (2)'s
again, waits for a second, and then either terminates or reboots the
system.
+
+Prior to unmounting all discs, the \fBSIGQUIT\fP signal is sent to the
+\fBinit\fP process, which will in turn exec \fBshutdown\fP(8). This
+allows for clean unmounting, even if the old inode for the \fBinit\fP
+process was unlinked. If the current process ID (PID) equals 1, then
+\fBshutdown\fP(8) will pause forever.
.SH OPTIONS
.TP
.B \-h
diff --git a/login-utils/shutdown.c b/login-utils/shutdown.c
index 7ccb748ac..e3ec93c1e 100644
--- a/login-utils/shutdown.c
+++ b/login-utils/shutdown.c
@@ -31,6 +31,8 @@
* 1999-02-22 Arkadiusz Mi¶kiewicz <misiek@misiek.eu.org>
* - added Native Language Support
*
+ * 2000-03-02 Richard Gooch <rgooch@atnf.csiro.au>
+ * - pause forever if (pid == 1) and send SIGQUIT to pid = 1
*/
#include <stdio.h>
@@ -75,7 +77,7 @@ char halt_action[256]; /* to find out what to do upon halt */
#define WR(s) write(fd, s, strlen(s))
#define WRCRLF write(fd, "\r\n", 2)
-#define ERRSTRING sys_errlist[errno]
+#define ERRSTRING strerror(errno)
void
@@ -115,7 +117,11 @@ main(int argc, char *argv[])
int c,i;
int fd;
char *ptr;
-
+
+ if (getpid () == 1) {
+ for (i = 0; i < getdtablesize (); i++) close (i);
+ while (1) pause ();
+ }
setlocale(LC_ALL, "");
bindtextdomain(PACKAGE, LOCALEDIR);
textdomain(PACKAGE);
@@ -361,6 +367,10 @@ main(int argc, char *argv[])
Let us see whether people complain. */
unlink(_PATH_NOLOGIN);
+ /* Tell init(8) to exec so that the old inode may be freed cleanly if
+ required. Need to sleep before remounting root read-only */
+ kill (1, SIGQUIT);
+
sync();
sleep(2);
diff --git a/login-utils/simpleinit.8 b/login-utils/simpleinit.8
index ad942d3b3..2a2f666ed 100644
--- a/login-utils/simpleinit.8
+++ b/login-utils/simpleinit.8
@@ -5,7 +5,7 @@
.SH NAME
simpleinit \- process control initialization
.SH SYNOPSIS
-.B "init [ single ]"
+.B "init [ single ] [ script ]"
.SH DESCRIPTION
.B init
is invoked as the last step in the Linux boot sequence. If the
@@ -35,43 +35,6 @@ file is executed, and the information in
.I /etc/inittab
will be used to start processes.
-While
-.B init
-is running, several signals are trapped, with special action taken. Since
-.B init
-has PID 1, sending signals to the
-.B init
-process is easy with the
-.BR kill (1)
-command.
-
-If
-.B init
-catches a SIGHUP (hangup) signal, the
-.I /etc/inittab
-will be read again.
-
-If
-.B init
-catches a SIGTSTP (terminal stop) signal, no more processes will be
-spawned. This is a toggle, which is reset is
-.B init
-catches another SIGTSTP signal.
-
-If
-.B init
-catches a SIGINT (interrupt) signal,
-.B init
-will sync a few times, and try to start
-.IR reboot .
-Failing this,
-.B init
-will execute the system
-.BR reboot (2)
-call. Under Linux, it is possible to configure the Ctrl-Alt-Del sequence
-to send a signal to
-.B init
-instead of rebooting the system.
.SH "THE INITTAB FILE"
Because of the number of init programs which are appearing in the Linux
community, the documentation for the
@@ -83,6 +46,12 @@ man page, is presented here:
The format is
.RS
+.B bootprog=file
+
+.B fileprefix=string
+
+.B PATH=search path
+
.B "ttyline:termcap-entry:getty-command"
.RE
@@ -90,6 +59,10 @@ An example is as follows:
.nf
.RS
+bootprog = rc
+fileprefix = /sbin/
+PATH = /sbin:/bin
+
tty1:linux:/sbin/getty 9600 tty1
tty2:linux:/sbin/getty 9600 tty2
tty3:linux:/sbin/getty 9600 tty3
@@ -106,6 +79,29 @@ character are treated as comments. Please see documentation for the
.B getty (8)
command that you are using, since there are several of these in the Linux
community at this time.
+.SH SIGNALS
+\fBsimpleinit\fP(8) responds to signals in a variety of ways:
+.TP
+.B SIGHUP
+The \fI/etc/inittab\fP configuration file will be read again.
+.TP
+.B SIGTSTP
+This flips a toggle, which controls whether more processes will be
+spawned.
+.TP
+.B SIGINT
+\fBsimpleinit\fP(8) will sync a few times, and try to start
+\fBreboot\fP(8). Failing this, it will execute the system
+\fBreboot\fP(2) call. Under Linux, it is possible to configure the
+Ctrl-Alt-Del sequence to send a signal to the \fBinit\fP process
+instead of rebooting the system (\fBsimpleinit\fP(8) does this by
+default).
+.TP
+.B SIGQUIT
+The \fBreboot\fP(8) programme is executed in place of the
+\fBsimpleinit\fP(8) programme. This allows \fBreboot\fP(8) to cleanly
+remount (read-only) the root filesystem, even if the old inode for the
+\fBinit\fP process was unlinked.
.SH FILES
.I /etc/inittab
.br
diff --git a/login-utils/simpleinit.c b/login-utils/simpleinit.c
index 1e496ad59..1baf50cd7 100644
--- a/login-utils/simpleinit.c
+++ b/login-utils/simpleinit.c
@@ -8,8 +8,8 @@
#include <sys/types.h>
#include <stdlib.h>
#include <unistd.h>
-#include <limits.h>
#include <stdio.h>
+#include <ctype.h>
#include <fcntl.h>
#include <string.h>
#include <signal.h>
@@ -18,7 +18,13 @@
#include <sys/wait.h>
#include <sys/stat.h>
#include <sys/sysmacros.h>
+#include <sys/time.h>
+#include <sys/ioctl.h>
+#include <dirent.h>
+#include <termios.h>
#include <utmp.h>
+#include <setjmp.h>
+#include <sched.h>
#ifdef SHADOW_PWD
# include <shadow.h>
#endif
@@ -26,12 +32,15 @@
#include "pathnames.h"
#include "linux_reboot.h"
#include "nls.h"
+#include "simpleinit.h"
-#define CMDSIZ 150 /* max size of a line in inittab */
-#define NUMCMD 30 /* max number of lines in inittab */
-#define NUMTOK 20 /* max number of tokens in inittab command */
+#define CMDSIZ 150 /* max size of a line in inittab */
+#define NUMCMD 30 /* max number of lines in inittab */
+#define NUMTOK 20 /* max number of tokens in inittab command */
+#define PATH_SIZE (CMDSIZ+CMDSIZ+1)
+
+#define MAX_RESPAWN_RATE 5 /* number of respawns per 100 seconds */
-#define RUN_RC
#define TZFILE "/etc/TZ"
char tzone[CMDSIZ];
/* #define DEBUGGING */
@@ -43,21 +52,42 @@ char tzone[CMDSIZ];
#define ever (;;)
struct initline {
- pid_t pid;
- char tty[10];
- char termcap[30];
- char *toks[NUMTOK];
- char line[CMDSIZ];
+ pid_t pid;
+ char tty[10];
+ char termcap[30];
+ char *toks[NUMTOK];
+ char line[CMDSIZ];
+ struct timeval last_start;
+ signed long rate;
};
struct initline inittab[NUMCMD];
int numcmd;
int stopped = 0; /* are we stopped */
-
-int do_rc();
+static char boot_script[PATH_SIZE] = _PATH_RC;
+static char script_prefix[PATH_SIZE] = "\0";
+static int caught_sigint = 0;
+static const char *initctl_name = "/dev/initctl";
+static int initctl_fd = -1;
+static volatile int do_longjmp = 0;
+static sigjmp_buf jmp_env;
+
+
+static void do_single ();
+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(), int_handler(), set_tz(), write_wtmp();
-int boot_single();
+void tstp_handler ();
+void int_handler ();
+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 ();
+
void err(char *s)
{
@@ -82,7 +112,7 @@ enter_single()
execl(_PATH_BSHELL, _PATH_BSHELL, NULL);
err(_("exec of single user shell failed\n"));
} else if(pid > 0) {
- while(wait(&i) != pid) /* nothing */;
+ while (waitpid (pid, &i, 0) != pid) /* Nothing */;
} else if(pid < 0) {
err(_("fork of single user shell failed\n"));
}
@@ -91,43 +121,63 @@ enter_single()
int main(int argc, char *argv[])
{
- int vec,i;
- pid_t pid;
+ int vec,i;
+ int want_single = 0;
+ pid_t pid;
+ struct sigaction sa;
+
#ifdef SET_TZ
set_tz();
#endif
- signal(SIGTSTP, tstp_handler);
- signal(SIGINT, int_handler);
+ sigemptyset (&sa.sa_mask);
+ sa.sa_flags = 0;
+ signal (SIGTSTP, tstp_handler);
+ signal (SIGINT, int_handler);
+ sa.sa_handler = sigchild_handler;
+ sigaction (SIGCHLD, &sa, NULL);
+ sa.sa_handler = sigquit_handler;
+ sigaction (SIGQUIT, &sa, NULL);
setlocale(LC_ALL, "");
bindtextdomain(PACKAGE, LOCALEDIR);
textdomain(PACKAGE);
+ my_reboot (LINUX_REBOOT_CMD_CAD_OFF);
+ /* Find script to run. Command-line overrides config file overrides
+ built-in default */
+ for (i = 0; i < NUMCMD; i++) inittab[i].pid = -1;
+ read_inittab ();
+ for (i = 1; i < argc; i++) {
+ if (strcmp (argv[i], "single") == 0) want_single = 1;
+ else {
+ char path[PATH_SIZE];
+
+ strcpy (path, script_prefix);
+ strcat (path, argv[i]);
+ if (access (path, R_OK | X_OK) == 0)
+ strcpy (boot_script, path);
+ }
+ }
+
+ if ( ( initctl_fd = open (initctl_name, O_RDWR, 0) ) < 0 ) {
+ mkfifo (initctl_name, S_IRUSR | S_IWUSR);
+ if ( ( initctl_fd = open (initctl_name, O_RDWR, 0) ) < 0 )
+ err ( _("error opening fifo\n") );
+ }
- /*
- * start up in single user mode if /etc/singleboot exists or if
- * argv[1] is "single".
- */
- if(boot_single(0, argc, argv)) enter_single();
+ if ( want_single || (access (_PATH_SINGLE, R_OK) == 0) ) do_single ();
-#ifdef RUN_RC
/*If we get a SIGTSTP before multi-user mode, do nothing*/
while(stopped)
pause();
- if(do_rc() != 0 && boot_single(1, argc, argv) && !stopped)
- enter_single();
+
+ if ( do_rc_tty (boot_script) ) do_single ();
+
while(stopped) /*Also if /etc/rc fails & we get SIGTSTP*/
pause();
-#endif
write_wtmp(); /* write boottime record */
-
- for(i = 0; i < NUMCMD; i++)
- inittab[i].pid = -1;
-
- read_inittab();
-
#ifdef DEBUGGING
for(i = 0; i < numcmd; i++) {
char **p;
@@ -140,13 +190,15 @@ int main(int argc, char *argv[])
#endif
signal(SIGHUP, hup_handler);
- for(i = 0; i < getdtablesize(); i++) close(i);
+ for (i = 0; i < getdtablesize (); i++)
+ if (i != initctl_fd) close (i);
for(i = 0; i < numcmd; i++)
spawn(i);
for ever {
- pid = wait(&vec);
+ pid = mywaitpid (-1, &vec, NULL);
+ if (pid == 0) continue;
/* clear utmp entry, and append to wtmp if possible */
{
@@ -194,80 +246,170 @@ int main(int argc, char *argv[])
#define MAXTRIES 3 /* number of tries allowed when giving the password */
/*
- * return true if we should boot up in singleuser mode. If argv[i] is
- * "single" or the file /etc/singleboot exists, then singleuser mode should
- * be entered. If /etc/securesingle exists ask for root password first.
+ * return true if singleuser mode is allowed.
+ * If /etc/securesingle exists ask for root password, otherwise always OK.
*/
-int boot_single(int singlearg, int argc, char *argv[])
+static int check_single_ok ()
{
- char *pass, *rootpass = NULL;
- struct passwd *pwd;
- int i;
+ char *pass, *rootpass = NULL;
+ struct passwd *pwd;
+ int i;
- for(i = 1; i < argc; i++) {
- if(argv[i] && !strcmp(argv[i], "single")) singlearg = 1;
- }
+ if (access (_PATH_SECURE, R_OK) != 0) return 1;
+ if ( ( pwd = getpwnam ("root") ) || ( pwd = getpwuid (0) ) )
+ rootpass = pwd->pw_passwd;
+ else
+ return 1; /* a bad /etc/passwd should not lock out */
- if(access(_PATH_SINGLE, 04) == 0 || singlearg) {
- if(access(_PATH_SECURE, 04) == 0) {
- if((pwd = getpwnam("root")) || (pwd = getpwuid(0)))
- rootpass = pwd->pw_passwd;
- else
- return 1; /* a bad /etc/passwd should not lock out */
-
- for(i = 0; i < MAXTRIES; i++) {
- pass = getpass(_("Password: "));
- if(pass == NULL) continue;
-
- if(!strcmp(crypt(pass, rootpass), rootpass)) {
- return 1;
- }
+ for (i = 0; i < MAXTRIES; i++)
+ {
+ pass = getpass (_ ("Password: ") );
+ if (pass == NULL) continue;
+
+ if ( !strcmp (crypt (pass, rootpass), rootpass) ) return 1;
- puts(_("\nWrong password.\n"));
- }
- } else return 1;
- }
- return 0;
+ puts (_ ("\nWrong password.\n") );
+ }
+ return 0;
}
+static void do_single ()
+{
+ char path[PATH_SIZE];
+
+ if (caught_sigint) return;
+ strcpy (path, script_prefix);
+ strcat (path, "single");
+ if (access (path, R_OK | X_OK) == 0)
+ if (do_rc_tty (path) == 0) return;
+ if ( check_single_ok () ) enter_single ();
+} /* End Function do_single */
+
/*
- * run /etc/rc. The environment is passed to the script, so the RC environment
- * variable can be used to decide what to do. RC may be set from LILO.
+ * run boot script(s). The environment is passed to the script(s), so the RC
+ * environment variable can be used to decide what to do.
+ * RC may be set from LILO.
+ * [RETURNS] 0 on success (exit status convention), otherwise error.
*/
-int do_rc()
+static int do_rc_tty (const char *path)
{
- pid_t pid;
- int stat;
-
- if((pid = fork()) == 0) {
- /* the child */
- char *argv[2];
-
- argv[0] = _PATH_BSHELL;
- argv[1] = (char *)0;
-
- close(0);
- if(open(_PATH_RC, O_RDONLY, 0) == 0) {
- execv(_PATH_BSHELL, argv);
- err(_("exec rc failed\n"));
- _exit(2);
- }
- err(_("open of rc file failed\n"));
- _exit(1);
- } else if(pid > 0) {
- /* parent, wait till rc process dies before spawning */
- while(wait(&stat) != pid) /* nothing */;
- } else if(pid < 0) {
- err(_("fork of rc shell failed\n"));
- }
- return WEXITSTATUS(stat);
-}
+ int status, rc_status = 0;
+ pid_t pid;
+ 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 () )
+ {
+ case 0: /* Child */
+ for (status = 1; status < NSIG; status++) signal (status, SIG_DFL);
+ sigfillset (&ss);
+ sigprocmask (SIG_UNBLOCK, &ss, NULL);
+ sigdelset (&ss, SIGINT);
+ sigdelset (&ss, SIGQUIT);
+ 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 */
+ case -1: /* Error */
+ return (1);
+ /*break;*/
+ default: /* Parent */
+ break;
+ }
+ /* Parent */
+ process_path (path, run_file);
+ while (rc_status == 0)
+ if (mywaitpid (-1, &status, &rc_status) == pid)
+ 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;
+} /* End Function do_rc_tty */
+
+static int process_path ( const char *path, int (*func) (const char *path) )
+{
+ struct stat statbuf;
+ DIR *dp;
+ struct dirent *de;
+
+ if (stat (path, &statbuf) != 0)
+ {
+ err (_ ("stat of path failed\n") );
+ return 1;
+ }
+ if ( !( statbuf.st_mode & (S_IXUSR | S_IXGRP | S_IXOTH) ) ) return 0;
+ if ( !S_ISDIR (statbuf.st_mode) ) return (*func) (path);
+ if ( ( dp = opendir (path) ) == NULL )
+ {
+ err (_ ("open of directory failed\n") );
+ return 1;
+ }
+ while ( ( de = readdir (dp) ) != NULL )
+ {
+ int retval;
+ char newpath[PATH_SIZE];
+
+ if (de->d_name[0] == '.') continue;
+ retval = sprintf (newpath, "%s/%s", path, de->d_name);
+ if (newpath[retval - 1] == '~') continue; /* Common mistake */
+ if ( ( retval = process_path (newpath, func) ) ) return retval;
+ }
+ closedir (dp);
+ return 0;
+} /* End Function process_path */
+
+static int preload_file (const char *path)
+{
+ int fd;
+ char ch;
+
+ if ( ( fd = open (path, O_RDONLY, 0) ) < 0) return 0;
+ while (read (fd, &ch, 1) == 1) lseek (fd, 1023, SEEK_CUR);
+ close (fd);
+ return 0;
+} /* End Function preload_file */
+
+static int run_file (const char *path)
+{
+ const char *ptr;
+
+ if ( ( ptr = strrchr ( (char *) path, '/' ) ) == NULL ) ptr = path;
+ else ++ptr;
+ return (run_command (path, ptr, 0) == SIG_FAILED) ? 1 : 0;
+} /* End Function preload_file */
void spawn(int i)
{
pid_t pid;
int j;
-
+ signed long ds_taken;
+ struct timeval ct;
+
+ if (inittab[i].toks[0] == NULL) return;
+ /* Check if respawning too fast */
+ gettimeofday (&ct, NULL);
+ ds_taken = ct.tv_sec - inittab[i].last_start.tv_sec;
+ ds_taken *= 10;
+ ds_taken += (ct.tv_usec - inittab[i].last_start.tv_usec) / 100000;
+ if (ds_taken < 1)
+ ds_taken = 1;
+ inittab[i].rate = (9 * inittab[i].rate + 1000 / ds_taken) / 10;
+ if (inittab[i].rate > MAX_RESPAWN_RATE) {
+ char txt[256];
+
+ inittab[i].toks[0] = NULL;
+ inittab[i].pid = -1;
+ inittab[i].rate = 0;
+ sprintf (txt,"respawning: \"%s\" too fast: quenching entry\n",
+ inittab[i].tty);
+ err (_(txt));
+ return;
+ }
+
if((pid = fork()) < 0) {
inittab[i].pid = -1;
err(_("fork failed\n"));
@@ -276,6 +418,7 @@ void spawn(int i)
if(pid) {
/* this is the parent */
inittab[i].pid = pid;
+ inittab[i].last_start = ct;
return;
} else {
/* this is the child */
@@ -310,7 +453,9 @@ void read_inittab()
FILE *f;
char buf[CMDSIZ];
int i,j,k;
+ int has_prog = 0;
char *ptr, *getty;
+ char prog[PATH_SIZE];
#ifdef SPECIAL_CONSOLE_TERM
char tty[50];
struct stat stb;
@@ -322,21 +467,43 @@ void read_inittab()
if(!(f = fopen(_PATH_INITTAB, "r"))) {
err(_("cannot open inittab\n"));
- _exit(1);
+ return;
}
+ prog[0] = '\0';
i = 0;
while(!feof(f) && i < NUMCMD - 2) {
if(fgets(buf, CMDSIZ - 1, f) == 0) break;
buf[CMDSIZ-1] = 0;
for(k = 0; k < CMDSIZ && buf[k]; k++) {
- if(buf[k] == '#') {
+ if ((buf[k] == '#') || (buf[k] == '\n')) {
buf[k] = 0; break;
}
}
if(buf[0] == 0 || buf[0] == '\n') continue;
+ ptr = strchr (buf, '=');
+ if (ptr) {
+ ptr++;
+ if ( !strncmp (buf, "bootprog", 8) ) {
+ while ( isspace (*ptr) ) ++ptr;
+ strcpy (prog, ptr);
+ has_prog = 1;
+ continue;
+ }
+ if ( !strncmp (buf, "fileprefix", 10) ) {
+ while ( isspace (*ptr) ) ++ptr;
+ strcpy (script_prefix, ptr);
+ continue;
+ }
+ if ( !strncmp (buf, "PATH", 4) ) {
+ while ( isspace (*ptr) ) ++ptr;
+ setenv ("PATH", ptr, 1);
+ continue;
+ }
+ }
+
(void) strcpy(inittab[i].line, buf);
@@ -373,6 +540,17 @@ void read_inittab()
}
fclose(f);
numcmd = i;
+ if (has_prog) {
+ int len;
+ char path[PATH_SIZE];
+
+ strcpy (path, script_prefix);
+ strcat (path, prog);
+ len = strlen (path);
+ if (path[len - 1] == '/') path[len - 1] = '\0';
+ if (access (path, R_OK | X_OK) == 0)
+ strcpy (boot_script, path);
+ }
}
void hup_handler()
@@ -413,13 +591,9 @@ void tstp_handler()
void int_handler()
{
- /*
- * After Linux 0.96b PL1, we get a SIGINT when
- * the user presses Ctrl-Alt-Del...
- */
-
- int pid;
+ pid_t pid;
+ caught_sigint = 1;
sync();
sync();
pid = fork();
@@ -432,6 +606,17 @@ void int_handler()
my_reboot(LINUX_REBOOT_CMD_RESTART);
}
+static void sigchild_handler (int sig)
+{
+ if (!do_longjmp) return;
+ siglongjmp (jmp_env, 1);
+}
+
+static void sigquit_handler (int sig)
+{
+ execl (_PATH_REBOOT, _PATH_REBOOT, NULL); /* It knows pid=1 must sleep */
+}
+
void set_tz()
{
FILE *f;
@@ -466,3 +651,285 @@ void write_wtmp()
close(lf);
}
}
+
+
+struct waiter_struct
+{
+ struct waiter_struct *next;
+ pid_t pid;
+};
+
+struct script_struct
+{
+ pid_t pid;
+ struct script_struct *prev, *next;
+ struct waiter_struct *first_waiter;
+ char name[1];
+};
+
+struct list_head
+{
+ struct script_struct *first, *last;
+};
+
+
+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 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 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)
+{
+ 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;
+
+ if (initctl_fd < 0) return waitpid (pid, status, 0);
+ if (status == NULL) status = &ival;
+ if ( ( pid = waitpid (pid, status, WNOHANG) ) > 0 )
+ {
+ process_pidstat (pid, *status, rc_status);
+ return pid;
+ }
+ /* Some magic to avoid races */
+ command->command = -1;
+ sigemptyset (&ss_new);
+ sigaddset (&ss_new, SIGCHLD);
+ sigprocmask (SIG_BLOCK, &ss_new, &ss_old);
+ ival = sigsetjmp (jmp_env, 0);
+ sigprocmask (SIG_SETMASK, &ss_old, NULL);
+ if (ival == 0) do_longjmp = 1;
+ else
+ {
+ do_longjmp = 0;
+ if (command->command < 0) return 0;
+ }
+ if (command->command < 0) read (initctl_fd, buffer, COMMAND_SIZE);
+ do_longjmp = 0;
+ switch (command->command)
+ {
+ case COMMAND_TEST:
+ kill (command->pid,
+ (find_script (command->name, &available_list) == 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);
+ break;
+ case COMMAND_ROLLBACK:
+ if (command->name[0] == '\0') script = NULL;
+ else
+ {
+ if ( ( script = find_script (command->name, &available_list) )
+ == NULL )
+ {
+ kill (command->pid, SIG_NOT_PRESENT);
+ break;
+ }
+ }
+ while (script != available_list.first)
+ {
+ struct script_struct *victim = available_list.first;
+
+ if ( ( pid = fork () ) == 0 ) /* Child */
+ {
+ for (ival = 1; ival < NSIG; ival++) signal (ival, SIG_DFL);
+ open ("/dev/console", O_RDONLY, 0);
+ open ("/dev/console", O_RDWR, 0);
+ dup2 (1, 2);
+ execlp (victim->name, victim->name, "stop", NULL);
+ err ( _("error running programme\n") );
+ _exit (SIG_NOT_STOPPED);
+ }
+ else if (pid == -1) break; /* Error */
+ else /* Parent */
+ {
+ while (waitpid (pid, &ival, 0) != pid) /* Nothing */;
+ if ( WIFEXITED (ival) && (WEXITSTATUS (ival) == 0) )
+ {
+ remove_entry (&available_list, victim);
+ free (victim);
+ }
+ else break;
+ }
+ }
+ kill (command->pid,
+ (script ==available_list.first) ? SIG_STOPPED : SIG_NOT_STOPPED);
+ break;
+ case COMMAND_DUMP_LIST:
+ if (fork () == 0)
+ {
+ 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);
+ fclose (fp);
+ _exit (0);
+ }
+ 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 */
+
+static int run_command (const char *path, const char *name, pid_t pid)
+{
+ struct script_struct *script;
+ struct waiter_struct *waiter = NULL;
+
+ 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 (pid != 0)
+ {
+ waiter = calloc (1, sizeof *waiter);
+ if (waiter == NULL) return SIG_FAILED;
+ waiter->pid = pid;
+ }
+ script = find_script (name, &starting_list);
+ if (script == NULL)
+ {
+ int i;
+
+ script = calloc (1, strlen (name) + sizeof *script);
+ if (script == NULL)
+ {
+ if (waiter != NULL) free (waiter);
+ return SIG_FAILED;
+ }
+ strcpy (script->name, name);
+ 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") );
+ _exit (SIG_FAILED);
+ break;
+ case -1: /* Error */
+ free (script);
+ if (waiter != NULL) free (waiter);
+ return SIG_FAILED;
+ /*break;*/
+ default: /* Parent */
+ insert_entry (&starting_list, script);
+ sched_yield ();
+ break;
+ }
+ }
+ if (waiter == NULL) return 0;
+ waiter->next = script->first_waiter;
+ script->first_waiter = waiter;
+ return 0;
+} /* End Function run_command */
+
+static struct script_struct *find_script (const char *name,
+ struct list_head *head)
+{
+ struct script_struct *entry;
+
+ for (entry = head->first; entry != NULL; entry = entry->next)
+ {
+ if (strcmp (entry->name, name) == 0) return (entry);
+ }
+ return NULL;
+} /* End Function find_script */
+
+static void insert_entry (struct list_head *head, struct script_struct *entry)
+{
+ if (entry == NULL) return;
+ entry->prev = NULL;
+ entry->next = head->first;
+ if (head->first != NULL) head->first->prev = entry;
+ head->first = entry;
+ if (head->last == NULL) head->last = entry;
+} /* End Function insert_entry */
+
+static void remove_entry (struct list_head *head, struct script_struct *entry)
+{
+ if (entry->prev == NULL) head->first = entry->next;
+ else entry->prev->next = entry->next;
+ if (entry->next == NULL) head->last = entry->prev;
+ else entry->next->prev = entry->prev;
+} /* End Function remove_entry */
+
+static void signal_waiters (struct script_struct *script, int sig)
+{
+ struct waiter_struct *waiter, *next_waiter;
+
+ for (waiter = script->first_waiter; waiter != NULL; waiter = next_waiter)
+ {
+ kill (waiter->pid, sig);
+ next_waiter = waiter->next;
+ free (waiter);
+ }
+ script->first_waiter = NULL;
+} /* End Function signal_waiters */
+
+static void forget_those_not_present ()
+{
+ struct script_struct *curr, *next;
+
+ for (curr = failed_list.first; curr != NULL; curr = next)
+ {
+ next = curr->next;
+ free (curr);
+ }
+ failed_list.first = NULL;
+ failed_list.last = NULL;
+ for (curr = unavailable_list.first; curr != NULL; curr = next)
+ {
+ next = curr->next;
+ free (curr);
+ }
+ unavailable_list.first = NULL;
+ unavailable_list.last = NULL;
+} /* End Function forget_those_not_present */
diff --git a/login-utils/simpleinit.h b/login-utils/simpleinit.h
new file mode 100644
index 000000000..ff26480f7
--- /dev/null
+++ b/login-utils/simpleinit.h
@@ -0,0 +1,25 @@
+#include <limits.h>
+#include <errno.h>
+
+
+#define ERRSTRING strerror (errno)
+#define COMMAND_SIZE (PIPE_BUF - 4)
+
+
+#define COMMAND_TEST 0 /* No wait, signal */
+#define COMMAND_NEED 1 /* Wait, signal */
+#define COMMAND_ROLLBACK 2 /* Wait, signal */
+#define COMMAND_DUMP_LIST 3 /* No wait, no signal */
+
+#define SIG_PRESENT SIGUSR1 /* Service is available */
+#define SIG_STOPPED SIGUSR1 /* Service was stopped OK */
+#define SIG_NOT_PRESENT SIGUSR2 /* Not present, but that's OK */
+#define SIG_FAILED SIGPOLL /* Startup failed */
+#define SIG_NOT_STOPPED SIGPOLL /* Failed to stop */
+
+struct command_struct /* Must always be COMMAND_SIZE */
+{
+ signed int command;
+ pid_t pid;
+ char name[1];
+};