Index: sbin/init/init.8 =================================================================== --- sbin/init/init.8 +++ sbin/init/init.8 @@ -31,7 +31,7 @@ .\" @(#)init.8 8.3 (Berkeley) 4/18/94 .\" $FreeBSD$ .\" -.Dd August 6, 2019 +.Dd July 20, 2021 .Dt INIT 8 .Os .Sh NAME @@ -279,6 +279,14 @@ .Dq Li reboot argument is used. .Pp +After all user processes have been terminated, +.Nm +will try to run the +.Pa /etc/rc.final +script. +This script can be used to finally prepare and unmount filesystems that may have +been needed during shutdown, for instance. +.Pp The role of .Nm is so critical that if it dies, the system will reboot itself @@ -371,9 +379,10 @@ or .Va init_script if set, as well as for the -.Pa /etc/rc +.Pa /etc/rc , +.Pa /etc/rc.shutdown , and -.Pa /etc/rc.shutdown +.Pa /etc/rc.final scripts. The value of the corresponding .Xr kenv 2 @@ -403,6 +412,8 @@ system startup commands .It Pa /etc/rc.shutdown system shutdown commands +.It Pa /etc/rc.final +system shutdown commands (after process termination) .It Pa /var/log/init.log log of .Xr rc 8 Index: sbin/init/init.c =================================================================== --- sbin/init/init.c +++ sbin/init/init.c @@ -109,6 +109,7 @@ static void revoke_ttys(void); static int runshutdown(void); static char *strk(char *); +static void runfinal(void); /* * We really need a recursive typedef... @@ -876,6 +877,8 @@ if (Reboot) { /* Instead of going single user, let's reboot the machine */ sync(); + /* Run scripts after all processes have been terminated. */ + runfinal(); if (reboot(howto) == -1) { emergency("reboot(%#x) failed, %m", howto); _exit(1); /* panic and reboot */ @@ -2039,3 +2042,48 @@ } } #endif + +/* + * Run /etc/rc.final to execute scripts after all user processes have been + * terminated. + */ +static void +runfinal(void) +{ + struct stat sb; + pid_t other_pid, pid; + sigset_t mask; + + /* Avoid any surprises. */ + alarm(0); + + /* rc.final is optional. */ + if (stat(_PATH_RUNFINAL, &sb) == -1 && errno == ENOENT) + return; + + pid = fork(); + if (pid == 0) { + /* + * Reopen stdin/stdout/stderr so that scripts can write to + * console. + */ + close(0); + open(_PATH_DEVNULL, O_RDONLY); + close(1); + close(2); + open_console(); + dup2(1, 2); + sigemptyset(&mask); + sigprocmask(SIG_SETMASK, &mask, (sigset_t *) 0); + signal(SIGCHLD, SIG_DFL); + execl(_PATH_RUNFINAL, _PATH_RUNFINAL, NULL); + perror("execl failed"); + exit(1); + } + + /* Wait for rc.final script to exit */ + while ((other_pid = waitpid(-1, (int *)0, 0)) != pid && + other_pid > 0) { + continue; + } +} Index: sbin/init/pathnames.h =================================================================== --- sbin/init/pathnames.h +++ sbin/init/pathnames.h @@ -41,5 +41,6 @@ #define _PATH_SLOGGER "/sbin/session_logger" #define _PATH_RUNCOM "/etc/rc" #define _PATH_RUNDOWN "/etc/rc.shutdown" +#define _PATH_RUNFINAL "/etc/rc.final" #define _PATH_REROOT "/dev/reroot" #define _PATH_REROOT_INIT _PATH_REROOT "/init"