boottrace: annotate init and shutdown utilities

Add boottrace annotations to record events in init(8), shutdown(8), and
reboot(8).

Sponsored by:	NetApp, Inc.
Sponsored by:	Klara, Inc.
X-NetApp-PR:	#23
Differential Revision:	https://reviews.freebsd.org/D31928
This commit is contained in:
Mitchell Horne 2022-02-21 20:16:07 -04:00
parent 5a8fceb3bd
commit 7b0a665d72
4 changed files with 137 additions and 13 deletions

View File

@ -47,21 +47,26 @@ static const char rcsid[] =
#endif /* not lint */
#include <sys/param.h>
#include <sys/boottrace.h>
#include <sys/ioctl.h>
#include <sys/mman.h>
#include <sys/mount.h>
#include <sys/sysctl.h>
#include <sys/wait.h>
#include <sys/reboot.h>
#include <sys/stat.h>
#include <sys/sysctl.h>
#include <sys/uio.h>
#include <sys/wait.h>
#include <db.h>
#include <err.h>
#include <errno.h>
#include <fcntl.h>
#include <kenv.h>
#include <libutil.h>
#include <paths.h>
#include <signal.h>
#include <stdarg.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@ -69,10 +74,6 @@ static const char rcsid[] =
#include <time.h>
#include <ttyent.h>
#include <unistd.h>
#include <sys/reboot.h>
#include <err.h>
#include <stdarg.h>
#ifdef SECURE
#include <pwd.h>
@ -213,6 +214,8 @@ main(int argc, char *argv[])
if (getuid() != 0)
errx(1, "%s", strerror(EPERM));
BOOTTRACE("init(8) starting...");
/* System V users like to reexec init. */
if (getpid() != 1) {
#ifdef COMPAT_SYSV_INIT
@ -876,6 +879,7 @@ single_user(void)
if (Reboot) {
/* Instead of going single user, let's reboot the machine */
BOOTTRACE("shutting down the system");
sync();
/* Run scripts after all processes have been terminated. */
runfinal();
@ -887,6 +891,7 @@ single_user(void)
_exit(0); /* panic as well */
}
BOOTTRACE("going to single user mode");
shell = get_shell();
if ((pid = fork()) == 0) {
@ -1028,8 +1033,10 @@ runcom(void)
{
state_func_t next_transition;
BOOTTRACE("/etc/rc starting...");
if ((next_transition = run_script(_PATH_RUNCOM)) != NULL)
return next_transition;
BOOTTRACE("/etc/rc finished");
runcom_mode = AUTOBOOT; /* the default */
return (state_func_t) read_ttys;
@ -1598,6 +1605,59 @@ collect_child(pid_t pid)
add_session(sp);
}
static const char *
get_current_state(void)
{
if (current_state == single_user)
return ("single-user");
if (current_state == runcom)
return ("runcom");
if (current_state == read_ttys)
return ("read-ttys");
if (current_state == multi_user)
return ("multi-user");
if (current_state == clean_ttys)
return ("clean-ttys");
if (current_state == catatonia)
return ("catatonia");
if (current_state == death)
return ("death");
if (current_state == death_single)
return ("death-single");
return ("unknown");
}
static void
boottrace_transition(int sig)
{
const char *action;
switch (sig) {
case SIGUSR2:
action = "halt & poweroff";
break;
case SIGUSR1:
action = "halt";
break;
case SIGINT:
action = "reboot";
break;
case SIGWINCH:
action = "powercycle";
break;
case SIGTERM:
action = Reboot ? "reboot" : "single-user";
break;
default:
BOOTTRACE("signal %d from %s", sig, get_current_state());
return;
}
/* Trace the shutdown reason. */
SHUTTRACE("%s from %s", action, get_current_state());
}
/*
* Catch a signal and request a state transition.
*/
@ -1605,6 +1665,7 @@ static void
transition_handler(int sig)
{
boottrace_transition(sig);
switch (sig) {
case SIGHUP:
if (current_state == read_ttys || current_state == multi_user ||
@ -1648,6 +1709,7 @@ transition_handler(int sig)
static state_func_t
multi_user(void)
{
static bool inmultiuser = false;
pid_t pid;
session_t *sp;
@ -1677,6 +1739,11 @@ multi_user(void)
add_session(sp);
}
if (requested_transition == 0 && !inmultiuser) {
inmultiuser = true;
/* This marks the change from boot-time tracing to run-time. */
RUNTRACE("multi-user start");
}
while (!requested_transition)
if ((pid = waitpid(-1, (int *) 0, 0)) != -1)
collect_child(pid);
@ -1843,6 +1910,7 @@ death_single(void)
revoke(_PATH_CONSOLE);
BOOTTRACE("start killing user processes");
for (i = 0; i < 2; ++i) {
if (kill(-1, death_sigs[i]) == -1 && errno == ESRCH)
return (state_func_t) single_user;
@ -1894,6 +1962,8 @@ runshutdown(void)
char *argv[4];
struct stat sb;
BOOTTRACE("init(8): start rc.shutdown");
/*
* rc.shutdown is optional, so to prevent any unnecessary
* complaints from the shell we simply don't run it if the
@ -1944,6 +2014,8 @@ runshutdown(void)
kill(wpid, SIGTERM);
warning("timeout expired for %s: %m; going to "
"single user mode", _PATH_RUNDOWN);
BOOTTRACE("rc.shutdown's %d sec timeout expired",
shutdowntimeout);
return -1;
}
if (wpid == -1) {

View File

@ -43,10 +43,12 @@ static char sccsid[] = "@(#)reboot.c 8.1 (Berkeley) 6/5/93";
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
#include <sys/reboot.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/boottrace.h>
#include <sys/reboot.h>
#include <sys/sysctl.h>
#include <sys/time.h>
#include <signal.h>
#include <err.h>
#include <errno.h>
@ -210,10 +212,12 @@ main(int argc, char *argv[])
}
/* Just stop init -- if we fail, we'll restart it. */
BOOTTRACE("SIGTSTP to init(8)...");
if (kill(1, SIGTSTP) == -1)
err(1, "SIGTSTP init");
/* Send a SIGTERM first, a chance to save the buffers. */
BOOTTRACE("SIGTERM to all other processes...");
if (kill(-1, SIGTERM) == -1 && errno != ESRCH)
err(1, "SIGTERM processes");
@ -235,6 +239,7 @@ main(int argc, char *argv[])
}
for (i = 1;; ++i) {
BOOTTRACE("SIGKILL to all other processes(%d)...", i);
if (kill(-1, SIGKILL) == -1) {
if (errno == ESRCH)
break;
@ -252,6 +257,7 @@ main(int argc, char *argv[])
/* FALLTHROUGH */
restart:
BOOTTRACE("SIGHUP to init(8)...");
sverrno = errno;
errx(1, "%s%s", kill(1, SIGHUP) == -1 ? "(can't restart init): " : "",
strerror(sverrno));

View File

@ -44,9 +44,10 @@ static char sccsid[] = "@(#)shutdown.c 8.4 (Berkeley) 4/28/95";
__FBSDID("$FreeBSD$");
#include <sys/param.h>
#include <sys/time.h>
#include <sys/boottrace.h>
#include <sys/resource.h>
#include <sys/syslog.h>
#include <sys/time.h>
#include <ctype.h>
#include <err.h>
@ -221,10 +222,13 @@ main(int argc, char **argv)
}
mbuflen = strlen(mbuf);
if (offset)
if (offset) {
BOOTTRACE("Shutdown at %s", ctime(&shuttime));
(void)printf("Shutdown at %.24s.\n", ctime(&shuttime));
else
} else {
BOOTTRACE("Shutdown NOW!");
(void)printf("Shutdown NOW!\n");
}
if (!(whom = getlogin()))
whom = (pw = getpwuid(getuid())) ? pw->pw_name : "???";
@ -360,12 +364,16 @@ die_you_gravy_sucking_pig_dog(void)
{
char *empty_environ[] = { NULL };
BOOTTRACE("%s by %s",
doreboot ? "reboot" : dohalt ? "halt" : dopower ? "power-down" :
docycle ? "power-cycle" : "shutdown", whom);
syslog(LOG_NOTICE, "%s by %s: %s",
doreboot ? "reboot" : dohalt ? "halt" : dopower ? "power-down" :
docycle ? "power-cycle" : "shutdown", whom, mbuf);
(void)printf("\r\nSystem shutdown time has arrived\007\007\r\n");
if (killflg) {
BOOTTRACE("fake shutdown...");
(void)printf("\rbut you'll have to do it yourself\r\n");
exit(0);
}
@ -383,6 +391,7 @@ die_you_gravy_sucking_pig_dog(void)
(void)printf("\nkill -HUP 1\n");
#else
if (!oflag) {
BOOTTRACE("signal to init(8)...");
(void)kill(1, doreboot ? SIGINT : /* reboot */
dohalt ? SIGUSR1 : /* halt */
dopower ? SIGUSR2 : /* power-down */
@ -390,6 +399,7 @@ die_you_gravy_sucking_pig_dog(void)
SIGTERM); /* single-user */
} else {
if (doreboot) {
BOOTTRACE("exec reboot(8) -l...");
execle(_PATH_REBOOT, "reboot", "-l", nosync,
(char *)NULL, empty_environ);
syslog(LOG_ERR, "shutdown: can't exec %s: %m.",
@ -397,6 +407,7 @@ die_you_gravy_sucking_pig_dog(void)
warn(_PATH_REBOOT);
}
else if (dohalt) {
BOOTTRACE("exec halt(8) -l...");
execle(_PATH_HALT, "halt", "-l", nosync,
(char *)NULL, empty_environ);
syslog(LOG_ERR, "shutdown: can't exec %s: %m.",
@ -404,6 +415,7 @@ die_you_gravy_sucking_pig_dog(void)
warn(_PATH_HALT);
}
else if (dopower) {
BOOTTRACE("exec halt(8) -l -p...");
execle(_PATH_HALT, "halt", "-l", "-p", nosync,
(char *)NULL, empty_environ);
syslog(LOG_ERR, "shutdown: can't exec %s: %m.",
@ -417,6 +429,7 @@ die_you_gravy_sucking_pig_dog(void)
_PATH_HALT);
warn(_PATH_HALT);
}
BOOTTRACE("SIGTERM to init(8)...");
(void)kill(1, SIGTERM); /* to single-user */
}
#endif

View File

@ -36,9 +36,42 @@
#define BT_EVENT_NAMELEN 40
#define BT_MSGLEN (BT_EVENT_NAMELEN + 1 + BT_EVENT_TDNAMELEN)
#ifdef _KERNEL
#ifndef _KERNEL
#include <stdarg.h>
#include <stdio.h>
#include <string.h>
#include <sys/sysctl.h>
/*
* Convenience macros.
* Convenience macros. Userland API.
*/
#define BOOTTRACE(...) _boottrace(_BOOTTRACE_BOOTTRACE, __VA_ARGS__)
#define RUNTRACE(...) _boottrace(_BOOTTRACE_RUNTRACE, __VA_ARGS__)
#define SHUTTRACE(...) _boottrace(_BOOTTRACE_SHUTTRACE, __VA_ARGS__)
/*
* Call the requested boottrace sysctl with provided va-formatted message.
*/
static __inline void
_boottrace(const char *sysctlname, const char *fmt, ...)
{
va_list ap;
char msg[BT_MSGLEN];
int len;
va_start(ap, fmt);
len = vsnprintf(msg, sizeof(msg), fmt, ap);
va_end(ap);
/* Log the event, even if truncated. */
if (len >= 0)
(void)sysctlbyname(sysctlname, NULL, NULL, msg, strlen(msg));
}
#else /* _KERNEL */
/*
* Convenience macros. Kernel API.
*/
#define _BOOTTRACE(tdname, ...) do { \
if (boottrace_enabled) \