diff options
author | Chris Larson <clarson@kergoth.com> | 2004-11-09 00:36:47 +0000 |
---|---|---|
committer | Chris Larson <clarson@kergoth.com> | 2004-11-09 00:36:47 +0000 |
commit | f96441b9faf769c9ecdd4d338b605ea3d0cc4010 (patch) | |
tree | edb17ec2c4ea13c5acb1c7350957a249a820e28d /sysvinit/sysvinit-2.86/sysvinit-2.86.patch | |
parent | b6588aa6851fb220cedc387d21c51513ef8d67f4 (diff) |
Disable bk EOLN_NATIVE conversions on all files in packages FILESPATHs, to prevent it screwing up patches.
BKrev: 4190111fA4MuVozAqwE7xOSL9fr-TA
Diffstat (limited to 'sysvinit/sysvinit-2.86/sysvinit-2.86.patch')
-rw-r--r-- | sysvinit/sysvinit-2.86/sysvinit-2.86.patch | 4880 |
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 |