init: execute /etc/rc.final after all user processes have terminated
This can be useful for, e.g., unmounting filesystems that were needed for shutdown. Reviewed by: kib Sponsored by: NetApp, Inc. Sponsored by: Klara, Inc. X-NetApp-PR: #63 Differential Revision: https://reviews.freebsd.org/D31230
This commit is contained in:
parent
67a51854e8
commit
4d15976919
|
@ -31,7 +31,7 @@
|
|||
.\" @(#)init.8 8.3 (Berkeley) 4/18/94
|
||||
.\" $FreeBSD$
|
||||
.\"
|
||||
.Dd August 6, 2019
|
||||
.Dd July 22, 2021
|
||||
.Dt INIT 8
|
||||
.Os
|
||||
.Sh NAME
|
||||
|
@ -279,6 +279,14 @@ Otherwise,
|
|||
.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 @@ It is used for running the
|
|||
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 @@ the terminal initialization information file
|
|||
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
|
||||
|
|
|
@ -109,6 +109,7 @@ static void disaster(int);
|
|||
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 @@ single_user(void)
|
|||
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,51 @@ setprocresources(const char *cname)
|
|||
}
|
||||
}
|
||||
#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;
|
||||
if (access(_PATH_RUNFINAL, X_OK) != 0) {
|
||||
warning("%s exists, but not executable", _PATH_RUNFINAL);
|
||||
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, NULL);
|
||||
signal(SIGCHLD, SIG_DFL);
|
||||
execl(_PATH_RUNFINAL, _PATH_RUNFINAL, NULL);
|
||||
perror("execl(" _PATH_RUNFINAL ") failed");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/* Wait for rc.final script to exit */
|
||||
while ((other_pid = waitpid(-1, NULL, 0)) != pid && other_pid > 0) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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"
|
||||
|
|
Loading…
Reference in New Issue
Block a user