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 , 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 + * 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 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 .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 #include #include - -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 +#ifdef __linux__ +#include #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 #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 #include @@ -13,8 +13,9 @@ #include #include -#include +#ifdef __linux__ +#include #include #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 #include #include #include +#ifdef __linux__ #include +#endif #include #include #include @@ -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 +#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 #include -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 +#include +#include +#include +#include +#include +#include +#include + +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, * @@ -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 +#include + +#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 #include #include +#include #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