summaryrefslogtreecommitdiffstats
path: root/login-utils
diff options
context:
space:
mode:
authorKarel Zak2006-12-07 00:25:44 +0100
committerKarel Zak2006-12-07 00:25:44 +0100
commit66ee8158b69525e12060ef558cb5d77feadab1dc (patch)
tree08b30f2d07df9213f5647bc6f60b5090a263ef43 /login-utils
parentImported from util-linux-2.10m tarball. (diff)
downloadkernel-qcow2-util-linux-66ee8158b69525e12060ef558cb5d77feadab1dc.tar.gz
kernel-qcow2-util-linux-66ee8158b69525e12060ef558cb5d77feadab1dc.tar.xz
kernel-qcow2-util-linux-66ee8158b69525e12060ef558cb5d77feadab1dc.zip
Imported from util-linux-2.10s tarball.
Diffstat (limited to 'login-utils')
-rw-r--r--login-utils/Makefile54
-rw-r--r--login-utils/agetty.c39
-rw-r--r--login-utils/checktty.c17
-rw-r--r--login-utils/chfn.c31
-rw-r--r--login-utils/chsh.c31
-rw-r--r--login-utils/cryptocard.c4
-rw-r--r--login-utils/cryptocard.h7
-rw-r--r--login-utils/initctl.8 (renamed from login-utils/need.8)51
-rw-r--r--login-utils/initctl.c (renamed from login-utils/need.c)120
-rw-r--r--login-utils/islocal.c2
-rw-r--r--login-utils/islocal.h1
-rw-r--r--login-utils/last.c54
-rw-r--r--login-utils/login.c105
-rw-r--r--login-utils/login.h8
-rw-r--r--login-utils/newgrp.c1
-rw-r--r--login-utils/passwd.c26
-rw-r--r--login-utils/setpwnam.c5
-rw-r--r--login-utils/setpwnam.h7
-rw-r--r--login-utils/shutdown.c191
-rw-r--r--login-utils/simpleinit.847
-rw-r--r--login-utils/simpleinit.c563
-rw-r--r--login-utils/simpleinit.h3
-rw-r--r--login-utils/ttymsg.c10
-rw-r--r--login-utils/ttymsg.h2
-rw-r--r--login-utils/vipw.c28
-rw-r--r--login-utils/wall.c45
26 files changed, 975 insertions, 477 deletions
diff --git a/login-utils/Makefile b/login-utils/Makefile
index 0960854ec..d986501e1 100644
--- a/login-utils/Makefile
+++ b/login-utils/Makefile
@@ -19,7 +19,7 @@ MAN1.PASSWD= passwd.1
MAN8.GETTY= agetty.8
MAN8.INIT= fastboot.8 fasthalt.8 halt.8 reboot.8 simpleinit.8 shutdown.8 \
- need.8
+ initctl.8
MAN8.PUTILS= vipw.8 vigr.8
@@ -28,7 +28,7 @@ MAN8.PUTILS= vipw.8 vigr.8
SBIN.GETTY= agetty
-SBIN.INIT= simpleinit shutdown need
+SBIN.INIT= simpleinit shutdown initctl
BIN.PUTILS= login
@@ -84,14 +84,22 @@ all-misc: $(USRBIN.MISC)
# Rules for everything else
-agetty.o: $(LIB)/pathnames.h
+checktty.o login.o: login.h
+cryptocard.o login.o: cryptocard.h
+chfn.o chsh.o islocal.o passwd.o: islocal.h
+chfn.o chsh.o passwd.o setpwnam.o vipw.o: setpwnam.h
+chfn.o chsh.o login.o newgrp.o passwd.o simpleinit.o: my_crypt.h
+initctl.o simpleinit.o: simpleinit.h
+agetty.o islocal.o last.o setpwnam.o shutdown.o simpleinit.o \
+ vipw.o: $(LIB)/pathnames.h
+shutdown.o simpleinit.o: $(LIB)/linux_reboot.h
+wall.o: ttymsg.h $(LIB)/carefulputc.h
+
agetty: agetty.o
chfn: chfn.o islocal.o setpwnam.o $(LIB)/env.o
$(CC) $(LDFLAGS) -o $@ $^ $(CRYPT) $(PAM)
chsh: chsh.o islocal.o setpwnam.o $(LIB)/env.o
$(CC) $(LDFLAGS) -o $@ $^ $(CRYPT) $(PAM)
-islocal.o: $(LIB)/pathnames.h
-last.o: $(LIB)/pathnames.h
last: last.o
ifeq "$(HAVE_PAM)" "yes"
@@ -107,36 +115,35 @@ mesg: mesg.o $(ERR_O)
newgrp: newgrp.o
$(CC) $(LDFLAGS) -o $@ $^ $(CRYPT) $(PAM)
-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.h
-need.o: simpleinit.h
simpleinit: simpleinit.o $(LIB)/my_reboot.o
$(CC) $(LDFLAGS) -o $@ $^ $(CRYPT)
-need: need.o
+initctl: initctl.o
$(CC) $(LDFLAGS) -o $@ $^
-vipw.o: $(LIB)/pathnames.h
vipw: vipw.o
newgrp.o: $(LIB)/pathnames.h
$(CC) -c $(CFLAGS) $(PAMFL) newgrp.c
-wall: wall.o ttymsg.o
+wall: wall.o ttymsg.o $(LIB)/carefulputc.o
+LOGINFLAGS=
ifeq "$(USE_TTY_GROUP)" "yes"
+ LOGINFLAGS += -DUSE_TTY_GROUP
+endif
+ifeq "$(ALLOW_VCS_USE)" "yes"
+ LOGINFLAGS += -DCHOWNVCS
+endif
+
login.o: login.c $(LIB)/pathnames.h $(LIB)/setproctitle.c $(LIB)/setproctitle.h
- $(CC) -c $(CFLAGS) $(PAMFL) -DUSE_TTY_GROUP login.c
+ $(CC) -c $(CFLAGS) $(PAMFL) $(LOGINFLAGS) login.c
+
+# LOGINFLAGS here only for -DUSE_TTY_GROUP
mesg.o: mesg.c $(LIB)/errs.h
- $(CC) -c $(CFLAGS) -DUSE_TTY_GROUP mesg.c
-else
-login.o: $(LIB)/pathnames.h
- $(CC) -c $(CFLAGS) $(PAMFL) login.c
-mesg.o: $(LIB)/errs.h
-endif
+ $(CC) -c $(CFLAGS) $(LOGINFLAGS) mesg.c
passwd: passwd.o islocal.o setpwnam.o $(LIB)/env.o
$(CC) $(LDFLAGS) -o $@ $^ $(CRYPT)
@@ -159,7 +166,7 @@ install: all $(WHAT_TO_INSTALL)
install-putils: $(BIN.PUTILS) $(USRBIN.PUTILS) $(USRSBIN.PUTILS)
$(INSTALLDIR) $(BINDIR) $(USRBINDIR) $(USRSBINDIR)
- $(INSTALLSUID) $(BIN.PUTILS) $(BINDIR)
+ $(INSTALLBIN) $(BIN.PUTILS) $(BINDIR)
$(INSTALLSUID) $(USRBIN.PUTILS) $(USRBINDIR)
$(INSTALLBIN) $(USRSBIN.PUTILS) $(USRSBINDIR)
(cd $(USRSBINDIR); ln -sf vipw vigr)
@@ -183,7 +190,12 @@ 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)
+ (cd $(SHUTDOWNDIR); ln -sf initctl need)
+ (cd $(SHUTDOWNDIR); ln -sf initctl display-services)
+ (cd $(SHUTDOWNDIR); ln -sf initctl provide)
+ (cd $(MAN8DIR); ln -sf initctl.8 need.8)
+ (cd $(MAN8DIR); ln -sf initctl.8 display-services.8)
+ (cd $(MAN8DIR); ln -sf initctl.8 provide.8)
install-getty: $(SBIN.GETTY)
diff --git a/login-utils/agetty.c b/login-utils/agetty.c
index 6ae4e8335..63f4adfa6 100644
--- a/login-utils/agetty.c
+++ b/login-utils/agetty.c
@@ -489,6 +489,38 @@ parse_args(argc, argv, op)
if (argc > optind && argv[optind])
setenv ("TERM", argv[optind], 1);
+#ifdef DO_DEVFS_FIDDLING
+ /*
+ * some devfs junk, following Goswin Brederlow:
+ * turn ttyS<n> into tts/<n>
+ * turn tty<n> into vc/<n>
+ */
+ if (op->tty && strlen(op->tty) < 90) {
+ char dev_name[100];
+ struct stat st;
+
+ if (strncmp(op->tty, "ttyS", 4) == 0) {
+ strcpy(dev_name, "/dev/");
+ strcat(dev_name, op->tty);
+ if (stat(dev_name, &st) < 0) {
+ strcpy(dev_name, "/dev/tts/");
+ strcat(dev_name, op->tty + 4);
+ if (stat(dev_name, &st) == 0)
+ op->tty = strdup(dev_name + 5);
+ }
+ } else if (strncmp(op->tty, "tty", 3) == 0) {
+ strcpy(dev_name, "/dev/");
+ strncat(dev_name, op->tty, 90);
+ if (stat(dev_name, &st) < 0) {
+ strcpy(dev_name, "/dev/vc/");
+ strcat(dev_name, op->tty + 3);
+ if (stat(dev_name, &st) == 0)
+ op->tty = strdup(dev_name + 5);
+ }
+ }
+ }
+#endif
+
debug(_("exiting parseargs\n"));
}
@@ -505,7 +537,7 @@ parse_speeds(op, arg)
for (cp = strtok(arg, ","); cp != 0; cp = strtok((char *) 0, ",")) {
if ((op->speeds[op->numspeed++] = bcode(cp)) <= 0)
error(_("bad speed: %s"), cp);
- if (op->numspeed > MAX_SPEED)
+ if (op->numspeed >= MAX_SPEED)
error(_("too many alternate speeds"));
}
debug(_("exiting parsespeeds\n"));
@@ -847,8 +879,11 @@ do_prompt(op, tp)
case 'o':
{
char domainname[256];
-
+#ifdef HAVE_getdomainname
getdomainname(domainname, sizeof(domainname));
+#else
+ strcpy(domainname, "unknown_domain");
+#endif
domainname[sizeof(domainname)-1] = '\0';
printf ("%s", domainname);
}
diff --git a/login-utils/checktty.c b/login-utils/checktty.c
index 66fee7338..6269b6b07 100644
--- a/login-utils/checktty.c
+++ b/login-utils/checktty.c
@@ -29,12 +29,7 @@
#endif
#include "pathnames.h"
-
-/* functions in login.c */
-void badlogin(const char *s);
-void sleepexit(int);
-extern struct hostent hostaddress;
-extern char *hostname;
+#include "login.h"
#ifdef TESTING
struct hostent hostaddress;
@@ -43,13 +38,13 @@ char *hostname;
void
badlogin(const char *s)
{
- printf(_("badlogin: %s\n"), s);
+ printf("badlogin: %s\n", s);
}
void
sleepexit(int x)
{
- printf(_("sleepexit %d\n"), x);
+ printf("sleepexit %d\n", x);
exit(1);
}
#endif
@@ -315,7 +310,7 @@ in_class(const char *tty, char *class)
}
/* start JDS - SBA */
-void
+static void
free_group(struct grplist *ge)
{
if (ge) {
@@ -326,7 +321,7 @@ free_group(struct grplist *ge)
}
}
-void
+static void
free_class(struct ttyclass *tc)
{
if (tc) {
@@ -339,7 +334,7 @@ free_class(struct ttyclass *tc)
}
}
-void
+static void
free_all(void)
{
free_class(ttyclasses);
diff --git a/login-utils/chfn.c b/login-utils/chfn.c
index 73a9b8918..de228241b 100644
--- a/login-utils/chfn.c
+++ b/login-utils/chfn.c
@@ -34,6 +34,8 @@
#include <ctype.h>
#include <getopt.h>
#include "my_crypt.h"
+#include "islocal.h"
+#include "setpwnam.h"
#include "nls.h"
#include "env.h"
@@ -42,15 +44,6 @@
#include <security/pam_misc.h>
#endif
-extern int is_local(char *);
-
-#undef P
-#if __STDC__
-#define P(foo) foo
-#else
-#define P(foo) ()
-#endif
-
typedef unsigned char boolean;
#define false 0
#define true 1
@@ -69,17 +62,15 @@ struct finfo {
char *other;
};
-static boolean parse_argv P((int argc, char *argv[], struct finfo *pinfo));
-static void usage P((FILE *fp));
-static void parse_passwd P((struct passwd *pw, struct finfo *pinfo));
-static void ask_info P((struct finfo *oldfp, struct finfo *newfp));
-static char *prompt P((char *question, char *def_val));
-static int check_gecos_string P((char *msg, char *gecos));
-static boolean set_changed_data P((struct finfo *oldfp, struct finfo *newfp));
-static int save_new_data P((struct finfo *pinfo));
-static void *xmalloc P((int bytes));
-
-extern int setpwnam P((struct passwd *pwd));
+static boolean parse_argv (int argc, char *argv[], struct finfo *pinfo);
+static void usage (FILE *fp);
+static void parse_passwd (struct passwd *pw, struct finfo *pinfo);
+static void ask_info (struct finfo *oldfp, struct finfo *newfp);
+static char *prompt (char *question, char *def_val);
+static int check_gecos_string (char *msg, char *gecos);
+static boolean set_changed_data (struct finfo *oldfp, struct finfo *newfp);
+static int save_new_data (struct finfo *pinfo);
+static void *xmalloc (int bytes);
#define memzero(ptr, size) memset((char *) ptr, 0, size)
diff --git a/login-utils/chsh.c b/login-utils/chsh.c
index f17b176fb..d1a3fa820 100644
--- a/login-utils/chsh.c
+++ b/login-utils/chsh.c
@@ -37,6 +37,8 @@
#include <ctype.h>
#include <getopt.h>
#include "my_crypt.h"
+#include "islocal.h"
+#include "setpwnam.h"
#include "nls.h"
#include "env.h"
@@ -45,15 +47,6 @@
#include <security/pam_misc.h>
#endif
-extern int is_local(char *);
-
-#undef P
-#if __STDC__
-#define P(foo) foo
-#else
-#define P(foo) ()
-#endif
-
typedef unsigned char boolean;
#define false 0
#define true 1
@@ -71,19 +64,17 @@ struct sinfo {
char *shell;
};
-static void parse_argv P((int argc, char *argv[], struct sinfo *pinfo));
-static void usage P((FILE *fp));
-static char *prompt P((char *question, char *def_val));
-static int check_shell P((char *shell));
-static boolean get_shell_list P((char *shell));
-static void *xmalloc P((int bytes));
-extern int setpwnam P((struct passwd *pwd));
+static void parse_argv (int argc, char *argv[], struct sinfo *pinfo);
+static void usage (FILE *fp);
+static char *prompt (char *question, char *def_val);
+static int check_shell (char *shell);
+static boolean get_shell_list (char *shell);
+static void *xmalloc (int bytes);
+
#define memzero(ptr, size) memset((char *) ptr, 0, size)
-int main (argc, argv)
- int argc;
- char *argv[];
-{
+int
+main (int argc, char *argv[]) {
char *cp, *shell, *oldshell;
uid_t uid;
struct sinfo info;
diff --git a/login-utils/cryptocard.c b/login-utils/cryptocard.c
index 1195b2eb8..9e221cbe6 100644
--- a/login-utils/cryptocard.c
+++ b/login-utils/cryptocard.c
@@ -54,9 +54,7 @@
#include "../libdes/des.h"
#endif /* EAY_LIBDES */
-extern char *getpass(const char *prompt);
-extern struct passwd *pwd;
-extern int timeout;
+#include "cryptocard.h"
static char *
generate_challenge(void)
diff --git a/login-utils/cryptocard.h b/login-utils/cryptocard.h
new file mode 100644
index 000000000..a967137f9
--- /dev/null
+++ b/login-utils/cryptocard.h
@@ -0,0 +1,7 @@
+/* defined in cryptocard.c */
+extern int cryptocard (void);
+
+/* defined in login.c */
+extern struct passwd *pwd;
+extern int timeout;
+
diff --git a/login-utils/need.8 b/login-utils/initctl.8
index cc3712d74..1aa421a02 100644
--- a/login-utils/need.8
+++ b/login-utils/initctl.8
@@ -18,26 +18,30 @@
.\" 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
+.\" initctl.8 Richard Gooch 6-NOV-2000
.\"
-.TH NEED 8 "28 Feb 2000" "Util-Linux Package"
+.TH INITCTL 8 "6 Nov 2000" "Util-Linux Package"
.SH NAME
-need \- utility to tell simpleinit(8) to start a service
+initctl \- utility to control simpleinit(8)
.SH SYNOPSIS
.nf
-\fBneed\fP [\fB-r\fP] [\fBservice\fP]
+\fBneed\fP [\fB-r\fP] \fBservice\fP
.BR display-services
+\fBprovide service\fP
.fi
-.SH DESCRIPTION
+.SH OVERVIEW
+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 DESCRIPTION for need
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
@@ -45,12 +49,24 @@ 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 DESCRIPTION for display-services
+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.
+
+.SH DESCRIPTION for provide
+When invoked as \fBprovide\fP it tells \fBsimpleinit\fP(8) that the
+parent (calling) process will be providing a service with name
+\fIservice\fP. If the calling process exits successfully (status 0)
+the service is deemed to be available. Only one instance of
+\fIservice\fP may be started, so alternate providers will block and
+may fail.
+
+Using \fBprovide\fP it is possible to have multiple potential
+providers for the same (generic) service (e.g. \fBsendmail\fP and
+\fBqmail\fP both provide a \fBmta\fP service), where only one actually
+provides the service. This may be used by service startup scripts
+which check for configuration files.
.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
@@ -61,6 +77,11 @@ 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).
+
+The exit code from \fBprovide\fP is 0 if the service may be provided,
+1 if it may not, and 2 if the parent process is not a child of
+init. It may block waiting for another provider which is initialising
+the service.
.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
diff --git a/login-utils/need.c b/login-utils/initctl.c
index 97690c461..6fb8d097f 100644
--- a/login-utils/need.c
+++ b/login-utils/initctl.c
@@ -1,6 +1,6 @@
-/* need.c
+/* initctl.c
- Source file for need (init(8) dependency tool).
+ Source file for initctl (init(8) control tool).
Copyright (C) 2000 Richard Gooch
@@ -24,16 +24,19 @@
*/
/*
- 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 will send control messages to init(8). For example, it may
+ 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
+ Updated by Richard Gooch 11-OCT-2000: Added provide support.
+
+ Last updated by Richard Gooch 6-NOV-2000: Renamed to initctl.c
*/
@@ -44,6 +47,7 @@
#include <sys/stat.h>
#include <fcntl.h>
#include <signal.h>
+#include <stdlib.h>
#include <string.h>
#include "simpleinit.h"
@@ -60,7 +64,7 @@ int main (int argc, char **argv)
struct sigaction sa;
sigset_t ss;
char *ptr;
- long buffer[COMMAND_SIZE / sizeof (long)];
+ long buffer[COMMAND_SIZE / sizeof (long) + 1];
struct command_struct *command = (struct command_struct *) buffer;
sigemptyset (&ss);
@@ -75,11 +79,55 @@ int main (int argc, char **argv)
sigaction (SIG_NOT_PRESENT, &sa, NULL);
sigaction (SIG_FAILED, &sa, NULL);
command->pid = getpid ();
+ command->ppid = getppid ();
if ( ( ptr = strrchr (argv[0], '/') ) == NULL ) ptr = argv[0];
else ++ptr;
+ /* First generate command number by looking at invocation name */
if (strcmp (ptr, "display-services") == 0)
- {
command->command = COMMAND_DUMP_LIST;
+ else if (strcmp (ptr, "need") == 0) command->command = COMMAND_NEED;
+ else if (strcmp (ptr, "provide") == 0) command->command = COMMAND_PROVIDE;
+ else command->command = COMMAND_TEST;
+ /* Now check for switches */
+ if ( (argc > 1) && (argv[1][0] == '-') )
+ {
+ switch (argv[1][1])
+ {
+ case 'n':
+ command->command = COMMAND_NEED;
+ break;
+ case 'r':
+ command->command = COMMAND_ROLLBACK;
+ break;
+ case 'd':
+ command->command = COMMAND_DUMP_LIST;
+ break;
+ case 'p':
+ command->command = COMMAND_PROVIDE;
+ break;
+ default:
+ fprintf (stderr, "Illegal switch: \"%s\"\n", argv[1]);
+ exit (1);
+ /*break;*/
+ }
+ --argc;
+ ++argv;
+ }
+ switch (command->command)
+ {
+ case COMMAND_NEED:
+ case COMMAND_PROVIDE:
+ if (argc < 2)
+ {
+ fprintf (stderr, "Usage:\tneed|provide programme\n");
+ exit (1);
+ }
+ /* Fall through */
+ case COMMAND_ROLLBACK:
+ if (argc > 1) strcpy (command->name, argv[1]);
+ else command->name[0] = '\0';
+ break;
+ case COMMAND_DUMP_LIST:
if (tmpnam (command->name) == NULL)
{
fprintf (stderr, "Unable to create a unique filename\t%s\n",
@@ -92,26 +140,7 @@ int main (int argc, char **argv)
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);
- }
- }
+ break;
}
if ( ( fd = open ("/dev/initctl", O_WRONLY, 0) ) < 0 )
{
@@ -128,14 +157,35 @@ int main (int argc, char **argv)
{
sigemptyset (&ss);
while (caught_signal == 0) sigsuspend (&ss);
- switch (caught_signal)
+ switch (command->command)
{
- case SIG_PRESENT:
- return 0;
- case SIG_NOT_PRESENT:
- return 2;
- case SIG_FAILED:
- return 1;
+ case COMMAND_PROVIDE:
+ switch (caught_signal)
+ {
+ case SIG_PRESENT:
+ return 1;
+ case SIG_NOT_PRESENT:
+ return 0;
+ case SIG_NOT_CHILD:
+ fprintf (stderr, "Error\n");
+ return 2;
+ default:
+ return 3;
+ }
+ break;
+ default:
+ switch (caught_signal)
+ {
+ case SIG_PRESENT:
+ return 0;
+ case SIG_NOT_PRESENT:
+ return 2;
+ case SIG_FAILED:
+ return 1;
+ default:
+ return 3;
+ }
+ break;
}
return 3;
}
diff --git a/login-utils/islocal.c b/login-utils/islocal.c
index 10a709b56..87f8f1cb2 100644
--- a/login-utils/islocal.c
+++ b/login-utils/islocal.c
@@ -17,10 +17,12 @@
*/
#include <stdio.h>
+#include <stdlib.h>
#include <string.h>
#include "nls.h"
#include "pathnames.h"
+#include "islocal.h"
#define MAX_LENGTH 1024
diff --git a/login-utils/islocal.h b/login-utils/islocal.h
new file mode 100644
index 000000000..305bc57c6
--- /dev/null
+++ b/login-utils/islocal.h
@@ -0,0 +1 @@
+extern int is_local(char *user);
diff --git a/login-utils/last.c b/login-utils/last.c
index b78d00b86..8375f9f07 100644
--- a/login-utils/last.c
+++ b/login-utils/last.c
@@ -90,16 +90,16 @@ static char *file = _PATH_WTMP; /* wtmp file */
static int doyear = 0; /* output year in dates */
static int dolong = 0; /* print also ip-addr */
-static void wtmp(), addarg(), hostconv();
-static int want();
-TTY *addtty();
-static char *ttyconv();
+static void wtmp(void);
+static void addarg(int, char *);
+static void hostconv(char *);
+static void onintr(int);
+static int want(struct utmp *, int);
+TTY *addtty(char *);
+static char *ttyconv(char *);
int
-main(argc, argv)
- int argc;
- char **argv;
-{
+main(int argc, char **argv) {
extern int optind;
extern char *optarg;
int ch;
@@ -159,10 +159,8 @@ main(argc, argv)
* print_partial_line --
* print the first part of each output line according to specified format
*/
-void
-print_partial_line(bp)
- struct utmp *bp;
-{
+static void
+print_partial_line(struct utmp *bp) {
char *ct;
ct = ctime(&bp->ut_time);
@@ -193,12 +191,10 @@ print_partial_line(bp)
* read through the wtmp file
*/
static void
-wtmp()
-{
+wtmp(void) {
register struct utmp *bp; /* current structure */
register TTY *T; /* tty list entry */
long delta; /* time difference */
- void onintr();
char *crmsg = NULL;
char *ct = NULL;
struct utmp **utmplist = NULL;
@@ -310,10 +306,7 @@ wtmp()
* see if want this entry
*/
static int
-want(bp, check)
- register struct utmp *bp;
- int check;
-{
+want(struct utmp *bp, int check) {
register ARG *step;
if (check) {
@@ -357,10 +350,7 @@ want(bp, check)
* add an entry to a linked list of arguments
*/
static void
-addarg(type, arg)
- int type;
- char *arg;
-{
+addarg(int type, char *arg) {
register ARG *cur;
if (!(cur = (ARG *)malloc((unsigned int)sizeof(ARG)))) {
@@ -378,9 +368,7 @@ addarg(type, arg)
* add an entry to a linked list of ttys
*/
TTY *
-addtty(ttyname)
- char *ttyname;
-{
+addtty(char *ttyname) {
register TTY *cur;
if (!(cur = (TTY *)malloc((unsigned int)sizeof(TTY)))) {
@@ -400,9 +388,7 @@ addtty(ttyname)
* off the domain suffix since that's what login(1) does.
*/
static void
-hostconv(arg)
- char *arg;
-{
+hostconv(char *arg) {
static int first = 1;
static char *hostdot,
name[MAXHOSTNAMELEN];
@@ -427,9 +413,7 @@ hostconv(arg)
* convert tty to correct name.
*/
static char *
-ttyconv(arg)
- char *arg;
-{
+ttyconv(char *arg) {
char *mval;
/*
@@ -459,10 +443,8 @@ ttyconv(arg)
* onintr --
* on interrupt, we inform the user how far we've gotten
*/
-void
-onintr(signo)
- int signo;
-{
+static void
+onintr(int signo) {
char *ct;
ct = ctime(&utmpbuf.ut_time);
diff --git a/login-utils/login.c b/login-utils/login.c
index eaaf1a520..3ad3b219c 100644
--- a/login-utils/login.c
+++ b/login-utils/login.c
@@ -116,7 +116,9 @@
#include <sys/syslog.h>
#include <sys/sysmacros.h>
#include <netdb.h>
+#include "pathnames.h"
#include "my_crypt.h"
+#include "login.h"
#include "nls.h"
#ifdef __linux__
@@ -188,25 +190,22 @@ struct lastlog
};
#endif
-#include "pathnames.h"
-#define P_(s) ()
-void opentty P_((const char *tty));
-void getloginname P_((void));
-void timedout P_((void));
-int rootterm P_((char *ttyn));
-void motd P_((void));
-void sigint P_((void));
-void checknologin P_((void));
-void dolastlog P_((int quiet));
-void badlogin P_((const char *name));
-char *stypeof P_((char *ttyid));
-void checktty P_((char *user, char *tty, struct passwd *pwd));
-void sleepexit P_((int eval));
+static void getloginname (void);
+static void timedout (int);
+static void sigint (int);
+static int rootterm (char *ttyn);
+static void motd (void);
+static void checknologin (void);
+static void dolastlog (int quiet);
+
+#ifndef __linux__
+static char *stypeof (char *ttyid);
+#endif
+
#ifdef CRYPTOCARD
-int cryptocard P_((void));
+#include "cryptocard.h"
#endif
-#undef P_
#ifdef KERBEROS
#include <kerberos/krb.h>
@@ -235,14 +234,14 @@ int kerror = KSUCCESS, notickets = 1;
#ifndef __linux__
int timeout = 300;
#else
-int timeout = 60;
+int timeout = 60; /* used in cryptocard.c */
#endif
-struct passwd *pwd;
-int failures = 1;
+struct passwd *pwd; /* used in cryptocard.c */
+struct hostent hostaddress; /* used in checktty.c */
char term[64], *hostname, *username, *tty;
-struct hostent hostaddress;
-char thishost[100];
+static char thishost[100];
+static int failures = 1;
#ifndef __linux__
struct sgttyb sgttyb;
@@ -266,7 +265,7 @@ const char *months[] =
connection. I believe login should open the line in the non-blocking mode
leaving the decision to make a connection to getty (where it actually
belongs). */
-void
+static void
opentty(const char * tty)
{
int i;
@@ -313,11 +312,7 @@ main(int argc, char **argv)
int quietlog, passwd_req;
char *domain, *ttyn;
char tbuf[MAXPATHLEN + 2], tname[sizeof(_PATH_TTY) + 10];
- char *ctime(), *ttyname(), *stypeof();
- time_t time();
- void timedout();
char *termenv;
- char vcsn[20], vcsan[20];
char * childArgv[10];
char * buff;
int childArgc = 0;
@@ -329,6 +324,9 @@ main(int argc, char **argv)
#else
char *salt, *pp;
#endif
+#ifdef CHOWNVCS
+ char vcsn[20], vcsan[20];
+#endif
#ifndef __linux__
int ioctlval;
#endif
@@ -446,6 +444,7 @@ main(int argc, char **argv)
ttyn = tname;
}
+#ifdef CHOWNVCS
/* find names of Virtual Console devices, for later mode change */
{
char *p = ttyn;
@@ -455,6 +454,7 @@ main(int argc, char **argv)
strcpy(vcsn, "/dev/vcs"); strcat(vcsn, p);
strcpy(vcsan, "/dev/vcsa"); strcat(vcsan, p);
}
+#endif
setpgrp();
@@ -464,8 +464,8 @@ main(int argc, char **argv)
tcgetattr(0, &tt);
ttt = tt;
ttt.c_cflag &= ~HUPCL;
-
- if((chown(ttyn, 0, 0) == 0) && (chmod(ttyn, 0622) == 0)) {
+
+ if((chown(ttyn, 0, 0) == 0) && (chmod(ttyn, TTY_MODE) == 0)) {
tcsetattr(0,TCSAFLUSH,&ttt);
signal(SIGHUP, SIG_IGN); /* so vhangup() wont kill us */
vhangup();
@@ -816,8 +816,8 @@ main(int argc, char **argv)
else if (tp.tv_sec - pwd->pw_change < TWOWEEKS && !quietlog) {
struct tm *ttp;
ttp = localtime(&pwd->pw_change);
- printf(_("Warning: your password expires on %s %d, %d\n"),
- months[ttp->tm_mon], ttp->tm_mday,
+ printf(_("Warning: your password expires on %d %s %d.\n"),
+ ttp->tm_mday, months[ttp->tm_mon],
TM_YEAR_BASE + ttp->tm_year);
}
}
@@ -830,8 +830,8 @@ main(int argc, char **argv)
else if (tp.tv_sec - pwd->pw_expire < TWOWEEKS && !quietlog) {
struct tm *ttp;
ttp = localtime(&pwd->pw_expire);
- printf(_("Warning: your account expires on %s %d, %d\n"),
- months[ttp->tm_mon], ttp->tm_mday,
+ printf(_("Warning: your account expires on %d %s %d.\n"),
+ ttp->tm_mday, months[ttp->tm_mon],
TM_YEAR_BASE + ttp->tm_year);
}
}
@@ -970,6 +970,7 @@ Michael Riepe <michael@stud.uni-hannover.de>
(gr = getgrnam(TTYGRPNAME)) ? gr->gr_gid : pwd->pw_gid);
chmod(ttyn, TTY_MODE);
+#ifdef CHOWNVCS
/* if tty is one of the VC's then change owner and mode of the
special /dev/vcs devices as well */
if (consoletty(0)) {
@@ -978,6 +979,7 @@ Michael Riepe <michael@stud.uni-hannover.de>
chmod(vcsn, TTY_MODE);
chmod(vcsan, TTY_MODE);
}
+#endif
setgid(pwd->pw_gid);
@@ -1184,12 +1186,10 @@ Michael Riepe <michael@stud.uni-hannover.de>
}
void
-getloginname()
-{
- register int ch;
- register char *p;
+getloginname(void) {
+ int ch, cnt, cnt2;
+ char *p;
static char nbuf[UT_NAMESIZE + 1];
- int cnt, cnt2;
cnt2 = 0;
for (;;) {
@@ -1231,8 +1231,7 @@ getloginname()
}
void
-timedout()
-{
+timedout(int sig) {
struct termio ti;
fprintf(stderr, _("Login timed out after %d seconds\n"), timeout);
@@ -1245,8 +1244,7 @@ timedout()
}
int
-rootterm(ttyn)
- char *ttyn;
+rootterm(char * ttyn)
#ifndef __linux__
{
struct ttyent *t;
@@ -1286,10 +1284,9 @@ rootterm(ttyn)
jmp_buf motdinterrupt;
void
-motd()
-{
- register int fd, nchars;
- void (*oldint)(), sigint();
+motd(void) {
+ int fd, nchars;
+ void (*oldint)(int);
char tbuf[8192];
if ((fd = open(_PATH_MOTDFILE, O_RDONLY, 0)) < 0)
@@ -1303,15 +1300,13 @@ motd()
}
void
-sigint()
-{
+sigint(int sig) {
longjmp(motdinterrupt, 1);
}
#ifndef USE_PAM /* PAM takes care of this */
void
-checknologin()
-{
+checknologin(void) {
register int fd, nchars;
char tbuf[8192];
@@ -1324,9 +1319,7 @@ checknologin()
#endif
void
-dolastlog(quiet)
- int quiet;
-{
+dolastlog(int quiet) {
struct lastlog ll;
int fd;
@@ -1385,9 +1378,7 @@ badlogin(const char *name)
#ifndef __linux__
char *
-stypeof(ttyid)
- char *ttyid;
-{
+stypeof(char *ttyid) {
struct ttyent *t;
return(ttyid && (t = getttynam(ttyid)) ? t->ty_type : UNKNOWN);
@@ -1396,9 +1387,7 @@ stypeof(ttyid)
/* should not be called from PAM code... Why? */
void
-sleepexit(eval)
- int eval;
-{
+sleepexit(int eval) {
sleep(SLEEP_EXIT_TIMEOUT);
exit(eval);
}
diff --git a/login-utils/login.h b/login-utils/login.h
new file mode 100644
index 000000000..14b698e32
--- /dev/null
+++ b/login-utils/login.h
@@ -0,0 +1,8 @@
+/* defined in login.c */
+extern void badlogin(const char *s);
+extern void sleepexit(int);
+extern struct hostent hostaddress;
+extern char *hostname;
+
+/* defined in checktty.c */
+extern void checktty(const char *user, const char *tty, struct passwd *pwd);
diff --git a/login-utils/newgrp.c b/login-utils/newgrp.c
index 1f8be95f2..ade173e53 100644
--- a/login-utils/newgrp.c
+++ b/login-utils/newgrp.c
@@ -12,6 +12,7 @@
#include <grp.h>
#include <string.h>
#include <stdio.h>
+#include <stdlib.h>
#include <errno.h>
#include "pathnames.h"
#include "my_crypt.h"
diff --git a/login-utils/passwd.c b/login-utils/passwd.c
index ba679cd23..6741ee210 100644
--- a/login-utils/passwd.c
+++ b/login-utils/passwd.c
@@ -64,7 +64,10 @@
#include <string.h>
#include <errno.h>
#include <sys/resource.h>
+#include <stdlib.h>
#include "my_crypt.h"
+#include "setpwnam.h"
+#include "islocal.h"
#include "nls.h"
#include "env.h"
@@ -79,9 +82,6 @@
#include <syslog.h>
#endif /* LOGALL */
-extern int is_local(char *); /* islocal.c */
-extern int setpwnam(struct passwd *); /* setpwnam.c */
-
#define ascii_to_bin(c) ((c)>='a'?(c-59):(c)>='A'?((c)-53):(c)-'.')
#define bin_to_ascii(c) ((c)>=38?((c)-38+'a'):(c)>=12?((c)-12+'A'):(c)+'.')
@@ -104,9 +104,8 @@ pexit(char *str, ...)
* This would probably be the best place for checking against
* dictionaries. :-)
*/
-
-int check_passwd_string(char *passwd, char *string)
-{
+static int
+check_passwd_string(char *passwd, char *string) {
int r;
char *p, *q;
@@ -152,8 +151,8 @@ int check_passwd_string(char *passwd, char *string)
return 1;
}
-int check_passwd(char *passwd, char *oldpasswd, char *user, char *gecos)
-{
+static int
+check_passwd(char *passwd, char *oldpasswd, char *user, char *gecos) {
int ucase, lcase, digit, other;
char *c, *g, *p;
@@ -216,17 +215,16 @@ int check_passwd(char *passwd, char *oldpasswd, char *user, char *gecos)
return 1; /* fine */
}
-void usage()
-{
+#if 0
+static void
+usage(void) {
printf (_("Usage: passwd [username [password]]\n"));
printf(_("Only root may use the one and two argument forms.\n"));
}
+#endif
int
-main(argc, argv)
- int argc;
- char *argv[];
-{
+main(int argc, char *argv[]) {
struct passwd *pe;
uid_t gotuid = getuid();
char *pwdstr = NULL, *cryptstr, *oldstr;
diff --git a/login-utils/setpwnam.c b/login-utils/setpwnam.c
index 8631e7adc..62d47a51c 100644
--- a/login-utils/setpwnam.c
+++ b/login-utils/setpwnam.c
@@ -64,6 +64,11 @@
#include "setpwnam.h"
+#define false 0
+#define true 1
+
+typedef int boolean;
+
static void pw_init(void);
/*
diff --git a/login-utils/setpwnam.h b/login-utils/setpwnam.h
index b4790f7ab..84d1c208f 100644
--- a/login-utils/setpwnam.h
+++ b/login-utils/setpwnam.h
@@ -14,11 +14,6 @@
#include "pathnames.h"
-#define false 0
-#define true 1
-
-typedef int boolean;
-
#ifndef DEBUG
#define PASSWD_FILE _PATH_PASSWD
#define PTMP_FILE _PATH_PTMP
@@ -36,3 +31,5 @@ typedef int boolean;
#define GTMP_FILE "/tmp/gtmp"
#define GTMPTMP_FILE "/tmp/gtmptmp"
#endif
+
+extern int setpwnam (struct passwd *pwd);
diff --git a/login-utils/shutdown.c b/login-utils/shutdown.c
index e3ec93c1e..d1034d5eb 100644
--- a/login-utils/shutdown.c
+++ b/login-utils/shutdown.c
@@ -33,6 +33,19 @@
*
* 2000-03-02 Richard Gooch <rgooch@atnf.csiro.au>
* - pause forever if (pid == 1) and send SIGQUIT to pid = 1
+ *
+ * 2000-11-04 Richard Gooch <rgooch@atnf.csiro.au>
+ * - continue reaping if (pid == 1)
+ *
+ * 2000-11-06 Richard Gooch <rgooch@atnf.csiro.au>
+ * - shut down "finalprog" from /etc/inittab
+ * - kill normal user (non-root and non-daemon) processes first with SIGTERM
+ *
+ * 2000-11-08 Richard Gooch <rgooch@atnf.csiro.au>
+ * - rollback services
+ * - do not unmount devfs (otherwise get harmless but annoying messages)
+ * - created syncwait() for faster shutting down
+ * - kill getty processes
*/
#include <stdio.h>
@@ -52,13 +65,22 @@
#include <sys/wait.h>
#include <syslog.h>
#include <sys/resource.h>
+#include <sys/types.h>
+#include <dirent.h>
+#include <sys/stat.h>
+#include <sys/utsname.h>
#include "linux_reboot.h"
#include "pathnames.h"
#include "nls.h"
-static void usage(), int_handler(), write_user(struct utmp *);
-static void wall(), write_wtmp(), unmount_disks(), unmount_disks_ourselves();
-static void swap_off(), do_halt(char *);
+static void usage(void), int_handler(int), write_user(struct utmp *);
+static void wall(void), write_wtmp(void), unmount_disks(void);
+static void unmount_disks_ourselves(void);
+static void swap_off(void), do_halt(char *);
+static void kill_mortals (int sig);
+static void stop_finalprog (void);
+static void syncwait (int timeval);
+
char *prog; /* name of the program */
int opt_reboot; /* true if -r option or reboot command */
@@ -81,14 +103,14 @@ char halt_action[256]; /* to find out what to do upon halt */
void
-usage()
+usage(void)
{
fprintf(stderr,
_("Usage: shutdown [-h|-r] [-fqs] [now|hh:ss|+mins]\n"));
exit(1);
}
-void
+static void
my_puts(char *s)
{
/* Use a fresh stdout after forking */
@@ -98,7 +120,7 @@ my_puts(char *s)
}
void
-int_handler()
+int_handler(int sig)
{
unlink(_PATH_NOLOGIN);
signal(SIGINT, SIG_DFL);
@@ -106,7 +128,7 @@ int_handler()
exit(1);
}
-int
+static int
iswhitespace(int a) {
return (a == ' ' || a == '\t');
}
@@ -120,14 +142,14 @@ main(int argc, char *argv[])
if (getpid () == 1) {
for (i = 0; i < getdtablesize (); i++) close (i);
- while (1) pause ();
+ while (1) wait (NULL); /* Grim reaper never stops */
}
setlocale(LC_ALL, "");
bindtextdomain(PACKAGE, LOCALEDIR);
textdomain(PACKAGE);
#ifndef DEBUGGING
- if(geteuid()) {
+ if(setreuid (0, 0)) {
fprintf(stderr, _("%s: Only root can shut a system down.\n"),
argv[0]);
exit(1);
@@ -350,6 +372,15 @@ main(int argc, char *argv[])
#ifndef DEBUGGING
/* a gentle kill of all other processes except init */
+ kill_mortals (SIGTERM);
+ stop_finalprog ();
+ sleep (1); /* Time for saves to start */
+ kill (1, SIGTERM); /* Tell init to kill spawned gettys */
+ usleep (100000); /* Wait for gettys to die */
+ my_puts (""); /* Get past the login prompt */
+ system ("/sbin/initctl -r"); /* Roll back services */
+ syncwait (1);
+ my_puts ("Sending SIGTERM to all remaining processes...");
kill(-1, SIGTERM);
sleep(2); /* default 2, some people need 5 */
@@ -371,17 +402,16 @@ main(int argc, char *argv[])
required. Need to sleep before remounting root read-only */
kill (1, SIGQUIT);
- sync();
- sleep(2);
+ sleep (1); /* Time for processes to die and close files */
+ syncwait (2);
/* remove swap files and partitions using swapoff */
swap_off();
/* unmount disks... */
unmount_disks();
- sync();
- sleep(1);
-
+ syncwait (1);
+
if(opt_reboot) {
my_reboot(LINUX_REBOOT_CMD_RESTART); /* RB_AUTOBOOT */
my_puts(_("\nWhy am I still alive after reboot?"));
@@ -390,6 +420,7 @@ main(int argc, char *argv[])
/* allow C-A-D now, faith@cs.unc.edu, re-fixed 8-Jul-96 */
my_reboot(LINUX_REBOOT_CMD_CAD_ON); /* RB_ENABLE_CAD */
+ sleep (1); /* Wait for devices to finish writing to media */
do_halt(halt_action);
}
/* NOTREACHED */
@@ -432,6 +463,9 @@ write_user(struct utmp *ut)
char msg[100];
minutes = timeout / 60;
+ hours = minutes / 60;
+ minutes %= 60;
+
(void) strncat(term, ut->ut_line, sizeof(ut->ut_line));
/* try not to get stuck on a mangled ut_line entry... */
@@ -443,16 +477,20 @@ write_user(struct utmp *ut)
WR(msg);
WRCRLF;
- if(minutes == 0) {
- sprintf(msg, _("System going down IMMEDIATELY!\n"));
- } else if(minutes > 60) {
- hours = minutes / 60;
- sprintf(msg, _("System going down in %d hour%s %d minutes"),
- hours, hours == 1 ? "" : _("s"), minutes - 60*hours);
- } else {
- sprintf(msg, _("System going down in %d minute%s\n"),
- minutes, minutes == 1 ? "" : _("s"));
- }
+ if (hours > 1)
+ sprintf(msg, _("System going down in %d hours %d minutes"),
+ hours, minutes);
+ else if (hours == 1)
+ sprintf(msg, _("System going down in 1 hour %d minutes"),
+ minutes);
+ else if (minutes > 1)
+ sprintf(msg, _("System going down in %d minutes\n"),
+ minutes);
+ else if (minutes == 1)
+ sprintf(msg, _("System going down in 1 minute\n"));
+ else
+ sprintf(msg, _("System going down IMMEDIATELY!\n"));
+
WR(msg);
WRCRLF;
@@ -464,7 +502,7 @@ write_user(struct utmp *ut)
}
void
-wall()
+wall(void)
{
/* write to all users, that the system is going down. */
struct utmp *ut;
@@ -480,7 +518,7 @@ wall()
}
void
-write_wtmp()
+write_wtmp(void)
{
/* write in wtmp that we are dying */
int fd;
@@ -500,7 +538,7 @@ write_wtmp()
}
void
-swap_off()
+swap_off(void)
{
/* swapoff esp. swap FILES so the underlying partition can be
unmounted. It you don't have swapoff(1) or use mount to
@@ -530,7 +568,7 @@ swap_off()
}
void
-unmount_disks()
+unmount_disks(void)
{
/* better to use umount directly because it may be smarter than us */
@@ -563,7 +601,7 @@ unmount_disks()
}
void
-unmount_disks_ourselves()
+unmount_disks_ourselves(void)
{
/* unmount all disks */
@@ -581,8 +619,8 @@ unmount_disks_ourselves()
}
n = 0;
while (n < 100 && (mnt = getmntent(mtab))) {
- mntlist[n++] = strdup(mnt->mnt_fsname[0] == '/' ?
- mnt->mnt_fsname : mnt->mnt_dir);
+ if (strcmp (mnt->mnt_type, "devfs") == 0) continue;
+ mntlist[n++] = strdup(mnt->mnt_dir);
}
endmntent(mtab);
@@ -594,7 +632,96 @@ unmount_disks_ourselves()
printf("umount %s\n", filesys);
#else
if (umount(mntlist[i]) < 0)
- printf(_("shutdown: Couldn't umount %s\n"), filesys);
+ printf(_("shutdown: Couldn't umount %s: %s\n"),
+ filesys, ERRSTRING);
#endif
}
}
+
+static void kill_mortals (int sig)
+{
+ int npids = 0;
+ int index = 0;
+ int pid;
+ struct stat statbuf;
+ DIR *dp;
+ struct dirent *de;
+ pid_t *pids = NULL;
+ char path[256];
+
+ if ( ( dp = opendir ("/proc") ) == NULL ) return;
+ while ( ( de = readdir (dp) ) != NULL )
+ {
+ if ( !isdigit (de->d_name[0]) ) continue;
+ pid = atoi (de->d_name);
+ sprintf (path, "/proc/%d", pid);
+ if (stat (path, &statbuf) != 0) continue;
+ if (statbuf.st_uid < 100) continue;
+ if (index <= npids)
+ {
+ pids = realloc (pids, npids + 16384);
+ if (pids == NULL) return;
+ npids += 16384;
+ }
+ pids[index++] = pid;
+ }
+ fputs ("Sending SIGTERM to mortals...", stderr);
+ for (--index; index >= 0; --index) kill (pids[index], sig);
+ free (pids);
+ closedir (dp);
+} /* End Function kill_mortals */
+
+static void stop_finalprog (void)
+{
+ char *p1, *p2;
+ FILE *fp;
+ char line[256];
+
+ if ( ( fp = fopen (_PATH_INITTAB, "r") ) == NULL ) return;
+ while (fgets (line, 256, fp) != NULL)
+ {
+ pid_t pid;
+
+ line[strlen (line) - 1] = '\0';
+ p1 = line;
+ while ( isspace (*p1) ) ++p1;
+ if (strncmp (p1, "finalprog", 9) != 0) continue;
+ if ( ( p1 = strchr (p1 + 9, '=') ) == NULL ) continue;
+ for (++p1; isspace (*p1); ++p1);
+ if (*p1 == '\0') continue;
+ for (p2 = p1; !isspace (*p2); ++p2);
+ *p2 = '\0';
+ switch ( pid = fork () )
+ {
+ case 0: /* Child */
+ execl (p1, p1, "stop", NULL);
+ break;
+ case -1: /* Error */
+ break;
+ default: /* Parent */
+ waitpid (pid, NULL, 0);
+ break;
+ }
+ fclose (fp);
+ return;
+ }
+ fclose (fp);
+} /* End Function stop_finalprog */
+
+static void syncwait (int timeval)
+{
+ static int do_wait = 0;
+ static int first_time = 1;
+
+ sync ();
+ /* Kernel version 1.3.20 and after are supposed to wait automatically */
+ if (first_time)
+ {
+ struct utsname uts;
+
+ first_time = 0;
+ uname (&uts);
+ if (uts.release[0] < '2') do_wait = 1;
+ }
+ if (do_wait) sleep (timeval);
+} /* End Function syncwait */
diff --git a/login-utils/simpleinit.8 b/login-utils/simpleinit.8
index 2a2f666ed..f367f2f63 100644
--- a/login-utils/simpleinit.8
+++ b/login-utils/simpleinit.8
@@ -1,7 +1,7 @@
.\" Copyright 1992, 1993 Rickard E. Faith (faith@cs.unc.edu)
.\" May be distributed under the GNU General Public License
.\" " for emacs's hilit19 mode :-)
-.TH SIMPLEINIT 8 "20 November 1993" "Linux 0.99" "Linux Programmer's Manual"
+.TH SIMPLEINIT 8 "4 November 2000" "Linux 0.99" "Linux Programmer's Manual"
.SH NAME
simpleinit \- process control initialization
.SH SYNOPSIS
@@ -33,7 +33,9 @@ After single user mode is terminated, the
.I /etc/rc
file is executed, and the information in
.I /etc/inittab
-will be used to start processes.
+will be used to start processes. Alternatively, the \fI/etc/inittab\fP
+file may be configured to run a different boot script. See below for
+details.
.SH "THE INITTAB FILE"
Because of the number of init programs which are appearing in the Linux
@@ -52,16 +54,21 @@ The format is
.B PATH=search path
+.B INIT_PATH=search path
+
.B "ttyline:termcap-entry:getty-command"
+
+.B finalprog=path
.RE
An example is as follows:
.nf
.RS
-bootprog = rc
-fileprefix = /sbin/
-PATH = /sbin:/bin
+bootprog =
+fileprefix = /sbin/init.d/
+PATH = /usr/sbin:/usr/bin:/sbin:/bin
+INIT_PATH = /sbin/init.d
tty1:linux:/sbin/getty 9600 tty1
tty2:linux:/sbin/getty 9600 tty2
@@ -70,6 +77,8 @@ tty4:linux:/sbin/getty 9600 tty4
# tty5:linux:/sbin/getty 9600 tty5
# ttyS1:dumb:/sbin/getty 9600 ttyS1
# ttyS2:dumb:/sbin/getty -m -t60 2400 ttyS2
+
+finalprog = /sbin/rc.xdm
.RE
.fi
@@ -79,6 +88,26 @@ 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.
+
+The \fBbootprog\fP value is appended to the \fBfileprefix\fP value,
+and the result specifies the boot programme (script) to run. If
+unspecified, the default is \fI/etc/rc\fP. If the boot programme is a
+directory, then all scripts in that directory tree are executed, in
+parallel. See the \fBneed\fP(8) programme for details on how to
+elegantly control order of execution and manage dependencies.
+
+The \fBPATH\fP value is assigned to the PATH environment variable of
+child processes (boot scripts). The \fBINIT_PATH\fP value is used by
+simpleinit(8) itself to find the location of scripts to run (if an
+absolute path is not given). If unset the default value \fBPATH\fP is
+used. This separation allows boot scripts to invoke programmes of the
+same name without conflict and without needing to specify absolute
+paths.
+
+The \fBfinalprog\fP value specifies the path of the programme to run
+after all \fBgetty\fP(8) instances are spawned. At bootup, it is
+passed a single argument: "start". At shutdown, it is called again,
+this time with the argument: "stop".
.SH SIGNALS
\fBsimpleinit\fP(8) responds to signals in a variety of ways:
.TP
@@ -121,7 +150,8 @@ remount (read-only) the root filesystem, even if the old inode for the
.BR termcap (5),
.BR getty (8),
.BR agetty (8),
-.BR shutdown (8)
+.BR shutdown (8),
+.BR need (8)
.SH BUGS
This program is called
.B simpleinit
@@ -135,4 +165,7 @@ for correct functionality.
Peter Orbaek (poe@daimi.aau.dk)
.br
Version 1.20, with patches for singleuser mode by Werner Almesberger
-
+.br
+Richard Gooch <rgooch@atnf.csiro.au>
+.br
+Dependency support
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 */
diff --git a/login-utils/simpleinit.h b/login-utils/simpleinit.h
index ff26480f7..1d8762975 100644
--- a/login-utils/simpleinit.h
+++ b/login-utils/simpleinit.h
@@ -10,16 +10,19 @@
#define COMMAND_NEED 1 /* Wait, signal */
#define COMMAND_ROLLBACK 2 /* Wait, signal */
#define COMMAND_DUMP_LIST 3 /* No wait, no signal */
+#define COMMAND_PROVIDE 4 /* Wait, 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 */
+#define SIG_NOT_CHILD SIGPOLL /* Not a child of init */
struct command_struct /* Must always be COMMAND_SIZE */
{
signed int command;
pid_t pid;
+ pid_t ppid;
char name[1];
};
diff --git a/login-utils/ttymsg.c b/login-utils/ttymsg.c
index 6bf2f82f6..b422abb85 100644
--- a/login-utils/ttymsg.c
+++ b/login-utils/ttymsg.c
@@ -53,9 +53,8 @@
#include <stdlib.h>
#include "nls.h"
-#ifdef __linux__
#include "pathnames.h"
-#endif
+#include "ttymsg.h"
/*
* Display the contents of a uio structure on a terminal. Used by wall(1),
@@ -65,12 +64,7 @@
* ignored (exclusive-use, lack of permission, etc.).
*/
char *
-ttymsg(iov, iovcnt, line, tmout)
- struct iovec *iov;
- int iovcnt;
- char *line;
- int tmout;
-{
+ttymsg(struct iovec *iov, int iovcnt, char *line, int tmout) {
static char device[MAXNAMLEN];
static char errbuf[MAXNAMLEN+1024];
register int cnt, fd, left, wret;
diff --git a/login-utils/ttymsg.h b/login-utils/ttymsg.h
new file mode 100644
index 000000000..5d2795197
--- /dev/null
+++ b/login-utils/ttymsg.h
@@ -0,0 +1,2 @@
+char *ttymsg(struct iovec *iov, int iovcnt, char *line, int tmout);
+
diff --git a/login-utils/vipw.c b/login-utils/vipw.c
index dfcdca2ed..665d77daa 100644
--- a/login-utils/vipw.c
+++ b/login-utils/vipw.c
@@ -77,11 +77,9 @@ char tmptmp_file[FILENAMELEN]; /* very tmp file */
void pw_error __P((char *, int, int));
-void
-copyfile(from, to)
- register int from, to;
-{
- register int nr, nw, off;
+static void
+copyfile(int from, int to) {
+ int nr, nw, off;
char buf[8*1024];
while ((nr = read(from, buf, sizeof(buf))) > 0)
@@ -94,9 +92,8 @@ copyfile(from, to)
}
-void
-pw_init()
-{
+static void
+pw_init(void) {
struct rlimit rlim;
/* Unlimited resource limits. */
@@ -125,9 +122,8 @@ pw_init()
(void)umask(0);
}
-int
-pw_lock()
-{
+static int
+pw_lock(void) {
int lockfd, fd, ret;
/*
@@ -179,9 +175,8 @@ pw_lock()
return(1);
}
-void
-pw_unlock()
-{
+static void
+pw_unlock(void) {
char tmp[FILENAMELEN];
sprintf(tmp, "%s%s", orig_file, ".OLD");
@@ -198,9 +193,8 @@ pw_unlock()
}
-void
-pw_edit(int notsetuid)
-{
+static void
+pw_edit(int notsetuid) {
int pstat;
pid_t pid;
char *p, *editor;
diff --git a/login-utils/wall.c b/login-utils/wall.c
index d476edd64..6840015d4 100644
--- a/login-utils/wall.c
+++ b/login-utils/wall.c
@@ -55,8 +55,11 @@
#include <string.h>
#include <unistd.h>
#include <utmp.h>
+
#include "nls.h"
+#include "ttymsg.h"
#include "pathnames.h"
+#include "carefulputc.h"
void makemsg __P((char *));
@@ -68,17 +71,13 @@ char *mbuf;
char *progname = "wall";
-/* ARGSUSED */
int
-main(argc, argv)
- int argc;
- char **argv;
-{
+main(int argc, char **argv) {
extern int optind;
int ch;
struct iovec iov;
struct utmp *utmpptr;
- char *p, *ttymsg();
+ char *p;
char line[sizeof(utmpptr->ut_line) + 1];
setlocale(LC_ALL, "");
@@ -139,7 +138,7 @@ makemsg(fname)
struct tm *lt;
struct passwd *pw;
struct stat sbuf;
- time_t now, time();
+ time_t now;
FILE *fp;
int fd;
char *p, *whom, *where, hostname[MAXHOSTNAMELEN],
@@ -184,11 +183,26 @@ makemsg(fname)
}
(void)fprintf(fp, "%79s\r\n", " ");
- if (fname && !(freopen(fname, "r", stdin))) {
- (void)fprintf(stderr, _("%s: can't read %s.\n"), progname, fname);
- exit(1);
+ if (fname) {
+ /*
+ * When we are not root, but suid or sgid, refuse to read files
+ * (e.g. device files) that the user may not have access to.
+ * After all, our invoker can easily do "wall < file"
+ * instead of "wall file".
+ */
+ int uid = getuid();
+ if (uid && (uid != geteuid() || getgid() != getegid())) {
+ fprintf(stderr, _("%s: will not read %s - use stdin.\n"),
+ progname, fname);
+ exit(1);
+ }
+ if (!freopen(fname, "r", stdin)) {
+ fprintf(stderr, _("%s: can't read %s.\n"), progname, fname);
+ exit(1);
+ }
}
- while (fgets(lbuf, sizeof(lbuf), stdin))
+
+ while (fgets(lbuf, sizeof(lbuf), stdin)) {
for (cnt = 0, p = lbuf; (ch = *p) != '\0'; ++p, ++cnt) {
if (cnt == 79 || ch == '\n') {
for (; cnt < 79; ++cnt)
@@ -197,15 +211,10 @@ makemsg(fname)
putc('\n', fp);
cnt = 0;
} else {
- /* Test for control chars added Fri Mar 10
- 19:49:30 1995, faith@cs.unc.edu */
- if (!isprint(ch) && !isspace(ch) && ch != '\007') {
- putc('^', fp);
- putc(ch^0x40,fp); /* DEL to ?, others to alpha */
- } else
- putc(ch, fp);
+ carefulputc(ch, fp);
}
}
+ }
(void)fprintf(fp, "%79s\r\n", " ");
rewind(fp);