aboutsummaryrefslogtreecommitdiffstats
path: root/sysvinit/sysvinit-2.86/sysvinit-2.86.patch
diff options
context:
space:
mode:
Diffstat (limited to 'sysvinit/sysvinit-2.86/sysvinit-2.86.patch')
-rw-r--r--sysvinit/sysvinit-2.86/sysvinit-2.86.patch4880
1 files changed, 4880 insertions, 0 deletions
diff --git a/sysvinit/sysvinit-2.86/sysvinit-2.86.patch b/sysvinit/sysvinit-2.86/sysvinit-2.86.patch
index e69de29bb2..b83f525c3e 100644
--- a/sysvinit/sysvinit-2.86/sysvinit-2.86.patch
+++ b/sysvinit/sysvinit-2.86/sysvinit-2.86.patch
@@ -0,0 +1,4880 @@
+diff -urNd -urNd sysvinit-2.85/COPYRIGHT sysvinit-2.86/COPYRIGHT
+--- sysvinit-2.85/COPYRIGHT 2003-04-15 03:45:44.000000000 -0500
++++ sysvinit-2.86/COPYRIGHT 2004-07-30 07:12:12.000000000 -0500
+@@ -1,4 +1,4 @@
+-Sysvinit is Copyright (C) 1991-2003 Miquel van Smoorenburg
++Sysvinit is Copyright (C) 1991-2004 Miquel van Smoorenburg
+
+ 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
+diff -urNd -urNd sysvinit-2.85/doc/Changelog sysvinit-2.86/doc/Changelog
+--- sysvinit-2.85/doc/Changelog 2003-04-15 09:37:58.000000000 -0500
++++ sysvinit-2.86/doc/Changelog 2004-07-30 07:15:06.000000000 -0500
+@@ -1,3 +1,29 @@
++sysvinit (2.86) cistron; urgency=low
++
++ * Fixed up bootlogd to read /proc/cmdline. Also keep an internal
++ linebuffer to process \r, \t and ^H. It is becoming useable.
++ * Applied trivial OWL patches
++ * Block signals in syslog(), since syslog() is not re-entrant
++ (James Olin Oden <joden@malachi.lee.k12.nc.us>, redhat bug #97534)
++ * Minor adjustements so that sysvinit compiles on the Hurd
++ * killall5 now skips kernel threads
++ * Inittab entries with both 'S' and other runlevels were broken.
++ Fix by Bryan Kadzban <bryan@kadzban.is-a-geek.net>
++ * Changed initreq.h to be more flexible and forwards-compatible.
++ * You can now through /dev/initctl set environment variables in
++ init that will be inherited by its children. For now, only
++ variables prefixed with INIT_ can be set and the maximum is
++ 16 variables. There's also a length limit due to the size
++ of struct init_request, so it should be safe from abuse.
++ * Option -P and -H to shutdown set INIT_HALT=POWERDOWN and
++ INIT_HALT=HALT as environment variables as described above
++ * Add "mountpoint" utility.
++ * Slightly better algorithm in killall5.c:pidof()
++ * Added some patches from fedora-core (halt-usage, last -t,
++ sulogin-message, user-console)
++
++ -- Miquel van Smoorenburg <miquels@cistron.nl> Fri, 30 Jul 2004 14:14:58 +0200
++
+ sysvinit (2.85) cistron; urgency=low
+
+ * Add IPv6 support in last(1)
+diff -urNd -urNd sysvinit-2.85/doc/Install sysvinit-2.86/doc/Install
+--- sysvinit-2.85/doc/Install 2003-04-15 03:46:49.000000000 -0500
++++ sysvinit-2.86/doc/Install 2004-07-30 07:15:40.000000000 -0500
+@@ -1,5 +1,5 @@
+
+- README for the System V style init, version 2.85
++ README for the System V style init, version 2.86
+
+ init, shutdown, halt, reboot, wall, last, mesg, runlevel,
+ killall5, pidof, sulogin.
+diff -urNd -urNd sysvinit-2.85/doc/bootlogd.README sysvinit-2.86/doc/bootlogd.README
+--- sysvinit-2.85/doc/bootlogd.README 2000-09-12 16:54:31.000000000 -0500
++++ sysvinit-2.86/doc/bootlogd.README 2004-06-09 07:47:45.000000000 -0500
+@@ -1,10 +1,12 @@
+
+ bootlogd: a way to capture all console output during bootup
+- in a logfile. ** PROOF OF CONCEPT IMPLEMENTATION **
++ in a logfile.
+
+-- bootlogd opens /dev/console
+-- finds out what the real console is with an ioctl()
+-- then opens the real console
++- bootlogd opens /dev/console and finds out what the real console is
++ with an ioctl() if TIOCCONS is available
++- otherwise bootlogd tries to parse /proc/cmdline for console=
++ kernel command line arguments
++- then opens the (most probable) real console
+ - allocates a pty pair
+ - redirects console I/O to the pty pair
+ - then goes in a loop reading from the pty, writing to the real
+diff -urNd -urNd sysvinit-2.85/doc/sysvinit-2.85.lsm sysvinit-2.86/doc/sysvinit-2.85.lsm
+--- sysvinit-2.85/doc/sysvinit-2.85.lsm 2003-04-18 16:04:12.000000000 -0500
++++ sysvinit-2.86/doc/sysvinit-2.85.lsm 2004-06-09 07:47:45.000000000 -0500
+@@ -1,7 +1,7 @@
+ Begin3
+ Title: sysvinit and utilities
+ Version: 2.85
+-Entered-Date: 18APR2003
++Entered-Date: 15APR2003
+ Description: This is the Linux System V init.
+ This version can be compiled with glibc 2.0.6 and up.
+ Author: miquels@cistron.nl (Miquel van Smoorenburg)
+diff -urNd -urNd sysvinit-2.85/doc/sysvinit-2.86.lsm sysvinit-2.86/doc/sysvinit-2.86.lsm
+--- sysvinit-2.85/doc/sysvinit-2.86.lsm 1969-12-31 18:00:00.000000000 -0600
++++ sysvinit-2.86/doc/sysvinit-2.86.lsm 2004-07-31 08:35:28.000000000 -0500
+@@ -0,0 +1,14 @@
++Begin3
++Title: sysvinit and utilities
++Version: 2.86
++Entered-Date: 30JUL2004
++Description: This is the Linux System V init.
++ This version can be compiled with glibc 2.0.6 and up.
++Author: miquels@cistron.nl (Miquel van Smoorenburg)
++Primary-Site: ftp.cistron.nl /pub/people/miquels/software
++ 92K sysvinit-2.86.tar.gz
++Alternate-Site: sunsite.unc.edu /pub/Linux/system/daemons/init
++ 92K sysvinit-2.86.tar.gz
++Copying-Policy: GPL
++Keywords: init shutdown halt reboot
++End
+diff -urNd -urNd sysvinit-2.85/man/bootlogd.8 sysvinit-2.86/man/bootlogd.8
+--- sysvinit-2.85/man/bootlogd.8 1969-12-31 18:00:00.000000000 -0600
++++ sysvinit-2.86/man/bootlogd.8 2004-06-09 07:47:45.000000000 -0500
+@@ -0,0 +1,39 @@
++.TH BOOTLOGD 8 "Jul 21, 2003" "" "Linux System Administrator's Manual"
++.SH NAME
++bootlogd \- record boot messages
++.SH SYNOPSIS
++.B /sbin/bootlogd
++.RB [ \-d ]
++.RB [ \-r ]
++.RB [ \-v ]
++.RB [ " -l logfile " ]
++.RB [ " -p pidfile " ]
++.SH DESCRIPTION
++\fBBootlogd\fP runs in the background and copies all strings sent to the
++\fI/dev/console\fP device to a logfile. If the logfile is not accessible,
++the messages will be buffered in-memory until it is.
++.SH OPTIONS
++.IP \fB\-d\fP
++Do not fork and run in the background.
++.IP \fB\-r\fP
++If there is an existing logfile called \fIlogfile\fP rename it to
++\fIlogfile~\fP unless \fIlogfile~\fP already exists.
++.IP \fB\-v\fP
++Show version.
++.IP \fB\-l logfile\fP
++Log to this logfile. The default is \fI/var/log/boot\fP.
++.IP \fB\-p pidfile\fP
++Put process-id in this file. The default is no pidfile.
++.SH BUGS
++Bootlogd works by redirecting the console output from the console
++device. It copies that output to the real console device and a
++logfile. There is no standard way to find out the real console device
++if you have a new-style \fI/dev/console\fP device (major 5, minor 1).
++\fBBootlogd\fP tries to parse the kernel command line, looking for
++console= lines and deducts the real console device from that. If that
++syntax is ever changed by the kernel, or a console-type is used
++bootlogd does not know about, bootlogd will not work.
++.SH AUTHOR
++Miquel van Smoorenburg, miquels@cistron.nl
++.SH "SEE ALSO"
++.BR dmesg (8)
+diff -urNd -urNd sysvinit-2.85/man/init.8 sysvinit-2.86/man/init.8
+--- sysvinit-2.85/man/init.8 2003-04-18 16:05:03.000000000 -0500
++++ sysvinit-2.86/man/init.8 2004-07-29 06:21:31.000000000 -0500
+@@ -1,6 +1,6 @@
+ .\"{{{}}}
+ .\"{{{ Title
+-.TH INIT 8 "18 April 2003" "" "Linux System Administrator's Manual"
++.TH INIT 8 "29 Jul 2004" "" "Linux System Administrator's Manual"
+ .\"}}}
+ .\"{{{ Name
+ .SH NAME
+@@ -160,7 +160,7 @@
+ .SH ENVIRONMENT
+ \fBInit\fP sets the following environment variables for all its children:
+ .IP \fBPATH\fP
+-\fI/usr/local/sbin:/sbin:/bin:/usr/sbin:/usr/bin\fP
++\fI/bin:/usr/bin:/sbin:/usr/sbin\fP
+ .IP \fBINIT_VERSION\fP
+ As the name says. Useful to determine if a script runs directly from \fBinit\fP.
+ .IP \fBRUNLEVEL\fP
+diff -urNd -urNd sysvinit-2.85/man/initscript.5 sysvinit-2.86/man/initscript.5
+--- sysvinit-2.85/man/initscript.5 1999-12-24 16:31:21.000000000 -0600
++++ sysvinit-2.86/man/initscript.5 2004-06-09 07:47:45.000000000 -0500
+@@ -1,4 +1,4 @@
+-.TH INITSCRIPT 5 "December 24, 1999" "" "Linux System Administrator's Manual"
++.TH INITSCRIPT 5 "July 10, 2003" "" "Linux System Administrator's Manual"
+ .SH NAME
+ initscript \- script that executes inittab commands.
+ .SH SYNOPSIS
+@@ -40,6 +40,12 @@
+
+ .sp
+ .RE
++.SH NOTES
++This script is not meant as startup script for daemons or somesuch.
++It has nothing to do with a \fIrc.local\fP style script. It's just
++a handler for things executed from \fB/etc/inittab\fP. Experimenting
++with this can make your system un(re)bootable.
++.RE
+ .SH FILES
+ /etc/inittab,
+ /etc/initscript.
+diff -urNd -urNd sysvinit-2.85/man/killall5.8 sysvinit-2.86/man/killall5.8
+--- sysvinit-2.85/man/killall5.8 1997-05-27 05:34:21.000000000 -0500
++++ sysvinit-2.86/man/killall5.8 2004-06-09 07:47:45.000000000 -0500
+@@ -1,4 +1,4 @@
+-.TH KILLALL5 8 "27 May 1997" "" "Linux System Administrator's Manual"
++.TH KILLALL5 8 "04 Nov 2003" "" "Linux System Administrator's Manual"
+ .SH NAME
+ killall5 -- send a signal to all processes.
+ .SH SYNOPSIS
+@@ -7,9 +7,9 @@
+ .SH DESCRIPTION
+ .B killall5
+ is the SystemV killall command. It sends a signal to all processes except
+-the processes in its own session, so it won't kill the shell that is
+-running the script it was called from. Its primary (only) use is in the
+-\fBrc\fP scripts found in the /etc/init.d directory.
++kernel threads and the processes in its own session, so it won't kill
++the shell that is running the script it was called from. Its primary
++(only) use is in the \fBrc\fP scripts found in the /etc/init.d directory.
+ .SH SEE ALSO
+ .BR halt (8),
+ .BR reboot (8)
+diff -urNd -urNd sysvinit-2.85/man/last.1 sysvinit-2.86/man/last.1
+--- sysvinit-2.85/man/last.1 1999-07-29 05:50:34.000000000 -0500
++++ sysvinit-2.86/man/last.1 2004-07-30 06:39:18.000000000 -0500
+@@ -1,6 +1,6 @@
+ .\"{{{}}}
+ .\"{{{ Title
+-.TH LAST,LASTB 1 "Jul 29, 1999" "" "Linux System Administrator's Manual"
++.TH LAST,LASTB 1 "Jul 31, 2004" "" "Linux System Administrator's Manual"
+ .\"}}}
+ .\"{{{ Name
+ .SH NAME
+@@ -14,6 +14,7 @@
+ .RB "[ \-\fBn\fP \fInum\fP ]"
+ .RB [ \-adiox ]
+ .RB "[ \-\fBf\fP \fIfile\fP ]"
++.RB "[ \-\fBt\fP \fIYYYYMMDDHHMMSS\fP ]"
+ .RI [ name... ]
+ .RI [ tty... ]
+ .br
+@@ -54,6 +55,11 @@
+ This is a count telling \fBlast\fP how many lines to show.
+ .IP "\fB\-n\fP \fInum\fP"
+ The same.
++.IP "\fB\-t\fP \fIYYYYMMDDHHMMSS\fP"
++Display the state of logins as of the specified time. This is
++useful, e.g., to determine easily who was logged in at a particular
++time -- specify that time with \fB\-t\fP and look for "still logged
++in".
+ .IP \fB\-R\fP
+ Suppresses the display of the hostname field.
+ .IP \fB\-a\fP
+diff -urNd -urNd sysvinit-2.85/man/mesg.1 sysvinit-2.86/man/mesg.1
+--- sysvinit-2.85/man/mesg.1 2001-02-26 06:01:10.000000000 -0600
++++ sysvinit-2.86/man/mesg.1 2004-06-09 07:47:45.000000000 -0500
+@@ -27,7 +27,7 @@
+ If no option is given, \fBmesg\fP prints out the current access state of your
+ terminal.
+ .PP NOTES
+-\fBMesg\fP assumes that it's standard input is connected to your
++\fBMesg\fP assumes that its standard input is connected to your
+ terminal. That also means that if you are logged in multiple times,
+ you can get/set the mesg status of other sessions by using redirection.
+ For example "mesg n < /dev/pts/46".
+diff -urNd -urNd sysvinit-2.85/man/mountpoint.1 sysvinit-2.86/man/mountpoint.1
+--- sysvinit-2.85/man/mountpoint.1 1969-12-31 18:00:00.000000000 -0600
++++ sysvinit-2.86/man/mountpoint.1 2004-06-09 07:47:45.000000000 -0500
+@@ -0,0 +1,37 @@
++.TH MOUNTPOINT 8 "Mar 15, 2004" "" "Linux System Administrator's Manual"
++.SH NAME
++mountpoint \- see if a directory is a mountpoint
++.SH SYNOPSIS
++.B /bin/mountpoint
++.RB [ \-q ]
++.RB [ \-d ]
++.I /path/to/directory
++.br
++.B /bin/mountpoint
++.RB \-x
++.I /dev/device
++.SH DESCRIPTION
++\fBMountpoint\fP checks if the directory is a mountpoint.
++
++.SH OPTIONS
++.IP \fB\-q\fP
++Be quiet - don't print anything.
++.IP \fB\-d\fP
++Print major/minor device number of the filesystem on stdout.
++.IP \fB\-x\fP
++Print major/minor device number of the blockdevice on stdout.
++.SH EXIT STATUS
++Zero if the directory is a mountpoint, non-zero if not.
++.SH NOTES
++Symbolic links are not followed, except when the \fB-x\fP option is
++used. To force following symlinks, add a trailing slash to the
++path of the directory.
++.PP
++The name of the command is misleading when the -x option is used,
++but the option is useful for comparing if a directory and a device
++match up, and there is no other command that can print the info easily.
++.PP
++.SH AUTHOR
++Miquel van Smoorenburg, miquels@cistron.nl
++.SH "SEE ALSO"
++.BR stat (1)
+diff -urNd -urNd sysvinit-2.85/man/shutdown.8 sysvinit-2.86/man/shutdown.8
+--- sysvinit-2.85/man/shutdown.8 2001-10-02 16:27:50.000000000 -0500
++++ sysvinit-2.86/man/shutdown.8 2004-06-09 07:47:45.000000000 -0500
+@@ -1,6 +1,6 @@
+ .\"{{{}}}
+ .\"{{{ Title
+-.TH SHUTDOWN 8 "Juli 31, 2001" "" "Linux System Administrator's Manual"
++.TH SHUTDOWN 8 "November 12, 2003" "" "Linux System Administrator's Manual"
+ .\"}}}
+ .\"{{{ Name
+ .SH NAME
+@@ -11,7 +11,7 @@
+ .B /sbin/shutdown
+ .RB [ \-t
+ .IR sec ]
+-.RB [ \-arkhncfF ]
++.RB [ \-arkhncfFHP ]
+ .I time
+ .RI [ warning-message ]
+ .\"}}}
+@@ -54,7 +54,16 @@
+ .\"}}}
+ .\"{{{ -h
+ .IP \fB\-h\fP
+-Halt after shutdown.
++Halt or poweroff after shutdown.
++.\"}}}
++.\"{{{ -H
++.IP \fB\-H\fP
++Halt action is to halt or drop into boot monitor on systems that
++support it.
++.\"}}}
++.\"{{{ -P
++.IP \fB\-P\fP
++Halt action is to turn off the power.
+ .\"}}}
+ .\"{{{ -n
+ .IP \fB\-n\fP
+@@ -141,6 +150,14 @@
+ .sp 1
+ Note that if \fI/etc/shutdown.allow\fP is not present, the \fB-a\fP
+ argument is ignored.
++.SH HALT OR POWEROFF
++The \fB-H\fP option just sets the \fIinit\fP environment variable
++\fIINIT_HALT\fP to \fIHALT\fP, and the \fB-P\fP option just sets
++that variable to \fIPOWEROFF\fP. The shutdown script that calls
++\fBhalt\fP(8) as the last thing in the shutdown sequence should
++check these environment variables and call \fBhalt\fP(8) with
++the right options for these options to actually have any effect.
++Debian 3.1 (sarge) supports this.
+ .SH FILES
+ .nf
+ /fastboot
+diff -urNd -urNd sysvinit-2.85/man/sulogin.8 sysvinit-2.86/man/sulogin.8
+--- sysvinit-2.85/man/sulogin.8 2000-09-11 07:19:25.000000000 -0500
++++ sysvinit-2.86/man/sulogin.8 2004-06-09 07:47:45.000000000 -0500
+@@ -1,4 +1,4 @@
+-.TH SULOGIN 8 "11 Sep 2000" "" "Linux System Administrator's Manual"
++.TH SULOGIN 8 "04 Nov 2003" "" "Linux System Administrator's Manual"
+ .SH NAME
+ sulogin -- Single-user login
+ .SH SYNOPSIS
+@@ -20,7 +20,7 @@
+ .br
+ (or type Control-D for normal startup):
+ .PP
+-\fIsulogin\fP will connected to the current terminal, or to the
++\fIsulogin\fP will be connected to the current terminal, or to the
+ optional device that can be specified on the command line
+ (typically \fB/dev/console\fP).
+ .PP
+@@ -45,16 +45,18 @@
+ .PP
+ boot: linux -b rw sushell=/sbin/sash
+ .SH FALLBACK METHODS
+-\fIsulogin\fP checks the root password using the standard methods first.
+-If the \fB-e\fP option was specified,
+-\fIsulogin\fP examines the next files to find the root password. If
+-they are damaged, or non-existant, it will use fallback methods that
+-even go so far as to provide you with a shell prompt without asking
+-for the root password if they are irrepairably damaged.
++\fIsulogin\fP checks the root password using the standard method (getpwnam)
++first.
++Then, if the \fB-e\fP option was specified,
++\fIsulogin\fP examines these files directly to find the root password:
+ .PP
+ /etc/passwd,
+ .br
+ /etc/shadow (if present)
++.PP
++If they are damaged or non-existant, sulogin will start a root shell
++without asking for a password. Only use the \fB-e\fP option if you
++are sure the console is physically protected against unauthorized access.
+ .SH AUTHOR
+ Miquel van Smoorenburg <miquels@cistron.nl>
+ .SH SEE ALSO
+diff -urNd -urNd sysvinit-2.85/man/wall.1 sysvinit-2.86/man/wall.1
+--- sysvinit-2.85/man/wall.1 2003-04-16 04:17:38.000000000 -0500
++++ sysvinit-2.86/man/wall.1 2004-06-09 07:47:45.000000000 -0500
+@@ -47,7 +47,7 @@
+ .I Wall
+ ignores the
+ .B TZ
+-variable - the time printed in the banner is based on the systems
++variable - the time printed in the banner is based on the system's
+ local time.
+
+ .SH SEE ALSO
+diff -urNd -urNd sysvinit-2.85/src/Makefile sysvinit-2.86/src/Makefile
+--- sysvinit-2.85/src/Makefile 2001-11-06 05:58:16.000000000 -0600
++++ sysvinit-2.86/src/Makefile 2004-06-09 07:47:45.000000000 -0500
+@@ -5,34 +5,56 @@
+ # clean cleans up object files
+ # clobber really cleans up
+ #
+-# Version: @(#)Makefile 2.83-3 06-Nov-2001 miquels@cistron.nl
++# Version: @(#)Makefile 2.85-13 23-Mar-2004 miquels@cistron.nl
+ #
+
+-CC = cc
+-CFLAGS = -Wall -O2 -D_GNU_SOURCE
++CC = gcc
++CFLAGS = -Wall -O2 -fomit-frame-pointer -D_GNU_SOURCE
+ LDFLAGS = -s
+ STATIC =
+
+-# For Debian we do not build all programs, otherwise we do.
+-ifeq ($(DEBIAN),)
+-PROGS = init halt shutdown killall5 runlevel sulogin utmpdump \
+- last mesg wall
+-else
+-PROGS = init halt shutdown killall5 runlevel sulogin last mesg
++# For some known distributions we do not build all programs, otherwise we do.
++BIN =
++SBIN = init halt shutdown runlevel killall5
++USRBIN = last mesg
++
++MAN1 = last.1 lastb.1 mesg.1
++MAN5 = initscript.5 inittab.5
++MAN8 = halt.8 init.8 killall5.8 pidof.8 poweroff.8 reboot.8 runlevel.8
++MAN8 += shutdown.8 telinit.8
++
++ifeq ($(DISTRO),)
++BIN += mountpoint
++SBIN += sulogin bootlogd
++USRBIN += utmpdump wall
++MAN1 += mountpoint.1 wall.1
++MAN8 += sulogin.8 bootlogd.8
++endif
++
++ifeq ($(DISTRO),Debian)
++BIN += mountpoint
++SBIN += sulogin bootlogd
++MAN1 += mountpoint.1
++MAN8 += sulogin.8 bootlogd.8
++endif
++
++ifeq ($(DISTRO),Owl)
++USRBIN += wall
++MAN1 += wall.1
+ endif
+
+ BIN_OWNER = root
+ BIN_GROUP = root
+-BIN_COMBO = $(BIN_OWNER).$(BIN_GROUP)
++BIN_COMBO = $(BIN_OWNER):$(BIN_GROUP)
+ INSTALL = install -o $(BIN_OWNER) -g $(BIN_GROUP)
+ MANDIR = /usr/share/man
+
+-# Additional libs for Gnu Libc
++# Additional libs for GNU libc.
+ ifneq ($(wildcard /usr/lib/libcrypt.a),)
+ LCRYPT = -lcrypt
+ endif
+
+-all: $(PROGS)
++all: $(BIN) $(SBIN) $(USRBIN)
+
+ init: init.o init_utmp.o
+ $(CC) $(LDFLAGS) $(STATIC) -o $@ init.o init_utmp.o
+@@ -46,6 +68,9 @@
+ mesg: mesg.o
+ $(CC) $(LDFLAGS) -o $@ mesg.o
+
++mountpoint: mountpoint.o
++ $(CC) $(LDFLAGS) -o $@ mountpoint.o
++
+ utmpdump: utmpdump.o
+ $(CC) $(LDFLAGS) -o $@ utmpdump.o
+
+@@ -62,9 +87,9 @@
+ $(CC) $(LDFLAGS) -o $@ dowall.o shutdown.o utmp.o
+
+ bootlogd: bootlogd.o
+- $(CC) $(LDFLAGS) -o $@ bootlogd.o
++ $(CC) $(LDFLAGS) -o $@ bootlogd.o -lutil
+
+-init.o: init.c init.h set.h reboot.h
++init.o: init.c init.h set.h reboot.h initreq.h
+ $(CC) -c $(CFLAGS) init.c
+
+ utmp.o: utmp.c init.h
+@@ -80,36 +105,44 @@
+ @echo Type \"make clobber\" to really clean up.
+
+ clobber: cleanobjs
+- rm -f $(PROGS)
++ rm -f $(BIN) $(SBIN) $(USRBIN)
+
+ distclean: clobber
+
+ install:
+- $(INSTALL) -m 755 halt init killall5 sulogin \
+- runlevel shutdown $(ROOT)/sbin
+- # These are not installed by default
+-ifeq ($(DEBIAN),)
+- $(INSTALL) -m 555 utmpdump wall $(ROOT)/usr/bin
+-endif
+- # $(INSTALL) -m 755 etc/initscript.sample $(ROOT)/etc
+- $(INSTALL) -m 755 mesg last $(ROOT)/usr/bin
+- cd $(ROOT)/sbin; ln -sf halt reboot; chown $(BIN_COMBO) reboot
+- cd $(ROOT)/sbin; ln -sf halt poweroff; chown $(BIN_COMBO) poweroff
+- cd $(ROOT)/sbin; ln -sf init telinit; chown $(BIN_COMBO) telinit
+- cd $(ROOT)/bin; ln -sf ../sbin/killall5 pidof; chown $(BIN_COMBO) pidof
+- cd $(ROOT)/usr/bin; ln -sf last lastb; chown $(BIN_COMBO) lastb
+- $(INSTALL) -m 644 initreq.h $(ROOT)/usr/include
+- $(INSTALL) -m 644 ../man/*.8 $(ROOT)$(MANDIR)/man8
+- $(INSTALL) -m 644 ../man/*.5 $(ROOT)$(MANDIR)/man5
+-ifeq ($(DEBIAN),)
+- $(INSTALL) -m 644 ../man/wall.1 $(ROOT)$(MANDIR)/man1
+-endif
+- $(INSTALL) -m 644 ../man/last.1 ../man/lastb.1 ../man/mesg.1 \
+- $(ROOT)$(MANDIR)/man1
++ for i in $(BIN); do \
++ $(INSTALL) -m 755 $$i $(ROOT)/bin/; \
++ done
++ for i in $(SBIN); do \
++ $(INSTALL) -m 755 $$i $(ROOT)/sbin/; \
++ done
++ for i in $(USRBIN); do \
++ $(INSTALL) -m 755 $$i $(ROOT)/usr/bin/; \
++ done
++ # $(INSTALL) -m 755 etc/initscript.sample $(ROOT)/etc/
++ ln -sf halt $(ROOT)/sbin/reboot
++ ln -sf halt $(ROOT)/sbin/poweroff
++ ln -sf init $(ROOT)/sbin/telinit
++ ln -sf ../sbin/killall5 $(ROOT)/bin/pidof
++ if [ ! -f $(ROOT)/usr/bin/lastb ]; then \
++ ln -sf last $(ROOT)/usr/bin/lastb; \
++ fi
++ $(INSTALL) -m 644 initreq.h $(ROOT)/usr/include/
++ for i in $(MAN1); do \
++ $(INSTALL) -m 644 ../man/$$i $(ROOT)$(MANDIR)/man1/; \
++ done
++ for i in $(MAN5); do \
++ $(INSTALL) -m 644 ../man/$$i $(ROOT)$(MANDIR)/man5/; \
++ done
++ for i in $(MAN8); do \
++ $(INSTALL) -m 644 ../man/$$i $(ROOT)$(MANDIR)/man8/; \
++ done
++ifeq ($(ROOT),)
+ #
+- # This part is skipped on debian systems, the
++ # This part is skipped on Debian systems, the
+ # debian.preinst script takes care of it.
+ @if [ ! -p /dev/initctl ]; then \
+ echo "Creating /dev/initctl"; \
+ rm -f /dev/initctl; \
+ mknod -m 600 /dev/initctl p; fi
++endif
+Binary files sysvinit-2.85/src/bootlogd and sysvinit-2.86/src/bootlogd differ
+diff -urNd -urNd sysvinit-2.85/src/bootlogd.c sysvinit-2.86/src/bootlogd.c
+--- sysvinit-2.85/src/bootlogd.c 2001-12-09 08:01:28.000000000 -0600
++++ sysvinit-2.86/src/bootlogd.c 2004-06-09 07:47:45.000000000 -0500
+@@ -3,12 +3,12 @@
+ * The file is usually located on the /var partition, and
+ * gets written (and fsynced) as soon as possible.
+ *
+- * Version: @(#)bootlogd 2.79 11-Sep-2000 miquels@cistron.nl
++ * Version: @(#)bootlogd 2.86pre 12-Jan-2004 miquels@cistron.nl
+ *
+ * Bugs: Uses openpty(), only available in glibc. Sorry.
+ *
+ * This file is part of the sysvinit suite,
+- * Copyright 1991-2000 Miquel van Smoorenburg.
++ * Copyright 1991-2004 Miquel van Smoorenburg.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+@@ -17,7 +17,9 @@
+ *
+ * *NOTE* *NOTE* *NOTE*
+ * This is a PROOF OF CONCEPT IMPLEMENTATION
+- * I do not recommend using this on production systems.
++ *
++ * I have bigger plans for Debian, but for now
++ * this has to do ;)
+ *
+ */
+
+@@ -38,18 +40,14 @@
+ #include <dirent.h>
+ #include <fcntl.h>
+ #include <pty.h>
+-
+-char *Version = "@(#) bootlogd 2.79 11-Sep-2000 MvS";
+-
+-/*
+- * Until the kernel knows about TIOCGDEV, use a really ugly
+- * non-portable (not even between architectures) hack.
+- */
+-#ifndef TIOCGDEV
+-# define TIOCTTYGSTRUCT_HACK 1
++#include <ctype.h>
++#ifdef __linux__
++#include <sys/mount.h>
+ #endif
+
+-#define LOGFILE "/var/log/boot.log"
++char *Version = "@(#) bootlogd 2.86 03-Jun-2004 miquels@cistron.nl";
++
++#define LOGFILE "/var/log/boot"
+
+ char ringbuf[32768];
+ char *endptr = ringbuf + sizeof(ringbuf);
+@@ -59,29 +57,32 @@
+ int got_signal = 0;
+ int didnl = 1;
+
++struct line {
++ char buf[256];
++ int pos;
++} line;
+
+-#ifdef TIOCTTYGSTRUCT_HACK
+-struct tty_offsets {
+- char *kver;
+- int offset;
+-} tty_offsets[] = {
+-#if ((~0UL) == 0xffffffff) /* 32 bits */
+- { "2.0.", 236 },
+- { "2.1.", 268 },
+- { "2.2.", 272 },
+- { "2.3.", 272 },
+- { "2.4.", 272 },
+- { "2.5.", 272 },
+-#else /* 64 bits */
+- { "2.2.", 480 },
+- { "2.3.", 480 },
+- { "2.4.", 480 },
+- { "2.5.", 480 },
+-#endif
+- { NULL, 0 },
++/*
++ * Console devices as listed on the kernel command line and
++ * the mapping to actual devices in /dev
++ */
++struct consdev {
++ char *cmdline;
++ char *dev1;
++ char *dev2;
++} consdev[] = {
++ { "ttySC", "/dev/ttySC%s", "/dev/ttsc/%s" },
++ { "ttyS", "/dev/ttyS%s", "/dev/tts/%s" },
++ { "tty", "/dev/tty%s", "/dev/vc/%s" },
++ { "hvc", "/dev/hvc%s", "/dev/hvc/%s" },
++ { NULL, NULL, NULL },
+ };
+-#endif
+
++/*
++ * Devices to try as console if not found on kernel command line.
++ * Tried from left to right (as opposed to kernel cmdline).
++ */
++char *defcons[] = { "tty0", "hvc0", "ttyS0", "ttySC0", NULL };
+
+ /*
+ * Catch signals.
+@@ -95,6 +96,8 @@
+ /*
+ * Scan /dev and find the device name.
+ * Side-effect: directory is changed to /dev
++ *
++ * FIXME: scan subdirectories for devfs support ?
+ */
+ int findtty(char *res, int rlen, dev_t dev)
+ {
+@@ -117,18 +120,88 @@
+ }
+ }
+ if (ent == NULL) {
+- fprintf(stderr, "bootlogd: cannot find console device\n");
++ fprintf(stderr, "bootlogd: cannot find console device "
++ "%d:%d in /dev\n", major(dev), minor(dev));
+ r = -1;
+- } else if (strlen(ent->d_name) >= rlen) {
++ } else if (strlen(ent->d_name) + 5 >= rlen) {
+ fprintf(stderr, "bootlogd: console device name too long\n");
+ r = -1;
+ } else
+- strcpy(res, ent->d_name);
++ snprintf(res, rlen, "/dev/%s", ent->d_name);
+ closedir(dir);
+
+ return r;
+ }
+
++/*
++ * For some reason, openpty() in glibc sometimes doesn't
++ * work at boot-time. It must be a bug with old-style pty
++ * names, as new-style (/dev/pts) is not available at that
++ * point. So, we find a pty/tty pair ourself if openpty()
++ * fails for whatever reason.
++ */
++int findpty(int *master, int *slave, char *name)
++{
++ char pty[16];
++ char tty[16];
++ int i, j;
++ int found;
++
++ if (openpty(master, slave, name, NULL, NULL) >= 0)
++ return 0;
++
++ found = 0;
++
++ for (i = 'p'; i <= 'z'; i++) {
++ for (j = '0'; j <= 'f'; j++) {
++ if (j == '9' + 1) j = 'a';
++ sprintf(pty, "/dev/pty%c%c", i, j);
++ sprintf(tty, "/dev/tty%c%c", i, j);
++ if ((*master = open(pty, O_RDWR|O_NOCTTY)) >= 0) {
++ *slave = open(tty, O_RDWR|O_NOCTTY);
++ if (*slave >= 0) {
++ found = 1;
++ break;
++ }
++ }
++ }
++ if (found) break;
++ }
++ if (found < 0) return -1;
++
++ if (name) strcpy(name, tty);
++
++ return 0;
++}
++/*
++ * See if a console taken from the kernel command line maps
++ * to a character device we know about, and if we can open it.
++ */
++int isconsole(char *s, char *res, int rlen)
++{
++ struct consdev *c;
++ int l, sl, i, fd;
++ char *p, *q;
++
++ sl = strlen(s);
++
++ for (c = consdev; c->cmdline; c++) {
++ l = strlen(c->cmdline);
++ if (sl <= l) continue;
++ p = s + l;
++ if (strncmp(s, c->cmdline, l) != 0 || !isdigit(*p))
++ continue;
++ for (i = 0; i < 2; i++) {
++ snprintf(res, rlen, i ? c->dev1 : c->dev2, p);
++ if ((q = strchr(res, ',')) != NULL) *q = 0;
++ if ((fd = open(res, O_RDONLY|O_NONBLOCK)) >= 0) {
++ close(fd);
++ return 1;
++ }
++ }
++ }
++ return 0;
++}
+
+ /*
+ * Find out the _real_ console. Assume that stdin is connected to
+@@ -136,21 +209,18 @@
+ */
+ int consolename(char *res, int rlen)
+ {
+- struct stat st;
+-#if TIOCTTYGSTRUCT_HACK
+- struct utsname uts;
+- struct tty_offsets *tt;
+- dev_t dev;
+- unsigned short *kdev;
+- char buf[4096];
+- int offset = -1;
+-#endif
+ #ifdef TIOCGDEV
+- kdev_t kdev;
++ unsigned int kdev;
+ #endif
++ struct stat st, st2;
++ char buf[256];
++ char *p;
++ int didmount = 0;
++ int n, r;
++ int fd;
+
+ fstat(0, &st);
+- if (st.st_rdev != 0x0501) {
++ if (major(st.st_rdev) != 5 || minor(st.st_rdev) != 1) {
+ /*
+ * Old kernel, can find real device easily.
+ */
+@@ -160,33 +230,78 @@
+ #ifdef TIOCGDEV
+ if (ioctl(0, TIOCGDEV, &kdev) == 0)
+ return findtty(res, rlen, (dev_t)kdev);
+- return -1;
++ if (errno != ENOIOCTLCMD) return -1;
+ #endif
+
++#ifdef __linux__
+ /*
+- * New kernel and new console device - hard to find
+- * out what device the real console is ..
++ * Read /proc/cmdline.
+ */
+-#if TIOCTTYGSTRUCT_HACK
+- if (ioctl(0, TIOCTTYGSTRUCT, buf) != 0) {
+- perror("bootlogd: TIOCTTYGSTRUCT");
++ stat("/", &st);
++ if (stat("/proc", &st2) < 0) {
++ perror("bootlogd: /proc");
+ return -1;
+ }
+- uname(&uts);
+- for (tt = tty_offsets; tt->kver; tt++)
+- if (!strncmp(uts.release, tt->kver, strlen(tt->kver))) {
+- offset = tt->offset;
++ if (st.st_dev == st2.st_dev) {
++ if (mount("proc", "/proc", "proc", 0, NULL) < 0) {
++ perror("bootlogd: mount /proc");
++ return -1;
++ }
++ didmount = 1;
++ }
++
++ n = 0;
++ r = -1;
++ if ((fd = open("/proc/cmdline", O_RDONLY)) < 0) {
++ perror("bootlogd: /proc/cmdline");
++ } else {
++ buf[0] = 0;
++ if ((n = read(fd, buf, sizeof(buf) - 1)) >= 0)
++ r = 0;
++ else
++ perror("bootlogd: /proc/cmdline");
++ close(fd);
++ }
++ if (didmount) umount("/proc");
++
++ if (r < 0) return r;
++
++ /*
++ * OK, so find console= in /proc/cmdline.
++ * Parse in reverse, opening as we go.
++ *
++ * Valid console devices: ttySC, ttyS, tty, hvc.
++ */
++ p = buf + n;
++ *p-- = 0;
++ r = -1;
++ while (p >= buf) {
++ if (*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n') {
++ *p-- = 0;
++ continue;
++ }
++ if (strncmp(p, "console=", 8) == 0 &&
++ isconsole(p + 8, res, rlen)) {
++ r = 0;
+ break;
+ }
+- if (offset < 0) {
+- fprintf(stderr, "bootlogd: don't know offsetof"
+- "(struct tty_struct, device) for kernel %s\n", uts.release);
+- return -1;
++ p--;
+ }
+- kdev = (unsigned short *)(&buf[offset]);
+- dev = (dev_t)(*kdev);
+- return findtty(res, rlen, dev);
++
++ if (r == 0) return r;
+ #endif
++
++ /*
++ * Okay, no console on the command line -
++ * guess the default console.
++ */
++ for (n = 0; defcons[n]; n++)
++ if (isconsole(defcons[n], res, rlen))
++ return 0;
++
++ fprintf(stderr, "bootlogd: cannot deduce real console device\n");
++
++ return -1;
+ }
+
+
+@@ -197,9 +312,13 @@
+ {
+ time_t t;
+ char *s;
++ char tmp[8];
+ int olen = len;
++ int dosync = 0;
++ int tlen;
+
+ while (len > 0) {
++ tmp[0] = 0;
+ if (didnl) {
+ time(&t);
+ s = ctime(&t);
+@@ -207,24 +326,51 @@
+ didnl = 0;
+ }
+ switch (*ptr) {
++ case 27: /* ESC */
++ strcpy(tmp, "^[");
++ break;
+ case '\r':
++ line.pos = 0;
++ break;
++ case 8: /* ^H */
++ if (line.pos > 0) line.pos--;
+ break;
+ case '\n':
+ didnl = 1;
++ dosync = 1;
++ break;
+ case '\t':
++ line.pos += (line.pos / 8 + 1) * 8;
++ if (line.pos >= sizeof(line.buf))
++ line.pos = sizeof(line.buf) - 1;
++ break;
+ case 32 ... 127:
+ case 161 ... 255:
+- fputc(*ptr, fp);
++ tmp[0] = *ptr;
++ tmp[1] = 0;
+ break;
+ default:
+- fprintf(fp, "\\%03o", *ptr);
++ sprintf(tmp, "\\%03o", *ptr);
+ break;
+ }
+ ptr++;
+ len--;
++
++ tlen = strlen(tmp);
++ if (tlen && (line.pos + tlen < sizeof(line.buf))) {
++ memcpy(line.buf + line.pos, tmp, tlen);
++ line.pos += tlen;
++ }
++ if (didnl) {
++ fprintf(fp, "%s\n", line.buf);
++ memset(&line, 0, sizeof(line));
++ }
++ }
++
++ if (dosync) {
++ fflush(fp);
++ fdatasync(fileno(fp));
+ }
+- fflush(fp);
+- fdatasync(fileno(fp));
+
+ outptr += olen;
+ if (outptr >= endptr)
+@@ -242,6 +388,40 @@
+ exit(1);
+ }
+
++int open_nb(char *buf)
++{
++ int fd, n;
++
++ if ((fd = open(buf, O_WRONLY|O_NONBLOCK|O_NOCTTY)) < 0)
++ return -1;
++ n = fcntl(fd, F_GETFL);
++ n &= ~(O_NONBLOCK);
++ fcntl(fd, F_SETFL, n);
++
++ return fd;
++}
++
++/*
++ * We got a write error on the real console. If its an EIO,
++ * somebody hung up our filedescriptor, so try to re-open it.
++ */
++int write_err(int pts, int realfd, char *realcons, int e)
++{
++ int fd;
++
++ if (e != EIO) {
++werr:
++ close(pts);
++ fprintf(stderr, "bootlogd: writing to console: %s\n",
++ strerror(e));
++ return -1;
++ }
++ close(realfd);
++ if ((fd = open_nb(realcons)) < 0)
++ goto werr;
++
++ return fd;
++}
+
+ int main(int argc, char **argv)
+ {
+@@ -249,6 +429,7 @@
+ struct timeval tv;
+ fd_set fds;
+ char buf[1024];
++ char realcons[1024];
+ char *p;
+ char *logfile;
+ char *pidfile;
+@@ -298,23 +479,32 @@
+ /*
+ * Open console device directly.
+ */
+- if (consolename(buf, sizeof(buf)) < 0)
++ if (consolename(realcons, sizeof(realcons)) < 0)
+ return 1;
+- if ((realfd = open(buf, O_WRONLY|O_NONBLOCK)) < 0) {
++
++ if (strcmp(realcons, "/dev/tty0") == 0)
++ strcpy(realcons, "/dev/tty1");
++ if (strcmp(realcons, "/dev/vc/0") == 0)
++ strcpy(realcons, "/dev/vc/1");
++
++ if ((realfd = open_nb(realcons)) < 0) {
+ fprintf(stderr, "bootlogd: %s: %s\n", buf, strerror(errno));
+ return 1;
+ }
+- n = fcntl(realfd, F_GETFL);
+- n &= ~(O_NONBLOCK);
+- fcntl(realfd, F_SETFL, n);
+
+ /*
+ * Grab a pty, and redirect console messages to it.
+ */
+- if (openpty(&ptm, &pts, buf, NULL, NULL) < 0) {
+- fprintf(stderr, "bootlogd: cannot allocate pseudo tty\n");
++ ptm = -1;
++ pts = -1;
++ buf[0] = 0;
++ if (findpty(&ptm, &pts, buf) < 0) {
++ fprintf(stderr,
++ "bootlogd: cannot allocate pseudo tty: %s\n",
++ strerror(errno));
+ return 1;
+ }
++
+ (void)ioctl(0, TIOCCONS, NULL);
+ #if 1
+ /* Work around bug in 2.1/2.2 kernels. Fixed in 2.2.13 and 2.3.18 */
+@@ -357,8 +547,8 @@
+ * open the logfile. There might be buffered messages
+ * we want to write.
+ */
+- tv.tv_sec = fp ? 86400 : 5;
+- tv.tv_usec = 0;
++ tv.tv_sec = 0;
++ tv.tv_usec = 500000;
+ FD_ZERO(&fds);
+ FD_SET(ptm, &fds);
+ if (select(ptm + 1, &fds, NULL, NULL, &tv) == 1) {
+@@ -374,10 +564,22 @@
+ p = inptr;
+ while (m > 0) {
+ i = write(realfd, p, m);
+- if (i <= 0) break;
+- m -= i;
+- p += i;
++ if (i >= 0) {
++ m -= i;
++ p += i;
++ continue;
++ }
++ /*
++ * Handle EIO (somebody hung
++ * up our filedescriptor)
++ */
++ realfd = write_err(pts, realfd,
++ realcons, errno);
++ if (realfd >= 0) continue;
++ got_signal = 1; /* Not really */
++ break;
+ }
++
+ /*
+ * Increment buffer position. Handle
+ * wraps, and also drag output pointer
+@@ -410,8 +612,8 @@
+ writelog(fp, outptr, todo);
+ }
+
+- if (fp && !didnl) {
+- fputc('\n', fp);
++ if (fp) {
++ if (!didnl) fputc('\n', fp);
+ fclose(fp);
+ }
+
+Binary files sysvinit-2.85/src/bootlogd.o and sysvinit-2.86/src/bootlogd.o differ
+diff -urNd -urNd sysvinit-2.85/src/dowall.c sysvinit-2.86/src/dowall.c
+--- sysvinit-2.85/src/dowall.c 2003-04-17 06:32:01.000000000 -0500
++++ sysvinit-2.86/src/dowall.c 2004-06-09 07:47:45.000000000 -0500
+@@ -3,7 +3,7 @@
+ *
+ * Author: Miquel van Smoorenburg, miquels@cistron.nl
+ *
+- * Version: @(#)dowall.c 2.85-1 15-Apr-2003 miquels@cistron.nl
++ * Version: @(#)dowall.c 2.85-5 02-Jul-2003 miquels@cistron.nl
+ *
+ * This file is part of the sysvinit suite,
+ * Copyright 1991-2003 Miquel van Smoorenburg.
+@@ -135,6 +135,13 @@
+ char *user, *tty;
+ int fd, flags;
+
++ /*
++ * Make sure tp and fd aren't in a register. Some versions
++ * of gcc clobber those after longjmp (or so I understand).
++ */
++ (void) &tp;
++ (void) &fd;
++
+ getuidtty(&user, &tty);
+
+ /* Get the time */
+Binary files sysvinit-2.85/src/dowall.o and sysvinit-2.86/src/dowall.o differ
+Binary files sysvinit-2.85/src/halt and sysvinit-2.86/src/halt differ
+diff -urNd -urNd sysvinit-2.85/src/halt.c sysvinit-2.86/src/halt.c
+--- sysvinit-2.85/src/halt.c 2001-11-27 06:12:03.000000000 -0600
++++ sysvinit-2.86/src/halt.c 2004-07-30 07:16:18.000000000 -0500
+@@ -8,12 +8,14 @@
+ * execute an "shutdown -r". This is for compatibility with
+ * sysvinit 2.4.
+ *
+- * Usage: halt [-n] [-w] [-d] [-f] [-p]
++ * Usage: halt [-n] [-w] [-d] [-f] [-h] [-i] [-p]
+ * -n: don't sync before halting the system
+ * -w: only write a wtmp reboot record and exit.
+ * -d: don't write a wtmp record.
+ * -f: force halt/reboot, don't call shutdown.
+- * -p: power down the system (if possible, otherwise halt)
++ * -h: put harddisks in standby mode
++ * -i: shut down all network interfaces.
++ * -p: power down the system (if possible, otherwise halt).
+ *
+ * Reboot and halt are both this program. Reboot
+ * is just a link to halt. Invoking the program
+@@ -21,10 +23,10 @@
+ *
+ * Author: Miquel van Smoorenburg, miquels@cistron.nl
+ *
+- * Version: 2.84, 27-Nov-2001
++ * Version: 2.86, 30-Jul-2004
+ *
+ * This file is part of the sysvinit suite,
+- * Copyright 1991-2001 Miquel van Smoorenburg.
++ * Copyright 1991-2004 Miquel van Smoorenburg.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+@@ -47,7 +49,7 @@
+ #include <getopt.h>
+ #include "reboot.h"
+
+-char *Version = "@(#)halt 2.84 27-Nov-2001 miquels@cistron.nl";
++char *Version = "@(#)halt 2.86 31-Jul-2004 miquels@cistron.nl";
+ char *progname;
+
+ #define KERNEL_MONITOR 1 /* If halt() puts you into the kernel monitor. */
+@@ -62,7 +64,16 @@
+ */
+ void usage(void)
+ {
+- fprintf(stderr, "usage: %s [-n] [-w] [-d] [-f] [-i] [-p]\n", progname);
++ fprintf(stderr, "usage: %s [-n] [-w] [-d] [-f] [-h] [-i]%s\n",
++ progname, strcmp(progname, "halt") ? "" : " [-p]");
++ fprintf(stderr, "\t-n: don't sync before halting the system\n");
++ fprintf(stderr, "\t-w: only write a wtmp reboot record and exit.\n");
++ fprintf(stderr, "\t-d: don't write a wtmp record.\n");
++ fprintf(stderr, "\t-f: force halt/reboot, don't call shutdown.\n");
++ fprintf(stderr, "\t-h: put harddisks in standby mode.\n");
++ fprintf(stderr, "\t-i: shut down all network interfaces.\n");
++ if (!strcmp(progname, "halt"))
++ fprintf(stderr, "\t-p: power down the system (if possible, otherwise halt).\n");
+ exit(1);
+ }
+
+@@ -172,11 +183,6 @@
+ else
+ progname = argv[0];
+
+- if (geteuid() != 0) {
+- fprintf(stderr, "%s: must be superuser.\n", progname);
+- exit(1);
+- }
+-
+ if (!strcmp(progname, "reboot")) do_reboot = 1;
+ if (!strcmp(progname, "poweroff")) do_poweroff = 1;
+
+@@ -216,6 +222,11 @@
+ }
+ if (argc != optind) usage();
+
++ if (geteuid() != 0) {
++ fprintf(stderr, "%s: must be superuser.\n", progname);
++ exit(1);
++ }
++
+ (void)chdir("/");
+
+ if (!do_hard && !do_nothing) {
+@@ -236,7 +247,7 @@
+ /*
+ * Exit if all we wanted to do was write a wtmp record.
+ */
+- if (do_nothing) exit(0);
++ if (do_nothing && !do_hddown && !do_ifdown) exit(0);
+
+ if (do_sync) {
+ sync();
+@@ -249,13 +260,17 @@
+ if (do_hddown)
+ (void)hddown();
+
++ if (do_nothing) exit(0);
++
+ if (do_reboot) {
+ init_reboot(BMAGIC_REBOOT);
+ } else {
+ /*
+ * Turn on hard reboot, CTRL-ALT-DEL will reboot now
+ */
++#ifdef BMAGIC_HARD
+ init_reboot(BMAGIC_HARD);
++#endif
+
+ /*
+ * Stop init; it is insensitive to the signals sent
+@@ -277,7 +292,9 @@
+ /*
+ * If we return, we (c)ontinued from the kernel monitor.
+ */
++#ifdef BMAGIC_SOFT
+ init_reboot(BMAGIC_SOFT);
++#endif
+ kill(1, SIGCONT);
+
+ exit(0);
+Binary files sysvinit-2.85/src/halt.o and sysvinit-2.86/src/halt.o differ
+diff -urNd -urNd sysvinit-2.85/src/hddown.c sysvinit-2.86/src/hddown.c
+--- sysvinit-2.85/src/hddown.c 2001-11-07 09:11:21.000000000 -0600
++++ sysvinit-2.86/src/hddown.c 2004-06-09 07:47:45.000000000 -0500
+@@ -3,7 +3,7 @@
+ * shut them down.
+ *
+ */
+-char *v_hddown = "@(#)hddown.c 1.01 07-Nov-2001 miquels@cistron.nl";
++char *v_hddown = "@(#)hddown.c 1.02 22-Apr-2003 miquels@cistron.nl";
+
+ #include <stdio.h>
+ #include <stdlib.h>
+@@ -13,8 +13,9 @@
+ #include <fcntl.h>
+ #include <dirent.h>
+
+-#include <sys/ioctl.h>
++#ifdef __linux__
+
++#include <sys/ioctl.h>
+ #include <linux/hdreg.h>
+
+ #define MAX_DISKS 64
+@@ -104,6 +105,15 @@
+ return 0;
+ }
+
++#else /* __linux__ */
++
++int hddown(void)
++{
++ return 0;
++}
++
++#endif /* __linux__ */
++
+ #ifdef STANDALONE
+ int main(int argc, char **argv)
+ {
+Binary files sysvinit-2.85/src/hddown.o and sysvinit-2.86/src/hddown.o differ
+Binary files sysvinit-2.85/src/ifdown.o and sysvinit-2.86/src/ifdown.o differ
+Binary files sysvinit-2.85/src/init and sysvinit-2.86/src/init differ
+diff -urNd -urNd sysvinit-2.85/src/init.c sysvinit-2.86/src/init.c
+--- sysvinit-2.85/src/init.c 2003-04-15 06:16:41.000000000 -0500
++++ sysvinit-2.86/src/init.c 2004-07-30 07:16:20.000000000 -0500
+@@ -5,34 +5,28 @@
+ * init [0123456SsQqAaBbCc]
+ * telinit [0123456SsQqAaBbCc]
+ *
+- * Version: @(#)init.c 2.85 15-Apr-2003 miquels@cistron.nl
++ * Version: @(#)init.c 2.86 30-Jul-2004 miquels@cistron.nl
+ */
+-#define VERSION "2.85"
+-#define DATE "15-Apr-2003"
++#define VERSION "2.86"
++#define DATE "31-Jul-2004"
+ /*
+ * This file is part of the sysvinit suite,
+- * Copyright 1991-2003 Miquel van Smoorenburg.
++ * Copyright 1991-2004 Miquel van Smoorenburg.
+ *
+ * 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.
+ *
+- * Modified: 21 Feb 1998, Al Viro:
+- * 'U' flag added to telinit. It forces init to re-exec itself
+- * (passing its state through exec, certainly).
+- * May be useful for smoother (heh) upgrades.
+- * 24 Feb 1998, AV:
+- * did_boot made global and added to state - thanks, Miquel.
+- * Yet another file descriptors leak - close state pipe if
+- * re_exec fails.
+ */
+
+ #include <sys/types.h>
+ #include <sys/stat.h>
+ #include <sys/ioctl.h>
+ #include <sys/wait.h>
++#ifdef __linux__
+ #include <sys/kd.h>
++#endif
+ #include <sys/resource.h>
+ #include <stdlib.h>
+ #include <unistd.h>
+@@ -70,6 +64,13 @@
+ # define SIGPWR SIGUSR2
+ #endif
+
++#ifndef CBAUD
++# define CBAUD 0
++#endif
++#ifndef CBAUDEX
++# define CBAUDEX 0
++#endif
++
+ /* Set a signal handler. */
+ #define SETSIG(sa, sig, fun, flags) \
+ do { \
+@@ -88,13 +89,13 @@
+ CHILD *newFamily = NULL; /* The list after inittab re-read */
+
+ CHILD ch_emerg = { /* Emergency shell */
+- 0, 0, 0, 0, 0,
+- "~~",
+- "S",
+- 3,
+- "/sbin/sulogin",
+- NULL,
+- NULL
++ 0, 0, 0, 0, 0,
++ "~~",
++ "S",
++ 3,
++ "/sbin/sulogin",
++ NULL,
++ NULL
+ };
+
+ char runlevel = 'S'; /* The current run level */
+@@ -108,8 +109,9 @@
+ int wrote_utmp_reboot = 1; /* Set when we wrote the reboot record */
+ int sltime = 5; /* Sleep time between TERM and KILL */
+ char *argv0; /* First arguments; show up in ps listing */
+-int maxproclen; /* Maximal length of argv[0] without \0 */
++int maxproclen; /* Maximal length of argv[0] with \0 */
+ struct utmp utproto; /* Only used for sizeof(utproto.ut_id) */
++char *user_console = NULL; /* User console device */
+ char *console_dev; /* Console device. */
+ int pipe_fd = -1; /* /dev/initctl */
+ int did_boot = 0; /* Did we already do BOOT* stuff? */
+@@ -186,6 +188,10 @@
+ {NULL,0}
+ };
+
++#define NR_EXTRA_ENV 16
++char *extra_env[NR_EXTRA_ENV];
++
++
+ /*
+ * Sleep a number of seconds.
+ *
+@@ -203,6 +209,35 @@
+ ;
+ }
+
++
++/*
++ * Non-failing allocation routines (init cannot fail).
++ */
++void *imalloc(size_t size)
++{
++ void *m;
++
++ while ((m = malloc(size)) == NULL) {
++ initlog(L_VB, "out of memory");
++ do_sleep(5);
++ }
++ memset(m, 0, size);
++ return m;
++}
++
++
++char *istrdup(char *s)
++{
++ char *m;
++ int l;
++
++ l = strlen(s) + 1;
++ m = imalloc(l);
++ memcpy(m, s, l);
++ return m;
++}
++
++
+ /*
+ * Send the state info of the previous running init to
+ * the new one, in a version-independant way.
+@@ -344,12 +379,9 @@
+ }
+ } while (cmd != C_REC);
+
+- while ((p = (CHILD *)malloc(sizeof(CHILD))) == NULL ) {
+- log(L_VB, "out of memory");
+- do_sleep(5);
+- }
+- memset(p, 0, sizeof(CHILD));
++ p = imalloc(sizeof(CHILD));
+ get_string(p->id, sizeof(p->id), f);
++
+ do switch(cmd = get_cmd(f)) {
+ case 0:
+ case C_EOR:
+@@ -420,7 +452,7 @@
+ #ifdef __GNUC__
+ __attribute__ ((format (printf, 1, 2)))
+ #endif
+-int setproctitle(char *fmt, ...)
++static int setproctitle(char *fmt, ...)
+ {
+ va_list ap;
+ int len;
+@@ -432,8 +464,10 @@
+ len = vsnprintf(buf, sizeof(buf), fmt, ap);
+ va_end(ap);
+
+- memset(argv0, 0, maxproclen + 1);
+- strncpy(argv0, buf, maxproclen - 1);
++ if (maxproclen > 2) {
++ memset(argv0, 0, maxproclen);
++ strncpy(argv0, buf, maxproclen - 2);
++ }
+
+ return len;
+ }
+@@ -448,7 +482,9 @@
+ int tried_vtmaster = 0;
+ char *s;
+
+- if ((s = getenv("CONSOLE")) != NULL)
++ if (user_console) {
++ console_dev = user_console;
++ } else if ((s = getenv("CONSOLE")) != NULL)
+ console_dev = s;
+ else {
+ console_dev = CONSOLE;
+@@ -528,10 +564,9 @@
+ if (errno == ECHILD) break;
+ for( ch = family; ch; ch = ch->next )
+ if ( ch->pid == pid && (ch->flags & RUNNING) ) {
+-#if DEBUG
+- log(L_VB, "chld_handler: marked %d as zombie",
++ INITDBG(L_VB,
++ "chld_handler: marked %d as zombie",
+ ch->pid);
+-#endif
+ ADDSET(got_signals, SIGCHLD);
+ ch->exstat = st;
+ ch->flags |= ZOMBIE;
+@@ -541,11 +576,9 @@
+ }
+ break;
+ }
+-#if DEBUG
+ if (ch == NULL)
+- log(L_VB, "chld_handler: unknown child %d exited.",
++ INITDBG(L_VB, "chld_handler: unknown child %d exited.",
+ pid);
+-#endif
+ }
+ errno = saved_errno;
+ }
+@@ -563,28 +596,34 @@
+ }
+
+ /*
+- * Dump core. Returns 0 if we are the child, so that the caller
+- * can return if it is a signal handler - SIGSEGV is blocked in
+- * the handler, so it will be raised when the handler returns.
++ * Fork and dump core in /.
+ */
+-int coredump(void)
++void coredump(void)
+ {
+- static int dumped = 0;
+- struct rlimit rlim;
++ static int dumped = 0;
++ struct rlimit rlim;
++ sigset_t mask;
+
+- if (dumped) return 1;
++ if (dumped) return;
+ dumped = 1;
+
+- if (fork() != 0) return 1;
++ if (fork() != 0) return;
++
++ sigfillset(&mask);
++ sigprocmask(SIG_SETMASK, &mask, NULL);
+
+ rlim.rlim_cur = RLIM_INFINITY;
+ rlim.rlim_max = RLIM_INFINITY;
+ setrlimit(RLIMIT_CORE, &rlim);
+-
+ chdir("/");
++
+ signal(SIGSEGV, SIG_DFL);
+ raise(SIGSEGV);
+- return 0;
++ sigdelset(&mask, SIGSEGV);
++ sigprocmask(SIG_SETMASK, &mask, NULL);
++
++ do_sleep(5);
++ exit(0);
+ }
+
+ /*
+@@ -592,7 +631,7 @@
+ * If we have the info, print where it occured.
+ * Then sleep 30 seconds and try to continue.
+ */
+-#ifdef STACK_DEBUG
++#if defined(STACK_DEBUG) && defined(__linux__)
+ void segv_handler(int sig, struct sigcontext ctx)
+ {
+ char *p = "";
+@@ -601,10 +640,10 @@
+ if ((void *)ctx.eip >= (void *)do_sleep &&
+ (void *)ctx.eip < (void *)main)
+ p = " (code)";
+- log(L_VB, "PANIC: segmentation violation at %p%s! "
++ initlog(L_VB, "PANIC: segmentation violation at %p%s! "
+ "sleeping for 30 seconds.", (void *)ctx.eip, p);
+- if (coredump() != 0)
+- do_sleep(30);
++ coredump();
++ do_sleep(30);
+ errno = saved_errno;
+ }
+ #else
+@@ -612,9 +651,10 @@
+ {
+ int saved_errno = errno;
+
+- log(L_VB, "PANIC: segmentation violation! sleeping for 30 seconds.");
+- if (coredump() != 0)
+- do_sleep(30);
++ initlog(L_VB,
++ "PANIC: segmentation violation! sleeping for 30 seconds.");
++ coredump();
++ do_sleep(30);
+ errno = saved_errno;
+ }
+ #endif
+@@ -641,7 +681,7 @@
+ int fd;
+
+ if ((fd = console_open(O_RDWR|O_NOCTTY)) < 0) {
+- log(L_VB, "can't open %s", console_dev);
++ initlog(L_VB, "can't open %s", console_dev);
+ return;
+ }
+
+@@ -697,10 +737,11 @@
+ #ifdef __GNUC__
+ __attribute__ ((format (printf, 2, 3)))
+ #endif
+-void log(int loglevel, char *s, ...)
++void initlog(int loglevel, char *s, ...)
+ {
+ va_list va_alist;
+ char buf[256];
++ sigset_t nmask, omask;
+
+ va_start(va_alist, s);
+ vsnprintf(buf, sizeof(buf), s, va_alist);
+@@ -708,11 +749,15 @@
+
+ if (loglevel & L_SY) {
+ /*
+- * Re-etablish connection with syslogd every time.
++ * Re-establish connection with syslogd every time.
++ * Block signals while talking to syslog.
+ */
++ sigfillset(&nmask);
++ sigprocmask(SIG_BLOCK, &nmask, &omask);
+ openlog("init", 0, LOG_DAEMON);
+ syslog(LOG_INFO, "%s", buf);
+ closelog();
++ sigprocmask(SIG_SETMASK, &omask, NULL);
+ }
+
+ /*
+@@ -727,14 +772,51 @@
+
+
+ /*
+- * See if one character of s2 is in s1
++ * Build a new environment for execve().
+ */
+-int any(char *s1, char *s2)
++char **init_buildenv(int child)
+ {
+- while(*s2)
+- if (strchr(s1, *s2++) != NULL)
+- return(1);
+- return(0);
++ char i_lvl[] = "RUNLEVEL=x";
++ char i_prev[] = "PREVLEVEL=x";
++ char i_cons[32];
++ char **e;
++ int n, i;
++
++ for (n = 0; environ[n]; n++)
++ ;
++ n += NR_EXTRA_ENV + 8;
++ e = calloc(n, sizeof(char *));
++
++ for (n = 0; environ[n]; n++)
++ e[n] = istrdup(environ[n]);
++
++ for (i = 0; i < NR_EXTRA_ENV; i++)
++ if (extra_env[i])
++ e[n++] = istrdup(extra_env[i]);
++
++ if (child) {
++ snprintf(i_cons, sizeof(i_cons), "CONSOLE=%s", console_dev);
++ i_lvl[9] = thislevel;
++ i_prev[10] = prevlevel;
++ e[n++] = istrdup(i_lvl);
++ e[n++] = istrdup(i_prev);
++ e[n++] = istrdup(i_cons);
++ e[n++] = istrdup(E_VERSION);
++ }
++
++ e[n++] = NULL;
++
++ return e;
++}
++
++
++void init_freeenv(char **e)
++{
++ int n;
++
++ for (n = 0; e[n]; n++)
++ free(e[n]);
++ free(e);
+ }
+
+
+@@ -753,9 +835,6 @@
+ time_t t; /* System time */
+ int oldAlarm; /* Previous alarm value */
+ char *proc = ch->process; /* Command line */
+- char i_lvl[] = "RUNLEVEL=x"; /* Runlevel in environment. */
+- char i_prev[] = "PREVLEVEL=x";/* Previous runlevel. */
+- char i_cons[32]; /* console device. */
+ pid_t pid, pgrp; /* child, console process group. */
+ sigset_t nmask, omask; /* For blocking SIGCHLD */
+ struct sigaction sa;
+@@ -781,8 +860,9 @@
+ /* Do we try to respawn too fast? */
+ if (ch->count >= MAXSPAWN) {
+
+- log(L_VB, "Id \"%s\" respawning too fast: disabled for %d minutes",
+- ch->id, SLEEPTIME / 60);
++ initlog(L_VB,
++ "Id \"%s\" respawning too fast: disabled for %d minutes",
++ ch->id, SLEEPTIME / 60);
+ ch->flags &= ~RUNNING;
+ ch->flags |= FAILING;
+
+@@ -813,7 +893,7 @@
+ }
+ args[6] = proc;
+ args[7] = NULL;
+- } else if (any(proc, "~`!$^&*()=|\\{}[];\"'<>?")) {
++ } else if (strpbrk(proc, "~`!$^&*()=|\\{}[];\"'<>?")) {
+ /* See if we need to fire off a shell for this command */
+ /* Give command line to shell */
+ args[1] = SHELL;
+@@ -868,15 +948,6 @@
+
+ sigprocmask(SIG_SETMASK, &omask, NULL);
+
+- /* Now set RUNLEVEL and PREVLEVEL */
+- snprintf(i_cons, sizeof(i_cons), "CONSOLE=%s", console_dev);
+- i_lvl[9] = thislevel;
+- i_prev[10] = prevlevel;
+- putenv(i_lvl);
+- putenv(i_prev);
+- putenv(i_cons);
+- putenv(E_VERSION);
+-
+ /*
+ * In sysinit, boot, bootwait or single user mode:
+ * for any wait-type subprocess we _force_ the console
+@@ -896,7 +967,7 @@
+ dup(f);
+ }
+ if ((pid = fork()) < 0) {
+- log(L_VB, "cannot fork");
++ initlog(L_VB, "cannot fork");
+ exit(1);
+ }
+ if (pid > 0) {
+@@ -926,7 +997,7 @@
+ * this with a temporary process.
+ */
+ if ((pid = fork()) < 0) {
+- log(L_VB, "cannot fork");
++ initlog(L_VB, "cannot fork");
+ exit(1);
+ }
+ if (pid == 0) {
+@@ -946,7 +1017,7 @@
+ } else {
+ setsid();
+ if ((f = console_open(O_RDWR|O_NOCTTY)) < 0) {
+- log(L_VB, "open(%s): %s", console_dev,
++ initlog(L_VB, "open(%s): %s", console_dev,
+ strerror(errno));
+ f = open("/dev/null", O_RDWR);
+ }
+@@ -954,15 +1025,15 @@
+ dup(f);
+ }
+
+- /* Reset all the signals */
++ /* Reset all the signals, set up environment */
+ for(f = 1; f < NSIG; f++) SETSIG(sa, f, SIG_DFL, SA_RESTART);
+- execvp(args[1], args + 1);
++ environ = init_buildenv(1);
+
+ /*
+- * Is this a bug in execvp? It does _not_ execute shell
+- * scripts (/etc/rc !), so we try again with
+- * 'sh -c exec ...'
++ * Execute prog. In case of ENOEXEC try again
++ * as a shell script.
+ */
++ execvp(args[1], args + 1);
+ if (errno == ENOEXEC) {
+ args[1] = SHELL;
+ args[2] = "-c";
+@@ -972,18 +1043,16 @@
+ args[4] = NULL;
+ execvp(args[1], args + 1);
+ }
+- log(L_VB, "cannot execute \"%s\"", args[1]);
++ initlog(L_VB, "cannot execute \"%s\"", args[1]);
+ exit(1);
+ }
+ *res = pid;
+ sigprocmask(SIG_SETMASK, &omask, NULL);
+
+-#if DEBUG
+- log(L_VB, "Started id %s (pid %d)", ch->id, pid);
+-#endif
++ INITDBG(L_VB, "Started id %s (pid %d)", ch->id, pid);
+
+ if (pid == -1) {
+- log(L_VB, "cannot fork, retry..");
++ initlog(L_VB, "cannot fork, retry..");
+ do_sleep(5);
+ continue;
+ }
+@@ -1032,66 +1101,45 @@
+ }
+ }
+
+-/*
+- * My version of strtok(3).
+- */
+-char *get_part(char *str, int tok)
+-{
+- static char *s;
+- char *p, *q;
+-
+- if (str != NULL)
+- s = str;
+- if (s == NULL || *s == 0)
+- return(NULL);
+- q = p = s;
+- while(*p != tok && *p)
+- p++;
+- if (*p == tok)
+- *p++ = 0;
+- s = p;
+-
+- return q;
+-}
+
+ /*
+ * Read the inittab file.
+ */
+ void read_inittab(void)
+ {
+- FILE *fp; /* The INITTAB file */
+- char buf[256]; /* Line buffer */
+- char err[64]; /* Error message. */
+- char *id, *rlevel,
+- *action, *process; /* Fields of a line */
+- char *p;
+- CHILD *ch, *old, *i; /* Pointers to CHILD structure */
+- CHILD *head = NULL; /* Head of linked list */
+- int lineNo = 0; /* Line number in INITTAB file */
+- int actionNo; /* Decoded action field */
+- int f; /* Counter */
+- int round; /* round 0 for SIGTERM, round 1 for SIGKILL */
+- int foundOne = 0; /* No killing no sleep */
+- int talk; /* Talk to the user */
+- int done = 0; /* Ready yet? */
+- sigset_t nmask, omask; /* For blocking SIGCHLD. */
++ FILE *fp; /* The INITTAB file */
++ CHILD *ch, *old, *i; /* Pointers to CHILD structure */
++ CHILD *head = NULL; /* Head of linked list */
+ #ifdef INITLVL
+- struct stat st; /* To stat INITLVL */
++ struct stat st; /* To stat INITLVL */
+ #endif
++ sigset_t nmask, omask; /* For blocking SIGCHLD. */
++ char buf[256]; /* Line buffer */
++ char err[64]; /* Error message. */
++ char *id, *rlevel,
++ *action, *process; /* Fields of a line */
++ char *p;
++ int lineNo = 0; /* Line number in INITTAB file */
++ int actionNo; /* Decoded action field */
++ int f; /* Counter */
++ int round; /* round 0 for SIGTERM, 1 for SIGKILL */
++ int foundOne = 0; /* No killing no sleep */
++ int talk; /* Talk to the user */
++ int done = 0; /* Ready yet? */
+
+ #if DEBUG
+ if (newFamily != NULL) {
+- log(L_VB, "PANIC newFamily != NULL");
++ INITDBG(L_VB, "PANIC newFamily != NULL");
+ exit(1);
+ }
+- log(L_VB, "Reading inittab");
++ INITDBG(L_VB, "Reading inittab");
+ #endif
+
+ /*
+ * Open INITTAB and real line by line.
+ */
+ if ((fp = fopen(INITTAB, "r")) == NULL)
+- log(L_VB, "No inittab file found");
++ initlog(L_VB, "No inittab file found");
+
+ while(!done) {
+ /*
+@@ -1103,9 +1151,9 @@
+ * See if we have a single user entry.
+ */
+ for(old = newFamily; old; old = old->next)
+- if (strcmp(old->rlevel, "S") == 0) break;
++ if (strpbrk(old->rlevel, "S")) break;
+ if (old == NULL)
+- snprintf(buf, sizeof(buf), "~~:S:wait:%s\n", SHELL);
++ snprintf(buf, sizeof(buf), "~~:S:wait:%s\n", SULOGIN);
+ else
+ continue;
+ }
+@@ -1120,10 +1168,10 @@
+ /*
+ * Decode the fields
+ */
+- id = get_part(p, ':');
+- rlevel = get_part(NULL, ':');
+- action = get_part(NULL, ':');
+- process = get_part(NULL, '\n');
++ id = strsep(&p, ":");
++ rlevel = strsep(&p, ":");
++ action = strsep(&p, ":");
++ process = strsep(&p, "\n");
+
+ /*
+ * Check if syntax is OK. Be very verbose here, to
+@@ -1145,10 +1193,8 @@
+ if (action && strlen(action) > 32)
+ strcpy(err, "action field too long");
+ if (err[0] != 0) {
+- log(L_VB, "%s[%d]: %s", INITTAB, lineNo, err);
+-#if DEBUG
+- log(L_VB, "%s:%s:%s:%s", id, rlevel, action, process);
+-#endif
++ initlog(L_VB, "%s[%d]: %s", INITTAB, lineNo, err);
++ INITDBG(L_VB, "%s:%s:%s:%s", id, rlevel, action, process);
+ continue;
+ }
+
+@@ -1162,7 +1208,7 @@
+ break;
+ }
+ if (actionNo == -1) {
+- log(L_VB, "%s[%d]: %s: unknown action field",
++ initlog(L_VB, "%s[%d]: %s: unknown action field",
+ INITTAB, lineNo, action);
+ continue;
+ }
+@@ -1172,7 +1218,7 @@
+ */
+ for(old = newFamily; old; old = old->next) {
+ if(strcmp(old->id, id) == 0 && strcmp(id, "~~")) {
+- log(L_VB, "%s[%d]: duplicate ID field \"%s\"",
++ initlog(L_VB, "%s[%d]: duplicate ID field \"%s\"",
+ INITTAB, lineNo, id);
+ break;
+ }
+@@ -1182,11 +1228,7 @@
+ /*
+ * Allocate a CHILD structure
+ */
+- while ((ch = malloc(sizeof(CHILD))) == NULL) {
+- log(L_VB, "out of memory");
+- do_sleep(5);
+- }
+- memset(ch, 0, sizeof(CHILD));
++ ch = imalloc(sizeof(CHILD));
+
+ /*
+ * And fill it in.
+@@ -1275,9 +1317,7 @@
+ * be killed.
+ */
+
+-#if DEBUG
+- log(L_VB, "Checking for children to kill");
+-#endif
++ INITDBG(L_VB, "Checking for children to kill");
+ for(round = 0; round < 2; round++) {
+ talk = 1;
+ for(ch = family; ch; ch = ch->next) {
+@@ -1328,19 +1368,19 @@
+ ch->flags &= ~KILLME;
+ continue;
+ }
+-#if DEBUG
+- log(L_VB, "Killing \"%s\"", ch->process);
+-#endif
++ INITDBG(L_VB, "Killing \"%s\"", ch->process);
+ switch(round) {
+ case 0: /* Send TERM signal */
+ if (talk)
+- log(L_CO, "Sending processes the TERM signal");
++ initlog(L_CO,
++ "Sending processes the TERM signal");
+ kill(-(ch->pid), SIGTERM);
+ foundOne = 1;
+ break;
+ case 1: /* Send KILL signal and collect status */
+ if (talk)
+- log(L_CO, "Sending processes the KILL signal");
++ initlog(L_CO,
++ "Sending processes the KILL signal");
+ kill(-(ch->pid), SIGKILL);
+ break;
+ }
+@@ -1380,12 +1420,11 @@
+ for(ch = family; ch; ch = ch->next)
+ if (ch->flags & KILLME) {
+ if (!(ch->flags & ZOMBIE))
+- log(L_CO, "Pid %d [id %s] seems to hang", ch->pid,
++ initlog(L_CO, "Pid %d [id %s] seems to hang", ch->pid,
+ ch->id);
+ else {
+-#if DEBUG
+- log(L_VB, "Updating utmp for pid %d [id %s]", ch->pid, ch->id);
+-#endif
++ INITDBG(L_VB, "Updating utmp for pid %d [id %s]",
++ ch->pid, ch->id);
+ ch->flags &= ~RUNNING;
+ if (ch->process[0] != '+')
+ write_utmp_wtmp("", ch->id, ch->pid, DEAD_PROCESS, NULL);
+@@ -1451,15 +1490,13 @@
+ CHILD *ch; /* Pointer to child */
+ int delete; /* Delete this entry from list? */
+
+-#if DEBUG
+- log(L_VB, "Checking for children to start");
+-#endif
++ INITDBG(L_VB, "Checking for children to start");
+
+ for(ch = family; ch; ch = ch->next) {
+
+ #if DEBUG
+ if (ch->rlevel[0] == 'C') {
+- log(L_VB, "%s: flags %d", ch->process, ch->flags);
++ INITDBG(L_VB, "%s: flags %d", ch->process, ch->flags);
+ }
+ #endif
+
+@@ -1545,7 +1582,8 @@
+ if (lvl > 0) {
+ if (islower(lvl)) lvl = toupper(lvl);
+ if (strchr("0123456789S", lvl) == NULL) {
+- log(L_VB, "Initdefault level '%c' is invalid", lvl);
++ initlog(L_VB,
++ "Initdefault level '%c' is invalid", lvl);
+ lvl = 0;
+ }
+ }
+@@ -1570,98 +1608,99 @@
+ */
+ int read_level(int arg)
+ {
+- unsigned char foo = 'X'; /* Contents of INITLVL */
+- CHILD *ch; /* Walk through list */
+- int ok = 1;
++ CHILD *ch; /* Walk through list */
++ unsigned char foo = 'X'; /* Contents of INITLVL */
++ int ok = 1;
+ #ifdef INITLVL
+- FILE *fp;
+- int st;
+- struct stat stt;
++ FILE *fp;
++ struct stat stt;
++ int st;
+ #endif
+
+- if (arg) foo = arg;
++ if (arg) foo = arg;
+
+ #ifdef INITLVL
+- ok = 0;
++ ok = 0;
+
+- if (arg == 0) {
+- fp = NULL;
+- if (stat(INITLVL, &stt) != 0 || stt.st_size != 0L)
+- fp = fopen(INITLVL, "r");
++ if (arg == 0) {
++ fp = NULL;
++ if (stat(INITLVL, &stt) != 0 || stt.st_size != 0L)
++ fp = fopen(INITLVL, "r");
+ #ifdef INITLVL2
+- if (fp == NULL && (stat(INITLVL2, &stt) != 0 || stt.st_size != 0L))
+- fp = fopen(INITLVL2, "r");
++ if (fp == NULL &&
++ (stat(INITLVL2, &stt) != 0 || stt.st_size != 0L))
++ fp = fopen(INITLVL2, "r");
+ #endif
+- if (fp == NULL) {
+- /* INITLVL file is empty or not there - act as 'init q' */
+- log(L_SY, "Re-reading inittab");
+- return(runlevel);
++ if (fp == NULL) {
++ /* INITLVL file empty or not there - act as 'init q' */
++ initlog(L_SY, "Re-reading inittab");
++ return(runlevel);
++ }
++ ok = fscanf(fp, "%c %d", &foo, &st);
++ fclose(fp);
++ } else {
++ /* We go to the new runlevel passed as an argument. */
++ foo = arg;
++ ok = 1;
+ }
+- ok = fscanf(fp, "%c %d", &foo, &st);
+- fclose(fp);
+- } else {
+- /* We go to the new runlevel passed as an argument. */
+- foo = arg;
+- ok = 1;
+- }
+- if (ok == 2) sltime = st;
++ if (ok == 2) sltime = st;
+
+ #endif /* INITLVL */
+
+- if (islower(foo)) foo = toupper(foo);
+- if (ok < 1 || ok > 2 || strchr("QS0123456789ABCU", foo) == NULL) {
+- log(L_VB, "bad runlevel: %c", foo);
+- return(runlevel);
+- }
++ if (islower(foo)) foo = toupper(foo);
++ if (ok < 1 || ok > 2 || strchr("QS0123456789ABCU", foo) == NULL) {
++ initlog(L_VB, "bad runlevel: %c", foo);
++ return runlevel;
++ }
+
+- /* Log this action */
+- switch(foo) {
+- case 'S':
+- log(L_VB, "Going single user");
+- break;
+- case 'Q':
+- log(L_SY, "Re-reading inittab");
+- break;
+- case 'A':
+- case 'B':
+- case 'C':
+- log(L_SY, "Activating demand-procedures for '%c'", foo);
+- break;
+- case 'U':
+- log(L_SY, "Trying to re-exec init");
+- return 'U';
+- default:
+- log(L_VB, "Switching to runlevel: %c", foo);
+- }
++ /* Log this action */
++ switch(foo) {
++ case 'S':
++ initlog(L_VB, "Going single user");
++ break;
++ case 'Q':
++ initlog(L_SY, "Re-reading inittab");
++ break;
++ case 'A':
++ case 'B':
++ case 'C':
++ initlog(L_SY,
++ "Activating demand-procedures for '%c'", foo);
++ break;
++ case 'U':
++ initlog(L_SY, "Trying to re-exec init");
++ return 'U';
++ default:
++ initlog(L_VB, "Switching to runlevel: %c", foo);
++ }
+
+- if (foo == 'Q') return(runlevel);
++ if (foo == 'Q') return runlevel;
+
+- /* Check if this is a runlevel a, b or c */
+- if (strchr("ABC", foo)) {
+- if (runlevel == 'S') return(runlevel);
++ /* Check if this is a runlevel a, b or c */
++ if (strchr("ABC", foo)) {
++ if (runlevel == 'S') return(runlevel);
+
+- /* Read inittab again first! */
+- read_inittab();
++ /* Read inittab again first! */
++ read_inittab();
+
+- /* Mark those special tasks */
+- for(ch = family; ch; ch = ch->next)
+- if (strchr(ch->rlevel, foo) != NULL ||
+- strchr(ch->rlevel, tolower(foo)) != NULL) {
+- ch->flags |= DEMAND;
+- ch->flags &= ~XECUTED;
+-#if DEBUG
+- log(L_VB, "Marking (%s) as ondemand, flags %d",
+- ch->id, ch->flags);
+-#endif
+- }
+- return(runlevel);
+- }
++ /* Mark those special tasks */
++ for(ch = family; ch; ch = ch->next)
++ if (strchr(ch->rlevel, foo) != NULL ||
++ strchr(ch->rlevel, tolower(foo)) != NULL) {
++ ch->flags |= DEMAND;
++ ch->flags &= ~XECUTED;
++ INITDBG(L_VB,
++ "Marking (%s) as ondemand, flags %d",
++ ch->id, ch->flags);
++ }
++ return runlevel;
++ }
+
+- /* Store both the old and the new runlevel. */
+- write_utmp_wtmp("runlevel", "~~", foo + 256*runlevel, RUN_LVL, "~");
+- thislevel = foo;
+- prevlevel = runlevel;
+- return(foo);
++ /* Store both the old and the new runlevel. */
++ write_utmp_wtmp("runlevel", "~~", foo + 256*runlevel, RUN_LVL, "~");
++ thislevel = foo;
++ prevlevel = runlevel;
++ return foo;
+ }
+
+
+@@ -1674,32 +1713,33 @@
+ */
+ void fail_check(void)
+ {
+- time_t t; /* System time */
+- CHILD *ch; /* Pointer to child structure */
+- time_t next_alarm = 0; /* When to set next alarm */
++ CHILD *ch; /* Pointer to child structure */
++ time_t t; /* System time */
++ time_t next_alarm = 0; /* When to set next alarm */
+
+- time(&t);
++ time(&t);
+
+- for(ch = family; ch; ch = ch->next) {
++ for(ch = family; ch; ch = ch->next) {
+
+- if (ch->flags & FAILING) {
+- /* Can we free this sucker? */
+- if (ch->tm + SLEEPTIME < t) {
+- ch->flags &= ~FAILING;
+- ch->count = 0;
+- ch->tm = 0;
+- } else {
+- /* No, we'll look again later */
+- if (next_alarm == 0 || ch->tm + SLEEPTIME > next_alarm)
+- next_alarm = ch->tm + SLEEPTIME;
++ if (ch->flags & FAILING) {
++ /* Can we free this sucker? */
++ if (ch->tm + SLEEPTIME < t) {
++ ch->flags &= ~FAILING;
++ ch->count = 0;
++ ch->tm = 0;
++ } else {
++ /* No, we'll look again later */
++ if (next_alarm == 0 ||
++ ch->tm + SLEEPTIME > next_alarm)
++ next_alarm = ch->tm + SLEEPTIME;
++ }
+ }
+ }
+- }
+- if (next_alarm) {
+- next_alarm -= t;
+- if (next_alarm < 1) next_alarm = 1;
+- alarm(next_alarm);
+- }
++ if (next_alarm) {
++ next_alarm -= t;
++ if (next_alarm < 1) next_alarm = 1;
++ alarm(next_alarm);
++ }
+ }
+
+ /* Set all 'Fail' timers to 0 */
+@@ -1752,9 +1792,9 @@
+ */
+ int check_pipe(int fd)
+ {
+- struct timeval t;
+- fd_set s;
+- char signature[8];
++ struct timeval t;
++ fd_set s;
++ char signature[8];
+
+ FD_ZERO(&s);
+ FD_SET(fd, &s);
+@@ -1789,10 +1829,11 @@
+ */
+ void re_exec(void)
+ {
+- sigset_t mask, oldset;
+- pid_t pid;
+- int fd;
+- CHILD *ch;
++ CHILD *ch;
++ sigset_t mask, oldset;
++ pid_t pid;
++ char **env;
++ int fd;
+
+ if (strchr("S12345",runlevel) == NULL)
+ return;
+@@ -1825,27 +1866,26 @@
+ */
+ for(ch = family; ch; ch = ch->next)
+ if (ch->flags & ZOMBIE) {
+-#if DEBUG
+- log(L_VB, "Child died, PID= %d", ch->pid);
+-#endif
++ INITDBG(L_VB, "Child died, PID= %d", ch->pid);
+ ch->flags &= ~(RUNNING|ZOMBIE|WAITING);
+ if (ch->process[0] != '+')
+ write_utmp_wtmp("", ch->id, ch->pid, DEAD_PROCESS, NULL);
+ }
+
+- if ((pid = fork()) > 0) {
+- /*
+- * Yup. _Parent_ exec's ...
+- */
+- execl(myname, myname, "--init", NULL);
+- } else if (pid == 0) {
++ if ((pid = fork()) == 0) {
+ /*
+- * ... while child sends her the
+- * state information and dies
++ * Child sends state information to the parent.
+ */
+ send_state(fd);
+ exit(0);
+ }
++
++ /*
++ * The existing init process execs a new init binary.
++ */
++ env = init_buildenv(0);
++ execl(myname, myname, "--init", NULL, env);
++
+ /*
+ * We shouldn't be here, something failed.
+ * Bitch, close the state pipe, unblock signals and return.
+@@ -1853,7 +1893,8 @@
+ close(fd);
+ close(STATE_PIPE);
+ sigprocmask(SIG_SETMASK, &oldset, NULL);
+- log(L_CO, "Attempt to re-exec failed");
++ init_freeenv(env);
++ initlog(L_CO, "Attempt to re-exec failed");
+ }
+
+
+@@ -1863,10 +1904,10 @@
+ */
+ void fifo_new_level(int level)
+ {
+- int oldlevel;
+ #if CHANGE_WAIT
+- CHILD *ch;
++ CHILD *ch;
+ #endif
++ int oldlevel;
+
+ if (level == runlevel) return;
+
+@@ -1894,6 +1935,59 @@
+ }
+ }
+
++
++/*
++ * Set/unset environment variables. The variables are
++ * encoded as KEY=VAL\0KEY=VAL\0\0. With "=VAL" it means
++ * setenv, without it means unsetenv.
++ */
++void initcmd_setenv(char *data, int size)
++{
++ char *env, *p, *e, *eq;
++ int i, sz;
++
++ e = data + size;
++
++ while (*data && data < e) {
++ eq = NULL;
++ for (p = data; *p && p < e; p++)
++ if (*p == '=') eq = p;
++ if (*p) break;
++ env = data;
++ data = ++p;
++
++ sz = eq ? (eq - env) : (p - env);
++
++ /*initlog(L_SY, "init_setenv: %s, %s, %d", env, eq, sz);*/
++
++ /*
++ * We only allow INIT_* to be set.
++ */
++ if (strncmp(env, "INIT_", 5) != 0)
++ continue;
++
++ /* Free existing vars. */
++ for (i = 0; i < NR_EXTRA_ENV; i++) {
++ if (extra_env[i] == NULL) continue;
++ if (!strncmp(extra_env[i], env, sz) &&
++ extra_env[i][sz] == '=') {
++ free(extra_env[i]);
++ extra_env[i] = NULL;
++ }
++ }
++
++ /* Set new vars if needed. */
++ if (eq == NULL) continue;
++ for (i = 0; i < NR_EXTRA_ENV; i++) {
++ if (extra_env[i] == NULL) {
++ extra_env[i] = istrdup(env);
++ break;
++ }
++ }
++ }
++}
++
++
+ /*
+ * Read from the init FIFO. Processes like telnetd and rlogind can
+ * ask us to create login processes on their behalf.
+@@ -1906,12 +2000,12 @@
+ */
+ void check_init_fifo(void)
+ {
+- struct init_request request;
+- int n;
+- fd_set fds;
+- int quit = 0;
+- struct stat st, st2;
+- struct timeval tv;
++ struct init_request request;
++ struct timeval tv;
++ struct stat st, st2;
++ fd_set fds;
++ int n;
++ int quit = 0;
+
+ /*
+ * First, try to create /dev/initctl if not present.
+@@ -1940,7 +2034,7 @@
+ if ((pipe_fd = open(INIT_FIFO, O_RDWR|O_NONBLOCK)) >= 0) {
+ fstat(pipe_fd, &st);
+ if (!S_ISFIFO(st.st_mode)) {
+- log(L_VB, "%s is not a fifo", INIT_FIFO);
++ initlog(L_VB, "%s is not a fifo", INIT_FIFO);
+ close(pipe_fd);
+ pipe_fd = -1;
+ }
+@@ -1987,7 +2081,7 @@
+ }
+ if (n <= 0) {
+ if (errno == EINTR) return;
+- log(L_VB, "error reading initrequest");
++ initlog(L_VB, "error reading initrequest");
+ continue;
+ }
+
+@@ -2001,7 +2095,7 @@
+ * Process request.
+ */
+ if (request.magic != INIT_MAGIC || n != sizeof(request)) {
+- log(L_VB, "got bogus initrequest");
++ initlog(L_VB, "got bogus initrequest");
+ continue;
+ }
+ switch(request.cmd) {
+@@ -2025,8 +2119,23 @@
+ do_power_fail('O');
+ quit = 1;
+ break;
++ case INIT_CMD_SETENV:
++ initcmd_setenv(request.i.data, sizeof(request.i.data));
++ break;
++ case INIT_CMD_CHANGECONS:
++ if (user_console) {
++ free(user_console);
++ user_console = NULL;
++ }
++ if (!request.i.bsd.reserved[0])
++ user_console = NULL;
++ else
++ user_console = strdup(request.i.bsd.reserved);
++ console_init();
++ quit = 1;
++ break;
+ default:
+- log(L_VB, "got unimplemented initrequest.");
++ initlog(L_VB, "got unimplemented initrequest.");
+ break;
+ }
+ }
+@@ -2045,11 +2154,11 @@
+ */
+ void boot_transitions()
+ {
+- CHILD *ch;
+- static int newlevel = 0;
+- int loglevel;
+- int oldlevel;
+- static int warn = 1;
++ CHILD *ch;
++ static int newlevel = 0;
++ static int warn = 1;
++ int loglevel;
++ int oldlevel;
+
+ /* Check if there is something to wait for! */
+ for( ch = family; ch; ch = ch->next )
+@@ -2061,9 +2170,7 @@
+ oldlevel = 'N';
+ switch(runlevel) {
+ case '#': /* SYSINIT -> BOOT */
+-#if DEBUG
+- log(L_VB, "SYSINIT -> BOOT");
+-#endif
++ INITDBG(L_VB, "SYSINIT -> BOOT");
+
+ /* Write a boot record. */
+ wrote_utmp_reboot = 0;
+@@ -2080,9 +2187,7 @@
+ runlevel = '*';
+ break;
+ case '*': /* BOOT -> NORMAL */
+-#if DEBUG
+- log(L_VB, "BOOT -> NORMAL");
+-#endif
++ INITDBG(L_VB, "BOOT -> NORMAL");
+ if (runlevel != newlevel)
+ loglevel = newlevel;
+ runlevel = newlevel;
+@@ -2091,9 +2196,7 @@
+ break;
+ case 'S': /* Ended SU mode */
+ case 's':
+-#if DEBUG
+- log(L_VB, "END SU MODE");
+-#endif
++ INITDBG(L_VB, "END SU MODE");
+ newlevel = get_init_default();
+ if (!did_boot && newlevel != 'S')
+ runlevel = '*';
+@@ -2110,7 +2213,8 @@
+ break;
+ default:
+ if (warn)
+- log(L_VB, "no more processes left in this runlevel");
++ initlog(L_VB,
++ "no more processes left in this runlevel");
+ warn = 0;
+ loglevel = -1;
+ if (got_signals == 0)
+@@ -2118,7 +2222,7 @@
+ break;
+ }
+ if (loglevel > 0) {
+- log(L_VB, "Entering runlevel: %c", runlevel);
++ initlog(L_VB, "Entering runlevel: %c", runlevel);
+ write_utmp_wtmp("runlevel", "~~", runlevel + 256 * oldlevel, RUN_LVL, "~");
+ thislevel = runlevel;
+ prevlevel = oldlevel;
+@@ -2133,16 +2237,14 @@
+ */
+ void process_signals()
+ {
+- int pwrstat;
+- int oldlevel;
+- int fd;
+- CHILD *ch;
+- char c;
++ CHILD *ch;
++ int pwrstat;
++ int oldlevel;
++ int fd;
++ char c;
+
+ if (ISMEMBER(got_signals, SIGPWR)) {
+-#if DEBUG
+- log(L_VB, "got SIGPWR");
+-#endif
++ INITDBG(L_VB, "got SIGPWR");
+ /* See _what_ kind of SIGPWR this is. */
+ pwrstat = 0;
+ if ((fd = open(PWRSTAT, O_RDONLY)) >= 0) {
+@@ -2157,9 +2259,7 @@
+ }
+
+ if (ISMEMBER(got_signals, SIGINT)) {
+-#if DEBUG
+- log(L_VB, "got SIGINT");
+-#endif
++ INITDBG(L_VB, "got SIGINT");
+ /* Tell ctrlaltdel entry to start up */
+ for(ch = family; ch; ch = ch->next)
+ if (ch->action == CTRLALTDEL)
+@@ -2168,9 +2268,7 @@
+ }
+
+ if (ISMEMBER(got_signals, SIGWINCH)) {
+-#if DEBUG
+- log(L_VB, "got SIGWINCH");
+-#endif
++ INITDBG(L_VB, "got SIGWINCH");
+ /* Tell kbrequest entry to start up */
+ for(ch = family; ch; ch = ch->next)
+ if (ch->action == KBREQUEST)
+@@ -2179,26 +2277,20 @@
+ }
+
+ if (ISMEMBER(got_signals, SIGALRM)) {
+-#if DEBUG
+- log(L_VB, "got SIGALRM");
+-#endif
++ INITDBG(L_VB, "got SIGALRM");
+ /* The timer went off: check it out */
+ DELSET(got_signals, SIGALRM);
+ }
+
+ if (ISMEMBER(got_signals, SIGCHLD)) {
+-#if DEBUG
+- log(L_VB, "got SIGCHLD");
+-#endif
++ INITDBG(L_VB, "got SIGCHLD");
+ /* First set flag to 0 */
+ DELSET(got_signals, SIGCHLD);
+
+ /* See which child this was */
+ for(ch = family; ch; ch = ch->next)
+ if (ch->flags & ZOMBIE) {
+-#if DEBUG
+- log(L_VB, "Child died, PID= %d", ch->pid);
+-#endif
++ INITDBG(L_VB, "Child died, PID= %d", ch->pid);
+ ch->flags &= ~(RUNNING|ZOMBIE|WAITING);
+ if (ch->process[0] != '+')
+ write_utmp_wtmp("", ch->id, ch->pid, DEAD_PROCESS, NULL);
+@@ -2207,9 +2299,7 @@
+ }
+
+ if (ISMEMBER(got_signals, SIGHUP)) {
+-#if DEBUG
+- log(L_VB, "got SIGHUP");
+-#endif
++ INITDBG(L_VB, "got SIGHUP");
+ #if CHANGE_WAIT
+ /* Are we waiting for a child? */
+ for(ch = family; ch; ch = ch->next)
+@@ -2240,9 +2330,7 @@
+ /*
+ * SIGUSR1 means close and reopen /dev/initctl
+ */
+-#if DEBUG
+- log(L_VB, "got SIGUSR1");
+-#endif
++ INITDBG(L_VB, "got SIGUSR1");
+ close(pipe_fd);
+ pipe_fd = -1;
+ DELSET(got_signals, SIGUSR1);
+@@ -2254,11 +2342,11 @@
+ */
+ int init_main()
+ {
+- int f, st;
+- pid_t rc;
+- CHILD *ch;
+- sigset_t sgt;
+- struct sigaction sa;
++ CHILD *ch;
++ struct sigaction sa;
++ sigset_t sgt;
++ pid_t rc;
++ int f, st;
+
+ if (!reload) {
+
+@@ -2278,6 +2366,7 @@
+ }
+ #endif
+
++#ifdef __linux__
+ /*
+ * Tell the kernel to send us SIGINT when CTRL-ALT-DEL
+ * is pressed, and that we want to handle keyboard signals.
+@@ -2288,6 +2377,7 @@
+ close(f);
+ } else
+ (void) ioctl(0, KDSIGACCEPT, SIGWINCH);
++#endif
+
+ /*
+ * Ignore all signals.
+@@ -2320,9 +2410,9 @@
+ setsid();
+
+ /*
+- * Set default PATH variable (for ksh)
++ * Set default PATH variable.
+ */
+- if (getenv("PATH") == NULL) putenv(PATH_DFL);
++ putenv(PATH_DFL);
+
+ /*
+ * Initialize /var/run/utmp (only works if /var is on
+@@ -2333,7 +2423,7 @@
+ /*
+ * Say hello to the world
+ */
+- log(L_CO, bootmsg, "booting");
++ initlog(L_CO, bootmsg, "booting");
+
+ /*
+ * See if we have to start an emergency shell.
+@@ -2358,7 +2448,7 @@
+ /*
+ * Restart: unblock signals and let the show go on
+ */
+- log(L_CO, bootmsg, "reloading");
++ initlog(L_CO, bootmsg, "reloading");
+ sigfillset(&sgt);
+ sigprocmask(SIG_UNBLOCK, &sgt, NULL);
+ }
+@@ -2368,9 +2458,7 @@
+
+ /* See if we need to make the boot transitions. */
+ boot_transitions();
+-#if DEBUG
+- log(L_VB, "init_main: waiting..");
+-#endif
++ INITDBG(L_VB, "init_main: waiting..");
+
+ /* Check if there are processes to be waited on. */
+ for(ch = family; ch; ch = ch->next)
+@@ -2405,10 +2493,10 @@
+ /*
+ * Tell the user about the syntax we expect.
+ */
+-void Usage(char *s)
++void usage(char *s)
+ {
+- fprintf(stderr, "Usage: %s 0123456SsQqAaBbCcUu\n", s);
+- exit(1);
++ fprintf(stderr, "Usage: %s 0123456SsQqAaBbCcUu\n", s);
++ exit(1);
+ }
+
+ int telinit(char *progname, int argc, char **argv)
+@@ -2418,28 +2506,51 @@
+ #endif
+ struct init_request request;
+ struct sigaction sa;
+- int f, fd;
++ int f, fd, l;
++ char *env = NULL;
+
+- while((f = getopt(argc, argv, "t:")) != EOF) switch(f) {
++ memset(&request, 0, sizeof(request));
++ request.magic = INIT_MAGIC;
++
++ while ((f = getopt(argc, argv, "t:e:")) != EOF) switch(f) {
+ case 't':
+ sltime = atoi(optarg);
+ break;
++ case 'e':
++ if (env == NULL)
++ env = request.i.data;
++ l = strlen(optarg);
++ if (env + l + 2 > request.i.data + sizeof(request.i.data)) {
++ fprintf(stderr, "%s: -e option data "
++ "too large\n", progname);
++ exit(1);
++ }
++ memcpy(env, optarg, l);
++ env += l;
++ *env++ = 0;
++ break;
+ default:
+- Usage(progname);
++ usage(progname);
+ break;
+ }
+
+- /* Check syntax. */
+- if (argc - optind != 1 || strlen(argv[optind]) != 1) Usage(progname);
+- if (!strchr("0123456789SsQqAaBbCcUu", argv[optind][0])) Usage(progname);
++ if (env) *env++ = 0;
+
+- /* Open the fifo and write a command. */
+- memset(&request, 0, sizeof(request));
+- request.magic = INIT_MAGIC;
+- request.cmd = INIT_CMD_RUNLVL;
+- request.runlevel = argv[optind][0];
+- request.sleeptime = sltime;
++ if (env) {
++ if (argc != optind)
++ usage(progname);
++ request.cmd = INIT_CMD_SETENV;
++ } else {
++ if (argc - optind != 1 || strlen(argv[optind]) != 1)
++ usage(progname);
++ if (!strchr("0123456789SsQqAaBbCcUu", argv[optind][0]))
++ usage(progname);
++ request.cmd = INIT_CMD_RUNLVL;
++ request.runlevel = env ? 0 : argv[optind][0];
++ request.sleeptime = sltime;
++ }
+
++ /* Open the fifo and write a command. */
+ /* Make sure we don't hang on opening /dev/initctl */
+ SETSIG(sa, SIGALRM, signal_handler, 0);
+ alarm(3);
+@@ -2449,7 +2560,27 @@
+ alarm(0);
+ return 0;
+ }
+-#ifndef TELINIT_USES_INITLVL
++
++#ifdef TELINIT_USES_INITLVL
++ if (request.cmd == INIT_CMD_RUNLVL) {
++ /* Fallthrough to the old method. */
++
++ /* Now write the new runlevel. */
++ if ((fp = fopen(INITLVL, "w")) == NULL) {
++ fprintf(stderr, "%s: cannot create %s\n",
++ progname, INITLVL);
++ exit(1);
++ }
++ fprintf(fp, "%s %d", argv[optind], sltime);
++ fclose(fp);
++
++ /* And tell init about the pending runlevel change. */
++ if (kill(INITPID, SIGHUP) < 0) perror(progname);
++
++ return 0;
++ }
++#endif
++
+ fprintf(stderr, "%s: ", progname);
+ if (ISMEMBER(got_signals, SIGALRM)) {
+ fprintf(stderr, "timeout opening/writing control channel %s\n",
+@@ -2458,24 +2589,6 @@
+ perror(INIT_FIFO);
+ }
+ return 1;
+-#endif
+-
+- /* Fallthrough to the old method. */
+-
+-#ifdef TELINIT_USES_INITLVL
+- /* Now write the new runlevel. */
+- if ((fp = fopen(INITLVL, "w")) == NULL) {
+- fprintf(stderr, "%s: cannot create %s\n", progname, INITLVL);
+- exit(1);
+- }
+- fprintf(fp, "%s %d", argv[optind], sltime);
+- fclose(fp);
+-
+- /* And tell init about the pending runlevel change. */
+- if (kill(INITPID, SIGHUP) < 0) perror(progname);
+-
+- return 0;
+-#endif
+ }
+
+ /*
+@@ -2518,7 +2631,7 @@
+
+ receive_state(STATE_PIPE);
+
+- myname = strdup(argv[0]);
++ myname = istrdup(argv[0]);
+ argv0 = argv[0];
+ maxproclen = 0;
+ for (f = 0; f < argc; f++)
+diff -urNd -urNd sysvinit-2.85/src/init.h sysvinit-2.86/src/init.h
+--- sysvinit-2.85/src/init.h 1999-06-03 14:22:59.000000000 -0500
++++ sysvinit-2.86/src/init.h 2004-07-29 06:21:01.000000000 -0500
+@@ -2,9 +2,8 @@
+ * init.h Several defines and declarations to be
+ * included by all modules of the init program.
+ *
+- * Version: @(#)init.h 2.74 09-Mar-1998 miquels@cistron.nl
++ * Version: @(#)init.h 2.85-5 02-Jul-2003 miquels@cistron.nl
+ *
+- * Modified: Re-exec patch; 24 Feb 1998, Al Viro.
+ */
+
+ /* Standard configuration */
+@@ -24,17 +23,26 @@
+ #define TESTTIME 120 /* this much seconds */
+ #define SLEEPTIME 300 /* Disable time */
+
+-/* Default path inherited by every child if it's not set. */
+-#define PATH_DFL "PATH=/usr/local/sbin:/sbin:/bin:/usr/sbin:/usr/bin"
++/* Default path inherited by every child. */
++#define PATH_DFL "PATH=/bin:/usr/bin:/sbin:/usr/sbin"
+
+
+ /* Prototypes. */
+ void write_utmp_wtmp(char *user, char *id, int pid, int type, char *line);
+ void write_wtmp(char *user, char *id, int pid, int type, char *line);
+-void log(int loglevel, char *fmt, ...);
++#ifdef __GNUC__
++__attribute__ ((format (printf, 2, 3)))
++#endif
++void initlog(int loglevel, char *fmt, ...);
+ void set_term(int how);
+ void print(char *fmt);
+
++#if DEBUG
++# define INITDBG(level, fmt, args...) initlog(level, fmt, ##args)
++#else
++# define INITDBG(level, fmt, args...)
++#endif
++
+ /* Actions to be taken by init */
+ #define RESPAWN 1
+ #define WAIT 2
+Binary files sysvinit-2.85/src/init.o and sysvinit-2.86/src/init.o differ
+Binary files sysvinit-2.85/src/init_utmp.o and sysvinit-2.86/src/init_utmp.o differ
+diff -urNd -urNd sysvinit-2.85/src/initreq.h sysvinit-2.86/src/initreq.h
+--- sysvinit-2.85/src/initreq.h 1996-01-02 12:22:06.000000000 -0600
++++ sysvinit-2.86/src/initreq.h 2004-07-30 06:56:51.000000000 -0500
+@@ -1,41 +1,77 @@
+ /*
+- * initreq.h Interface to let init spawn programs on behalf of
+- * other programs/daemons.
+- * Definitions based on sys_term.c from the BSD 4.4
+- * telnetd source.
++ * initreq.h Interface to talk to init through /dev/initctl.
+ *
+- * Version: @(#)initreq.h 1.25 28-Dec-1995 MvS
++ * Copyright (C) 1995-2004 Miquel van Smoorenburg
++ *
++ * This library is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU Lesser General Public
++ * License as published by the Free Software Foundation; either
++ * version 2 of the License, or (at your option) any later version.
++ *
++ * Version: @(#)initreq.h 1.28 31-Mar-2004 MvS
+ *
+- * Notes: Implemented in sysvinit-2.58 and up, but only
+- * for "telinit". Support for rlogind, telnetd
+- * and rxvt/xterm will follow shortly.
+ */
+ #ifndef _INITREQ_H
+ #define _INITREQ_H
+
+ #include <sys/param.h>
+
++#if defined(__FreeBSD_kernel__)
++# define INIT_FIFO "/etc/.initctl"
++#else
++# define INIT_FIFO "/dev/initctl"
++#endif
++
+ #define INIT_MAGIC 0x03091969
+-#define INIT_FIFO "/dev/initctl"
+-#define INIT_CMD_START 0
+-#define INIT_CMD_RUNLVL 1
+-#define INIT_CMD_POWERFAIL 2
+-#define INIT_CMD_POWERFAILNOW 3
+-#define INIT_CMD_POWEROK 4
++#define INIT_CMD_START 0
++#define INIT_CMD_RUNLVL 1
++#define INIT_CMD_POWERFAIL 2
++#define INIT_CMD_POWERFAILNOW 3
++#define INIT_CMD_POWEROK 4
++#define INIT_CMD_BSD 5
++#define INIT_CMD_SETENV 6
++#define INIT_CMD_UNSETENV 7
++
++#define INIT_CMD_CHANGECONS 12345
++
++#ifdef MAXHOSTNAMELEN
++# define INITRQ_HLEN MAXHOSTNAMELEN
++#else
++# define INITRQ_HLEN 64
++#endif
++
++/*
++ * This is what BSD 4.4 uses when talking to init.
++ * Linux doesn't use this right now.
++ */
++struct init_request_bsd {
++ char gen_id[8]; /* Beats me.. telnetd uses "fe" */
++ char tty_id[16]; /* Tty name minus /dev/tty */
++ char host[INITRQ_HLEN]; /* Hostname */
++ char term_type[16]; /* Terminal type */
++ int signal; /* Signal to send */
++ int pid; /* Process to send to */
++ char exec_name[128]; /* Program to execute */
++ char reserved[128]; /* For future expansion. */
++};
++
+
++/*
++ * Because of legacy interfaces, "runlevel" and "sleeptime"
++ * aren't in a seperate struct in the union.
++ *
++ * The weird sizes are because init expects the whole
++ * struct to be 384 bytes.
++ */
+ struct init_request {
+- int magic; /* Magic number */
+- int cmd; /* What kind of request */
+- int runlevel; /* Runlevel to change to */
+- int sleeptime; /* Time between TERM and KILL */
+- char gen_id[8]; /* Beats me.. telnetd uses "fe" */
+- char tty_id[16]; /* Tty name minus /dev/tty */
+- char host[MAXHOSTNAMELEN]; /* Hostname */
+- char term_type[16]; /* Terminal type */
+- int signal; /* Signal to send */
+- int pid; /* Process to send to */
+- char exec_name[128]; /* Program to execute */
+- char reserved[128]; /* For future expansion. */
++ int magic; /* Magic number */
++ int cmd; /* What kind of request */
++ int runlevel; /* Runlevel to change to */
++ int sleeptime; /* Time between TERM and KILL */
++ union {
++ struct init_request_bsd bsd;
++ char data[368];
++ } i;
+ };
+
+ #endif
+Binary files sysvinit-2.85/src/killall5 and sysvinit-2.86/src/killall5 differ
+diff -urNd -urNd sysvinit-2.85/src/killall5.c sysvinit-2.86/src/killall5.c
+--- sysvinit-2.85/src/killall5.c 2003-04-14 04:59:11.000000000 -0500
++++ sysvinit-2.86/src/killall5.c 2004-07-30 07:16:23.000000000 -0500
+@@ -5,7 +5,7 @@
+ *
+ * pidof.c Tries to get the pid of the process[es] named.
+ *
+- * Version: 2.85 14-Apr-2003 MvS
++ * Version: 2.86 30-Jul-2004 MvS
+ *
+ * Usage: killall5 [-][signal]
+ * pidof [-s] [-o omitpid [-o omitpid]] program [program..]
+@@ -20,7 +20,7 @@
+ * - swapped out programs pids are caught now
+ *
+ * This file is part of the sysvinit suite,
+- * Copyright 1991-2003 Miquel van Smoorenburg.
++ * Copyright 1991-2004 Miquel van Smoorenburg.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+@@ -41,34 +41,43 @@
+ #include <getopt.h>
+ #include <stdarg.h>
+
+-char *Version = "@(#)killall5 2.85 14-Apr-2003 miquels@cistron.nl";
++char *Version = "@(#)killall5 2.86 31-Jul-2004 miquels@cistron.nl";
++
++#define STATNAMELEN 15
+
+ /* Info about a process. */
+-typedef struct _proc_
+-{
+- char *fullname; /* Name as found out from argv[0] */
+- char *basename; /* Only the part after the last / */
+- char *statname; /* the statname without braces */
+- ino_t ino; /* Inode number */
+- dev_t dev; /* Device it is on */
+- pid_t pid; /* Process ID. */
+- int sid; /* Session ID. */
+- struct _proc_ *next; /* Pointer to next struct. */
++typedef struct proc {
++ char *argv0; /* Name as found out from argv[0] */
++ char *argv0base; /* `basename argv[1]` */
++ char *argv1; /* Name as found out from argv[1] */
++ char *argv1base; /* `basename argv[1]` */
++ char *statname; /* the statname without braces */
++ ino_t ino; /* Inode number */
++ dev_t dev; /* Device it is on */
++ pid_t pid; /* Process ID. */
++ int sid; /* Session ID. */
++ int kernel; /* Kernel thread or zombie. */
++ struct proc *next; /* Pointer to next struct. */
+ } PROC;
+
+ /* pid queue */
+-typedef struct _pidq_ {
+- struct _pidq_ *front;
+- struct _pidq_ *next;
+- struct _pidq_ *rear;
+- PROC *proc;
++
++typedef struct pidq {
++ PROC *proc;
++ struct pidq *next;
+ } PIDQ;
+
++typedef struct {
++ PIDQ *head;
++ PIDQ *tail;
++ PIDQ *next;
++} PIDQ_HEAD;
++
+ /* List of processes. */
+ PROC *plist;
+
+-/* Did we stop a number of processes? */
+-int stopped;
++/* Did we stop all processes ? */
++int sent_sigstop;
+
+ int scripts_too = 0;
+
+@@ -86,7 +95,7 @@
+ void *p;
+
+ if ((p = malloc(bytes)) == NULL) {
+- if (stopped) kill(-1, SIGCONT);
++ if (sent_sigstop) kill(-1, SIGCONT);
+ nsyslog(LOG_ERR, "out of memory");
+ exit(1);
+ }
+@@ -98,14 +107,14 @@
+ */
+ int mount_proc(void)
+ {
+- struct stat st;
+- pid_t pid, rc;
+- int wst;
+- char *args[] = { "mount", "-t", "proc", "none", "/proc", NULL };
+- int did_mount = 0;
++ struct stat st;
++ char *args[] = { "mount", "-t", "proc", "proc", "/proc", 0 };
++ pid_t pid, rc;
++ int wst;
++ int did_mount = 0;
+
+ /* Stat /proc/version to see if /proc is mounted. */
+- if (stat("/proc/version", &st) < 0) {
++ if (stat("/proc/version", &st) < 0 && errno == ENOENT) {
+
+ /* It's not there, so mount it. */
+ if ((pid = fork()) < 0) {
+@@ -115,7 +124,6 @@
+ if (pid == 0) {
+ /* Try a few mount binaries. */
+ execv("/sbin/mount", args);
+- execv("/etc/mount", args);
+ execv("/bin/mount", args);
+
+ /* Okay, I give up. */
+@@ -134,28 +142,42 @@
+
+ /* See if mount succeeded. */
+ if (stat("/proc/version", &st) < 0) {
+- nsyslog(LOG_ERR, "/proc not mounted, failed to mount.");
++ if (errno == ENOENT)
++ nsyslog(LOG_ERR, "/proc not mounted, failed to mount.");
++ else
++ nsyslog(LOG_ERR, "/proc unavailable.");
+ exit(1);
+ }
+
+ return did_mount;
+ }
+
++int readarg(FILE *fp, char *buf, int sz)
++{
++ int c = 0, f = 0;
++
++ while (f < (sz-1) && (c = fgetc(fp)) != EOF && c)
++ buf[f++] = c;
++ buf[f] = 0;
++
++ return (c == EOF && f == 0) ? c : f;
++}
++
+ /*
+ * Read the proc filesystem.
+ */
+ int readproc()
+ {
+- DIR *dir;
+- struct dirent *d;
+- char path[256];
+- char buf[256];
+- char *s, *q;
+- FILE *fp;
+- int pid, f;
+- PROC *p, *n;
+- struct stat st;
+- int c;
++ DIR *dir;
++ FILE *fp;
++ PROC *p, *n;
++ struct dirent *d;
++ struct stat st;
++ char path[256];
++ char buf[256];
++ char *s, *q;
++ unsigned long startcode, endcode;
++ int pid, f;
+
+ /* Open the /proc directory. */
+ if ((dir = opendir("/proc")) == NULL) {
+@@ -167,7 +189,8 @@
+ n = plist;
+ for (p = plist; n; p = n) {
+ n = p->next;
+- if (p->fullname) free(p->fullname);
++ if (p->argv0) free(p->argv0);
++ if (p->argv1) free(p->argv1);
+ free(p);
+ }
+ plist = NULL;
+@@ -188,7 +211,7 @@
+ /* Read SID & statname from it. */
+ if ((fp = fopen(path, "r")) != NULL) {
+ buf[0] = 0;
+- fgets(buf, 256, fp);
++ fgets(buf, sizeof(buf), fp);
+
+ /* See if name starts with '(' */
+ s = buf;
+@@ -215,14 +238,21 @@
+ p->statname = (char *)xmalloc(strlen(s)+1);
+ strcpy(p->statname, s);
+
+- /* This could be replaced by getsid(pid) */
+- if (sscanf(q, "%*c %*d %*d %d", &p->sid) != 1) {
++ /* Get session, startcode, endcode. */
++ startcode = endcode = 0;
++ if (sscanf(q, "%*c %*d %*d %d %*d %*d %*u %*u "
++ "%*u %*u %*u %*u %*u %*d %*d "
++ "%*d %*d %*d %*d %*u %*u %*d "
++ "%*u %lu %lu",
++ &p->sid, &startcode, &endcode) != 3) {
+ p->sid = 0;
+ nsyslog(LOG_ERR, "can't read sid from %s\n",
+ path);
+ free(p);
+ continue;
+ }
++ if (startcode == 0 && endcode == 0)
++ p->kernel = 1;
+ fclose(fp);
+ } else {
+ /* Process disappeared.. */
+@@ -230,24 +260,44 @@
+ continue;
+ }
+
+- /* Now read argv[0] */
+ snprintf(path, sizeof(path), "/proc/%s/cmdline", d->d_name);
+ if ((fp = fopen(path, "r")) != NULL) {
+- f = 0;
+- while(f < 127 && (c = fgetc(fp)) != EOF && c)
+- buf[f++] = c;
+- buf[f++] = 0;
+- fclose(fp);
+
+- /* Store the name into malloced memory. */
+- p->fullname = (char *)xmalloc(f);
+- strcpy(p->fullname, buf);
++ /* Now read argv[0] */
++ f = readarg(fp, buf, sizeof(buf));
++
++ if (buf[0]) {
++ /* Store the name into malloced memory. */
++ p->argv0 = (char *)xmalloc(f + 1);
++ strcpy(p->argv0, buf);
++
++ /* Get a pointer to the basename. */
++ p->argv0base = strrchr(p->argv0, '/');
++ if (p->argv0base != NULL)
++ p->argv0base++;
++ else
++ p->argv0base = p->argv0;
++ }
++
++ /* And read argv[1] */
++ while ((f = readarg(fp, buf, sizeof(buf))) != EOF)
++ if (buf[0] != '-') break;
++
++ if (buf[0]) {
++ /* Store the name into malloced memory. */
++ p->argv1 = (char *)xmalloc(f + 1);
++ strcpy(p->argv1, buf);
++
++ /* Get a pointer to the basename. */
++ p->argv1base = strrchr(p->argv1, '/');
++ if (p->argv1base != NULL)
++ p->argv1base++;
++ else
++ p->argv1base = p->argv1;
++ }
++
++ fclose(fp);
+
+- /* Get a pointer to the basename. */
+- if ((p->basename = strrchr(p->fullname, '/')) != NULL)
+- p->basename++;
+- else
+- p->basename = p->fullname;
+ } else {
+ /* Process disappeared.. */
+ free(p);
+@@ -272,19 +322,18 @@
+ return 0;
+ }
+
+-PIDQ *init_pid_q(PIDQ *q)
++PIDQ_HEAD *init_pid_q(PIDQ_HEAD *q)
+ {
+- q->front = q->next = q->rear = NULL;
+- q->proc = NULL;
++ q->head = q->next = q->tail = NULL;
+ return q;
+ }
+
+-int empty_q(PIDQ *q)
++int empty_q(PIDQ_HEAD *q)
+ {
+- return (q->front == NULL);
++ return (q->head == NULL);
+ }
+
+-int add_pid_to_q(PIDQ *q, PROC *p)
++int add_pid_to_q(PIDQ_HEAD *q, PROC *p)
+ {
+ PIDQ *tmp;
+
+@@ -294,23 +343,23 @@
+ tmp->next = NULL;
+
+ if (empty_q(q)) {
+- q->front = tmp;
+- q->rear = tmp;
++ q->head = tmp;
++ q->tail = tmp;
+ } else {
+- q->rear->next = tmp;
+- q->rear = tmp;
++ q->tail->next = tmp;
++ q->tail = tmp;
+ }
+ return 0;
+ }
+
+-PROC *get_next_from_pid_q(PIDQ *q)
++PROC *get_next_from_pid_q(PIDQ_HEAD *q)
+ {
+- PROC *p;
+- PIDQ *tmp = q->front;
++ PROC *p;
++ PIDQ *tmp = q->head;
+
+ if (!empty_q(q)) {
+- p = q->front->proc;
+- q->front = tmp->next;
++ p = q->head->proc;
++ q->head = tmp->next;
+ free(tmp);
+ return p;
+ }
+@@ -319,15 +368,15 @@
+ }
+
+ /* Try to get the process ID of a given process. */
+-PIDQ *pidof(char *prog)
++PIDQ_HEAD *pidof(char *prog)
+ {
+- struct stat st;
+- int dostat = 0;
+- PROC *p;
+- PIDQ *q;
+- char *s;
+- int foundone = 0;
+- int ok = 0;
++ PROC *p;
++ PIDQ_HEAD *q;
++ struct stat st;
++ char *s;
++ int dostat = 0;
++ int foundone = 0;
++ int ok = 0;
+
+ /* Try to stat the executable. */
+ if (prog[0] == '/' && stat(prog, &st) == 0) dostat++;
+@@ -338,7 +387,7 @@
+ else
+ s++;
+
+- q = (PIDQ *)xmalloc(sizeof(PIDQ));
++ q = (PIDQ_HEAD *)xmalloc(sizeof(PIDQ_HEAD));
+ q = init_pid_q(q);
+
+ /* First try to find a match based on dev/ino pair. */
+@@ -352,20 +401,31 @@
+ }
+
+ /* If we didn't find a match based on dev/ino, try the name. */
+- if (!foundone) {
+- for (p = plist; p; p = p->next) {
+- ok = 0;
++ if (!foundone) for (p = plist; p; p = p->next) {
++ ok = 0;
+
+- ok += (strcmp(p->fullname, prog) == 0);
+- ok += (strcmp(p->basename, s) == 0);
++ /* Compare name (both basename and full path) */
++ ok += (p->argv0 && strcmp(p->argv0, prog) == 0);
++ ok += (p->argv0 && strcmp(p->argv0base, s) == 0);
+
+- if (p->fullname[0] == 0 ||
+- strchr(p->fullname, ' ') ||
+- scripts_too)
+- ok += (strcmp(p->statname, s) == 0);
++ /* For scripts, compare argv[1] as well. */
++ if (scripts_too && p->argv1 &&
++ !strncmp(p->statname, p->argv1base, STATNAMELEN)) {
++ ok += (strcmp(p->argv1, prog) == 0);
++ ok += (strcmp(p->argv1base, s) == 0);
++ }
+
+- if (ok) add_pid_to_q(q, p);
++ /*
++ * if we have a space in argv0, process probably
++ * used setproctitle so try statname.
++ */
++ if (strlen(s) <= STATNAMELEN &&
++ (p->argv0 == NULL ||
++ p->argv0[0] == 0 ||
++ strchr(p->argv0, ' '))) {
++ ok += (strcmp(p->statname, s) == 0);
+ }
++ if (ok) add_pid_to_q(q, p);
+ }
+
+ return q;
+@@ -410,12 +470,12 @@
+ */
+ int main_pidof(int argc, char **argv)
+ {
+- PROC *p;
+- PIDQ *q;
+- int f;
+- int first = 1;
+- int i,oind, opt, flags = 0;
+- pid_t opid[PIDOF_OMITSZ], spid;
++ PIDQ_HEAD *q;
++ PROC *p;
++ pid_t opid[PIDOF_OMITSZ], spid;
++ int f;
++ int first = 1;
++ int i, oind, opt, flags = 0;
+
+ for (oind = PIDOF_OMITSZ-1; oind > 0; oind--)
+ opid[oind] = 0;
+@@ -498,9 +558,9 @@
+ /* Main for either killall or pidof. */
+ int main(int argc, char **argv)
+ {
+- PROC *p;
+- int pid, sid = -1;
+- int sig = SIGKILL;
++ PROC *p;
++ int pid, sid = -1;
++ int sig = SIGKILL;
+
+ /* Get program name. */
+ if ((progname = strrchr(argv[0], '/')) == NULL)
+@@ -511,9 +571,6 @@
+ /* Now connect to syslog. */
+ openlog(progname, LOG_CONS|LOG_PID, LOG_DAEMON);
+
+- /* First get the /proc filesystem online. */
+- mount_proc();
+-
+ /* Were we called as 'pidof' ? */
+ if (strcmp(progname, "pidof") == 0)
+ return main_pidof(argc, argv);
+@@ -525,6 +582,9 @@
+ if ((sig = atoi(argv[1])) <= 0 || sig > 31) usage();
+ }
+
++ /* First get the /proc filesystem online. */
++ mount_proc();
++
+ /*
+ * Ignoring SIGKILL and SIGSTOP do not make sense, but
+ * someday kill(-1, sig) might kill ourself if we don't
+@@ -537,24 +597,19 @@
+
+ /* Now stop all processes. */
+ kill(-1, SIGSTOP);
+- stopped = 1;
++ sent_sigstop = 1;
+
+- /* Find out our own 'sid'. */
++ /* Read /proc filesystem */
+ if (readproc() < 0) {
+ kill(-1, SIGCONT);
+ exit(1);
+ }
+
+- pid = getpid();
+- for (p = plist; p; p = p->next)
+- if (p->pid == pid) {
+- sid = p->sid;
+- break;
+- }
+-
+ /* Now kill all processes except our session. */
++ sid = (int)getsid(0);
++ pid = (int)getpid();
+ for (p = plist; p; p = p->next)
+- if (p->pid != pid && p->sid != sid)
++ if (p->pid != pid && p->sid != sid && !p->kernel)
+ kill(p->pid, sig);
+
+ /* And let them continue. */
+Binary files sysvinit-2.85/src/last and sysvinit-2.86/src/last differ
+diff -urNd -urNd sysvinit-2.85/src/last.c sysvinit-2.86/src/last.c
+--- sysvinit-2.85/src/last.c 2003-04-17 06:38:56.000000000 -0500
++++ sysvinit-2.86/src/last.c 2004-07-30 07:16:26.000000000 -0500
+@@ -6,10 +6,10 @@
+ *
+ * Author: Miquel van Smoorenburg, miquels@cistron.nl
+ *
+- * Version: @(#)last 2.85 16-Apr-2003 miquels@cistron.nl
++ * Version: @(#)last 2.85 30-Jul-2004 miquels@cistron.nl
+ *
+ * This file is part of the sysvinit suite,
+- * Copyright 1991-2003 Miquel van Smoorenburg.
++ * Copyright 1991-2004 Miquel van Smoorenburg.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+@@ -40,7 +40,7 @@
+ # define SHUTDOWN_TIME 254
+ #endif
+
+-char *Version = "@(#) last 2.85 16-Apr-2003 miquels";
++char *Version = "@(#) last 2.85 31-Apr-2004 miquels";
+
+ #define CHOP_DOMAIN 0 /* Define to chop off local domainname. */
+ #define NEW_UTMP 1 /* Fancy & fast utmp read code. */
+@@ -491,10 +491,48 @@
+ void usage(char *s)
+ {
+ fprintf(stderr, "Usage: %s [-num | -n num] [-f file] "
++ "[-t YYYYMMDDHHMMSS] "
+ "[-R] [-x] [-o] [username..] [tty..]\n", s);
+ exit(1);
+ }
+
++time_t parsetm(char *ts)
++{
++ struct tm u = {0}, origu;
++ time_t tm;
++
++ if (sscanf(ts, "%4d%2d%2d%2d%2d%2d", &u.tm_year,
++ &u.tm_mon, &u.tm_mday, &u.tm_hour, &u.tm_min,
++ &u.tm_sec) != 6)
++ return (time_t)-1;
++
++ u.tm_year -= 1900;
++ u.tm_mon -= 1;
++ u.tm_isdst = -1;
++
++ origu = u;
++
++ if ((tm = mktime(&u)) == (time_t)-1)
++ return tm;
++
++ /*
++ * Unfortunately mktime() is much more forgiving than
++ * it should be. For example, it'll gladly accept
++ * "30" as a valid month number. This behavior is by
++ * design, but we don't like it, so we want to detect
++ * it and complain.
++ */
++ if (u.tm_year != origu.tm_year ||
++ u.tm_mon != origu.tm_mon ||
++ u.tm_mday != origu.tm_mday ||
++ u.tm_hour != origu.tm_hour ||
++ u.tm_min != origu.tm_min ||
++ u.tm_sec != origu.tm_sec)
++ return (time_t)-1;
++
++ return tm;
++}
++
+ int main(int argc, char **argv)
+ {
+ FILE *fp; /* Filepointer of wtmp file */
+@@ -518,10 +556,12 @@
+ int extended = 0; /* Lots of info. */
+ char *altufile = NULL;/* Alternate wtmp */
+
++ time_t until = 0; /* at what time to stop parsing the file */
++
+ progname = mybasename(argv[0]);
+
+ /* Process the arguments. */
+- while((c = getopt(argc, argv, "f:n:Rxadio0123456789")) != EOF)
++ while((c = getopt(argc, argv, "f:n:Rxadiot:0123456789")) != EOF)
+ switch(c) {
+ case 'R':
+ showhost = 0;
+@@ -552,6 +592,13 @@
+ case 'a':
+ altlist++;
+ break;
++ case 't':
++ if ((until = parsetm(optarg)) == (time_t)-1) {
++ fprintf(stderr, "%s: Invalid time value \"%s\"\n",
++ progname, optarg);
++ usage(progname);
++ }
++ break;
+ case '0': case '1': case '2': case '3': case '4':
+ case '5': case '6': case '7': case '8': case '9':
+ maxrecs = 10*maxrecs + c - '0';
+@@ -650,6 +697,9 @@
+ if (uread(fp, &ut, &quit) != 1)
+ break;
+
++ if (until && until < ut.ut_time)
++ continue;
++
+ if (memcmp(&ut, &oldut, sizeof(struct utmp)) == 0) continue;
+ memcpy(&oldut, &ut, sizeof(struct utmp));
+ lastdate = ut.ut_time;
+Binary files sysvinit-2.85/src/last.o and sysvinit-2.86/src/last.o differ
+Binary files sysvinit-2.85/src/mesg and sysvinit-2.86/src/mesg differ
+Binary files sysvinit-2.85/src/mesg.o and sysvinit-2.86/src/mesg.o differ
+Binary files sysvinit-2.85/src/mountpoint and sysvinit-2.86/src/mountpoint differ
+diff -urNd -urNd sysvinit-2.85/src/mountpoint.c sysvinit-2.86/src/mountpoint.c
+--- sysvinit-2.85/src/mountpoint.c 1969-12-31 18:00:00.000000000 -0600
++++ sysvinit-2.86/src/mountpoint.c 2004-06-09 07:47:45.000000000 -0500
+@@ -0,0 +1,119 @@
++/*
++ * mountpoint See if a directory is a mountpoint.
++ *
++ * Author: Miquel van Smoorenburg.
++ *
++ * Version: @(#)mountpoint 2.85-12 17-Mar-2004 miquels@cistron.nl
++ *
++ * This file is part of the sysvinit suite,
++ * Copyright 1991-2004 Miquel van Smoorenburg.
++ *
++ * 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.
++ */
++
++#include <sys/stat.h>
++#include <unistd.h>
++#include <stdlib.h>
++#include <string.h>
++#include <errno.h>
++#include <stdarg.h>
++#include <getopt.h>
++#include <stdio.h>
++
++int dostat(char *path, struct stat *st, int do_lstat, int quiet)
++{
++ int n;
++
++ if (do_lstat)
++ n = lstat(path, st);
++ else
++ n = stat(path, st);
++
++ if (n != 0) {
++ if (!quiet)
++ fprintf(stderr, "mountpoint: %s: %s\n", path,
++ strerror(errno));
++ return -1;
++ }
++ return 0;
++}
++
++void usage(void) {
++ fprintf(stderr, "Usage: mountpoint [-q] [-d] [-x] path\n");
++ exit(1);
++}
++
++int main(int argc, char **argv)
++{
++ struct stat st, st2;
++ char buf[256];
++ char *path;
++ int quiet = 0;
++ int showdev = 0;
++ int xdev = 0;
++ int c, r;
++
++ while ((c = getopt(argc, argv, "dqx")) != EOF) switch(c) {
++ case 'd':
++ showdev = 1;
++ break;
++ case 'q':
++ quiet = 1;
++ break;
++ case 'x':
++ xdev = 1;
++ break;
++ default:
++ usage();
++ break;
++ }
++ if (optind != argc - 1) usage();
++ path = argv[optind];
++
++ if (dostat(path, &st, !xdev, quiet) < 0)
++ return 1;
++
++ if (xdev) {
++#ifdef __linux__
++ if (!S_ISBLK(st.st_mode))
++#else
++ if (!S_ISBLK(st.st_mode) && !S_ISCHR(st.st_mode))
++#endif
++ {
++ if (quiet)
++ printf("\n");
++ else
++ fprintf(stderr, "mountpoint: %s: not a block device\n",
++ path);
++ return 1;
++ }
++ printf("%u:%u\n", major(st.st_rdev), minor(st.st_rdev));
++ return 0;
++ }
++
++ if (!S_ISDIR(st.st_mode)) {
++ if (!quiet)
++ fprintf(stderr, "mountpoint: %s: not a directory\n",
++ path);
++ return 1;
++ }
++
++ memset(buf, 0, sizeof(buf));
++ strncpy(buf, path, sizeof(buf) - 4);
++ strcat(buf, "/..");
++ if (dostat(buf, &st2, 0, quiet) < 0)
++ return 1;
++
++ r = (st.st_dev != st2.st_dev) ||
++ (st.st_dev == st2.st_dev && st.st_ino == st2.st_ino);
++
++ if (!quiet && !showdev)
++ printf("%s is %sa mountpoint\n", path, r ? "" : "not ");
++ if (showdev)
++ printf("%u:%u\n", major(st.st_dev), minor(st.st_dev));
++
++ return r ? 0 : 1;
++}
+Binary files sysvinit-2.85/src/mountpoint.o and sysvinit-2.86/src/mountpoint.o differ
+diff -urNd -urNd sysvinit-2.85/src/paths.h sysvinit-2.86/src/paths.h
+--- sysvinit-2.85/src/paths.h 2003-04-14 06:37:01.000000000 -0500
++++ sysvinit-2.86/src/paths.h 2004-06-09 07:47:45.000000000 -0500
+@@ -1,7 +1,7 @@
+ /*
+ * paths.h Paths of files that init and related utilities need.
+ *
+- * Version: @(#) paths.h 2.84 27-Nov-2001
++ * Version: @(#) paths.h 2.85-8 05-Nov-2003
+ *
+ * Author: Miquel van Smoorenburg, <miquels@cistron.nl>
+ *
+@@ -24,6 +24,7 @@
+ #define FORCEFSCK "/forcefsck" /* Force fsck on boot */
+ #define SDPID "/var/run/shutdown.pid" /* PID of shutdown program */
+ #define SHELL "/bin/sh" /* Default shell */
++#define SULOGIN "/sbin/sulogin" /* Sulogin */
+ #define INITSCRIPT "/etc/initscript" /* Initscript. */
+ #define PWRSTAT "/etc/powerstatus" /* COMPAT: SIGPWR reason (OK/BAD) */
+
+diff -urNd -urNd sysvinit-2.85/src/reboot.h sysvinit-2.86/src/reboot.h
+--- sysvinit-2.85/src/reboot.h 1997-09-24 03:55:52.000000000 -0500
++++ sysvinit-2.86/src/reboot.h 2004-06-09 07:47:45.000000000 -0500
+@@ -2,22 +2,35 @@
+ * reboot.h Headerfile that defines how to handle
+ * the reboot() system call.
+ *
+- * Version: @(#)reboot.h 1.00 23-Jul-1996 miquels@cistron.nl
++ * Version: @(#)reboot.h 2.85-17 04-Jun-2004 miquels@cistron.nl
+ *
+ */
+
+-#if defined(__GLIBC__)
+-# include <sys/reboot.h>
++#include <sys/reboot.h>
++
++#ifdef RB_ENABLE_CAD
++# define BMAGIC_HARD RB_ENABLE_CAD
+ #endif
+
+-#define BMAGIC_HARD 0x89ABCDEF
+-#define BMAGIC_SOFT 0
+-#define BMAGIC_REBOOT 0x01234567
+-#define BMAGIC_HALT 0xCDEF0123
+-#define BMAGIC_POWEROFF 0x4321FEDC
++#ifdef RB_DISABLE_CAD
++# define BMAGIC_SOFT RB_DISABLE_CAD
++#endif
+
+-#if defined(__GLIBC__)
+- #define init_reboot(magic) reboot(magic)
++#ifdef RB_HALT_SYSTEM
++# define BMAGIC_HALT RB_HALT_SYSTEM
+ #else
+- #define init_reboot(magic) reboot(0xfee1dead, 672274793, magic)
++# define BMAGIC_HALT RB_HALT
+ #endif
++
++#define BMAGIC_REBOOT RB_AUTOBOOT
++
++#ifdef RB_POWER_OFF
++# define BMAGIC_POWEROFF RB_POWER_OFF
++#elif defined(RB_POWEROFF)
++# define BMAGIC_POWEROFF RB_POWEROFF
++#else
++# define BMAGIC_POWEROFF BMAGIC_HALT
++#endif
++
++#define init_reboot(magic) reboot(magic)
++
+Binary files sysvinit-2.85/src/runlevel and sysvinit-2.86/src/runlevel differ
+Binary files sysvinit-2.85/src/runlevel.o and sysvinit-2.86/src/runlevel.o differ
+Binary files sysvinit-2.85/src/shutdown and sysvinit-2.86/src/shutdown differ
+diff -urNd -urNd sysvinit-2.85/src/shutdown.c sysvinit-2.86/src/shutdown.c
+--- sysvinit-2.85/src/shutdown.c 2003-04-14 06:35:51.000000000 -0500
++++ sysvinit-2.86/src/shutdown.c 2004-07-30 06:59:04.000000000 -0500
+@@ -13,10 +13,10 @@
+ *
+ * Author: Miquel van Smoorenburg, miquels@cistron.nl
+ *
+- * Version: @(#)shutdown 2.85 14-Apr-2003 miquels@cistron.nl
++ * Version: @(#)shutdown 2.86-1 31-Jul-2004 miquels@cistron.nl
+ *
+ * This file is part of the sysvinit suite,
+- * Copyright 1991-2003 Miquel van Smoorenburg.
++ * Copyright 1991-2004 Miquel van Smoorenburg.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+@@ -36,10 +36,12 @@
+ #include <fcntl.h>
+ #include <stdarg.h>
+ #include <utmp.h>
++#include <syslog.h>
+ #include "paths.h"
+ #include "reboot.h"
++#include "initreq.h"
+
+-char *Version = "@(#) shutdown 2.85 14-Apr-2003 miquels@cistron.nl";
++char *Version = "@(#) shutdown 2.86-1 31-Jul-2004 miquels@cistron.nl";
+
+ #define MESSAGELEN 256
+
+@@ -52,6 +54,7 @@
+ char *sltime = 0; /* Sleep time */
+ char newstate[64]; /* What are we gonna do */
+ int doself = 0; /* Don't use init */
++int got_alrm = 0;
+
+ char *clean_env[] = {
+ "HOME=/",
+@@ -67,93 +70,152 @@
+ extern void write_wtmp(char *user, char *id, int pid, int type, char *line);
+
+ /*
+- * Sleep without being interrupted.
++ * Sleep without being interrupted.
+ */
+ void hardsleep(int secs)
+ {
+- struct timespec ts, rem;
++ struct timespec ts, rem;
+
+- ts.tv_sec = secs;
+- ts.tv_nsec = 0;
++ ts.tv_sec = secs;
++ ts.tv_nsec = 0;
+
+- while(nanosleep(&ts, &rem) < 0 && errno == EINTR)
++ while(nanosleep(&ts, &rem) < 0 && errno == EINTR)
+ ts = rem;
+ }
+
+ /*
+- * Break off an already running shutdown.
++ * Break off an already running shutdown.
+ */
+-void stopit()
++void stopit(int sig)
+ {
+- unlink(NOLOGIN);
+- unlink(FASTBOOT);
+- unlink(FORCEFSCK);
+- unlink(SDPID);
+- printf("\r\nShutdown cancelled.\r\n");
+- exit(0);
++ unlink(NOLOGIN);
++ unlink(FASTBOOT);
++ unlink(FORCEFSCK);
++ unlink(SDPID);
++ printf("\r\nShutdown cancelled.\r\n");
++ exit(0);
+ }
+
+ /*
+- * Show usage message.
++ * Show usage message.
+ */
+-void usage()
++void usage(void)
+ {
+- fprintf(stderr,
+- "Usage:\t shutdown [-akrhfnc] [-t secs] time [warning message]\n"
++ fprintf(stderr,
++ "Usage:\t shutdown [-akrhHPfnc] [-t secs] time [warning message]\n"
+ "\t\t -a: use /etc/shutdown.allow\n"
+ "\t\t -k: don't really shutdown, only warn.\n"
+ "\t\t -r: reboot after shutdown.\n"
+ "\t\t -h: halt after shutdown.\n"
++ "\t\t -P: halt action is to turn off power.\n"
++ "\t\t -H: halt action is to just halt.\n"
+ "\t\t -f: do a 'fast' reboot (skip fsck).\n"
+ "\t\t -F: Force fsck on reboot.\n"
+ "\t\t -n: do not go through \"init\" but go down real fast.\n"
+ "\t\t -c: cancel a running shutdown.\n"
+ "\t\t -t secs: delay between warning and kill signal.\n"
+ "\t\t ** the \"time\" argument is mandatory! (try \"now\") **\n");
+- exit(1);
++ exit(1);
+ }
+
++
++void alrm_handler(int sig)
++{
++ got_alrm = sig;
++}
++
++
+ /*
+- * Tell everyone the system is going down in 'mins' minutes.
++ * Set environment variables in the init process.
+ */
+-void warn(mins)
+-int mins;
++int init_setenv(char *name, char *value)
+ {
+- char buf[MESSAGELEN + sizeof(newstate)];
+- int len;
++ struct init_request request;
++ struct sigaction sa;
++ int fd;
++ int nl, vl;
+
+- buf[0] = 0;
+- strncat(buf, message, sizeof(buf) - 1);
+- len = strlen(buf);
++ memset(&request, 0, sizeof(request));
++ request.magic = INIT_MAGIC;
++ request.cmd = INIT_CMD_SETENV;
++ nl = strlen(name);
++ vl = value ? strlen(value) : 0;
+
+- if (mins == 0)
+- snprintf(buf + len, sizeof(buf) - len,
+- "\rThe system is going down %s NOW!\r\n",
+- newstate);
+- else
+- snprintf(buf + len, sizeof(buf) - len,
+- "\rThe system is going DOWN %s in %d minute%s!\r\n",
+- newstate, mins, mins == 1 ? "" : "s");
+- wall(buf, 1, 0);
++ if (nl + vl + 3 >= sizeof(request.i.data))
++ return -1;
++
++ memcpy(request.i.data, name, nl);
++ if (value) {
++ request.i.data[nl] = '=';
++ memcpy(request.i.data + nl + 1, value, vl);
++ }
++
++ /*
++ * Open the fifo and write the command.
++ * Make sure we don't hang on opening /dev/initctl
++ */
++ memset(&sa, 0, sizeof(sa));
++ sa.sa_handler = alrm_handler;
++ sigaction(SIGALRM, &sa, NULL);
++ got_alrm = 0;
++ alarm(3);
++ if ((fd = open(INIT_FIFO, O_WRONLY)) >= 0 &&
++ write(fd, &request, sizeof(request)) == sizeof(request)) {
++ close(fd);
++ alarm(0);
++ return 0;
++ }
++
++ fprintf(stderr, "shutdown: ");
++ if (got_alrm) {
++ fprintf(stderr, "timeout opening/writing control channel %s\n",
++ INIT_FIFO);
++ } else {
++ perror(INIT_FIFO);
++ }
++ return -1;
+ }
+
++
+ /*
+- * Create the /etc/nologin file.
++ * Tell everyone the system is going down in 'mins' minutes.
++ */
++void warn(int mins)
++{
++ char buf[MESSAGELEN + sizeof(newstate)];
++ int len;
++
++ buf[0] = 0;
++ strncat(buf, message, sizeof(buf) - 1);
++ len = strlen(buf);
++
++ if (mins == 0)
++ snprintf(buf + len, sizeof(buf) - len,
++ "\rThe system is going down %s NOW!\r\n",
++ newstate);
++ else
++ snprintf(buf + len, sizeof(buf) - len,
++ "\rThe system is going DOWN %s in %d minute%s!\r\n",
++ newstate, mins, mins == 1 ? "" : "s");
++ wall(buf, 1, 0);
++}
++
++/*
++ * Create the /etc/nologin file.
+ */
+ void donologin(int min)
+ {
+- FILE *fp;
+- time_t t;
++ FILE *fp;
++ time_t t;
+
+- time(&t);
+- t += 60 * min;
++ time(&t);
++ t += 60 * min;
+
+- unlink(NOLOGIN);
+- if ((fp = fopen(NOLOGIN, "w")) != NULL) {
+- fprintf(fp, "\rThe system is going down on %s\r\n", ctime(&t));
+- if (message[0]) fputs(message, fp);
+- fclose(fp);
+- }
++ if ((fp = fopen(NOLOGIN, "w")) != NULL) {
++ fprintf(fp, "\rThe system is going down on %s\r\n", ctime(&t));
++ if (message[0]) fputs(message, fp);
++ fclose(fp);
++ }
+ }
+
+ /*
+@@ -202,131 +264,146 @@
+ return 0;
+ }
+
+-/* Kill all processes, call /etc/init.d/halt (if present) */
++/*
++ * Kill all processes, call /etc/init.d/halt (if present)
++ */
+ void fastdown()
+ {
+- int do_halt = (down_level[0] == '0');
+- int i;
++ int do_halt = (down_level[0] == '0');
++ int i;
+ #if 0
+- char cmd[128];
+- char *script;
++ char cmd[128];
++ char *script;
+
+- /* Currently, the halt script is either init.d/halt OR rc.d/rc.0,
+- * likewise for the reboot script. Test for the presence
+- * of either.
+- */
+- if (do_halt) {
+- if (access(HALTSCRIPT1, X_OK) == 0)
+- script = HALTSCRIPT1;
+- else
+- script = HALTSCRIPT2;
+- } else {
+- if (access(REBOOTSCRIPT1, X_OK) == 0)
+- script = REBOOTSCRIPT1;
+- else
+- script = REBOOTSCRIPT2;
+- }
++ /*
++ * Currently, the halt script is either init.d/halt OR rc.d/rc.0,
++ * likewise for the reboot script. Test for the presence
++ * of either.
++ */
++ if (do_halt) {
++ if (access(HALTSCRIPT1, X_OK) == 0)
++ script = HALTSCRIPT1;
++ else
++ script = HALTSCRIPT2;
++ } else {
++ if (access(REBOOTSCRIPT1, X_OK) == 0)
++ script = REBOOTSCRIPT1;
++ else
++ script = REBOOTSCRIPT2;
++ }
+ #endif
+
+- /* First close all files. */
+- for(i = 0; i < 3; i++)
+- if (!isatty(i)) {
+- close(i);
+- open("/dev/null", O_RDWR);
+- }
+- for(i = 3; i < 20; i++) close(i);
+- close(255);
++ /* First close all files. */
++ for(i = 0; i < 3; i++)
++ if (!isatty(i)) {
++ close(i);
++ open("/dev/null", O_RDWR);
++ }
++ for(i = 3; i < 20; i++) close(i);
++ close(255);
+
+- /* First idle init. */
+- if (kill(1, SIGTSTP) < 0) {
+- fprintf(stderr, "shutdown: can't idle init.\r\n");
+- exit(1);
+- }
++ /* First idle init. */
++ if (kill(1, SIGTSTP) < 0) {
++ fprintf(stderr, "shutdown: can't idle init.\r\n");
++ exit(1);
++ }
+
+- /* Kill all processes. */
+- fprintf(stderr, "shutdown: sending all processes the TERM signal...\r\n");
+- (void) kill(-1, SIGTERM);
+- if (sltime)
+- sleep(atoi(sltime));
+- else
+- sleep(3);
+- fprintf(stderr, "shutdown: sending all processes the KILL signal.\r\n");
+- (void) kill(-1, SIGKILL);
++ /* Kill all processes. */
++ fprintf(stderr, "shutdown: sending all processes the TERM signal...\r\n");
++ kill(-1, SIGTERM);
++ sleep(sltime ? atoi(sltime) : 3);
++ fprintf(stderr, "shutdown: sending all processes the KILL signal.\r\n");
++ (void) kill(-1, SIGKILL);
+
+ #if 0
+- /* See if we can run /etc/init.d/halt */
+- if (access(script, X_OK) == 0) {
+- spawn(1, cmd, "fast", NULL);
+- fprintf(stderr, "shutdown: %s returned - falling back on default routines\r\n", script);
+- }
++ /* See if we can run /etc/init.d/halt */
++ if (access(script, X_OK) == 0) {
++ spawn(1, cmd, "fast", NULL);
++ fprintf(stderr, "shutdown: %s returned - falling back "
++ "on default routines\r\n", script);
++ }
+ #endif
+
+- /* script failed or not present: do it ourself. */
+- sleep(1); /* Give init the chance to collect zombies. */
++ /* script failed or not present: do it ourself. */
++ sleep(1); /* Give init the chance to collect zombies. */
+
+- /* Record the fact that we're going down */
+- write_wtmp("shutdown", "~~", 0, RUN_LVL, "~~");
++ /* Record the fact that we're going down */
++ write_wtmp("shutdown", "~~", 0, RUN_LVL, "~~");
+
+- /* This is for those who have quota installed. */
+- spawn(1, "accton", NULL);
+- spawn(1, "quotaoff", "-a", NULL);
++ /* This is for those who have quota installed. */
++ spawn(1, "accton", NULL);
++ spawn(1, "quotaoff", "-a", NULL);
+
+- sync();
+- fprintf(stderr, "shutdown: turning off swap\r\n");
+- spawn(0, "swapoff", "-a", NULL);
+- fprintf(stderr, "shutdown: unmounting all file systems\r\n");
+- spawn(0, "umount", "-a", NULL);
++ sync();
++ fprintf(stderr, "shutdown: turning off swap\r\n");
++ spawn(0, "swapoff", "-a", NULL);
++ fprintf(stderr, "shutdown: unmounting all file systems\r\n");
++ spawn(0, "umount", "-a", NULL);
+
+- /* We're done, halt or reboot now. */
+- if (do_halt) {
+- fprintf(stderr, "The system is halted. Press CTRL-ALT-DEL or turn off power\r\n");
+- init_reboot(BMAGIC_HALT);
++ /* We're done, halt or reboot now. */
++ if (do_halt) {
++ fprintf(stderr, "The system is halted. Press CTRL-ALT-DEL "
++ "or turn off power\r\n");
++ init_reboot(BMAGIC_HALT);
++ exit(0);
++ }
++
++ fprintf(stderr, "Please stand by while rebooting the system.\r\n");
++ init_reboot(BMAGIC_REBOOT);
+ exit(0);
+- }
+- fprintf(stderr, "Please stand by while rebooting the system.\r\n");
+- init_reboot(BMAGIC_REBOOT);
+- exit(0);
+ }
+
+ /*
+- * Go to runlevel 0, 1 or 6.
++ * Go to runlevel 0, 1 or 6.
+ */
+-void shutdown()
++void shutdown(char *halttype)
+ {
+- char *args[8];
+- int argp = 0;
++ char *args[8];
++ int argp = 0;
++ int do_halt = (down_level[0] == '0');
+
+- /* Warn for the last time (hehe) */
+- warn(0);
+- if (dontshut) {
+- hardsleep(1);
+- stopit();
+- }
++ /* Warn for the last time */
++ warn(0);
++ if (dontshut) {
++ hardsleep(1);
++ stopit(0);
++ }
++ openlog("shutdown", LOG_PID, LOG_USER);
++ if (do_halt)
++ syslog(LOG_NOTICE, "shutting down for system halt");
++ else
++ syslog(LOG_NOTICE, "shutting down for system reboot");
++ closelog();
+
+- /* See if we have to do it ourself. */
+- if (doself) fastdown();
++ /* See if we have to do it ourself. */
++ if (doself) fastdown();
+
+- /* Create the arguments for init. */
+- args[argp++] = INIT;
+- if (sltime) {
+- args[argp++] = "-t";
+- args[argp++] = sltime;
+- }
+- args[argp++] = down_level;
+- args[argp] = (char *)NULL;
++ /* Create the arguments for init. */
++ args[argp++] = INIT;
++ if (sltime) {
++ args[argp++] = "-t";
++ args[argp++] = sltime;
++ }
++ args[argp++] = down_level;
++ args[argp] = (char *)NULL;
+
+- unlink(SDPID);
+- unlink(NOLOGIN);
++ unlink(SDPID);
++ unlink(NOLOGIN);
+
+- /* Now execute init to change runlevel. */
+- sync();
+- execv(INIT, args);
++ /* Now execute init to change runlevel. */
++ sync();
++ init_setenv("INIT_HALT", halttype);
++ execv(INIT, args);
+
+- /* Oops - failed. */
+- fprintf(stderr, "\rshutdown: cannot execute %s\r\n", INIT);
+- unlink(FASTBOOT);
+- unlink(FORCEFSCK);
+- exit(1);
++ /* Oops - failed. */
++ fprintf(stderr, "\rshutdown: cannot execute %s\r\n", INIT);
++ unlink(FASTBOOT);
++ unlink(FORCEFSCK);
++ init_setenv("INIT_HALT", NULL);
++ openlog("shutdown", LOG_PID, LOG_USER);
++ syslog(LOG_NOTICE, "shutdown failed");
++ closelog();
++ exit(1);
+ }
+
+ /*
+@@ -349,274 +426,287 @@
+ }
+
+ /*
+- * Main program.
+- * Process the options and do the final countdown.
++ * Main program.
++ * Process the options and do the final countdown.
+ */
+-int main(argc, argv)
+-int argc;
+-char **argv;
++int main(int argc, char **argv)
+ {
+- extern int getopt();
+- extern int optind;
+- int c, i, wt, hours, mins;
+- struct tm *lt;
+- time_t t;
+- char *sp;
+- char *when = NULL;
+- int didnolog = 0;
+- int cancel = 0;
+- int useacl = 0;
+- int pid = 0;
+- uid_t realuid;
+- FILE *fp;
+- char *downusers[32];
+- char buf[128];
+- char term[UT_LINESIZE + 6];
+- struct stat st;
+- struct utmp *ut;
+- int user_ok = 0;
+- struct sigaction sa;
++ FILE *fp;
++ extern int getopt();
++ extern int optind;
++ struct sigaction sa;
++ struct tm *lt;
++ struct stat st;
++ struct utmp *ut;
++ time_t t;
++ uid_t realuid;
++ char *halttype;
++ char *downusers[32];
++ char buf[128];
++ char term[UT_LINESIZE + 6];
++ char *sp;
++ char *when = NULL;
++ int c, i, wt;
++ int hours, mins;
++ int didnolog = 0;
++ int cancel = 0;
++ int useacl = 0;
++ int pid = 0;
++ int user_ok = 0;
+
+- /* We can be installed setuid root (executable for a special group) */
+- realuid = getuid();
+- setuid(geteuid());
++ /* We can be installed setuid root (executable for a special group) */
++ realuid = getuid();
++ setuid(geteuid());
+
+- if (getuid() != 0) {
+- fprintf(stderr, "shutdown: you must be root to do that!\n");
+- exit(1);
+- }
+- strcpy(down_level, "1");
++ if (getuid() != 0) {
++ fprintf(stderr, "shutdown: you must be root to do that!\n");
++ exit(1);
++ }
++ strcpy(down_level, "1");
++ halttype = NULL;
+
+- /* Process the options. */
+- while((c = getopt(argc, argv, "acqkrhnfFyt:g:i:")) != EOF) {
+- switch(c) {
+- case 'a': /* Access control. */
+- useacl = 1;
+- break;
+- case 'c': /* Cancel an already running shutdown. */
+- cancel = 1;
+- break;
+- case 'k': /* Don't really shutdown, only warn.*/
+- dontshut = 1;
+- break;
+- case 'r': /* Automatic reboot */
+- down_level[0] = '6';
+- break;
+- case 'h': /* Halt after shutdown */
+- down_level[0] = '0';
+- break;
+- case 'f': /* Don't perform fsck after next boot */
+- fastboot = 1;
+- break;
+- case 'F': /* Force fsck after next boot */
+- forcefsck = 1;
+- break;
+- case 'n': /* Don't switch runlevels. */
+- doself = 1;
+- break;
+- case 't': /* Delay between TERM and KILL */
+- sltime = optarg;
+- break;
+- case 'y': /* Ignored for sysV compatibility */
+- break;
+- case 'g': /* sysv style to specify time. */
+- when = optarg;
+- down_level[0] = '0';
+- break;
+- case 'i': /* Level to go to. */
+- if (!strchr("0156aAbBcCsS", optarg[0])) {
+- fprintf(stderr, "shutdown: `%s': bad runlevel\n",
++ /* Process the options. */
++ while((c = getopt(argc, argv, "HPacqkrhnfFyt:g:i:")) != EOF) {
++ switch(c) {
++ case 'H':
++ halttype = "HALT";
++ break;
++ case 'P':
++ halttype = "POWERDOWN";
++ break;
++ case 'a': /* Access control. */
++ useacl = 1;
++ break;
++ case 'c': /* Cancel an already running shutdown. */
++ cancel = 1;
++ break;
++ case 'k': /* Don't really shutdown, only warn.*/
++ dontshut = 1;
++ break;
++ case 'r': /* Automatic reboot */
++ down_level[0] = '6';
++ break;
++ case 'h': /* Halt after shutdown */
++ down_level[0] = '0';
++ break;
++ case 'f': /* Don't perform fsck after next boot */
++ fastboot = 1;
++ break;
++ case 'F': /* Force fsck after next boot */
++ forcefsck = 1;
++ break;
++ case 'n': /* Don't switch runlevels. */
++ doself = 1;
++ break;
++ case 't': /* Delay between TERM and KILL */
++ sltime = optarg;
++ break;
++ case 'y': /* Ignored for sysV compatibility */
++ break;
++ case 'g': /* sysv style to specify time. */
++ when = optarg;
++ break;
++ case 'i': /* Level to go to. */
++ if (!strchr("0156aAbBcCsS", optarg[0])) {
++ fprintf(stderr,
++ "shutdown: `%s': bad runlevel\n",
+ optarg);
+- exit(1);
+- }
+- down_level[0] = optarg[0];
+- break;
+- default:
+- usage();
+- break;
+- }
+- }
++ exit(1);
++ }
++ down_level[0] = optarg[0];
++ break;
++ default:
++ usage();
++ break;
++ }
++ }
+
+- /* Do we need to use the shutdown.allow file ? */
+- if (useacl && (fp = fopen(SDALLOW, "r")) != NULL) {
++ /* Do we need to use the shutdown.allow file ? */
++ if (useacl && (fp = fopen(SDALLOW, "r")) != NULL) {
+
+- /* Read /etc/shutdown.allow. */
+- i = 0;
+- while(fgets(buf, 128, fp)) {
+- if (buf[0] == '#' || buf[0] == '\n') continue;
+- if (i > 31) continue;
+- for(sp = buf; *sp; sp++) if (*sp == '\n') *sp = 0;
+- downusers[i++] = strdup(buf);
+- }
+- if (i < 32) downusers[i] = 0;
+- fclose(fp);
++ /* Read /etc/shutdown.allow. */
++ i = 0;
++ while(fgets(buf, 128, fp)) {
++ if (buf[0] == '#' || buf[0] == '\n') continue;
++ if (i > 31) continue;
++ for(sp = buf; *sp; sp++) if (*sp == '\n') *sp = 0;
++ downusers[i++] = strdup(buf);
++ }
++ if (i < 32) downusers[i] = 0;
++ fclose(fp);
+
+- /* Now walk through /var/run/utmp to find logged in users. */
+- while(!user_ok && (ut = getutent()) != NULL) {
++ /* Now walk through /var/run/utmp to find logged in users. */
++ while(!user_ok && (ut = getutent()) != NULL) {
+
+- /* See if this is a user process on a VC. */
+- if (ut->ut_type != USER_PROCESS) continue;
+- sprintf(term, "/dev/%.*s", UT_LINESIZE, ut->ut_line);
+- if (stat(term, &st) < 0) continue;
++ /* See if this is a user process on a VC. */
++ if (ut->ut_type != USER_PROCESS) continue;
++ sprintf(term, "/dev/%.*s", UT_LINESIZE, ut->ut_line);
++ if (stat(term, &st) < 0) continue;
+ #ifdef major /* glibc */
+- if (major(st.st_rdev) != 4 ||
+- minor(st.st_rdev) > 63) continue;
++ if (major(st.st_rdev) != 4 ||
++ minor(st.st_rdev) > 63) continue;
+ #else
+- if ((st.st_rdev & 0xFFC0) != 0x0400) continue;
++ if ((st.st_rdev & 0xFFC0) != 0x0400) continue;
+ #endif
+- /* Root is always OK. */
+- if (strcmp(ut->ut_user, "root") == 0) {
+- user_ok++;
+- break;
+- }
+-
+- /* See if this is an allowed user. */
+- for(i = 0; i < 32 && downusers[i]; i++)
+- if (!strncmp(downusers[i], ut->ut_user, UT_NAMESIZE)) {
++ /* Root is always OK. */
++ if (strcmp(ut->ut_user, "root") == 0) {
+ user_ok++;
+ break;
+ }
+- }
+- endutent();
+
+- /* See if user was allowed. */
+- if (!user_ok) {
+- if ((fp = fopen(CONSOLE, "w")) != NULL) {
+- fprintf(fp, "\rshutdown: no authorized users logged in.\r\n");
+- fclose(fp);
++ /* See if this is an allowed user. */
++ for(i = 0; i < 32 && downusers[i]; i++)
++ if (!strncmp(downusers[i], ut->ut_user,
++ UT_NAMESIZE)) {
++ user_ok++;
++ break;
++ }
+ }
+- exit(1);
+- }
+- }
++ endutent();
+
+- /* Read pid of running shutdown from a file */
+- if ((fp = fopen(SDPID, "r")) != NULL) {
+- fscanf(fp, "%d", &pid);
+- fclose(fp);
+- }
++ /* See if user was allowed. */
++ if (!user_ok) {
++ if ((fp = fopen(CONSOLE, "w")) != NULL) {
++ fprintf(fp, "\rshutdown: no authorized users "
++ "logged in.\r\n");
++ fclose(fp);
++ }
++ exit(1);
++ }
++ }
+
+- /* Read remaining words, skip time if needed. */
+- message[0] = 0;
+- for(c = optind + (!cancel && !when); c < argc; c++) {
+- if (strlen(message) + strlen(argv[c]) + 4 > MESSAGELEN)
+- break;
+- strcat(message, argv[c]);
+- strcat(message, " ");
+- }
+- if (message[0]) strcat(message, "\r\n");
++ /* Read pid of running shutdown from a file */
++ if ((fp = fopen(SDPID, "r")) != NULL) {
++ fscanf(fp, "%d", &pid);
++ fclose(fp);
++ }
+
+- /* See if we want to run or cancel. */
+- if (cancel) {
+- if (pid <= 0) {
+- fprintf(stderr, "shutdown: cannot find pid of running shutdown.\n");
+- exit(1);
++ /* Read remaining words, skip time if needed. */
++ message[0] = 0;
++ for(c = optind + (!cancel && !when); c < argc; c++) {
++ if (strlen(message) + strlen(argv[c]) + 4 > MESSAGELEN)
++ break;
++ strcat(message, argv[c]);
++ strcat(message, " ");
+ }
+- if (kill(pid, SIGINT) < 0) {
+- fprintf(stderr, "shutdown: not running.\n");
+- exit(1);
++ if (message[0]) strcat(message, "\r\n");
++
++ /* See if we want to run or cancel. */
++ if (cancel) {
++ if (pid <= 0) {
++ fprintf(stderr, "shutdown: cannot find pid "
++ "of running shutdown.\n");
++ exit(1);
++ }
++ init_setenv("INIT_HALT", NULL);
++ if (kill(pid, SIGINT) < 0) {
++ fprintf(stderr, "shutdown: not running.\n");
++ exit(1);
++ }
++ if (message[0]) wall(message, 1, 0);
++ exit(0);
+ }
+- if (message[0]) wall(message, 1, 0);
+- exit(0);
+- }
+
+- /* Check syntax. */
+- if (when == NULL) {
+- if (optind == argc) usage();
+- when = argv[optind++];
+- }
++ /* Check syntax. */
++ if (when == NULL) {
++ if (optind == argc) usage();
++ when = argv[optind++];
++ }
+
+- /* See if we are already running. */
+- if (pid > 0 && kill(pid, 0) == 0) {
+- fprintf(stderr, "\rshutdown: already running.\r\n");
+- exit(1);
+- }
++ /* See if we are already running. */
++ if (pid > 0 && kill(pid, 0) == 0) {
++ fprintf(stderr, "\rshutdown: already running.\r\n");
++ exit(1);
++ }
+
+- /* Extra check. */
+- if (doself && down_level[0] != '0' && down_level[0] != '6') {
+- fprintf(stderr, "shutdown: can use \"-n\" for halt or reboot only.\r\n");
+- exit(1);
+- }
++ /* Extra check. */
++ if (doself && down_level[0] != '0' && down_level[0] != '6') {
++ fprintf(stderr,
++ "shutdown: can use \"-n\" for halt or reboot only.\r\n");
++ exit(1);
++ }
+
+- /* Tell users what we're gonna do. */
+- switch(down_level[0]) {
+- case '0':
+- strcpy(newstate, "for system halt");
+- break;
+- case '6':
+- strcpy(newstate, "for reboot");
+- break;
+- case '1':
+- strcpy(newstate, "to maintenance mode");
+- break;
+- default:
+- sprintf(newstate, "to runlevel %s", down_level);
+- break;
+- }
++ /* Tell users what we're gonna do. */
++ switch(down_level[0]) {
++ case '0':
++ strcpy(newstate, "for system halt");
++ break;
++ case '6':
++ strcpy(newstate, "for reboot");
++ break;
++ case '1':
++ strcpy(newstate, "to maintenance mode");
++ break;
++ default:
++ sprintf(newstate, "to runlevel %s", down_level);
++ break;
++ }
+
+- /* Create a new PID file. */
+- unlink(SDPID);
+- umask(022);
+- if ((fp = fopen(SDPID, "w")) != NULL) {
+- fprintf(fp, "%d\n", getpid());
+- fclose(fp);
+- } else if (errno != EROFS)
+- fprintf(stderr, "shutdown: warning: cannot open %s\n", SDPID);
++ /* Create a new PID file. */
++ unlink(SDPID);
++ umask(022);
++ if ((fp = fopen(SDPID, "w")) != NULL) {
++ fprintf(fp, "%d\n", getpid());
++ fclose(fp);
++ } else if (errno != EROFS)
++ fprintf(stderr, "shutdown: warning: cannot open %s\n", SDPID);
+
+- /*
+- * Catch some common signals.
+- */
+- signal(SIGQUIT, SIG_IGN);
+- signal(SIGCHLD, SIG_IGN);
+- signal(SIGHUP, SIG_IGN);
+- signal(SIGTSTP, SIG_IGN);
+- signal(SIGTTIN, SIG_IGN);
+- signal(SIGTTOU, SIG_IGN);
++ /*
++ * Catch some common signals.
++ */
++ signal(SIGQUIT, SIG_IGN);
++ signal(SIGCHLD, SIG_IGN);
++ signal(SIGHUP, SIG_IGN);
++ signal(SIGTSTP, SIG_IGN);
++ signal(SIGTTIN, SIG_IGN);
++ signal(SIGTTOU, SIG_IGN);
+
+- sa.sa_handler = stopit;
+- sa.sa_flags = SA_RESTART;
+- sigaction(SIGINT, &sa, NULL);
++ memset(&sa, 0, sizeof(sa));
++ sa.sa_handler = stopit;
++ sigaction(SIGINT, &sa, NULL);
+
+- /* Go to the root directory */
+- chdir("/");
+- if (fastboot) close(open(FASTBOOT, O_CREAT | O_RDWR, 0644));
+- if (forcefsck) close(open(FORCEFSCK, O_CREAT | O_RDWR, 0644));
++ /* Go to the root directory */
++ chdir("/");
++ if (fastboot) close(open(FASTBOOT, O_CREAT | O_RDWR, 0644));
++ if (forcefsck) close(open(FORCEFSCK, O_CREAT | O_RDWR, 0644));
+
+- /* Alias now and take care of old '+mins' notation. */
+- if (!strcmp(when, "now")) strcpy(when, "0");
+- if (when[0] == '+') when++;
++ /* Alias now and take care of old '+mins' notation. */
++ if (!strcmp(when, "now")) strcpy(when, "0");
++ if (when[0] == '+') when++;
+
+- /* Decode shutdown time. */
+- for (sp = when; *sp; sp++) {
+- if (*sp != ':' && (*sp < '0' || *sp > '9'))
+- usage();
+- }
+- if (strchr(when, ':') == NULL) {
+- /* Time in minutes. */
+- wt = atoi(when);
+- if (wt == 0 && when[0] != '0') usage();
+- } else {
+- /* Time in hh:mm format. */
+- if (sscanf(when, "%d:%2d", &hours, &mins) != 2) usage();
+- if (hours > 23 || mins > 59) usage();
+- time(&t);
+- lt = localtime(&t);
+- wt = (60*hours + mins) - (60*lt->tm_hour + lt->tm_min);
+- if (wt < 0) wt += 1440;
+- }
+- /* Shutdown NOW if time == 0 */
+- if (wt == 0) shutdown();
++ /* Decode shutdown time. */
++ for (sp = when; *sp; sp++) {
++ if (*sp != ':' && (*sp < '0' || *sp > '9'))
++ usage();
++ }
++ if (strchr(when, ':') == NULL) {
++ /* Time in minutes. */
++ wt = atoi(when);
++ if (wt == 0 && when[0] != '0') usage();
++ } else {
++ /* Time in hh:mm format. */
++ if (sscanf(when, "%d:%2d", &hours, &mins) != 2) usage();
++ if (hours > 23 || mins > 59) usage();
++ time(&t);
++ lt = localtime(&t);
++ wt = (60*hours + mins) - (60*lt->tm_hour + lt->tm_min);
++ if (wt < 0) wt += 1440;
++ }
++ /* Shutdown NOW if time == 0 */
++ if (wt == 0) shutdown(halttype);
+
+- /* Give warnings on regular intervals and finally shutdown. */
+- if (wt < 15 && !needwarning(wt)) warn(wt);
+- while(wt) {
+- if (wt <= 5 && !didnolog) {
+- donologin(wt);
+- didnolog++;
++ /* Give warnings on regular intervals and finally shutdown. */
++ if (wt < 15 && !needwarning(wt)) warn(wt);
++ while(wt) {
++ if (wt <= 5 && !didnolog) {
++ donologin(wt);
++ didnolog++;
++ }
++ if (needwarning(wt)) warn(wt);
++ hardsleep(60);
++ wt--;
+ }
+- if (needwarning(wt)) warn(wt);
+- hardsleep(60);
+- wt--;
+- }
+- shutdown();
+- return(0); /* Never happens */
++ shutdown(halttype);
++
++ return 0; /* Never happens */
+ }
+Binary files sysvinit-2.85/src/shutdown.o and sysvinit-2.86/src/shutdown.o differ
+Binary files sysvinit-2.85/src/sulogin and sysvinit-2.86/src/sulogin differ
+diff -urNd -urNd sysvinit-2.85/src/sulogin.c sysvinit-2.86/src/sulogin.c
+--- sysvinit-2.85/src/sulogin.c 2003-04-14 04:53:49.000000000 -0500
++++ sysvinit-2.86/src/sulogin.c 2004-07-30 06:40:28.000000000 -0500
+@@ -8,7 +8,7 @@
+ * encrypted root password is "x" the shadow
+ * password will be used.
+ *
+- * Version: @(#)sulogin 2.85 14-Apr-2003 miquels@cistron.nl
++ * Version: @(#)sulogin 2.85-3 23-Apr-2003 miquels@cistron.nl
+ *
+ */
+
+@@ -35,11 +35,15 @@
+ #define F_SHADOW "/etc/shadow"
+ #define BINSH "/bin/sh"
+
+-char *Version = "@(#)sulogin 2.85 14-Apr-2003 miquels@cistron.nl";
++char *Version = "@(#)sulogin 2.85-3 23-Apr-2003 miquels@cistron.nl";
+
+ int timeout = 0;
+ int profile = 0;
+
++#ifndef IUCLC
++# define IUCLC 0
++#endif
++
+ #if 0
+ /*
+ * Fix the tty modes and set reasonable defaults.
+@@ -252,7 +256,7 @@
+ printf("Give root password for maintenance\n");
+ else
+ printf("Press enter for maintenance\n");
+- printf("(or type Control-D for normal startup): ");
++ printf("(or type Control-D to continue): ");
+ fflush(stdout);
+
+ tcgetattr(0, &old);
+Binary files sysvinit-2.85/src/sulogin.o and sysvinit-2.86/src/sulogin.o differ
+Binary files sysvinit-2.85/src/utmp.o and sysvinit-2.86/src/utmp.o differ