From 7689106aa10f7852b707b4c21ec080ccb2767280 Mon Sep 17 00:00:00 2001 From: William Hubbs Date: Fri, 2 Jun 2017 14:07:40 -0500 Subject: [PATCH] add support for writing reboot and shutdown records to wtmp --- src/includes/rc-wtmp.h | 26 +++++++++++++++++ src/rc/Makefile | 6 ++-- src/rc/openrc-init.c | 2 ++ src/rc/openrc-shutdown.c | 61 ++++++++++++++++++++++++++-------------- src/rc/rc-wtmp.c | 50 ++++++++++++++++++++++++++++++++ 5 files changed, 121 insertions(+), 24 deletions(-) create mode 100644 src/includes/rc-wtmp.h create mode 100644 src/rc/rc-wtmp.c diff --git a/src/includes/rc-wtmp.h b/src/includes/rc-wtmp.h new file mode 100644 index 00000000..6645774b --- /dev/null +++ b/src/includes/rc-wtmp.h @@ -0,0 +1,26 @@ +/* + * rc-wtmp.h + * This is private to us and not for user consumption +*/ + +/* + * Copyright (c) 2017 The OpenRC Authors. + * See the Authors file at the top-level directory of this distribution and + * https://github.com/OpenRC/openrc/blob/master/AUTHORS + * + * This file is part of OpenRC. It is subject to the license terms in + * the LICENSE file found in the top-level directory of this + * distribution and at https://github.com/OpenRC/openrc/blob/master/LICENSE + * This file may not be copied, modified, propagated, or distributed + * except according to the terms contained in the LICENSE file. + */ + +#ifndef __RC_WTMP_H__ +#define __RC_WTMP_H__ + +#include + +void log_wtmp(const char *user, const char *id, pid_t pid, int type, + const char *line); + +#endif diff --git a/src/rc/Makefile b/src/rc/Makefile index 5874ed17..19adcafb 100644 --- a/src/rc/Makefile +++ b/src/rc/Makefile @@ -14,7 +14,7 @@ SRCS+= rc-selinux.c endif ifeq (${OS},Linux) -SRCS+= kill_all.c openrc-init.c openrc-shutdown.c +SRCS+= kill_all.c openrc-init.c openrc-shutdown.c rc-wtmp.c endif CLEANFILES= version.h rc-selinux.o @@ -111,7 +111,7 @@ veinfo vewarn vebegin veend vewend veindent veoutdent: do_e.o rc-misc.o fstabinfo: fstabinfo.o _usage.o rc-misc.o ${CC} ${LOCAL_CFLAGS} ${LOCAL_LDFLAGS} ${CFLAGS} ${LDFLAGS} -o $@ $^ ${LDADD} -openrc-init: openrc-init.o +openrc-init: openrc-init.o rc-wtmp.o ${CC} ${LOCAL_CFLAGS} ${LOCAL_LDFLAGS} ${CFLAGS} ${LDFLAGS} -o $@ $^ ${LDADD} is_newer_than: is_newer_than.o rc-misc.o @@ -132,7 +132,7 @@ mountinfo: mountinfo.o _usage.o rc-misc.o openrc rc: rc.o rc-logger.o rc-misc.o rc-plugin.o _usage.o ${CC} ${LOCAL_CFLAGS} ${LOCAL_LDFLAGS} ${CFLAGS} ${LDFLAGS} -o $@ $^ ${LDADD} -openrc-shutdown: openrc-shutdown.o _usage.o +openrc-shutdown: openrc-shutdown.o _usage.o rc-wtmp.o ${CC} ${LOCAL_CFLAGS} ${LOCAL_LDFLAGS} ${CFLAGS} ${LDFLAGS} -o $@ $^ ${LDADD} openrc-run runscript: openrc-run.o _usage.o rc-misc.o rc-plugin.o diff --git a/src/rc/openrc-init.c b/src/rc/openrc-init.c index 003ce31f..eb346f59 100644 --- a/src/rc/openrc-init.c +++ b/src/rc/openrc-init.c @@ -32,6 +32,7 @@ #include "helpers.h" #include "rc.h" +#include "rc-wtmp.h" #include "version.h" static const char *rc_default_runlevel = "default"; @@ -82,6 +83,7 @@ static void init(const char *default_runlevel) } pid = do_openrc(runlevel); waitpid(pid, NULL, 0); + log_wtmp("reboot", "~~", 0, RUN_LVL, "~~"); } static void handle_reexec(char *my_name) diff --git a/src/rc/openrc-shutdown.c b/src/rc/openrc-shutdown.c index ecb251a8..4ba619c5 100644 --- a/src/rc/openrc-shutdown.c +++ b/src/rc/openrc-shutdown.c @@ -27,46 +27,63 @@ #include #include #include +#include #include "einfo.h" #include "rc.h" #include "helpers.h" #include "_usage.h" +#include "rc-wtmp.h" const char *applet = NULL; const char *extraopts = NULL; -const char *getoptstring = "dHkpRr" getoptstring_COMMON; +const char *getoptstring = "dDHKpRrw" getoptstring_COMMON; const struct option longopts[] = { - { "dry-run", no_argument, NULL, 'd'}, + { "no-write", no_argument, NULL, 'd'}, + { "dry-run", no_argument, NULL, 'D'}, { "halt", no_argument, NULL, 'H'}, - { "kexec", no_argument, NULL, 'k'}, + { "kexec", no_argument, NULL, 'K'}, { "poweroff", no_argument, NULL, 'p'}, { "reexec", no_argument, NULL, 'R'}, { "reboot", no_argument, NULL, 'r'}, + { "write-only", no_argument, NULL, 'w'}, longopts_COMMON }; const char * const longopts_help[] = { + "do not write wtmp record", "print actions instead of executing them", "halt the system", "reboot the system using kexec", "power off the system", "re-execute init (use after upgrading)", "reboot the system", + "write wtmp boot record and exit", longopts_help_COMMON }; const char *usagestring = NULL; const char *exclusive = "Select one of " "--halt, --kexec, --poweroff, --reexec or --reboot"; -static void send_cmd(const char *cmd, bool dryrun) +static bool do_dryrun = false; +static bool do_halt = false; +static bool do_kexec = false; +static bool do_poweroff = false; +static bool do_reboot = false; +static bool do_reexec = false; +static bool do_wtmp = true; +static bool do_wtmp_only = false; + +static void send_cmd(const char *cmd) { FILE *fifo; size_t ignored; - if (dryrun) { + if (do_dryrun) { einfo("Would send %s to init", cmd); return; } + if (do_wtmp && (do_halt || do_kexec || do_reboot || do_poweroff)) + log_wtmp("shutdown", "~~", 0, RUN_LVL, "~~"); fifo = fopen(RC_INIT_FIFO, "w"); if (!fifo) { perror("fopen"); @@ -83,26 +100,23 @@ int main(int argc, char **argv) { int opt; int cmd_count = 0; - bool do_dryrun = false; - bool do_halt = false; - bool do_kexec = false; - bool do_poweroff = false; - bool do_reboot = false; - bool do_reexec = false; applet = basename_c(argv[0]); while ((opt = getopt_long(argc, argv, getoptstring, longopts, (int *) 0)) != -1) { switch (opt) { - case 'd': + case 'd': + do_wtmp = false; + break; + case 'D': do_dryrun = true; break; case 'H': do_halt = true; cmd_count++; break; - case 'k': + case 'K': do_kexec = true; cmd_count++; break; @@ -118,26 +132,31 @@ int main(int argc, char **argv) do_reboot = true; cmd_count++; break; + case 'w': + do_wtmp_only = true; + break; case_RC_COMMON_GETOPT } } -if (geteuid() != 0 && ! do_dryrun) - eerrorx("%s: you must be root\n", applet); + if (geteuid() != 0 && ! do_dryrun) + eerrorx("%s: you must be root\n", applet); if (cmd_count > 1) { eerror("%s: %s\n", applet, exclusive); usage(EXIT_FAILURE); } if (do_halt) - send_cmd("halt", do_dryrun); + send_cmd("halt"); else if (do_kexec) - send_cmd("kexec", do_dryrun); + send_cmd("kexec"); else if (do_poweroff) - send_cmd("poweroff", do_dryrun); + send_cmd("poweroff"); else if (do_reboot) - send_cmd("reboot", do_dryrun); + send_cmd("reboot"); else if (do_reexec) - send_cmd("reexec", do_dryrun); + send_cmd("reexec"); + else if (do_wtmp_only) + log_wtmp("shutdown", "~~", 0, RUN_LVL, "~~"); else - send_cmd("single", do_dryrun); + send_cmd("single"); return 0; } diff --git a/src/rc/rc-wtmp.c b/src/rc/rc-wtmp.c new file mode 100644 index 00000000..913fa06b --- /dev/null +++ b/src/rc/rc-wtmp.c @@ -0,0 +1,50 @@ +/* + * rc-wtmp.c + * This file contains routines to deal with the wtmp file. + */ + +/* + * Copyright 2017 The OpenRC Authors. + * See the Authors file at the top-level directory of this distribution and + * https://github.com/OpenRC/openrc/blob/master/AUTHORS + * + * This file is part of OpenRC. It is subject to the license terms in + * the LICENSE file found in the top-level directory of this + * distribution and at https://github.com/OpenRC/openrc/blob/master/LICENSE + * This file may not be copied, modified, propagated, or distributed + * except according to the terms contained in the LICENSE file. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "rc-wtmp.h" + +void log_wtmp(const char *user, const char *id, pid_t pid, int type, + const char *line) +{ + struct timeval tv; + struct utmp utmp; + struct utsname uname_buf; + + memset(&utmp, 0, sizeof(utmp)); + gettimeofday(&tv, NULL); + utmp.ut_tv.tv_sec = tv.tv_sec; + utmp.ut_tv.tv_usec = tv.tv_usec; + utmp.ut_pid = pid; + utmp.ut_type = type; + strncpy(utmp.ut_name, user, sizeof(utmp.ut_name)); + strncpy(utmp.ut_id , id , sizeof(utmp.ut_id )); + strncpy(utmp.ut_line, line, sizeof(utmp.ut_line)); + + /* Put the OS version in place of the hostname */ + if (uname(&uname_buf) == 0) + strncpy(utmp.ut_host, uname_buf.release, sizeof(utmp.ut_host)); + + updwtmp(WTMP_FILE, &utmp); +}