diff options
-rw-r--r-- | Makefile | 10 | ||||
-rw-r--r-- | initscripts.spec | 7 | ||||
-rwxr-xr-x | rc.d/init.d/functions | 120 | ||||
-rwxr-xr-x | rc.d/init.d/halt | 4 | ||||
-rwxr-xr-x | rc.d/init.d/network | 12 | ||||
-rwxr-xr-x | rc.d/rc | 26 | ||||
-rwxr-xr-x | rc.d/rc.sysinit | 96 | ||||
-rw-r--r-- | src/Makefile | 31 | ||||
-rw-r--r-- | src/initlog.1 | 48 | ||||
-rw-r--r-- | src/initlog.c | 317 | ||||
-rw-r--r-- | src/initlog.h | 16 | ||||
-rw-r--r-- | src/minilogd.c | 164 | ||||
-rw-r--r-- | src/process.c | 216 | ||||
-rw-r--r-- | src/process.h | 9 | ||||
-rw-r--r-- | sysconfig.txt | 8 |
15 files changed, 999 insertions, 85 deletions
@@ -8,11 +8,11 @@ all: install: mkdir -p $(ROOT)/etc/profile.d $(ROOT)/sbin - install -m644 -o root -g root inittab $(ROOT)/etc - install -m644 -o root -g root adjtime $(ROOT)/etc - install -m644 -o root -g root inputrc $(ROOT)/etc - install -m755 -o root -g root setsysfont $(ROOT)/sbin - install -m755 -o root -g root lang.sh $(ROOT)/etc/profile.d + install -m644 inittab $(ROOT)/etc + install -m644 adjtime $(ROOT)/etc + install -m644 inputrc $(ROOT)/etc + install -m755 setsysfont $(ROOT)/sbin + install -m755 lang.sh $(ROOT)/etc/profile.d cp -af rc.d sysconfig ppp $(ROOT)/etc mkdir -p $(ROOT)/sbin mv $(ROOT)/etc/sysconfig/network-scripts/ifup $(ROOT)/sbin diff --git a/initscripts.spec b/initscripts.spec index 36eb84e0..d0cef8ae 100644 --- a/initscripts.spec +++ b/initscripts.spec @@ -1,6 +1,6 @@ Summary: inittab and /etc/rc.d scripts Name: initscripts -%define version 3.83 +%define version 3.84 Version: %{version} Copyright: GPL Group: Base @@ -142,9 +142,12 @@ rm -rf $RPM_BUILD_ROOT /bin/doexec /bin/ipcalc /bin/usleep -/usr/sbin/usernetctl +%attr(4755,root,root) /usr/sbin/usernetctl /sbin/netreport +/sbin/initlog +/sbin/minilogd /usr/man/man1/doexec.1 +/usr/man/man1/initlog.1 /usr/man/man1/ipcalc.1 /usr/man/man1/usleep.1 /usr/man/man1/usernetctl.1 diff --git a/rc.d/init.d/functions b/rc.d/init.d/functions index a651d699..e69f27f4 100755 --- a/rc.d/init.d/functions +++ b/rc.d/init.d/functions @@ -1,4 +1,5 @@ -#! /bin/sh + +#!/bin/sh # # functions This file contains functions to be used by most or all # shell scripts in the /etc/init.d directory. @@ -12,6 +13,15 @@ # First set up a default search path. export PATH="/sbin:/usr/sbin:/bin:/usr/bin" +# Read in our configuration +if [ -f /etc/sysconfig/init ]; then + . /etc/sysconfig/init +else + BOOTUP=color +fi + + + # A function to start a program. daemon() { # Test syntax. @@ -30,15 +40,17 @@ daemon() { pid=`pidofproc $base` [ -n "$pid" ] && ps h $pid >/dev/null 2>&1 && return - # echo basename of the program. - echo -n "$base " - # make sure it doesn't core dump anywhere; while this could mask # problems with the daemon, it also closes some security problems ulimit -c 0 + + # + if [ $BOOTUP != "color" ]; then + echo -n $base + fi # And start it up. - nice -n $nicelevel "$@" + nice -n $nicelevel initlog -q -c "$*" && success -n "$base startup" || failure -n "$base startup" } # A function to stop a program. @@ -150,3 +162,101 @@ status() { echo "$1 is stopped" return 3 } + +echo_success() { + echo $* "[300C[10D[ [1;32mOK[0;39m ]" + return 0 +} + +echo_failure() { + echo $* "[300C[10D[[1;31mFAILED[0;39m]" + return 0 +} + +success() { + if [ "$1" = "-n" ]; then + ECHOARGS="-n" + shift + else + ECHOARGS="" + fi + if [ -z "$IN_INITLOG" ]; then + initlog -n $0 -s "$1" -e 1 + else + echo "-n $0 -s \"$1\" -e 1" >&21 + fi + [ "$BOOTUP" = "color" ] && echo_success $ECHOARGS + return 0 +} + +failure() { + if [ "$1" = "-n" ]; then + ECHOARGS="-n" + shift + else + ECHOARGS="" + fi + if [ -z "$IN_INITLOG" ]; then + initlog -n $0 -s "$1" -e 2 + else + echo "-n $0 -s \"$1\" -e 2" >&21 + fi + [ "$BOOTUP" = "color" ] && echo_failure $ECHOARGS + return 0 +} + +action() { + if [ "$1" = "-n" ]; then + ECHOARGS="-n" + shift + else + ECHOARGS="" + fi + STRING=$1 + echo $ECHOARGS "$STRING " + shift + if [ -z "$IN_INITLOG" ]; then + initlog -q -c "$*" && success "$STRING" || failure "$STRING" + else + # This sucks. + output=`$*` + rc=$? + if [ -n "$output" ]; then + cmdname=`basename $1` + initlogcmds=`echo $output | sed -e "s/^/ -n $cmdname -s \"/" | sed -e "s/$/\"/"` + echo "$initlogcmds" >&21 + fi + + if [ $rc ]; then + success "$STRING" + else + echo $output + failure "$STRING" + fi + fi + return 0 +} + +# Confirm whether we really want to run this service +confirm() { + echo -n "Start service $1 (Y)es/(N)o/(C)ontinue? [Y] " + read answer + case $answer in + y|Y|"") + return 0 + ;; + c|C) + return 2 + ;; + n|N) + return 1 + ;; + *) + confirm $1 + return $? + ;; + esac +} + + + diff --git a/rc.d/init.d/halt b/rc.d/init.d/halt index 5134770b..552f8f16 100755 --- a/rc.d/init.d/halt +++ b/rc.d/init.d/halt @@ -15,7 +15,7 @@ PATH=/sbin:/bin:/usr/bin:/usr/sbin case "$0" in *halt) message="The system is halted" - command="halt" + command="halt -p" ;; *reboot) message="Please stand by while rebooting the system..." @@ -44,7 +44,7 @@ echo "Turning off swap and accounting" swapoff -a [ -x /sbin/accton ] && /sbin/accton echo "Unmounting file systems" -umount -a +umount -a -f mount -n -o remount,ro / # turn off raid diff --git a/rc.d/init.d/network b/rc.d/init.d/network index 425d6c38..f21de187 100755 --- a/rc.d/init.d/network +++ b/rc.d/init.d/network @@ -57,8 +57,7 @@ ipv4_forward_set () fi if [ $value != `cat /proc/sys/net/ipv4/ip_forward` ]; then - echo $message - echo "$value" > /proc/sys/net/ipv4/ip_forward + action -n "$message" echo "$value" > /proc/sys/net/ipv4/ip_forward fi fi fi @@ -70,7 +69,7 @@ case "$1" in start) ipv4_forward_set - ./ifup ifcfg-lo + action "Bringing up interface lo" ./ifup ifcfg-lo case "$IPX" in yes|true) @@ -81,14 +80,14 @@ case "$1" in esac for i in $interfaces; do - ./ifup $i boot + action "Bringing up interface $i" ./ifup $i boot done touch /var/lock/subsys/network ;; stop) for i in $interfaces; do - ./ifdown $i boot + action "Shutting down interface $i" ./ifdown $i boot done case "$IPX" in yes|true) @@ -96,8 +95,7 @@ case "$1" in ;; esac ./ifdown ifcfg-lo - echo "Disabling IPv4 packet forwarding." - echo 0 > /proc/sys/net/ipv4/ip_forward + action -n "Disabling IPv4 packet forwarding." echo 0 > /proc/sys/net/ipv4/ip_forward rm -f /var/lock/subsys/network ;; status) @@ -19,6 +19,15 @@ runlevel=$2 previous=$1 export runlevel previous +# See if we want to be in user confirmation mode +if [ "$previous" = "N" ]; then + if grep -i confirm /proc/cmdline >/dev/null ; then + CONFIRM=yes + else + CONFIRM= + fi +fi + # Get first argument. Set new runlevel to this argument. [ "$1" != "" ] && runlevel="$argv1" @@ -58,6 +67,23 @@ if [ -d /etc/rc.d/rc$runlevel.d ]; then subsys=${i#/etc/rc.d/rc$runlevel.d/S??} [ -f /var/lock/subsys/$subsys ] || \ [ -f /var/lock/subsys/${subsys}.init ] && continue + + # If we're in confirmation mode, get user confirmation + [ -n "$CONFIRM" ] && + { + confirm $subsys + case $? in + 0) + : + ;; + 2) + CONFIRM= + ;; + *) + continue + ;; + esac + } # Bring the subsystem up. $i start diff --git a/rc.d/rc.sysinit b/rc.d/rc.sysinit index acd2b5fa..0b84f72f 100755 --- a/rc.d/rc.sysinit +++ b/rc.d/rc.sysinit @@ -1,10 +1,15 @@ -#! /bin/sh +#!/bin/sh # # /etc/rc.d/rc.sysinit - run once at boot time # # Taken in part from Miquel van Smoorenburg's bcheckrc. # +# Rerun ourselves through initlog +if [ -z "$IN_INITLOG" ]; then + [ -f /sbin/initlog ] && exec /sbin/initlog -r /etc/rc.d/rc.sysinit +fi + # Set the path PATH=/bin:/sbin:/usr/bin:/usr/sbin export PATH @@ -17,17 +22,18 @@ else HOSTNAME=localhost fi +# Source functions +. /etc/rc.d/init.d/functions + # Start up swapping. -echo "Activating swap partitions" -swapon -a +action -n "Activating swap partitions" swapon -a # Set the hostname. -hostname ${HOSTNAME} -echo hostname: `hostname` +action -n "Setting hostname ${HOSTNAME}" hostname ${HOSTNAME} # Set the NIS domain name if [ -n "$NISDOMAIN" ]; then - domainname $NISDOMAIN + action -n "Setting NIS domain name $NISDOMAIN" domainname $NISDOMAIN else domainname "" fi @@ -39,12 +45,10 @@ if [ -f /fsckoptions ]; then fi if [ ! -f /fastboot ]; then - echo "Checking root filesystems." - fsck -V -a $fsckoptions / - + action -n "Checking root filesystem" fsck -T -a $fsckoptions / rc=$? - - # A return of 2 or higher means there were serious problems. + + # A return of 2 or higher means there were serious problems. if [ $rc -gt 1 ]; then echo echo @@ -60,17 +64,19 @@ if [ ! -f /fastboot ]; then mount -n -o remount,ro / echo "Automatic reboot in progress." reboot + elif [ "$rc" = "1" -a -x /sbin/quotacheck ]; then + action -n "Checking root filesystem quotas" /sbin/quotacheck -v / fi fi if [ -x /sbin/quotaon ]; then - echo "Turning on user and group quotas for root filesystem" - /sbin/quotaon / + action -n "Turning on user and group quotas for root filesystem" /sbin/quotaon / fi # check for arguments mount -t proc /proc /proc + if grep -i nopnp /proc/cmdline >/dev/null ; then PNP= else @@ -80,23 +86,20 @@ fi # set up pnp if [ -x /sbin/isapnp -a -f /etc/isapnp.conf ]; then if [ -n "$PNP" ]; then - echo "Setting up ISA PNP devices" - /sbin/isapnp /etc/isapnp.conf + action -n "Setting up ISA PNP devices" /sbin/isapnp /etc/isapnp.conf else - echo "Skipping ISA PNP configuration at users request" + action -n "Skipping ISA PNP configuration at users request" /bin/true fi fi # Remount the root filesystem read-write. -echo "Remounting root filesystem in read-write mode." -mount -n -o remount,rw / +action -n "Remounting root filesystem in read-write mode" mount -n -o remount,rw / -# Check quotas if fsck fixed something. -if [ "$rc" = "1" -a -x /sbin/quotacheck ]; then - echo "Checking root filesystem quotas" - /sbin/quotacheck -v / +if [ -n "$IN_INITLOG" ]; then + IN_INITLOG= fi + if [ ! -f /etc/HOSTNAME ]; then echo ${HOSTNAME} > /etc/HOSTNAME fi @@ -129,22 +132,20 @@ fi if [ -x /sbin/depmod -a -n "$USEMODULES" ]; then # Get ready for kerneld if module support in the kernel - echo -n "Finding module dependencies... " if [ -e /lib/modules/preferred ]; then - depmod -a preferred + action -n "Finding module dependencies" depmod -a preferred else - depmod -a + action -n "Finding module dependencies" depmod -a fi - echo "done" fi # load sound modules if ! grep -i nomodules /proc/cmdline >/dev/null ; then if [ -n "$USEMODULES" ]; then if grep -s "alias sound" /etc/conf.modules > /dev/null ; then - modprobe sound + action -n "Loading sound module" modprobe sound if grep -s "alias midi" /etc/conf.modules > /dev/null ; then - modprobe midi + action -n "Loading midi module" modprobe midi fi fi fi @@ -162,8 +163,7 @@ fi # Add raid devices if [ -f /proc/mdstat -a -f /etc/raidtab -a -x /sbin/raidadd ]; then - echo "Starting up RAID devices." - raidadd -a + action -n "Starting up RAID devices" raidadd -a rc=$? @@ -193,8 +193,7 @@ fi # Check filesystems if [ ! -f /fastboot ]; then - echo "Checking filesystems." - fsck -R -A -V -a $fsckoptions + action -n "Checking filesystems" fsck -T -R -A -a $fsckoptions rc=$? @@ -214,29 +213,23 @@ if [ ! -f /fastboot ]; then mount -n -o remount,ro / echo "Automatic reboot in progress." reboot + elif [ "$rc" = "1" -a -x /sbin/quotacheck ]; then + action -n "Checking filesystem quotas" /sbin/quotacheck -v -R -a fi fi # Mount all other filesystems (except for NFS and /proc, which is already # mounted). Contrary to standard usage, # filesystems are NOT unmounted in single user mode. -echo "Mounting local filesystems." -mount -a -t nonfs,proc +action -n "Mounting local filesystems" mount -a -t nonfs,proc # set the console font if [ -x /sbin/setsysfont ]; then /sbin/setsysfont fi -# Check quotas if fsck fixed something. -if [ "$rc" = "1" -a -x /sbin/quotacheck ]; then - echo "Checking filesystem quotas" - /sbin/quotacheck -v -R -a -fi - if [ -x /sbin/quotaon ]; then - echo "Turning on user and group quotas for local filesystems" - /sbin/quotaon -a + action -n "Turning on user and group quotas for local filesystems" /sbin/quotaon -a fi # Clean out /etc. @@ -263,8 +256,6 @@ rm -f /tmp/.X*-lock rm -f /tmp/.s.PGSQL.* # Set the system clock. -echo -n "Setting clock" - ARC=0 UTC=0 if [ -f /etc/sysconfig/clock ]; then @@ -278,6 +269,7 @@ if [ -f /etc/sysconfig/clock ]; then fi fi +CLOCKDEF="" if [ -x /sbin/hwclock ]; then CLOCKFLAGS="--hctosys" CLOCK=/sbin/hwclock @@ -289,25 +281,22 @@ fi case "$UTC" in yes|true) CLOCKFLAGS="$CLOCKFLAGS -u"; - echo -n " (utc)" + CLOCKDEF="$CLOCKDEF (utc)"; ;; esac case "$ARC" in yes|true) CLOCKFLAGS="$CLOCKFLAGS -A"; - echo -n " (arc)" + CLOCKDEF="$CLOCKDEF (arc)"; ;; esac -echo -n ": " $CLOCK $CLOCKFLAGS - -date +action -n "Setting clock $CLOCKDEF: `date`" date # Right, now turn on swap in case we swap to files. -echo "Enabling swap space." -swapon -a 2>&1 | grep -v "busy" +action -n "Enabling swap space" swapon -a 2>&1 | grep -v "busy" # Initialize the serial ports. if [ -f /etc/rc.d/rc.serial ]; then @@ -335,7 +324,6 @@ fi dmesg > /var/log/dmesg # Feed entropy into the entropy pool -# XXX Random is also started as S20random but randomization may be needed -# XXX for packet sequence numbers during network initialization so we'll -# XXX add entropy here too. /etc/rc.d/init.d/random start + +sleep 10 diff --git a/src/Makefile b/src/Makefile index c0e3f573..c2751e9e 100644 --- a/src/Makefile +++ b/src/Makefile @@ -1,6 +1,6 @@ -CFLAGS+=-Wall +CFLAGS+=-Wall -D_GNU_SOURCE -PROGS=usernetctl doexec netreport testd usleep ipcalc +PROGS=usernetctl doexec netreport testd usleep ipcalc initlog minilogd all: $(PROGS) @@ -9,11 +9,14 @@ clean: install: mkdir -p $(ROOT)/bin $(ROOT)/usr/sbin $(ROOT)/usr/man/man1 - install -o 0 -g 0 -s -m 755 doexec $(ROOT)/bin/doexec - install -o 0 -g 0 -s -m 755 usleep $(ROOT)/bin/usleep - install -o 0 -g 0 -s -m 4755 usernetctl $(ROOT)/usr/sbin/usernetctl - install -o 0 -g 0 -s -m 2755 netreport $(ROOT)/sbin/netreport - install -o 0 -g 0 -s -m 755 ipcalc $(ROOT)/bin/ipcalc + install -s -m 755 doexec $(ROOT)/bin/doexec + install -s -m 755 usleep $(ROOT)/bin/usleep + install -s -m 4755 usernetctl $(ROOT)/usr/sbin/usernetctl + install -s -m 2755 netreport $(ROOT)/sbin/netreport + install -s -m 755 ipcalc $(ROOT)/bin/ipcalc + install -s -m 755 initlog $(ROOT)/sbin/initlog + install -s -m 755 minilogd $(ROOT)/sbin/minilogd + install -m 644 initlog.1 $(ROOT)/usr/man/man1 install -m 644 doexec.1 $(ROOT)/usr/man/man1 install -m 644 netreport.1 $(ROOT)/usr/man/man1 install -m 644 usleep.1 $(ROOT)/usr/man/man1 @@ -23,8 +26,18 @@ install: # this daemon and initscript are useful for testing the up/down/status stuff # not installed by default, only comes from sources. install-test: - install -o 0 -g 0 -s -m 755 testd $(ROOT)/usr/sbin/testd - install -o 0 -g 0 -m 755 testdinit $(ROOT)/etc/rc.d/init.d/testd + install -s -m 755 testd $(ROOT)/usr/sbin/testd + install -m 755 testdinit $(ROOT)/etc/rc.d/init.d/testd ipcalc: ipcalc.o $(CC) $(LDFLAGS) -o $@ $< -lpopt + +minilogd: minilogd.o + $(CC) $(LDFLAGS) -o $@ $< + +initlog: initlog.o process.o + $(CC) $(LDFLAGS) -o $@ $< -lpopt + +clean: + rm ipcalc initlog minilogd *.o core *~ + diff --git a/src/initlog.1 b/src/initlog.1 new file mode 100644 index 00000000..103ef3fd --- /dev/null +++ b/src/initlog.1 @@ -0,0 +1,48 @@ +.TH initlog 8 "Sun Jan 24 1999" +.SH NAME +initlog \- log messages and events to the system logger +.SH SYNOPSIS +.B initlog +[\-cefnprs] [\-\-cmd=ARG] [\-\-event=ARG] [\-\-facility=ARG] +[\-\-name=ARG] [\-\-priority=ARG] [\-\-run=ARG] [\-\-string=ARG] +.SH DESCRIPTION +\fBinitlog\fR logs messages and events to the system logger. +It is mainly designed for use in init scripts. + +.SS OPTIONS +.TP +.I "\-c, \-\-cmd=[program]" +Execute the specified program, logging anything output to +stdout or stderr. +.TP +.I "\-e, \-\-event=[number]" +Logs that the specified event happened. Usually used in conjuction +with \fB\-\-name\fR. Currently specified events are: +.nf + \fB1\fR the action completed successfully + \fB2\fR the action failed + \fB3\fR the action was cancelled at user request + \fB4\fR the action failed due to the failure of a dependent action +.TP +.I "\-f, \-\-facility=[facility]" + +Log at the specified syslog facility. The default +is \fBdaemon\fR (see syslog(3)). +.TP +.I "\-n, \-\-name=[string]" +Log the event under the specified string, such as +"inetd". +.TP +.I "\-p, \-\-priority=[priority]" +Log at the specified syslog priority. The default +is \fBnotice\fR (see syslog(3)). +.TP +.I "\-r, \-\-run=[program]" +Execute the specified program, with an open file +descriptor so that the program can pass back +commands to initlog. +.TP +.I "\-s, \-\-string=[string] +Log the specified string to the logger. +.SH "SEE ALSO" +syslog(3), logger(1) diff --git a/src/initlog.c b/src/initlog.c new file mode 100644 index 00000000..96b5af87 --- /dev/null +++ b/src/initlog.c @@ -0,0 +1,317 @@ + +#include <errno.h> +#include <fcntl.h> +#include <libintl.h> +#include <locale.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +#define SYSLOG_NAMES +#include <syslog.h> + +#include <sys/wait.h> + +#define _(String) gettext((String)) + +#include <popt.h> + +#include "initlog.h" +#include "process.h" + +static int logfacility=LOG_DAEMON; +static int logpriority=LOG_NOTICE; +static int reexec=0; +static int quiet=0; + +static int logEntries = 0; +struct logInfo *logData = NULL; + +char *getLine(char **data) { + /* Get one line from data */ + char *x, *y; + + if (!*data) return NULL; + + for (x = *data; *x && (*x != '\n'); x++); + if (*x) { + x++; + } else { + if (x-*data) { + y=malloc(x-*data+1); + y[x-*data] = 0; + y[x-*data-1] = '\n'; + memcpy(y,*data,x-*data); + } else { + y=NULL; + } + *data = NULL; + return y; + } + y = malloc(x-*data); + y[x-*data-1] = 0; + memcpy(y,*data,x-*data-1); + *data = x; + return y; +} + +char **toArray(char *line, int *num) { + /* Converts a long string into an array of lines. */ + char **lines; + char *tmpline; + + *num = 0; + lines = NULL; + + while ((tmpline=getLine(&line))) { + if (!*num) + lines = (char **) malloc(sizeof(char *)); + else + lines = (char **) realloc(lines, (*num+1)*sizeof(char *)); + lines[*num] = tmpline; + (*num)++; + } + return lines; +} + +int startDaemon() { + int pid; + int rc; + + if ( (pid = fork()) == -1 ) { + perror("fork"); + return -1; + } + if ( pid ) { + /* parent */ + waitpid(pid,&rc,0); + if (rc) + return -1; + else + return 0; + } else { + int fd; + + fd=open("/dev/null",O_RDWR); + dup2(fd,0); + dup2(fd,1); + dup2(fd,2); + /* kid */ + execlp("minilogd","minilogd",NULL); + perror("exec"); + exit(-1); + } +} + +int logLine(struct logInfo *logEnt) { + /* Logs a line... somewhere. */ + int x; + + /* Don't log empty or null lines */ + if (!logEnt->line || !strcmp(logEnt->line,"\n")) return 0; + + if ((x=access(_PATH_LOG,W_OK))) { + /* syslog isn't running, so start something... */ + if ( (x=startDaemon()) ==-1) { + logData=realloc(logData,(logEntries+1)*sizeof(struct logInfo)); + logData[logEntries]= (*logEnt); + logEntries++; + } else { + if (logEntries>0) { + for (x=0;x<logEntries;x++) { + openlog(logData[x].cmd,0,logData[x].fac); + printf("flushing %s\n",logData[x].line); + syslog(logData[x].pri,"%s",logData[x].line); + closelog(); + } + free(logData); + logEntries = 0; + } + openlog(logEnt->cmd,0,logEnt->fac); + syslog(logEnt->pri,"%s",logEnt->line); + closelog(); + } + } else { + if (logEntries>0) { + for (x=0;x<logEntries;x++) { + openlog(logData[x].cmd,0,logData[x].fac); + printf("flushing %s\n",logData[x].line); + syslog(logData[x].pri,"%s",logData[x].line); + closelog(); + } + free(logData); + logEntries = 0; + } + openlog(logEnt->cmd,0,logEnt->fac); + syslog(logEnt->pri,"%s",logEnt->line); + closelog(); + } + return 0; +} + +int logEvent(char *cmd, int eventtype,char *string) { + char *eventtable [] = { + _("%s babbles incoherently"), + _("%s succeeded"), + _("%s failed"), + _("%s cancelled at user request"), + _("%s failed due to a failed dependency"), + /* insert more here */ + NULL + }; + int x=0,len; + struct logInfo logentry; + + + if (cmd) { + logentry.cmd = strdup(basename(cmd)); + if ((logentry.cmd[0] =='K' || logentry.cmd[0] == 'S') && ( 30 <= logentry.cmd[1] <= 39 ) + && ( 30 <= logentry.cmd[2] <= 39 ) ) + logentry.cmd+=3; + } else + logentry.cmd = strdup(_("(none)")); + if (!string) + string = strdup(cmd); + + while (eventtable[x] && x<eventtype) x++; + if (!(eventtable[x])) x=0; + + len=strlen(eventtable[x])+strlen(string); + logentry.line=malloc(len); + snprintf(logentry.line,len,eventtable[x],string); + + logentry.pri = logpriority; + logentry.fac = logfacility; + + return logLine(&logentry); +} + +int logString(char *cmd, char *string) { + struct logInfo logentry; + + if (cmd) { + logentry.cmd = strdup(basename(cmd)); + if ((logentry.cmd[0] =='K' || logentry.cmd[0] == 'S') && ( 30 <= logentry.cmd[1] <= 39 ) + && ( 30 <= logentry.cmd[2] <= 39 ) ) + logentry.cmd+=3; + } else + logentry.cmd = strdup(_("")); + logentry.line = strdup(string); + logentry.pri = logpriority; + logentry.fac = logfacility; + + return logLine(&logentry); +} + +void processArgs(int argc, char **argv) { + char *cmdname=NULL; + int cmdevent=0; + char *cmd=NULL; + char *logstring=NULL; + char *fac=NULL,*pri=NULL; + poptContext context; + int rc; + struct poptOption optTable[] = { + POPT_AUTOHELP + { "name", 'n', POPT_ARG_STRING, &cmdname, 0, + "name of service being logged", NULL + }, + { "event", 'e', POPT_ARG_INT, &cmdevent, 0, + "event being logged (see man page)", NULL + }, + { "cmd", 'c', POPT_ARG_STRING, &cmd, 0, + "command to run, logging output", NULL + }, + { "run", 'r', POPT_ARG_STRING, &cmd, 3, + "command to run, accepting input on open fd", NULL + }, + { "string", 's', POPT_ARG_STRING, &logstring, 0, + "string to log", NULL + }, + { "facility", 'f', POPT_ARG_STRING, &fac, 1, + "facility to log at (default: 'daemon')", NULL + }, + { "priority", 'p', POPT_ARG_STRING, &pri, 2, + "priority to log at (default: 'notice')", NULL + }, + { "quiet", 'q', POPT_ARG_NONE, &quiet, 0, + "suppress stdout/stderr", NULL + }, + { 0, 0, 0, 0, 0, 0 } + }; + + context = poptGetContext("initlog", argc, argv, optTable, 0); + + while ((rc = poptGetNextOpt(context)) > 0) { + switch (rc) { + case 1: + logfacility=atoi(fac); + if ((logfacility == 0) && strcmp(fac,"0")) { + int x =0; + + logfacility = LOG_DAEMON; + for (x=0;facilitynames[x].c_name;x++) { + if (!strcmp(fac,facilitynames[x].c_name)) { + logfacility = facilitynames[x].c_val; + break; + } + } + } + break; + case 2: + logpriority = atoi(pri); + if ((logpriority == 0) && strcmp(pri,"0")) { + int x=0; + + logpriority = LOG_NOTICE; + for (x=0;prioritynames[x].c_name;x++) { + if (!strcmp(pri,prioritynames[x].c_name)) { + logpriority = prioritynames[x].c_val; + break; + } + } + } + break; + case 3: + reexec = 1; + break; + default: + break; + } + } + + if ((rc < -1)) { + fprintf(stderr, "%s: %s\n", + poptBadOption(context, POPT_BADOPTION_NOALIAS), + poptStrerror(rc)); + exit(-1); + } + if ( (cmd && logstring) || (cmd && cmdname) ) { + fprintf(stderr, _("--cmd and --run are incompatible with --string or --name\n")); + exit(-1); + } + if ( cmdname && (!logstring && !cmdevent)) { + fprintf(stderr, _("--name requires one of --event or --string\n")); + exit(-1); + } + if (cmdevent) { + logEvent(cmdname,cmdevent,logstring); + } else if (logstring) { + logString(cmdname,logstring); + } else if ( cmd ) { + exit(runCommand(cmd,reexec,quiet)); + } else { + fprintf(stderr,"nothing to do!\n"); + exit(-1); + } +} + +int main(int argc, char **argv) { + + setlocale(LC_ALL,""); + bindtextdomain("initlog","/etc/locale"); + textdomain("initlog"); + processArgs(argc,argv); + exit (0); +} diff --git a/src/initlog.h b/src/initlog.h new file mode 100644 index 00000000..244ff9a0 --- /dev/null +++ b/src/initlog.h @@ -0,0 +1,16 @@ + +#ifndef INITLOG_H +#define INITLOG_H + +struct logInfo { + char *cmd; + char *line; + int fac; + int pri; +}; + +char *getLine(char **data); +int logString(char *cmd, char *string); +void processArgs(int argc, char **argv); + +#endif diff --git a/src/minilogd.c b/src/minilogd.c new file mode 100644 index 00000000..d15b8d9a --- /dev/null +++ b/src/minilogd.c @@ -0,0 +1,164 @@ + +/* minilogd.c + * + * A pale imitation of syslogd. Most notably, doesn't write anything + * anywhere except possibly back to syslogd. + * + */ + +#include <errno.h> +#include <fcntl.h> +#include <signal.h> +#include <stdio.h> +#include <stdlib.h> +#include <syslog.h> +#include <unistd.h> + +#include <sys/poll.h> +#include <sys/socket.h> +#include <sys/stat.h> +#include <sys/un.h> + +static int we_own_log=0; +static char **buffer=NULL; +static int buflines=0; + +void freeBuffer() { + struct sockaddr_un addr; + int sock; + int x=0,conn; + + bzero(&addr,sizeof(addr)); + addr.sun_family = AF_LOCAL; + strncpy(addr.sun_path,_PATH_LOG,sizeof(addr.sun_path)-1); + /* wait for klogd to hit syslog */ + sleep(1); + sock = socket(AF_LOCAL, SOCK_STREAM,0); + conn=connect(sock,(struct sockaddr *) &addr,sizeof(addr)); + while (x<buflines) { + if (!conn) write(sock,buffer[x],strlen(buffer[x])+1); + free(buffer[x]); + x++; + } +} + +void cleanup(int exitcode) { + /* If we own the log, unlink it before trying to free our buffer. + * Otherwise, sending the buffer to /dev/log doesn't make much sense.... */ + if (we_own_log) { + perror("wol"); + unlink(_PATH_LOG); + } + /* Don't try to free buffer if we were called from a signal handler */ + perror("foo"); + if (exitcode<=0) { + if (buffer) freeBuffer(); + exit(exitcode); + } else + exit(exitcode+128); +} + +void runDaemon(int sock) { + struct sockaddr_un addr; + int x,len,addrlen,recvsock,done=0; + char *message; + struct stat s1,s2; + struct pollfd pfds; + FILE *foo; + + foo=fopen("./foo","a"); + + daemon(0,-1); + /* try not to leave stale sockets lying around */ + /* Hopefully, we won't actually get any of these */ + signal(SIGHUP,cleanup); + signal(SIGINT,cleanup); + signal(SIGQUIT,cleanup); + signal(SIGILL,cleanup); + signal(SIGABRT,cleanup); + signal(SIGFPE,cleanup); + signal(SIGSEGV,cleanup); + signal(SIGPIPE,cleanup); + signal(SIGBUS,cleanup); + signal(SIGTERM,cleanup); + done = 0; + /* Get stat info on dev log so we can later check to make sure we + * still own it... */ + stat(_PATH_LOG,&s1); + while (!done) { + pfds.fd = sock; + pfds.events = POLLIN|POLLPRI; + if ( ( (x=poll(&pfds,1,500))==-1) && errno !=EINTR) { + perror("poll"); + cleanup(-1); + } + if ( (x>0) && pfds.revents & (POLLIN | POLLPRI)) { + printf("foo!\n"); + message = calloc(8192,sizeof(char)); + recvsock = accept(sock,(struct sockaddr *) &addr, &addrlen); + len = read(recvsock,message,8192); + if (buffer) + buffer = realloc(buffer,(buflines+1)*sizeof(char *)); + else + buffer = malloc(sizeof(char *)); + if (len>0) { + message[strlen(message)]='\n'; + fprintf(foo,"%s",message); + buffer[buflines]=message; + buflines++; + close(recvsock); + } + else { + close(recvsock); + recvsock=-1; + } + } + if ( (x>0) && ( pfds.revents & (POLLHUP | POLLNVAL)) ) + done = 1; + /* Check to see if syslogd's yanked our socket out from under us */ + if ( (stat(_PATH_LOG,&s2)!=0) || + (s1.st_ino != s2.st_ino ) || (s1.st_ctime != s2.st_ctime) || + (s1.st_mtime != s2.st_mtime) || (s1.st_atime != s2.st_atime) ) { + done = 1; + we_own_log = 0; + } + } + fclose(foo); + cleanup(0); +} + +int main() { + struct sockaddr_un addr; + int sock; + int pid; + + /* just in case */ + sock = open("/dev/null",O_RDWR); + dup2(sock,0); + dup2(sock,1); + dup2(sock,2); + + bzero(&addr, sizeof(addr)); + addr.sun_family = AF_LOCAL; + strncpy(addr.sun_path,_PATH_LOG,sizeof(addr.sun_path)-1); + sock = socket(AF_LOCAL, SOCK_STREAM,0); + unlink(_PATH_LOG); + /* Bind socket before forking, so we know if the server started */ + if (!bind(sock,(struct sockaddr *) &addr, sizeof(addr))) { + we_own_log = 1; + listen(sock,5); + if ((pid=fork())==-1) { + perror("fork"); + exit(-1); + } + if (pid) { + exit(0); + } else { + runDaemon(sock); + /* shouldn't get back here... */ + exit(-1); + } + } else { + exit(-1); + } +} diff --git a/src/process.c b/src/process.c new file mode 100644 index 00000000..48f3b314 --- /dev/null +++ b/src/process.c @@ -0,0 +1,216 @@ + +#include <errno.h> +#include <fcntl.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +#include <sys/poll.h> +#include <sys/wait.h> + +#include <popt.h> + +#include "initlog.h" +#include "process.h" + +int forkCommand(char **args, int *outfd, int *errfd, int *cmdfd, int quiet) { + /* Fork command 'cmd', returning pid, and optionally pointer + * to open file descriptor fd */ + int fdin, fdout, fderr, fdcmd, pid; + int outpipe[2], errpipe[2], fdpipe[2]; + + if ( (pipe(outpipe)==-1) || (pipe(errpipe)==-1) || (pipe(fdpipe)==-1) ) { + perror("pipe"); + return -1; + } + + dup2(0,fdin); + if (outfd) { + fdout = outpipe[1]; + *outfd = outpipe[0]; + } else { + if (!quiet) + dup2(1,fdout); + } + if (errfd) { + fderr = errpipe[1]; + *errfd = errpipe[0]; + } else { + if (!quiet) + dup2(2,fderr); + } + fdcmd = fdpipe[1]; + if (cmdfd) + *cmdfd = fdpipe[0]; + if ((pid = fork())==-1) { + perror("fork"); + return -1; + } + if (pid) { + /* parent */ + close(fdin); + close(fdout); + close(fderr); + close(fdcmd); + return pid; + } else { + /* kid */ + if (outfd) { + if ( (dup2(fdout,1)==-1) ) { + perror("dup2"); + exit(-1); + } + } else if (quiet) + if ((dup2(open("/dev/null",O_WRONLY),1))==-1) { + perror("dup2"); + exit(-1); + } + + if (errfd) { + if ((dup2(fderr,2)==-1)) { + perror("dup2"); + exit(-1); + } + } else if (quiet) + if ((dup2(open("/dev/null",O_WRONLY),2))==-1) { + perror("dup2"); + exit(-1); + } + + + if ((dup2(fdcmd,CMD_FD)==-1)) { + perror("dup2"); + exit(-1); + } + close(fdout); + close(fderr); + close(fdcmd); + if (outfd) + close(*outfd); + if (errfd) + close(*errfd); + if (cmdfd) + close(*cmdfd); + execvp(args[0],args); + perror("execvp"); + exit(-1); + } +} + +int monitor(char *cmdname, int pid, int numfds, int *fds, int reexec, int quiet) { + struct pollfd *pfds; + char *buf=malloc(2048*sizeof(char)); + int outpipe[2]; + char *tmpstr=NULL; + int x,y,rc=-1; + int done=0; + int output=0; + + pipe(outpipe); + + pfds = malloc(numfds*sizeof(struct pollfd)); + for (x=0;x<numfds;x++) { + pfds[x].fd = fds[x]; + pfds[x].events = POLLIN | POLLPRI; + } + + while (!done) { + if ((x=poll(pfds,numfds,500))==-1) { + perror("poll"); + return -1; + } + if (waitpid(pid,&rc,WNOHANG)) + done=1; + y=0; + while (y<numfds) { + if ( x && ((pfds[y].revents & (POLLIN | POLLPRI)) )) { + int bytesread = 0; + + do { + buf=calloc(2048,sizeof(char)); + bytesread = read(pfds[y].fd,buf,2048); + if (bytesread==-1) { + perror("read"); + return -1; + } + if (bytesread) { + if (!quiet && !reexec) + write(1,buf,bytesread); + if (quiet) { + output = 1; + write(outpipe[1],buf,bytesread); + } + while ((tmpstr=getLine(&buf))) { + if (!reexec) + logString(cmdname,tmpstr); + else { + char **cmdargs=NULL; + char **tmpargs=NULL; + int cmdargc,x; + + poptParseArgvString(tmpstr,&cmdargc,&tmpargs); + cmdargs=malloc( (cmdargc++) * sizeof(char *) ); + cmdargs[0]=strdup("initlog"); + for (x=0;x<(cmdargc-1);x++) { + cmdargs[x+1]=tmpargs[x]; + } + processArgs(cmdargc,cmdargs); + } + } + } + + } while ( bytesread==2048 ); + } + y++; + } + } + rc = rc>>8; + + if (!rc) + return 0; + else { + /* If there was an error and we're quiet, be loud */ + int x; + + if (quiet && output) { + buf=calloc(2048,sizeof(char)); + do { + x=read(outpipe[0],buf,2048); + write(1,buf,x); + buf=calloc(2048,sizeof(char)); + } while (x==2048); + } + return (rc); + } +} + +int runCommand(char *cmd, int reexec, int quiet) { + int fds[2]; + int pid,x; + char **args, **tmpargs; + char *cmdname; + + poptParseArgvString(cmd,&x,&tmpargs); + args = malloc((x+1)*sizeof(char *)); + for ( pid = 0; pid < x ; pid++) { + args[pid] = strdup(tmpargs[pid]); + } + args[pid] = NULL; + if (strcmp(args[0],"sh") && strcmp(args[0],"/bin/sh")) + cmdname = basename(args[0]); + else + cmdname = basename(args[1]); + if ((cmdname[0] =='K' || cmdname[0] == 'S') && ( 30 <= cmdname[1] <= 39 ) + && ( 30 <= cmdname[2] <= 39 ) ) + cmdname+=3; + if (!reexec) { + pid=forkCommand(args,&fds[0],&fds[1],NULL,quiet); + x=monitor(cmdname,pid,2,fds,reexec,quiet); + } else { + setenv("IN_INITLOG","yes",1); + pid=forkCommand(args,NULL,NULL,&fds[0],quiet); + unsetenv("IN_INITLOG"); + x=monitor(cmdname,pid,1,&fds[0],reexec,quiet); + } + return x; +} diff --git a/src/process.h b/src/process.h new file mode 100644 index 00000000..6c796cb2 --- /dev/null +++ b/src/process.h @@ -0,0 +1,9 @@ +#ifndef PROCESS_H +#define PROCESS_H + + +#define CMD_FD 21 + +int runCommand(char *cmd, int reexec, int quiet); + +#endif diff --git a/sysconfig.txt b/sysconfig.txt index aa0b5650..b385eefa 100644 --- a/sysconfig.txt +++ b/sysconfig.txt @@ -18,6 +18,12 @@ Files in /etc/sysconfig 42-year time offset is in effect; otherwise the normal Unix epoch is assumed +/etc/sysconfig/init: + + BOOTUP=<some bootup mode> + BOOTUP=color means new (as of RH6.0) boot display. Anything + else means old-style display + /etc/sysconfig/keyboard: @@ -300,7 +306,7 @@ Files in /etc/sysconfig/network-scripts/ LINGUAS= can be a : separated list of language codes SYSTERM= use to set default TERM environment variable - The above three variables are used in rc.sysinit. + The above four variables are used in rc.sysinit. SYSFONT= any font that is legal when used as /usr/sbin/setfont $SYSFONT ... |