From c03e2fac2ba7c4397ef4cb2d6b00f8270dca64c8 Mon Sep 17 00:00:00 2001 From: Jesse Smith Date: Fri, 23 Nov 2018 18:00:23 -0400 Subject: [PATCH 01/13] Added fix to pidof which re-enabled the omit (-o) flag. this was broken when formatting was added in the 2.92 release. Closes Debian bug #914494. --- doc/Changelog | 11 ++++++++++- src/killall5.c | 2 +- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/doc/Changelog b/doc/Changelog index f9526b5..edf4c10 100644 --- a/doc/Changelog +++ b/doc/Changelog @@ -1,4 +1,13 @@ -sysvinit (2.92) unreleased; urgency=low +sysvinit (2.93) released; urgency=low + + [ Jesse Smith ] + + * Fixed error where pidof would not omit checking PIDs passed + to it when the -o flag was used. + Fixes Debian bug #913394. + + +sysvinit (2.92) released; urgency=low [ Jesse Smith ] diff --git a/src/killall5.c b/src/killall5.c index 27b5778..25b333e 100644 --- a/src/killall5.c +++ b/src/killall5.c @@ -1006,7 +1006,7 @@ int main_pidof(int argc, char **argv) if ((token = getenv("PIDOF_NETFS")) && (strcmp(token,"no") != 0)) flags |= PIDOF_NETFS; - while ((opt = getopt(argc,argv,"qhcof:sxn")) != EOF) switch (opt) { + while ((opt = getopt(argc,argv,"qhco:f:sxn")) != EOF) switch (opt) { case '?': nsyslog(LOG_ERR,"invalid options on command line!\n"); closelog(); From f0e93128bc52314f850ff80a75aee6e111bb2b8c Mon Sep 17 00:00:00 2001 From: Jesse Smith Date: Fri, 23 Nov 2018 22:11:42 -0400 Subject: [PATCH 02/13] When the halt command is called with the -p flag (or as poweroff) the command now passes the "-h -P" flags to shutdown. This in turn sets the INIT_HALT environment variable to POWEROFF. Assuming this value is checked by initscripts during the shutting down procedure, it should cause the system to be powered off. If halt is called without -p then the value of INIT_HALT is not set and the default action (often set in /etc/defaut/halt) is taken. --- doc/Changelog | 9 +++++++++ src/halt.c | 8 +++++--- 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/doc/Changelog b/doc/Changelog index edf4c10..e4743d6 100644 --- a/doc/Changelog +++ b/doc/Changelog @@ -5,6 +5,15 @@ sysvinit (2.93) released; urgency=low * Fixed error where pidof would not omit checking PIDs passed to it when the -o flag was used. Fixes Debian bug #913394. + * When the halt command is called with the -p flag (or as poweroff) + the command now passes the "-h -P" flags to shutdown. This + in turn sets the INIT_HALT environment variable to POWEROFF. + Assuming this value is checked by initscripts during the + shutting down procedure, it should cause the system to + be powered off. + If halt is called without -p then the value of INIT_HALT + is not set and the default action (often set in /etc/defaut/halt) + is taken. sysvinit (2.92) released; urgency=low diff --git a/src/halt.c b/src/halt.c index 98bdadf..a469147 100644 --- a/src/halt.c +++ b/src/halt.c @@ -155,13 +155,15 @@ int get_runlevel(void) /* * Switch to another runlevel. */ -void do_shutdown(char *fl, char *tm) +void do_shutdown(char *fl, int should_poweroff, char *tm) { - char *args[8]; + char *args[9]; int i = 0; args[i++] = "shutdown"; args[i++] = fl; + if ( (! strcmp(fl, "-h") ) && (should_poweroff) ) + args[i++] = "-P"; if (tm) { args[i++] = "-t"; args[i++] = tm; @@ -259,7 +261,7 @@ int main(int argc, char **argv) */ c = get_runlevel(); if (c != '0' && c != '6') - do_shutdown(do_reboot ? "-r" : "-h", tm); + do_shutdown(do_reboot ? "-r" : "-h", do_poweroff, tm); } /* From 64ebef64c81a05fda89498e2e52a76f35a18ddca Mon Sep 17 00:00:00 2001 From: Jesse Smith Date: Sat, 24 Nov 2018 12:49:14 -0400 Subject: [PATCH 03/13] Updated changelog to reflect new version number. --- doc/Changelog | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/doc/Changelog b/doc/Changelog index e4743d6..95669c3 100644 --- a/doc/Changelog +++ b/doc/Changelog @@ -1,10 +1,7 @@ -sysvinit (2.93) released; urgency=low +sysvinit (2.94) unreleased; urgency=low [ Jesse Smith ] - * Fixed error where pidof would not omit checking PIDs passed - to it when the -o flag was used. - Fixes Debian bug #913394. * When the halt command is called with the -p flag (or as poweroff) the command now passes the "-h -P" flags to shutdown. This in turn sets the INIT_HALT environment variable to POWEROFF. @@ -15,6 +12,14 @@ sysvinit (2.93) released; urgency=low is not set and the default action (often set in /etc/defaut/halt) is taken. +sysvinit (2.93) released; urgency=low + + [ Jesse Smith ] + + * Fixed error where pidof would not omit checking PIDs passed + to it when the -o flag was used. + Fixes Debian bug #913394. + sysvinit (2.92) released; urgency=low From 5dc965ba10cb5f9bd12b49eeaf28399f9bf3398f Mon Sep 17 00:00:00 2001 From: Jesse Smith Date: Sun, 9 Dec 2018 17:55:52 -0400 Subject: [PATCH 04/13] Removed references to malloc.h Allocating and freeing memory is now handled by stdlib.h --- doc/Changelog | 3 +++ src/bootlogd.c | 1 - src/last.c | 1 - 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/doc/Changelog b/doc/Changelog index 95669c3..7328a1d 100644 --- a/doc/Changelog +++ b/doc/Changelog @@ -11,6 +11,9 @@ sysvinit (2.94) unreleased; urgency=low If halt is called without -p then the value of INIT_HALT is not set and the default action (often set in /etc/defaut/halt) is taken. + * Removed unnecessary malloc.h includes. Memory allocation + and freeing is now handled in stdlib.h + sysvinit (2.93) released; urgency=low diff --git a/src/bootlogd.c b/src/bootlogd.c index c8c06d6..2b32744 100644 --- a/src/bootlogd.c +++ b/src/bootlogd.c @@ -40,7 +40,6 @@ #include #include #include -#include #include #include #include diff --git a/src/last.c b/src/last.c index 9c15b39..5252015 100644 --- a/src/last.c +++ b/src/last.c @@ -34,7 +34,6 @@ #include #include #include -#include #include #include #include From be8d5841618808420cbbf20e7d5349d71a958b29 Mon Sep 17 00:00:00 2001 From: Jesse Smith Date: Sun, 9 Dec 2018 19:32:04 -0400 Subject: [PATCH 05/13] Added some defines and compile-time conditionals to make some components of sysvinit compile on FreeBSD. --- doc/Changelog | 3 ++- src/bootlogd.c | 8 ++++++++ src/init.c | 20 +++++++++++++++++--- src/init.h | 9 +++++++++ src/shutdown.c | 7 +++++++ src/utmp.c | 4 ++++ 6 files changed, 47 insertions(+), 4 deletions(-) diff --git a/doc/Changelog b/doc/Changelog index 7328a1d..8008200 100644 --- a/doc/Changelog +++ b/doc/Changelog @@ -13,7 +13,8 @@ sysvinit (2.94) unreleased; urgency=low is taken. * Removed unnecessary malloc.h includes. Memory allocation and freeing is now handled in stdlib.h - + * Added defines for FreeBSD to make some components compile + on FreeBSD 11. sysvinit (2.93) released; urgency=low diff --git a/src/bootlogd.c b/src/bootlogd.c index 2b32744..bf3983c 100644 --- a/src/bootlogd.c +++ b/src/bootlogd.c @@ -47,7 +47,15 @@ #include #include #include +#ifdef __linux__ #include +#endif + +#ifdef __FreeBSD__ +#include +#include +#endif + #include #ifdef __linux__ #include diff --git a/src/init.c b/src/init.c index 0a56111..f877444 100644 --- a/src/init.c +++ b/src/init.c @@ -52,7 +52,11 @@ Version information is not placed in the top-level Makefile by default #include #include #include +#ifdef __FreeBSD__ +#include +#else #include +#endif #include #include #include @@ -62,6 +66,9 @@ Version information is not placed in the top-level Makefile by default #ifdef WITH_SELINUX # include #endif +#ifdef __FreeBSD__ +extern char **environ; +#endif #ifdef __i386__ # ifdef __GLIBC__ @@ -521,8 +528,12 @@ int receive_state(int fd) * Set the process title. */ #ifdef __GNUC__ +#ifndef __FreeBSD__ __attribute__ ((format (printf, 1, 2))) #endif +#endif +/* This function already exists on FreeBSD. No need to delcare it. */ +#ifndef __FreeBSD__ static int setproctitle(char *fmt, ...) { va_list ap; @@ -542,6 +553,7 @@ static int setproctitle(char *fmt, ...) return len; } +#endif /* * Set console_dev to a working console. @@ -2160,9 +2172,11 @@ int make_pipe(int fd) /* * Attempt to re-exec. + * Renaming to my_re_exec since re_exec is now a common function name + * which conflicts. */ static -void re_exec(void) +void my_re_exec(void) { CHILD *ch; sigset_t mask, oldset; @@ -2279,7 +2293,7 @@ void fifo_new_level(int level) runlevel = read_level(level); if (runlevel == 'U') { runlevel = oldlevel; - re_exec(); + my_re_exec(); } else { if (oldlevel != 'S' && runlevel == 'S') console_stty(); if (runlevel == '6' || runlevel == '0' || @@ -2681,7 +2695,7 @@ void process_signals() #endif if (runlevel == 'U') { runlevel = oldlevel; - re_exec(); + my_re_exec(); } else { if (oldlevel != 'S' && runlevel == 'S') console_stty(); if (runlevel == '6' || runlevel == '0' || diff --git a/src/init.h b/src/init.h index 7a35706..1b70d6d 100644 --- a/src/init.h +++ b/src/init.h @@ -154,3 +154,12 @@ extern char prevlevel; #define D_WROTE_WTMP_RLEVEL -16 #define D_WROTE_UTMP_RLEVEL -17 +#ifdef __FreeBSD__ +#define UTMP_FILE "/var/run/utmp" +#define RUN_LVL 1 +struct utmp +{ + char ut_id[4]; +}; +#endif + diff --git a/src/shutdown.c b/src/shutdown.c index 91a4097..0e6f450 100644 --- a/src/shutdown.c +++ b/src/shutdown.c @@ -54,13 +54,20 @@ #include #include #include +#ifdef __FreeBSD__ +#include +#else #include +#endif #include #include "paths.h" #include "reboot.h" #include "initreq.h" #include "init.h" +#ifdef __FreeBSD__ +extern char **environ; +#endif #define MESSAGELEN 256 diff --git a/src/utmp.c b/src/utmp.c index c1ae0c9..fce3e32 100644 --- a/src/utmp.c +++ b/src/utmp.c @@ -32,7 +32,11 @@ #include #include #include +#ifdef __FreeBSD__ +#include +#else #include +#endif #include "init.h" #include "initreq.h" From 9e8553cacb8778880c404d61e467f1fb9e58a287 Mon Sep 17 00:00:00 2001 From: Jesse Smith Date: Thu, 27 Dec 2018 15:31:14 -0400 Subject: [PATCH 06/13] Updated copyright in init and removed unused Version variable from killall5.c --- src/Makefile | 4 ++-- src/init.c | 29 +++++++++++++++-------------- src/killall5.c | 2 -- 3 files changed, 17 insertions(+), 18 deletions(-) diff --git a/src/Makefile b/src/Makefile index 3c93783..a345e0e 100644 --- a/src/Makefile +++ b/src/Makefile @@ -23,7 +23,7 @@ MNTPOINT= # For some known distributions we do not build all programs, otherwise we do. BIN = -SBIN = init halt shutdown runlevel killall5 fstab-decode +SBIN = init halt shutdown runlevel killall5 fstab-decode USRBIN = last mesg readbootlog MAN1 = last.1 lastb.1 mesg.1 readbootlog.1 @@ -151,7 +151,7 @@ sulogin.o: sulogin.c runlevellog.o: runlevellog.h runlevellog.c paths.h init.o: CPPFLAGS += $(SELINUX_DEF) -init.o: init.c init.h initreq.h paths.h reboot.h runlevellog.h runlevellog.c set.h paths.h +init.o: init.c init.h initreq.h paths.h reboot.h runlevellog.h runlevellog.c set.h utmp.o: diff --git a/src/init.c b/src/init.c index f877444..4369beb 100644 --- a/src/init.c +++ b/src/init.c @@ -13,11 +13,12 @@ Version information is not placed in the top-level Makefile by default */ #ifndef VERSION -#define VERSION "2.91" +#define VERSION "2.94" #endif /* * This file is part of the sysvinit suite, * Copyright (C) 1991-2004 Miquel van Smoorenburg. + * Copyright (C) 2017-2019 Jesse Smith * * 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 @@ -140,7 +141,7 @@ int wrote_wtmp_reboot = 1; /* Set when we wrote the reboot record */ int wrote_utmp_reboot = 1; /* Set when we wrote the reboot record */ int wrote_wtmp_rlevel = 1; /* Set when we wrote the runlevel record */ int wrote_utmp_rlevel = 1; /* Set when we wrote the runlevel record */ -int sltime = WAIT_BETWEEN_SIGNALS; /* Sleep time between TERM and KILL */ +int sleep_time = WAIT_BETWEEN_SIGNALS; /* Sleep time between TERM and KILL */ char *argv0; /* First arguments; show up in ps listing */ int maxproclen; /* Maximal length of argv[0] with \0 */ struct utmp utproto; /* Only used for sizeof(utproto.ut_id) */ @@ -151,7 +152,7 @@ int main(int, char **); /* Used by re-exec part */ int reload = 0; /* Should we do initialization stuff? */ -char *myname="/sbin/init"; /* What should we exec */ +char *myname=INIT; /* What should we exec */ int oops_error; /* Used by some of the re-exec code. */ const char *Signature = "12567362"; /* Signature for re-exec fd */ @@ -295,7 +296,7 @@ void send_state(int fd) fprintf(fp, "-SI%u\n", got_signals); fprintf(fp, "-WR%d\n", wrote_wtmp_reboot); fprintf(fp, "-WU%d\n", wrote_utmp_reboot); - fprintf(fp, "-ST%d\n", sltime); + fprintf(fp, "-ST%d\n", sleep_time); fprintf(fp, "-DB%d\n", did_boot); for (p = family; p; p = p->next) { @@ -423,7 +424,7 @@ static CHILD *get_record(FILE *f) } break; case D_SLTIME: - if (fscanf(f, "%d\n", &sltime) == EOF && errno != 0) { + if (fscanf(f, "%d\n", &sleep_time) == EOF && errno != 0) { fprintf(stderr, "%s (%d): %s\n", __FILE__, __LINE__, strerror(errno)); } break; @@ -1717,7 +1718,7 @@ void read_inittab(void) /* * Yup, but check every second if we still have children. */ - for(f = 0; f < sltime; f++) { + for(f = 0; f < sleep_time; f++) { for(ch = family; ch; ch = ch->next) { if (!(ch->flags & KILLME)) continue; if ((ch->flags & RUNNING) && !(ch->flags & ZOMBIE)) @@ -1971,7 +1972,7 @@ int read_level(int arg) foo = arg; ok = 1; } - if (ok == 2) sltime = st; + if (ok == 2) sleep_time = st; #endif /* INITLVL */ @@ -2474,22 +2475,22 @@ void check_init_fifo(void) } switch(request.cmd) { case INIT_CMD_RUNLVL: - sltime = request.sleeptime; + sleep_time = request.sleeptime; fifo_new_level(request.runlevel); quit = 1; break; case INIT_CMD_POWERFAIL: - sltime = request.sleeptime; + sleep_time = request.sleeptime; do_power_fail('F'); quit = 1; break; case INIT_CMD_POWERFAILNOW: - sltime = request.sleeptime; + sleep_time = request.sleeptime; do_power_fail('L'); quit = 1; break; case INIT_CMD_POWEROK: - sltime = request.sleeptime; + sleep_time = request.sleeptime; do_power_fail('O'); quit = 1; break; @@ -2916,7 +2917,7 @@ int telinit(char *progname, int argc, char **argv) while ((f = getopt(argc, argv, "t:e:")) != EOF) switch(f) { case 't': - sltime = atoi(optarg); + sleep_time = atoi(optarg); break; case 'e': if (env == NULL) @@ -2949,7 +2950,7 @@ int telinit(char *progname, int argc, char **argv) usage(progname); request.cmd = INIT_CMD_RUNLVL; request.runlevel = argv[optind][0]; - request.sleeptime = sltime; + request.sleeptime = sleep_time; } /* Change to the root directory. */ @@ -2991,7 +2992,7 @@ int telinit(char *progname, int argc, char **argv) progname, INITLVL); exit(1); } - fprintf(fp, "%s %d", argv[optind], sltime); + fprintf(fp, "%s %d", argv[optind], sleep_time); fclose(fp); /* And tell init about the pending runlevel change. */ diff --git a/src/killall5.c b/src/killall5.c index 25b333e..d8a399e 100644 --- a/src/killall5.c +++ b/src/killall5.c @@ -58,8 +58,6 @@ #include #include -char *Version = "@(#)killall5 2.86 31-Jul-2004 miquels@cistron.nl"; - #ifndef PATH_MAX # ifdef MAXPATHLEN # define PATH_MAX MAXPATHLEN From 5d955d55c8736a1e7494c9021f7b4cbf316cfc3e Mon Sep 17 00:00:00 2001 From: Jesse Smith Date: Sat, 29 Dec 2018 14:46:10 -0400 Subject: [PATCH 07/13] Increased the size of the kernel command line buffer in bootlogd from 256 characters to 4096. This size is defined in KERNEL_COMMAND_LENGTH for easy modification downstream. --- doc/Changelog | 4 ++++ src/bootlogd.c | 8 +++----- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/doc/Changelog b/doc/Changelog index 8008200..ba64343 100644 --- a/doc/Changelog +++ b/doc/Changelog @@ -15,6 +15,10 @@ sysvinit (2.94) unreleased; urgency=low and freeing is now handled in stdlib.h * Added defines for FreeBSD to make some components compile on FreeBSD 11. + * Increased the size of the kernel command line buffer in bootlogd + from 256 characters to 4096. This size is defined in KERNEL_COMMAND_LENGTH + for easy modification downstream. + sysvinit (2.93) released; urgency=low diff --git a/src/bootlogd.c b/src/bootlogd.c index bf3983c..66057ee 100644 --- a/src/bootlogd.c +++ b/src/bootlogd.c @@ -63,6 +63,7 @@ #include "bootlogd.h" #define MAX_CONSOLES 16 +#define KERNEL_COMMAND_LENGTH 4096 char ringbuf[32768]; char *endptr = ringbuf + sizeof(ringbuf); @@ -257,7 +258,7 @@ int consolenames(struct real_cons *cons, int max_consoles) /* This appears to be unused. unsigned int kdev; */ #endif struct stat st, st2; - char buf[256]; + char buf[KERNEL_COMMAND_LENGTH]; char *p; int didmount = 0; int n; @@ -286,17 +287,14 @@ int consolenames(struct real_cons *cons, int max_consoles) perror("bootlogd: /proc/cmdline"); } else { buf[0] = 0; - if ((n = read(fd, buf, sizeof(buf) - 1)) < 0) + if ((n = read(fd, buf, KERNEL_COMMAND_LENGTH - 1)) < 0) perror("bootlogd: /proc/cmdline"); close(fd); } if (didmount) umount("/proc"); - if (n < 0) return 0; - - /* * OK, so find console= in /proc/cmdline. * Parse in reverse, opening as we go. From 3f2b4a5704bb2e362933847e466a9468544705d4 Mon Sep 17 00:00:00 2001 From: Jesse Smith Date: Mon, 31 Dec 2018 16:31:34 -0400 Subject: [PATCH 08/13] Added logsave.c and logsave.8 manual page from e2fsprogs to make sure logsave is available to initscripts. Updated src/Makefile to make sure bootlogd compiles with Clang. --- doc/Changelog | 3 + man/logsave.8 | 61 +++++++++ src/Makefile | 17 ++- src/bootlogd.c | 6 - src/logsave.c | 333 +++++++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 410 insertions(+), 10 deletions(-) create mode 100644 man/logsave.8 create mode 100644 src/logsave.c diff --git a/doc/Changelog b/doc/Changelog index ba64343..36601ec 100644 --- a/doc/Changelog +++ b/doc/Changelog @@ -18,6 +18,9 @@ sysvinit (2.94) unreleased; urgency=low * Increased the size of the kernel command line buffer in bootlogd from 256 characters to 4096. This size is defined in KERNEL_COMMAND_LENGTH for easy modification downstream. + * Added logsave.c and logsave.8 manual page from e2fsprogs to make + sure logsave is available to initscripts. + * Updated src/Makefile to make sure bootlogd compiles with Clang. sysvinit (2.93) released; urgency=low diff --git a/man/logsave.8 b/man/logsave.8 new file mode 100644 index 0000000..cc3ffde --- /dev/null +++ b/man/logsave.8 @@ -0,0 +1,61 @@ +.\" -*- nroff -*- +.\" Copyright 2003 by Theodore Ts'o. All Rights Reserved. +.\" This file may be copied under the terms of the GNU Public License. +.\" +.TH LOGSAVE 8 "@E2FSPROGS_MONTH@ @E2FSPROGS_YEAR@" "E2fsprogs version @E2FSPROGS_VERSION@" +.SH NAME +logsave \- save the output of a command in a logfile +.SH SYNOPSIS +.B logsave +[ +.B \-asv +] +.I logfile cmd_prog [ ... ] +.SH DESCRIPTION +The +.B logsave +program will execute +.I cmd_prog +with the specified argument(s), and save a copy of its output to +.IR logfile . +If the containing directory for +.I logfile +does not exist, +.B logsave +will accumulate the output in memory until it can be written out. +A copy of the output will also be written to standard output. +.PP +If +.I cmd_prog +is a single hyphen ('-'), then instead of executing a program, +.B logsave +will take its input from standard input and save it in +.I logfile +.PP +.B logsave +is useful for saving the output of initial boot scripts +until the /var partition is mounted, so the output can be written to +/var/log. +.SH OPTIONS +.TP +.B \-a +This option will cause the output to be appended to +.IR logfile , +instead of replacing its current contents. +.TP +.B \-s +This option will cause +.B logsave +to skip writing to the log file text which is bracketed with a control-A +(ASCII 001 or Start of Header) and control-B (ASCII 002 or Start of +Text). This allows progress bar information to be visible to the user +on the console, while not being written to the log file. +.TP +.B \-v +This option will make +.B logsave +to be more verbose in its output to the user. +.SH AUTHOR +Theodore Ts'o (tytso@mit.edu) +.SH SEE ALSO +.BR fsck (8) diff --git a/src/Makefile b/src/Makefile index a345e0e..e54c051 100644 --- a/src/Makefile +++ b/src/Makefile @@ -23,13 +23,13 @@ MNTPOINT= # For some known distributions we do not build all programs, otherwise we do. BIN = -SBIN = init halt shutdown runlevel killall5 fstab-decode +SBIN = init halt shutdown runlevel killall5 fstab-decode logsave USRBIN = last mesg readbootlog MAN1 = last.1 lastb.1 mesg.1 readbootlog.1 MAN5 = initscript.5 inittab.5 initctl.5 MAN8 = halt.8 init.8 killall5.8 pidof.8 poweroff.8 reboot.8 runlevel.8 -MAN8 += shutdown.8 telinit.8 fstab-decode.8 +MAN8 += shutdown.8 telinit.8 fstab-decode.8 logsave.8 ifeq ($(DISTRO),) SBIN += sulogin bootlogd @@ -115,6 +115,9 @@ halt: halt.o ifdown.o hddown.o utmp.o runlevellog.o last: LDLIBS += $(STATIC) last: last.o +logsave: LDLIBS += $(STATIC) +logsave: logsave.o + mesg: LDLIBS += $(STATIC) mesg: mesg.o @@ -137,10 +140,10 @@ shutdown: LDLIBS += $(STATIC) shutdown: dowall.o shutdown.o utmp.o bootlogd: LDLIBS += -lutil $(STATIC) -bootlogd: bootlogd.o bootlogd.h +bootlogd: bootlogd.o readbootlog: LDLIBS += $(STATIC) -readbootlog: readbootlog.o bootlogd.h +readbootlog: readbootlog.o fstab-decode: LDLIBS += $(STATIC) fstab-decode: fstab-decode.o @@ -159,6 +162,10 @@ init_utmp.o: CPPFLAGS += -DINIT_MAIN init_utmp.o: utmp.c init.h initreq.h paths.h $(CC) $(CFLAGS) $(CPPFLAGS) -c -o $@ $< +bootlogd.o: bootlogd.c bootlogd.h + +readbootlog.o: readbootlog.c + utmpdump.o: utmpdump.c oldutmp.h shutdown.o: shutdown.c paths.h reboot.h initreq.h init.h @@ -167,6 +174,8 @@ halt.o: halt.c reboot.h paths.h runlevellog.c runlevellog.h last.o: last.c oldutmp.h +logsave.o: logsave.c + consoles.o: consoles.c consoles.h cleanobjs: diff --git a/src/bootlogd.c b/src/bootlogd.c index 66057ee..f046a01 100644 --- a/src/bootlogd.c +++ b/src/bootlogd.c @@ -24,12 +24,6 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * - * *NOTE* *NOTE* *NOTE* - * This is a PROOF OF CONCEPT IMPLEMENTATION - * - * I have bigger plans for Debian, but for now - * this has to do ;) - * */ #include diff --git a/src/logsave.c b/src/logsave.c new file mode 100644 index 0000000..c027032 --- /dev/null +++ b/src/logsave.c @@ -0,0 +1,333 @@ +/* + * logsave.c --- A program which saves the output of a program until + * /var/log is mounted. + * + * Copyright (C) 2003 Theodore Ts'o. + * + * %Begin-Header% + * This file may be redistributed under the terms of the GNU Public + * License. + * %End-Header% + */ + +#ifndef _XOPEN_SOURCE +#define _XOPEN_SOURCE 600 /* for inclusion of sa_handler in Solaris */ +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef HAVE_GETOPT_H +#include +#else +extern char *optarg; +extern int optind; +#endif + +static int outfd = -1; +static int outbufsize = 0; +static void *outbuf = 0; +static int verbose = 0; +static int do_skip = 0; +static int skip_mode = 0; +static pid_t child_pid = -1; + +static void usage(char *progname) +{ + printf("Usage: %s [-asv] logfile program\n", progname); + exit(1); +} + +#define SEND_LOG 0x01 +#define SEND_CONSOLE 0x02 +#define SEND_BOTH 0x03 + +/* + * Helper function that does the right thing if write returns a + * partial write, or an EAGAIN/EINTR error. + */ +static int write_all(int fd, const char *buf, size_t count) +{ + ssize_t ret; + int c = 0; + + while (count > 0) { + ret = write(fd, buf, count); + if (ret < 0) { + if ((errno == EAGAIN) || (errno == EINTR)) + continue; + return -1; + } + count -= ret; + buf += ret; + c += ret; + } + return c; +} + +static void send_output(const char *buffer, int c, int flag) +{ + const char *cp; + char *n; + int cnt, d, del; + + if (c == 0) + c = strlen(buffer); + + if (flag & SEND_CONSOLE) { + cnt = c; + cp = buffer; + while (cnt) { + del = 0; + for (d=0; d < cnt; d++) { + if (skip_mode && + (cp[d] == '\001' || cp[d] == '\002')) { + del = 1; + break; + } + } + write_all(1, cp, d); + if (del) + d++; + cnt -= d; + cp += d; + } + } + if (!(flag & SEND_LOG)) + return; + if (outfd > 0) + write_all(outfd, buffer, c); + else { + n = realloc(outbuf, outbufsize + c); + if (n) { + outbuf = n; + memcpy(((char *)outbuf)+outbufsize, buffer, c); + outbufsize += c; + } + } +} + +static int do_read(int fd) +{ + int c; + char buffer[4096], *cp, *sep; + + c = read(fd, buffer, sizeof(buffer)-1); + if (c <= 0) + return c; + if (do_skip) { + send_output(buffer, c, SEND_CONSOLE); + buffer[c] = 0; + cp = buffer; + while (*cp) { + if (skip_mode) { + cp = strchr(cp, '\002'); + if (!cp) + return 0; + cp++; + skip_mode = 0; + continue; + } + sep = strchr(cp, '\001'); + if (sep) + *sep = 0; + send_output(cp, 0, SEND_LOG); + if (sep) { + cp = sep + 1; + skip_mode = 1; + } else + break; + } + } else + send_output(buffer, c, SEND_BOTH); + return c; +} + +static void signal_term(int sig) +{ + if (child_pid > 0) + kill(child_pid, sig); +} + +static int run_program(char **argv) +{ + int fds[2]; + int status, rc, pid; + char buffer[80]; +#ifdef HAVE_SIGNAL_H + struct sigaction sa; +#endif + + if (pipe(fds) < 0) { + perror("pipe"); + exit(1); + } + +#ifdef HAVE_SIGNAL_H + memset(&sa, 0, sizeof(struct sigaction)); + sa.sa_handler = signal_term; + sigaction(SIGINT, &sa, 0); + sigaction(SIGTERM, &sa, 0); +#ifdef SA_RESTART + sa.sa_flags = SA_RESTART; +#endif +#endif + + pid = fork(); + if (pid < 0) { + perror("vfork"); + exit(1); + } + if (pid == 0) { + dup2(fds[1],1); /* fds[1] replaces stdout */ + dup2(fds[1],2); /* fds[1] replaces stderr */ + close(fds[0]); /* don't need this here */ + close(fds[1]); + + execvp(argv[0], argv); + perror(argv[0]); + exit(1); + } + child_pid = pid; + close(fds[1]); + + while (!(waitpid(pid, &status, WNOHANG ))) { + do_read(fds[0]); + } + child_pid = -1; + do_read(fds[0]); + close(fds[0]); + + if ( WIFEXITED(status) ) { + rc = WEXITSTATUS(status); + if (rc) { + send_output(argv[0], 0, SEND_BOTH); + sprintf(buffer, " exited with status code %d\n", rc); + send_output(buffer, 0, SEND_BOTH); + } + } else { + if (WIFSIGNALED(status)) { + send_output(argv[0], 0, SEND_BOTH); + sprintf(buffer, "died with signal %d\n", + WTERMSIG(status)); + send_output(buffer, 0, SEND_BOTH); + return 1; + } + rc = 0; + } + return rc; +} + +static int copy_from_stdin(void) +{ + int c, bad_read = 0; + + while (1) { + c = do_read(0); + if ((c == 0 ) || + ((c < 0) && ((errno == EAGAIN) || (errno == EINTR)))) { + if (bad_read++ > 3) + break; + continue; + } + if (c < 0) { + perror("read"); + exit(1); + } + bad_read = 0; + } + return 0; +} + + + +int main(int argc, char **argv) +{ + int c, pid, rc; + char *outfn, **cpp; + int openflags = O_CREAT|O_WRONLY|O_TRUNC; + int send_flag = SEND_LOG; + int do_stdin; + time_t t; + + while ((c = getopt(argc, argv, "+asv")) != EOF) { + switch (c) { + case 'a': + openflags &= ~O_TRUNC; + openflags |= O_APPEND; + break; + case 's': + do_skip = 1; + break; + case 'v': + verbose++; + send_flag |= SEND_CONSOLE; + break; + } + } + if (optind == argc || optind+1 == argc) + usage(argv[0]); + outfn = argv[optind]; + optind++; + argv += optind; + argc -= optind; + + outfd = open(outfn, openflags, 0644); + do_stdin = !strcmp(argv[0], "-"); + + send_output("Log of ", 0, send_flag); + if (do_stdin) + send_output("stdin", 0, send_flag); + else { + for (cpp = argv; *cpp; cpp++) { + send_output(*cpp, 0, send_flag); + send_output(" ", 0, send_flag); + } + } + send_output("\n", 0, send_flag); + t = time(0); + send_output(ctime(&t), 0, send_flag); + send_output("\n", 0, send_flag); + + if (do_stdin) + rc = copy_from_stdin(); + else + rc = run_program(argv); + + send_output("\n", 0, send_flag); + t = time(0); + send_output(ctime(&t), 0, send_flag); + send_output("----------------\n", 0, send_flag); + + if (outbuf) { + pid = fork(); + if (pid < 0) { + perror("fork"); + exit(1); + } + if (pid) { + if (verbose) + printf("Backgrounding to save %s later\n", + outfn); + exit(rc); + } + setsid(); /* To avoid getting killed by init */ + while (outfd < 0) { + outfd = open(outfn, openflags, 0644); + sleep(1); + } + write_all(outfd, outbuf, outbufsize); + free(outbuf); + } + if (outfd >= 0) + close(outfd); + + exit(rc); +} From 5af4ee50a87058d07d296a2e48c67b9d69029f85 Mon Sep 17 00:00:00 2001 From: Jesse Smith Date: Tue, 1 Jan 2019 17:06:07 -0400 Subject: [PATCH 09/13] Minor update to defines and Makefile to avoid compile warnings when building logsave. --- src/logsave.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/logsave.c b/src/logsave.c index c027032..0c9b1fd 100644 --- a/src/logsave.c +++ b/src/logsave.c @@ -13,6 +13,9 @@ #ifndef _XOPEN_SOURCE #define _XOPEN_SOURCE 600 /* for inclusion of sa_handler in Solaris */ #endif +#ifndef HAVE_SIGNAL_H +#define HAVE_SIGNAL_H +#endif #include #include @@ -23,7 +26,9 @@ #include #include #include +#ifdef HAVE_SIGNAL_H #include +#endif #ifdef HAVE_GETOPT_H #include #else @@ -188,7 +193,7 @@ static int run_program(char **argv) if (pid == 0) { dup2(fds[1],1); /* fds[1] replaces stdout */ dup2(fds[1],2); /* fds[1] replaces stderr */ - close(fds[0]); /* don't need this here */ + close(fds[0]); /* don't need this here */ close(fds[1]); execvp(argv[0], argv); From 43b5c64126415a26738aa702827b3c806e91399b Mon Sep 17 00:00:00 2001 From: Jesse Smith Date: Sun, 13 Jan 2019 12:24:12 -0400 Subject: [PATCH 10/13] Use defined constant for field length for easier updating/patching in sulogin.c --- src/sulogin.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/sulogin.c b/src/sulogin.c index 612f7e7..4200f8e 100644 --- a/src/sulogin.c +++ b/src/sulogin.c @@ -72,6 +72,8 @@ # include #endif +#define PASSWORD_LENGTH 256 + #include "consoles.h" #define CONMAX 16 @@ -418,8 +420,8 @@ struct passwd *getrootpwent(int try_manually) struct passwd *pw; struct spwd *spw; FILE *fp; - static char line[256]; - static char sline[256]; + static char line[PASSWORD_LENGTH]; + static char sline[PASSWORD_LENGTH]; char *p; /* @@ -453,7 +455,7 @@ struct passwd *getrootpwent(int try_manually) /* * Find root in the password file. */ - while((p = fgets(line, 256, fp)) != NULL) { + while((p = fgets(line, PASSWORD_LENGTH, fp)) != NULL) { if (strncmp(line, "root:", 5) != 0) continue; p += 5; @@ -487,7 +489,7 @@ struct passwd *getrootpwent(int try_manually) fprintf(stderr, "sulogin: %s: root password garbled\n\r", F_PASSWD); return &pwd; } - while((p = fgets(sline, 256, fp)) != NULL) { + while((p = fgets(sline, PASSWORD_LENGTH, fp)) != NULL) { if (strncmp(sline, "root:", 5) != 0) continue; p += 5; From 483dc777d2c80552cff5a0368c05355bd7c13f95 Mon Sep 17 00:00:00 2001 From: Jesse Smith Date: Sun, 27 Jan 2019 15:55:08 -0400 Subject: [PATCH 11/13] Changed the way the "when" variable is used internally in shutdown.c. It starts as a NULL pointer, then might get set as a pointer to optarg, then it might get set to point to an argv parameter, then it might have a string value copied into it, over-writing the original data. We should not risk over-writing internal variables which might get used for something else (it's rude and security risk). Set up "when" as its own buffer that has data from optargs and/or argv copied into it. Minor code fixes across multiple source files to avoid buffer overflows, or uninitialized strings. --- doc/Changelog | 11 +++++++++++ src/killall5.c | 6 +++++- src/last.c | 17 +++++++++++------ src/logsave.c | 2 +- src/mountpoint.c | 8 ++++++-- src/shutdown.c | 32 ++++++++++++++++++-------------- 6 files changed, 52 insertions(+), 24 deletions(-) diff --git a/doc/Changelog b/doc/Changelog index 36601ec..36624c9 100644 --- a/doc/Changelog +++ b/doc/Changelog @@ -21,6 +21,17 @@ sysvinit (2.94) unreleased; urgency=low * Added logsave.c and logsave.8 manual page from e2fsprogs to make sure logsave is available to initscripts. * Updated src/Makefile to make sure bootlogd compiles with Clang. + * Use defined constants for password length in sulogin. Makes + it easier to update/patch later. + * Minor code fixes across multiple source files to avoid buffer + overflows, or uninitialized strings. + * Changed the way the "when" variable is used internally in shutdown.c. + It starts as a NULL pointer, then might get set as a pointer to optarg, + then it might get set to point to an argv parameter, then it might have + a string value copied into it, over-writing the original data. We should + not risk over-writing internal variables which might get used for something + else (it's rude and security risk). Set up "when" as its own buffer + that has data from optargs and/or argv copied into it. sysvinit (2.93) released; urgency=low diff --git a/src/killall5.c b/src/killall5.c index d8a399e..8f2ad50 100644 --- a/src/killall5.c +++ b/src/killall5.c @@ -433,7 +433,11 @@ int check4nfs(const char * path, char * real) } while (1); - if (real) strcpy(real, curr); + if (real) /* real is defined elsewhere as being PATH_MAX + 1 */ + { + memset(real, '\0', PATH_MAX + 1); + strncpy(real, curr, PATH_MAX); + } if (errno == EINVAL) { const size_t nlen = strlen(curr); diff --git a/src/last.c b/src/last.c index 5252015..1c028cc 100644 --- a/src/last.c +++ b/src/last.c @@ -48,6 +48,10 @@ # define SHUTDOWN_TIME 254 #endif +#ifndef PATH_MAX +#define PATH_MAX 2048 +#endif + char *Version = "@(#) last 2.85 31-Apr-2004 miquels"; #define CHOP_DOMAIN 0 /* Define to chop off local domainname. */ @@ -253,10 +257,11 @@ int uread(FILE *fp, struct utmp *u, int *quit) #define BTMP_FILE getbtmp() char *getbtmp() { - static char btmp[128]; + static char btmp[PATH_MAX + 5]; /* max path + btmp + null terminator */ char *p; - strcpy(btmp, WTMP_FILE); + memset(btmp, '\0', PATH_MAX + 5); + strncpy(btmp, WTMP_FILE, PATH_MAX); if ((p = strrchr(btmp, '/')) == NULL) p = btmp; else @@ -841,7 +846,7 @@ int main(int argc, char **argv) switch (ut.ut_type) { case SHUTDOWN_TIME: if (extended) { - strcpy(ut.ut_line, "system down"); + strncpy(ut.ut_line, "system down", OLD_LINESIZE - 1); quit = list(&ut, lastboot, R_NORMAL); } lastdown = lastrch = ut.ut_time; @@ -850,14 +855,14 @@ int main(int argc, char **argv) case OLD_TIME: case NEW_TIME: if (extended) { - strcpy(ut.ut_line, + strncpy(ut.ut_line, ut.ut_type == NEW_TIME ? "new time" : - "old time"); + "old time", OLD_LINESIZE - 1); quit = list(&ut, lastdown, R_TIMECHANGE); } break; case BOOT_TIME: - strcpy(ut.ut_line, "system boot"); + strncpy(ut.ut_line, "system boot", OLD_LINESIZE - 1); quit = list(&ut, lastdown, R_REBOOT); lastboot = ut.ut_time; down = 1; diff --git a/src/logsave.c b/src/logsave.c index 0c9b1fd..1c52245 100644 --- a/src/logsave.c +++ b/src/logsave.c @@ -282,7 +282,7 @@ int main(int argc, char **argv) outfn = argv[optind]; optind++; argv += optind; - argc -= optind; + /* argc -= optind; - this is not used */ outfd = open(outfn, openflags, 0644); do_stdin = !strcmp(argv[0], "-"); diff --git a/src/mountpoint.c b/src/mountpoint.c index 3daf470..b24335e 100644 --- a/src/mountpoint.c +++ b/src/mountpoint.c @@ -32,6 +32,10 @@ #include #include +#ifndef PATH_MAX +#define PATH_MAX 2048 +#endif + int dostat(char *path, struct stat *st, int do_lstat, int quiet) { int n; @@ -105,7 +109,7 @@ void usage(void) { int main(int argc, char **argv) { struct stat st, st2; - char buf[256]; + char buf[PATH_MAX + 1]; char *path; int quiet = 0; int showdev = 0; @@ -163,7 +167,7 @@ int main(int argc, char **argv) memset(buf, 0, sizeof(buf)); strncpy(buf, path, sizeof(buf) - 4); - strcat(buf, "/.."); + strncat(buf, "/..", 3); if (dostat(buf, &st2, 0, quiet) < 0) return 1; diff --git a/src/shutdown.c b/src/shutdown.c index 0e6f450..b744a2c 100644 --- a/src/shutdown.c +++ b/src/shutdown.c @@ -70,6 +70,8 @@ extern char **environ; #endif #define MESSAGELEN 256 +#define STATELEN 64 +#define WHEN_SIZE 64 /* Whether we should warn system is shutting down */ #define QUIET_FULL 2 @@ -83,7 +85,7 @@ int fastboot = 0; /* Do a 'fast' reboot */ int forcefsck = 0; /* Force fsck on reboot */ char message[MESSAGELEN]; /* Warning message */ char *sltime = 0; /* Sleep time */ -char newstate[64]; /* What are we gonna do */ +char newstate[STATELEN]; /* What are we gonna do */ int doself = 0; /* Don't use init */ int got_alrm = 0; @@ -232,11 +234,11 @@ int init_setenv(char *name, char *value) */ void issue_warn(int mins) { - char buf[MESSAGELEN + sizeof(newstate)]; + char buf[MESSAGELEN + sizeof(newstate) + 1]; int len; buf[0] = 0; - strncat(buf, message, sizeof(buf) - 1); + strncpy(buf, message, MESSAGELEN); len = strlen(buf); if (mins == 0) @@ -519,7 +521,7 @@ int main(int argc, char **argv) char buf[128]; char term[UT_LINESIZE + 6]; char *sp; - char *when = NULL; + char when[WHEN_SIZE]; int c, i, wt; int hours, mins; int didnolog = 0; @@ -547,6 +549,7 @@ int main(int argc, char **argv) } strcpy(down_level, "1"); halttype = NULL; + memset(when, '\0', WHEN_SIZE); /* Process the options. */ while((c = getopt(argc, argv, "HPacqQkrhnfFyt:g:i:")) != EOF) { @@ -593,7 +596,7 @@ int main(int argc, char **argv) case 'y': /* Ignored for sysV compatibility */ break; case 'g': /* sysv style to specify time. */ - when = optarg; + strncpy(when, optarg, WHEN_SIZE - 1); break; case 'i': /* Level to go to. */ if (!strchr("0156aAbBcCsS", optarg[0])) { @@ -679,7 +682,7 @@ int main(int argc, char **argv) /* Read remaining words, skip time if needed. */ message[0] = 0; - for(c = optind + (!cancel && !when); c < argc; c++) { + for(c = optind + (!cancel && !when[0]); c < argc; c++) { if (strlen(message) + strlen(argv[c]) + 4 > MESSAGELEN) break; strcat(message, argv[c]); @@ -704,9 +707,9 @@ int main(int argc, char **argv) } /* Check syntax. */ - if (when == NULL) { + if (when[0] == '\0') { if (optind == argc) usage(); - when = argv[optind++]; + strncpy(when, argv[optind++], WHEN_SIZE - 1); } /* See if we are already running. */ @@ -725,16 +728,16 @@ int main(int argc, char **argv) /* Tell users what we're gonna do. */ switch(down_level[0]) { case '0': - strcpy(newstate, "for system halt"); + strncpy(newstate, "for system halt", STATELEN); break; case '6': - strcpy(newstate, "for reboot"); + strncpy(newstate, "for reboot", STATELEN); break; case '1': - strcpy(newstate, "to maintenance mode"); + strncpy(newstate, "to maintenance mode", STATELEN); break; default: - sprintf(newstate, "to runlevel %s", down_level); + snprintf(newstate, STATELEN, "to runlevel %s", down_level); break; } @@ -772,10 +775,11 @@ int main(int argc, char **argv) /* Alias now and take care of old '+mins' notation. */ if (!strcmp(when, "now")) strcpy(when, "0"); - if (when[0] == '+') when++; + sp = when; + if (when[0] == '+') sp++; /* Decode shutdown time. */ - for (sp = when; *sp; sp++) { + for ( ; *sp; sp++) { if (*sp != ':' && (*sp < '0' || *sp > '9')) usage(); } From 09f8dcc90e03b16b2fe330818892dc9237368d77 Mon Sep 17 00:00:00 2001 From: Jesse Smith Date: Sun, 27 Jan 2019 16:04:13 -0400 Subject: [PATCH 12/13] Updated wall.c to make it easier to adjust buffer sizes without causing overflow or off-by-one errors. --- src/wall.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/wall.c b/src/wall.c index 4352b0f..d3a2c70 100644 --- a/src/wall.c +++ b/src/wall.c @@ -34,12 +34,13 @@ #define MAXLEN 4096 +#define LINE_SIZE 80 #define MAXLINES 20 int main(int argc, char **argv) { char buf[MAXLEN]; - char line[83]; + char line[LINE_SIZE + 3]; /* leave room for \r\n\0 */ int i, f, ch; int len = 0; int remote = 0; @@ -81,7 +82,7 @@ int main(int argc, char **argv) if ((argc - optind) > 0) { for(f = optind; f < argc; f++) { len += strlen(argv[f]) + 1; - if (len >= MAXLEN-2) break; + if (len >= MAXLEN-4) break; strcat(buf, argv[f]); if (f < argc-1) strcat(buf, " "); } From aa3b8121e1d1084e760b6ac1dcb69f9f3a343a06 Mon Sep 17 00:00:00 2001 From: Jesse Smith Date: Sun, 17 Feb 2019 21:51:13 -0400 Subject: [PATCH 13/13] Fixed typo in init.8 manual page. --- doc/Changelog | 1 + man/init.8 | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/doc/Changelog b/doc/Changelog index 36624c9..885b1e9 100644 --- a/doc/Changelog +++ b/doc/Changelog @@ -32,6 +32,7 @@ sysvinit (2.94) unreleased; urgency=low not risk over-writing internal variables which might get used for something else (it's rude and security risk). Set up "when" as its own buffer that has data from optargs and/or argv copied into it. + * Fixed typo in init.8 manual page. sysvinit (2.93) released; urgency=low diff --git a/man/init.8 b/man/init.8 index cbfbf07..594784b 100644 --- a/man/init.8 +++ b/man/init.8 @@ -276,7 +276,7 @@ On receipt of this signals, init closes and re-opens its control fifo, .TP 0.5i .B SIGUSR2 When init receives SIGUSR2, init closes and leaves the control fifo, -\fB/run/initctl\f\P, closed. This may be used to make sure init is not +\fB/run/initctl\fP, closed. This may be used to make sure init is not holding open any files. However, it also prevents init from switching runlevels. Which means commands like shutdown no longer work. The fifo can be re-opened by sending init the SIGUSR1 signal.