Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F148301939
D3693.id8834.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
11 KB
Referenced Files
None
Subscribers
None
D3693.id8834.diff
View Options
Index: sbin/init/Makefile
===================================================================
--- sbin/init/Makefile
+++ sbin/init/Makefile
@@ -2,12 +2,18 @@
# $FreeBSD$
PROG= init
+SRCS= init.c getmntopts.c
MAN= init.8
PRECIOUSPROG=
INSTALLFLAGS=-b -B.bak
CFLAGS+=-DDEBUGSHELL -DSECURE -DLOGIN_CAP -DCOMPAT_SYSV_INIT
LIBADD= util crypt
+# Needed for getmntopts.c
+MOUNT= ${.CURDIR}/../../sbin/mount
+CFLAGS+=-I${MOUNT}
+.PATH: ${MOUNT}
+
NO_SHARED?= YES
.include <bsd.prog.mk>
Index: sbin/init/init.c
===================================================================
--- sbin/init/init.c
+++ sbin/init/init.c
@@ -46,6 +46,7 @@
#include <sys/param.h>
#include <sys/ioctl.h>
+#include <sys/mman.h>
#include <sys/mount.h>
#include <sys/sysctl.h>
#include <sys/wait.h>
@@ -79,6 +80,7 @@
#include <login_cap.h>
#endif
+#include "mntopts.h"
#include "pathnames.h"
/*
@@ -122,6 +124,8 @@
static state_func_t catatonia(void);
static state_func_t death(void);
static state_func_t death_single(void);
+static state_func_t reroot(void);
+static state_func_t reroot_phase_two(void);
static state_func_t run_script(const char *);
@@ -193,7 +197,7 @@
{
state_t initial_transition = runcom;
char kenv_value[PATH_MAX];
- int c;
+ int c, error;
struct sigaction sa;
sigset_t mask;
@@ -226,6 +230,9 @@
case 'q': /* rescan /etc/ttys */
sig = SIGHUP;
break;
+ case 'r': /* remount root */
+ sig = SIGEMT;
+ break;
default:
goto invalid;
}
@@ -247,7 +254,7 @@
/*
* Create an initial session.
*/
- if (setsid() < 0)
+ if (setsid() < 0 && (errno != EPERM || getsid(0) != 1))
warning("initial setsid() failed: %m");
/*
@@ -261,7 +268,7 @@
* This code assumes that we always get arguments through flags,
* never through bits set in some random machine register.
*/
- while ((c = getopt(argc, argv, "dsf")) != -1)
+ while ((c = getopt(argc, argv, "dsfR")) != -1)
switch (c) {
case 'd':
devfs = 1;
@@ -272,6 +279,9 @@
case 'f':
runcom_mode = FASTBOOT;
break;
+ case 'R':
+ initial_transition = reroot_phase_two;
+ break;
default:
warning("unrecognized flag '-%c'", c);
break;
@@ -287,13 +297,13 @@
handle(badsys, SIGSYS, 0);
handle(disaster, SIGABRT, SIGFPE, SIGILL, SIGSEGV, SIGBUS, SIGXCPU,
SIGXFSZ, 0);
- handle(transition_handler, SIGHUP, SIGINT, SIGTERM, SIGTSTP, SIGUSR1,
- SIGUSR2, 0);
+ handle(transition_handler, SIGHUP, SIGINT, SIGEMT, SIGTERM, SIGTSTP,
+ SIGUSR1, SIGUSR2, 0);
handle(alrm_handler, SIGALRM, 0);
sigfillset(&mask);
delset(&mask, SIGABRT, SIGFPE, SIGILL, SIGSEGV, SIGBUS, SIGSYS,
- SIGXCPU, SIGXFSZ, SIGHUP, SIGINT, SIGTERM, SIGTSTP, SIGALRM,
- SIGUSR1, SIGUSR2, 0);
+ SIGXCPU, SIGXFSZ, SIGHUP, SIGINT, SIGEMT, SIGTERM, SIGTSTP,
+ SIGALRM, SIGUSR1, SIGUSR2, 0);
sigprocmask(SIG_SETMASK, &mask, (sigset_t *) 0);
sigemptyset(&sa.sa_mask);
sa.sa_flags = 0;
@@ -373,6 +383,16 @@
free(s);
}
+ if (initial_transition != reroot_phase_two) {
+ /*
+ * Unmount reroot leftovers. This runs after init(8)
+ * gets reexecuted after reroot_phase_two() is done.
+ */
+ error = unmount(_PATH_REROOT, MNT_FORCE);
+ if (error != 0 && errno != EINVAL)
+ warning("Cannot unmount %s: %m", _PATH_REROOT);
+ }
+
/*
* Start the state machine.
*/
@@ -620,6 +640,176 @@
write(STDERR_FILENO, message, strlen(message));
}
+static int
+read_file(const char *path, void **bufp, size_t *bufsizep)
+{
+ struct stat sb;
+ int error, fd;
+ size_t bufsize;
+ void *buf;
+ ssize_t nbytes;
+
+ fd = open(path, O_RDONLY);
+ if (fd < 0) {
+ emergency("%s: %s", path, strerror(errno));
+ return (-1);
+ }
+
+ error = fstat(fd, &sb);
+ if (error != 0) {
+ emergency("fstat: %s", strerror(errno));
+ return (error);
+ }
+
+ bufsize = sb.st_size;
+ buf = malloc(bufsize);
+ if (buf == NULL) {
+ emergency("malloc: %s", strerror(errno));
+ return (error);
+ }
+
+ nbytes = read(fd, buf, bufsize);
+ if (nbytes != (ssize_t)bufsize) {
+ emergency("read: %s", strerror(errno));
+ free(buf);
+ return (error);
+ }
+
+ error = close(fd);
+ if (error != 0) {
+ emergency("close: %s", strerror(errno));
+ free(buf);
+ return (error);
+ }
+
+ *bufp = buf;
+ *bufsizep = bufsize;
+
+ return (0);
+}
+
+static int
+create_file(const char *path, void *buf, size_t bufsize)
+{
+ int error, fd;
+ ssize_t nbytes;
+
+ fd = open(path, O_WRONLY | O_CREAT | O_EXCL, 0700);
+ if (fd < 0) {
+ emergency("%s: %s", path, strerror(errno));
+ return (-1);
+ }
+
+ nbytes = write(fd, buf, bufsize);
+ if (nbytes != (ssize_t)bufsize) {
+ emergency("write: %s", strerror(errno));
+ return (-1);
+ }
+
+ error = close(fd);
+ if (error != 0) {
+ emergency("close: %s", strerror(errno));
+ free(buf);
+ return (-1);
+ }
+
+ return (0);
+}
+
+static int
+mount_tmpfs(const char *fspath)
+{
+ struct iovec *iov = NULL;
+ char errmsg[255];
+ int error, iovlen = 0;
+
+ memset(errmsg, 0, sizeof(errmsg));
+
+ build_iovec(&iov, &iovlen, "fstype",
+ __DECONST(void *, "tmpfs"), (size_t)-1);
+ build_iovec(&iov, &iovlen, "fspath",
+ __DECONST(void *, fspath), (size_t)-1);
+ build_iovec(&iov, &iovlen, "errmsg",
+ errmsg, sizeof(errmsg));
+
+ error = nmount(iov, iovlen, 0);
+ if (error != 0) {
+ if (*errmsg != '\0') {
+ emergency("cannot mount tmpfs on %s: %s: %s",
+ fspath, errmsg, strerror(errno));
+ } else {
+ emergency("cannot mount tmpfs on %s: %s",
+ fspath, strerror(errno));
+ }
+ return (error);
+ }
+
+ return (0);
+}
+
+static state_func_t
+reroot(void)
+{
+ int error;
+ void *buf;
+ size_t bufsize;
+
+ runshutdown();
+
+ /*
+ * Copy the init binary into tmpfs, so that we can unmount
+ * the old rootfs without committing suicide.
+ */
+ error = read_file(_PATH_INIT, &buf, &bufsize);
+ if (error != 0)
+ goto out;
+ error = mount_tmpfs(_PATH_REROOT);
+ if (error != 0)
+ goto out;
+ error = create_file(_PATH_REROOT_INIT, buf, bufsize);
+ if (error != 0)
+ goto out;
+
+ /*
+ * Execute the temporary init.
+ */
+ execl(_PATH_REROOT_INIT, _PATH_REROOT_INIT, "-R", NULL);
+ emergency("cannot exec %s: %s", _PATH_REROOT_INIT, strerror(errno));
+
+out:
+ emergency("reroot failed; going to single user mode");
+
+ return (state_func_t) single_user;
+}
+
+static state_func_t
+reroot_phase_two(void)
+{
+ int error;
+
+ /*
+ * Ask the kernel to mount the new rootfs.
+ */
+ error = reboot(RB_REROOT);
+ if (error != 0) {
+ emergency("RB_REBOOT failed: %s", strerror(errno));
+ goto out;
+ }
+
+ /*
+ * Execute init(8) from the new rootfs.
+ *
+ * Note that at this point, all this warning() stuff is useless
+ * anyway; we don't have stderr nor stdout.
+ */
+ execl(_PATH_INIT, _PATH_INIT, NULL);
+ emergency("cannot exec %s: %s", _PATH_INIT, strerror(errno));
+
+out:
+ emergency("reroot failed; going to single user mode");
+ return (state_func_t) single_user;
+}
+
/*
* Bring the system up single user.
*/
@@ -1323,6 +1513,9 @@
current_state == multi_user || current_state == catatonia)
requested_transition = catatonia;
break;
+ case SIGEMT:
+ requested_transition = reroot;
+ break;
default:
requested_transition = 0;
break;
@@ -1486,21 +1679,7 @@
static state_func_t
death(void)
{
- session_t *sp;
-
- /*
- * Also revoke the TTY here. Because runshutdown() may reopen
- * the TTY whose getty we're killing here, there is no guarantee
- * runshutdown() will perform the initial open() call, causing
- * the terminal attributes to be misconfigured.
- */
- for (sp = sessions; sp; sp = sp->se_next) {
- sp->se_flags |= SE_SHUTDOWN;
- kill(sp->se_process, SIGHUP);
- revoke(sp->se_device);
- }
- /* Try to run the rc.shutdown script within a period of time */
runshutdown();
return (state_func_t) death_single;
@@ -1559,6 +1738,19 @@
const char *shell;
struct sigaction sa;
struct stat sb;
+ session_t *sp;
+
+ /*
+ * Also revoke the TTY here. Because runshutdown() may reopen
+ * the TTY whose getty we're killing here, there is no guarantee
+ * runshutdown() will perform the initial open() call, causing
+ * the terminal attributes to be misconfigured.
+ */
+ for (sp = sessions; sp; sp = sp->se_next) {
+ sp->se_flags |= SE_SHUTDOWN;
+ kill(sp->se_process, SIGHUP);
+ revoke(sp->se_device);
+ }
/*
* rc.shutdown is optional, so to prevent any unnecessary
Index: sbin/init/pathnames.h
===================================================================
--- sbin/init/pathnames.h
+++ sbin/init/pathnames.h
@@ -35,7 +35,10 @@
#include <paths.h>
-#define _PATH_INITLOG "/var/log/init.log"
-#define _PATH_SLOGGER "/sbin/session_logger"
-#define _PATH_RUNCOM "/etc/rc"
-#define _PATH_RUNDOWN "/etc/rc.shutdown"
+#define _PATH_INITLOG "/var/log/init.log"
+#define _PATH_SLOGGER "/sbin/session_logger"
+#define _PATH_RUNCOM "/etc/rc"
+#define _PATH_RUNDOWN "/etc/rc.shutdown"
+#define _PATH_INIT "/sbin/init"
+#define _PATH_REROOT "/dev/reroot"
+#define _PATH_REROOT_INIT _PATH_REROOT "/init"
Index: sbin/reboot/reboot.8
===================================================================
--- sbin/reboot/reboot.8
+++ sbin/reboot/reboot.8
@@ -28,7 +28,7 @@
.\" @(#)reboot.8 8.1 (Berkeley) 6/9/93
.\" $FreeBSD$
.\"
-.Dd October 11, 2010
+.Dd May 22, 2015
.Dt REBOOT 8
.Os
.Sh NAME
@@ -42,7 +42,7 @@
.Op Fl lnpq
.Op Fl k Ar kernel
.Nm
-.Op Fl dlnpq
+.Op Fl dlnpqr
.Op Fl k Ar kernel
.Nm fasthalt
.Op Fl lnpq
@@ -111,6 +111,12 @@
.Fl n
option is not specified).
This option should probably not be used.
+.It Fl r
+The system kills all processes, unmounts all filesystems, mounts the new
+root filesystem, and begins the usual startup sequence.
+It can be used after updating vfs.root.mountfrom using
+.Xr kenv 8 ,
+to change the root filesystem while preserving kernel state.
.El
.Pp
The
@@ -128,6 +134,13 @@
utility is used when the system needs to be halted or restarted, giving
users advance warning of their impending doom and cleanly terminating
specific programs.
+.Sh EXAMPLES
+Replace current root filesystem with UFS mounted from
+.Pa /dev/ada0s1a :
+.Bd -literal -offset indent
+kenv vfs.root.mountfrom=ufs:/dev/ada0s1a
+reboot -r
+.Ed
.Sh SEE ALSO
.Xr getutxent 3 ,
.Xr boot 8 ,
Index: sbin/reboot/reboot.c
===================================================================
--- sbin/reboot/reboot.c
+++ sbin/reboot/reboot.c
@@ -77,7 +77,7 @@
} else
howto = 0;
lflag = nflag = qflag = 0;
- while ((ch = getopt(argc, argv, "dk:lnpq")) != -1)
+ while ((ch = getopt(argc, argv, "dk:lnpqr")) != -1)
switch(ch) {
case 'd':
howto |= RB_DUMP;
@@ -98,6 +98,9 @@
case 'q':
qflag = 1;
break;
+ case 'r':
+ howto |= RB_REROOT;
+ break;
case '?':
default:
usage();
@@ -107,6 +110,8 @@
if ((howto & (RB_DUMP | RB_HALT)) == (RB_DUMP | RB_HALT))
errx(1, "cannot dump (-d) when halting; must reboot instead");
+ if ((howto & RB_REROOT) != 0 && (howto & RB_REROOT) != RB_REROOT)
+ errx(1, "-r flag is mutually exclusive with -d, -n, and -p");
if (geteuid()) {
errno = EPERM;
err(1, NULL);
@@ -137,6 +142,9 @@
if (dohalt) {
openlog("halt", 0, LOG_AUTH | LOG_CONS);
syslog(LOG_CRIT, "halted by %s", user);
+ } else if (howto & RB_REROOT) {
+ openlog("reroot", 0, LOG_AUTH | LOG_CONS);
+ syslog(LOG_CRIT, "rerooted by %s", user);
} else {
openlog("reboot", 0, LOG_AUTH | LOG_CONS);
syslog(LOG_CRIT, "rebooted by %s", user);
@@ -170,6 +178,16 @@
*/
(void)signal(SIGPIPE, SIG_IGN);
+ /*
+ * Nobody but init(8) can perform rerooting.
+ */
+ if (howto & RB_REROOT) {
+ if (kill(1, SIGEMT) == -1)
+ err(1, "SIGEMT init");
+
+ return (0);
+ }
+
/* Just stop init -- if we fail, we'll restart it. */
if (kill(1, SIGTSTP) == -1)
err(1, "SIGTSTP init");
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Wed, Mar 18, 1:43 AM (15 h, 1 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
29867675
Default Alt Text
D3693.id8834.diff (11 KB)
Attached To
Mode
D3693: Reroot support, userspace part.
Attached
Detach File
Event Timeline
Log In to Comment