Skip site navigation (1)Skip section navigation (2)
Date:      Fri, 23 Jul 2021 04:26:24 GMT
From:      Kyle Evans <kevans@FreeBSD.org>
To:        src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-main@FreeBSD.org
Subject:   git: 4d1597691916 - main - init: execute /etc/rc.final after all user processes have terminated
Message-ID:  <202107230426.16N4QOAE086636@gitrepo.freebsd.org>

next in thread | raw e-mail | index | archive | help
The branch main has been updated by kevans:

URL: https://cgit.FreeBSD.org/src/commit/?id=4d1597691916240b9023ee9f15e249503abf67fd

commit 4d1597691916240b9023ee9f15e249503abf67fd
Author:     Kyle Evans <kevans@FreeBSD.org>
AuthorDate: 2021-07-20 10:40:30 +0000
Commit:     Kyle Evans <kevans@FreeBSD.org>
CommitDate: 2021-07-23 04:26:11 +0000

    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
---
 sbin/init/init.8      | 17 ++++++++++++++---
 sbin/init/init.c      | 51 +++++++++++++++++++++++++++++++++++++++++++++++++++
 sbin/init/pathnames.h |  1 +
 3 files changed, 66 insertions(+), 3 deletions(-)

diff --git a/sbin/init/init.8 b/sbin/init/init.8
index d852c32ef487..9475b1cce48f 100644
--- a/sbin/init/init.8
+++ b/sbin/init/init.8
@@ -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
diff --git a/sbin/init/init.c b/sbin/init/init.c
index 943db9f26bd3..230c141bd351 100644
--- a/sbin/init/init.c
+++ b/sbin/init/init.c
@@ -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;
+	}
+}
diff --git a/sbin/init/pathnames.h b/sbin/init/pathnames.h
index 2ed366e4f7f7..7dc75ba52491 100644
--- a/sbin/init/pathnames.h
+++ b/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"



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?202107230426.16N4QOAE086636>