From 09204e767089d0d9f6f376551f8c1b9a2eade3ee Mon Sep 17 00:00:00 2001 From: ae Date: Sun, 10 Jan 2016 13:53:57 +0000 Subject: MFC r292057: Make detection of GPT a bit more reliable. When we are detecting a partition table and didn't find PMBR, try to read backup GPT header from the last sector and if it is correct, assume that we have GPT. Differential Revision: https://reviews.freebsd.org/D4282 MFC r292058: Remove a note about damaged PMBR. Now GPT will be detected automatically with such corruption. Relnotes: yes --- sbin/geom/class/part/gpart.8 | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) (limited to 'sbin') diff --git a/sbin/geom/class/part/gpart.8 b/sbin/geom/class/part/gpart.8 index 3421ba0..ba579bf 100644 --- a/sbin/geom/class/part/gpart.8 +++ b/sbin/geom/class/part/gpart.8 @@ -24,7 +24,7 @@ .\" .\" $FreeBSD$ .\" -.Dd July 14, 2015 +.Dd December 10, 2015 .Dt GPART 8 .Os .Sh NAME @@ -1107,15 +1107,6 @@ and .Cm recover are the only operations allowed on corrupt tables. .Pp -If the first sector of a provider is corrupt, the kernel can not detect GPT -even if the partition table itself is not corrupt. -The protective MBR can be rewritten using the -.Xr dd 1 -command, to restore the ability to detect the GPT. -The copy of the protective MBR is usually located in the -.Pa /boot/pmbr -file. -.Pp If one GPT header appears to be corrupt but the other copy remains intact, the kernel will log the following: .Bd -literal -offset indent @@ -1330,7 +1321,6 @@ and /sbin/gpart backup ada0 | /sbin/gpart restore -F ada1 ada2 .Ed .Sh SEE ALSO -.Xr dd 1 , .Xr geom 4 , .Xr boot0cfg 8 , .Xr geom 8 , -- cgit v1.1 From 55bfa73168c6ab3fba2227fe818ec03c0c79fa5a Mon Sep 17 00:00:00 2001 From: trasz Date: Mon, 11 Jan 2016 20:01:50 +0000 Subject: MFC 289113: Add 'p' postfix to mdconfig(8). Sponsored by: The FreeBSD Foundation --- sbin/mdconfig/mdconfig.8 | 8 ++++---- sbin/mdconfig/mdconfig.c | 7 +++++-- 2 files changed, 9 insertions(+), 6 deletions(-) (limited to 'sbin') diff --git a/sbin/mdconfig/mdconfig.8 b/sbin/mdconfig/mdconfig.8 index 8cb9a69..ede3045 100644 --- a/sbin/mdconfig/mdconfig.8 +++ b/sbin/mdconfig/mdconfig.8 @@ -41,7 +41,7 @@ .\" .\" $FreeBSD$ .\" -.Dd August 6, 2015 +.Dd October 10, 2015 .Dt MDCONFIG 8 .Os .Sh NAME @@ -163,11 +163,11 @@ prefix. Size of the memory disk. .Ar Size is the number of 512 byte sectors unless suffixed with a -.Cm b , k , m , g , +.Cm b , k , m , g , t , or -.Cm t +.Cm p which -denotes byte, kilobyte, megabyte, gigabyte and terabyte respectively. +denotes byte, kilobyte, megabyte, gigabyte, terabyte and petabyte respectively. When used without the .Fl r option, the diff --git a/sbin/mdconfig/mdconfig.c b/sbin/mdconfig/mdconfig.c index d741c77..1b4e4ce 100644 --- a/sbin/mdconfig/mdconfig.c +++ b/sbin/mdconfig/mdconfig.c @@ -88,8 +88,8 @@ usage(void) fprintf(stderr, "\t\ttype = {malloc, vnode, swap}\n"); fprintf(stderr, "\t\toption = {cluster, compress, reserve}\n"); fprintf(stderr, "\t\tsize = %%d (512 byte blocks), %%db (B),\n"); - fprintf(stderr, "\t\t %%dk (kB), %%dm (MB), %%dg (GB) or\n"); - fprintf(stderr, "\t\t %%dt (TB)\n"); + fprintf(stderr, "\t\t %%dk (kB), %%dm (MB), %%dg (GB), \n"); + fprintf(stderr, "\t\t %%dt (TB), or %%dp (PB)\n"); exit(1); } @@ -217,6 +217,9 @@ main(int argc, char **argv) else if (*p == 't' || *p == 'T') { mdio.md_mediasize <<= 30; mdio.md_mediasize <<= 10; + } else if (*p == 'p' || *p == 'P') { + mdio.md_mediasize <<= 30; + mdio.md_mediasize <<= 20; } else errx(1, "unknown suffix on -s argument"); break; -- cgit v1.1 From 8a895b1fb59b27dada94e93a01fc4613e07517d3 Mon Sep 17 00:00:00 2001 From: trasz Date: Mon, 11 Jan 2016 20:10:14 +0000 Subject: MFC r287396: It's 2015, and some people are still trying to use fdisk and then go asking what debug flags to set for GEOM to make it work. Advice them to use gpart(8) instead. Something similar should probably done with disklabel, but I need to rewrite the disklabel examples first. Sponsored by: The FreeBSD Foundation --- sbin/bsdlabel/bsdlabel.8 | 6 ++++-- sbin/dumpfs/dumpfs.8 | 2 +- sbin/fdisk/fdisk.8 | 7 +++++++ sbin/ffsinfo/ffsinfo.8 | 2 +- sbin/mdconfig/mdconfig.8 | 3 +-- sbin/newfs/newfs.8 | 2 +- sbin/newfs_msdos/newfs_msdos.8 | 4 +--- sbin/newfs_nandfs/newfs_nandfs.8 | 4 +--- sbin/reboot/boot_i386.8 | 2 +- 9 files changed, 18 insertions(+), 14 deletions(-) (limited to 'sbin') diff --git a/sbin/bsdlabel/bsdlabel.8 b/sbin/bsdlabel/bsdlabel.8 index d31187b..8137171 100644 --- a/sbin/bsdlabel/bsdlabel.8 +++ b/sbin/bsdlabel/bsdlabel.8 @@ -445,7 +445,10 @@ to properly recognize the disk: .Bd -literal -offset indent dd if=/dev/zero of=/dev/da0 bs=512 count=32 -fdisk -BI da0 +gpart create -s MBR da0 +gpart add -t freebsd da0 +gpart set -a active -i 1 da0 +gpart bootcode -b /boot/mbr da0 dd if=/dev/zero of=/dev/da0s1 bs=512 count=32 bsdlabel -w -B da0s1 bsdlabel -e da0s1 @@ -495,6 +498,5 @@ are not generally compatible. .Xr md 4 , .Xr disktab 5 , .Xr boot0cfg 8 , -.Xr fdisk 8 , .Xr gpart 8 , .Xr newfs 8 diff --git a/sbin/dumpfs/dumpfs.8 b/sbin/dumpfs/dumpfs.8 index feb8758..bb8e93c 100644 --- a/sbin/dumpfs/dumpfs.8 +++ b/sbin/dumpfs/dumpfs.8 @@ -100,8 +100,8 @@ flag is needed if the filesystem uses .Sh SEE ALSO .Xr disktab 5 , .Xr fs 5 , -.Xr disklabel 8 , .Xr fsck 8 , +.Xr gpart 8 , .Xr newfs 8 , .Xr tunefs 8 .Sh HISTORY diff --git a/sbin/fdisk/fdisk.8 b/sbin/fdisk/fdisk.8 index fcab133..6894ab9 100644 --- a/sbin/fdisk/fdisk.8 +++ b/sbin/fdisk/fdisk.8 @@ -39,6 +39,13 @@ The utility can be used to divide space on the disk into slices and set one active. .Sh DESCRIPTION +.Bf -symbolic +This command is obsolete. +Users are advised to use +.Xr gpart 8 +instead. +.Ef +.Pp The .Fx utility, diff --git a/sbin/ffsinfo/ffsinfo.8 b/sbin/ffsinfo/ffsinfo.8 index 9753cf7..0c114bd 100644 --- a/sbin/ffsinfo/ffsinfo.8 +++ b/sbin/ffsinfo/ffsinfo.8 @@ -121,9 +121,9 @@ to .Pa /var/tmp/ffsinfo with all available information. .Sh SEE ALSO -.Xr disklabel 8 , .Xr dumpfs 8 , .Xr fsck 8 , +.Xr gpart 8 , .Xr growfs 8 , .Xr gvinum 8 , .Xr newfs 8 , diff --git a/sbin/mdconfig/mdconfig.8 b/sbin/mdconfig/mdconfig.8 index ede3045..d273128 100644 --- a/sbin/mdconfig/mdconfig.8 +++ b/sbin/mdconfig/mdconfig.8 @@ -304,8 +304,7 @@ mount /dev/md1.nop /mnt .Sh SEE ALSO .Xr md 4 , .Xr ffs 7 , -.Xr bsdlabel 8 , -.Xr fdisk 8 , +.Xr gpart 8 , .Xr mdmfs 8 , .Xr malloc 9 .Sh HISTORY diff --git a/sbin/newfs/newfs.8 b/sbin/newfs/newfs.8 index 6764adc..f1bdd6b 100644 --- a/sbin/newfs/newfs.8 +++ b/sbin/newfs/newfs.8 @@ -303,11 +303,11 @@ on file systems that contain many small files. .Xr geom 4 , .Xr disktab 5 , .Xr fs 5 , -.Xr bsdlabel 8 , .Xr camcontrol 8 , .Xr dump 8 , .Xr dumpfs 8 , .Xr fsck 8 , +.Xr gpart 8 , .Xr gjournal 8 , .Xr growfs 8 , .Xr makefs 8 , diff --git a/sbin/newfs_msdos/newfs_msdos.8 b/sbin/newfs_msdos/newfs_msdos.8 index 218da93..8901673 100644 --- a/sbin/newfs_msdos/newfs_msdos.8 +++ b/sbin/newfs_msdos/newfs_msdos.8 @@ -228,9 +228,7 @@ Create a 30MB image file, with the FAT partition starting newfs_msdos -C 30M -@63s ./somefile .Ed .Sh SEE ALSO -.Xr disktab 5 , -.Xr disklabel 8 , -.Xr fdisk 8 , +.Xr gpart 8 , .Xr newfs 8 .Sh HISTORY The diff --git a/sbin/newfs_nandfs/newfs_nandfs.8 b/sbin/newfs_nandfs/newfs_nandfs.8 index 6997430..b357547 100644 --- a/sbin/newfs_nandfs/newfs_nandfs.8 +++ b/sbin/newfs_nandfs/newfs_nandfs.8 @@ -63,9 +63,7 @@ Create a file system, using default parameters, on newfs_nandfs /dev/ada0s1 .Ed .Sh SEE ALSO -.Xr disktab 5 , -.Xr disklabel 8 , -.Xr fdisk 8 , +.Xr gpart 8 , .Xr newfs 8 .Sh HISTORY The diff --git a/sbin/reboot/boot_i386.8 b/sbin/reboot/boot_i386.8 index e21e53f..b86e318 100644 --- a/sbin/reboot/boot_i386.8 +++ b/sbin/reboot/boot_i386.8 @@ -348,9 +348,9 @@ requirement has not been adhered to. .Xr make.conf 5 , .Xr ttys 5 , .Xr boot0cfg 8 , -.Xr bsdlabel 8 , .Xr btxld 8 , .Xr config 8 , +.Xr gpart 8 , .Xr gptboot 8 , .Xr halt 8 , .Xr loader 8 , -- cgit v1.1 From 89e4c13d2a7797207e2aa459cc9a0e2f9ec446cc Mon Sep 17 00:00:00 2001 From: trasz Date: Mon, 11 Jan 2016 20:11:41 +0000 Subject: MFC r287429: The dumpfs(8) utility doesn't actually use disktab(5); remove it from "SEE ALSO". Sponsored by: The FreeBSD Foundation --- sbin/dumpfs/dumpfs.8 | 1 - 1 file changed, 1 deletion(-) (limited to 'sbin') diff --git a/sbin/dumpfs/dumpfs.8 b/sbin/dumpfs/dumpfs.8 index bb8e93c..0d41059 100644 --- a/sbin/dumpfs/dumpfs.8 +++ b/sbin/dumpfs/dumpfs.8 @@ -98,7 +98,6 @@ The flag is needed if the filesystem uses .Xr gjournal 8 . .Sh SEE ALSO -.Xr disktab 5 , .Xr fs 5 , .Xr fsck 8 , .Xr gpart 8 , -- cgit v1.1 From 1b837fdf71654caab7c47e99243ae1310269a286 Mon Sep 17 00:00:00 2001 From: asomers Date: Mon, 11 Jan 2016 20:24:56 +0000 Subject: MFC r292020 Increase devd's client socket buffer size to 256KB. This is not as large as it looks, because we'll hit the sockbuf's mbuf limit long before hitting its data limit. A 256KB data limit allows creating a ZFS pool on about 450 drives without overflowing the client socket buffers. --- sbin/devd/devd.cc | 23 +++++++++++++++++------ 1 file changed, 17 insertions(+), 6 deletions(-) (limited to 'sbin') diff --git a/sbin/devd/devd.cc b/sbin/devd/devd.cc index a0cb037..1667219 100644 --- a/sbin/devd/devd.cc +++ b/sbin/devd/devd.cc @@ -108,15 +108,26 @@ __FBSDID("$FreeBSD$"); /* * Since the client socket is nonblocking, we must increase its send buffer to * handle brief event storms. On FreeBSD, AF_UNIX sockets don't have a receive - * buffer, so the client can't increate the buffersize by itself. + * buffer, so the client can't increase the buffersize by itself. * * For example, when creating a ZFS pool, devd emits one 165 character - * resource.fs.zfs.statechange message for each vdev in the pool. A 64k - * buffer has enough space for almost 400 drives, which would be very large but - * not impossibly large pool. A 128k buffer has enough space for 794 drives, - * which is more than can fit in a rack with modern technology. + * resource.fs.zfs.statechange message for each vdev in the pool. The kernel + * allocates a 4608B mbuf for each message. Modern technology places a limit of + * roughly 450 drives/rack, and it's unlikely that a zpool will ever be larger + * than that. + * + * 450 drives * 165 bytes / drive = 74250B of data in the sockbuf + * 450 drives * 4608B / drive = 2073600B of mbufs in the sockbuf + * + * We can't directly set the sockbuf's mbuf limit, but we can do it indirectly. + * The kernel sets it to the minimum of a hard-coded maximum value and sbcc * + * kern.ipc.sockbuf_waste_factor, where sbcc is the socket buffer size set by + * the user. The default value of kern.ipc.sockbuf_waste_factor is 8. If we + * set the bufsize to 256k and use the kern.ipc.sockbuf_waste_factor, then the + * kernel will set the mbuf limit to 2MB, which is just large enough for 450 + * drives. It also happens to be the same as the hardcoded maximum value. */ -#define CLIENT_BUFSIZE 131072 +#define CLIENT_BUFSIZE 262144 using namespace std; -- cgit v1.1 From 30790e76c24aea499d29d0d91d9b66ec174e60e0 Mon Sep 17 00:00:00 2001 From: allanjude Date: Tue, 12 Jan 2016 05:56:49 +0000 Subject: MFC: r287842 Make ifconfig always exit with an error code if an important ioctl fails PR: 203062 --- sbin/ifconfig/ifconfig.c | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) (limited to 'sbin') diff --git a/sbin/ifconfig/ifconfig.c b/sbin/ifconfig/ifconfig.c index 558c205..19bd1ac 100644 --- a/sbin/ifconfig/ifconfig.c +++ b/sbin/ifconfig/ifconfig.c @@ -838,7 +838,7 @@ setifmetric(const char *val, int dummy __unused, int s, strncpy(ifr.ifr_name, name, sizeof (ifr.ifr_name)); ifr.ifr_metric = atoi(val); if (ioctl(s, SIOCSIFMETRIC, (caddr_t)&ifr) < 0) - warn("ioctl (set metric)"); + err(1, "ioctl SIOCSIFMETRIC (set metric)"); } static void @@ -848,7 +848,7 @@ setifmtu(const char *val, int dummy __unused, int s, strncpy(ifr.ifr_name, name, sizeof (ifr.ifr_name)); ifr.ifr_mtu = atoi(val); if (ioctl(s, SIOCSIFMTU, (caddr_t)&ifr) < 0) - warn("ioctl (set mtu)"); + err(1, "ioctl SIOCSIFMTU (set mtu)"); } static void @@ -858,15 +858,12 @@ setifname(const char *val, int dummy __unused, int s, char *newname; newname = strdup(val); - if (newname == NULL) { - warn("no memory to set ifname"); - return; - } + if (newname == NULL) + err(1, "no memory to set ifname"); ifr.ifr_data = newname; if (ioctl(s, SIOCSIFNAME, (caddr_t)&ifr) < 0) { - warn("ioctl (set name)"); free(newname); - return; + err(1, "ioctl SIOCSIFNAME (set name)"); } strlcpy(name, newname, sizeof(name)); free(newname); @@ -893,7 +890,7 @@ setifdescr(const char *val, int dummy __unused, int s, } if (ioctl(s, SIOCSIFDESCR, (caddr_t)&ifr) < 0) - warn("ioctl (set descr)"); + err(1, "ioctl SIOCSIFDESCR (set descr)"); free(newdescr); } -- cgit v1.1 From 2d6e438962defed89637a9fe01b045d3619185d0 Mon Sep 17 00:00:00 2001 From: trasz Date: Tue, 12 Jan 2016 09:27:01 +0000 Subject: MFC r289110: Make geom_nop(4) collect statistics on all types of BIOs, not just reads and writes. PR: kern/198405 Submitted by: Matthew D. Fuller Sponsored by: The FreeBSD Foundation Differential Revision: https://reviews.freebsd.org/D3679 --- sbin/geom/class/nop/gnop.8 | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) (limited to 'sbin') diff --git a/sbin/geom/class/nop/gnop.8 b/sbin/geom/class/nop/gnop.8 index 0103579..ae350d0 100644 --- a/sbin/geom/class/nop/gnop.8 +++ b/sbin/geom/class/nop/gnop.8 @@ -24,7 +24,7 @@ .\" .\" $FreeBSD$ .\" -.Dd September 15, 2015 +.Dd October 10, 2015 .Dt GNOP 8 .Os .Sh NAME @@ -72,9 +72,10 @@ The utility is used for setting up transparent providers on existing ones. Its main purpose is testing other GEOM classes, as it allows forced provider removal and I/O error simulation with a given probability. -It also gathers the following statistics: number of read requests, number of -write requests, number of bytes read and number of bytes written. -In addition, it can be used as a good starting point for implementing new GEOM +It also gathers statistics on the number of read, write, delete, +getattr, flush, and other requests, and the number of bytes read and written. +.Nm +can also be used as a good starting point for implementing new GEOM classes. .Pp The first argument to -- cgit v1.1 From 3aea2923e9c1218bee7ad00506dcb6857d7eaaa4 Mon Sep 17 00:00:00 2001 From: trasz Date: Tue, 12 Jan 2016 10:14:57 +0000 Subject: MFC r290548: Userspace part of reroot support. This makes it possible to change the root filesystem without full reboot, using "reboot -r". This can be used to to eg. boot from a temporary md_image preloaded by loader(8), setup an iSCSI session, and continue booting from rootfs mounted over iSCSI. Relnotes: yes Sponsored by: The FreeBSD Foundation Differential Revision: https://reviews.freebsd.org/D3693 --- sbin/init/Makefile | 6 ++ sbin/init/init.c | 284 +++++++++++++++++++++++++++++++++++++++++++++++--- sbin/init/pathnames.h | 10 +- sbin/reboot/reboot.8 | 18 +++- sbin/reboot/reboot.c | 20 +++- 5 files changed, 316 insertions(+), 22 deletions(-) (limited to 'sbin') diff --git a/sbin/init/Makefile b/sbin/init/Makefile index 7497a4b..eebaf59 100644 --- a/sbin/init/Makefile +++ b/sbin/init/Makefile @@ -2,6 +2,7 @@ # $FreeBSD$ PROG= init +SRCS= init.c getmntopts.c MAN= init.8 PRECIOUSPROG= INSTALLFLAGS=-b -B.bak @@ -9,6 +10,11 @@ CFLAGS+=-DDEBUGSHELL -DSECURE -DLOGIN_CAP -DCOMPAT_SYSV_INIT DPADD= ${LIBUTIL} ${LIBCRYPT} LDADD= -lutil -lcrypt +# Needed for getmntopts.c +MOUNT= ${.CURDIR}/../../sbin/mount +CFLAGS+=-I${MOUNT} +.PATH: ${MOUNT} + NO_SHARED?= YES .include diff --git a/sbin/init/init.c b/sbin/init/init.c index e6f567c..e7079bd 100644 --- a/sbin/init/init.c +++ b/sbin/init/init.c @@ -46,6 +46,7 @@ static const char rcsid[] = #include #include +#include #include #include #include @@ -79,6 +80,7 @@ static const char rcsid[] = #include #endif +#include "mntopts.h" #include "pathnames.h" /* @@ -103,6 +105,7 @@ static void warning(const char *, ...) __printflike(1, 2); static void emergency(const char *, ...) __printflike(1, 2); static void disaster(int); static void badsys(int); +static void revoke_ttys(void); static int runshutdown(void); static char *strk(char *); @@ -122,6 +125,8 @@ static state_func_t clean_ttys(void); 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 *); @@ -194,7 +199,7 @@ main(int argc, char *argv[]) { state_t initial_transition = runcom; char kenv_value[PATH_MAX]; - int c; + int c, error; struct sigaction sa; sigset_t mask; @@ -227,6 +232,9 @@ main(int argc, char *argv[]) case 'q': /* rescan /etc/ttys */ sig = SIGHUP; break; + case 'r': /* remount root */ + sig = SIGEMT; + break; default: goto invalid; } @@ -248,7 +256,7 @@ invalid: /* * Create an initial session. */ - if (setsid() < 0) + if (setsid() < 0 && (errno != EPERM || getsid(0) != 1)) warning("initial setsid() failed: %m"); /* @@ -262,7 +270,7 @@ invalid: * 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; @@ -273,6 +281,9 @@ invalid: case 'f': runcom_mode = FASTBOOT; break; + case 'r': + initial_transition = reroot_phase_two; + break; default: warning("unrecognized flag '-%c'", c); break; @@ -288,13 +299,13 @@ invalid: 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; @@ -374,6 +385,16 @@ invalid: 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. */ @@ -621,6 +642,228 @@ write_stderr(const char *message) write(STDERR_FILENO, message, strlen(message)); } +static int +read_file(const char *path, void **bufp, size_t *bufsizep) +{ + struct stat sb; + size_t bufsize; + void *buf; + ssize_t nbytes; + int error, fd; + + 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) +{ + ssize_t nbytes; + int error, fd; + + 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; + char errmsg[255]; + int error, iovlen; + + iov = NULL; + 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) +{ + void *buf; + char init_path[PATH_MAX]; + size_t bufsize, init_path_len; + int error, name[4]; + + name[0] = CTL_KERN; + name[1] = KERN_PROC; + name[2] = KERN_PROC_PATHNAME; + name[3] = -1; + init_path_len = sizeof(init_path); + error = sysctl(name, 4, init_path, &init_path_len, NULL, 0); + if (error != 0) { + emergency("failed to get kern.proc.pathname: %s", + strerror(errno)); + goto out; + } + + revoke_ttys(); + runshutdown(); + + /* + * Make sure nobody can interfere with our scheme. + */ + error = kill(-1, SIGKILL); + if (error != 0) { + emergency("kill(2) failed: %s", strerror(errno)); + goto out; + } + + /* + * Pacify GCC. + */ + buf = NULL; + bufsize = 0; + + /* + * Copy the init binary into tmpfs, so that we can unmount + * the old rootfs without committing suicide. + */ + error = read_file(init_path, &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) +{ + char init_path[PATH_MAX], *path, *path_component; + size_t init_path_len; + int nbytes, 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; + } + + /* + * Figure out where the destination init(8) binary is. Note that + * the path could be different than what we've started with. Use + * the value from kenv, if set, or the one from sysctl otherwise. + * The latter defaults to a hardcoded value, but can be overridden + * by a build time option. + */ + nbytes = kenv(KENV_GET, "init_path", init_path, sizeof(init_path)); + if (nbytes <= 0) { + init_path_len = sizeof(init_path); + error = sysctlbyname("kern.init_path", + init_path, &init_path_len, NULL, 0); + if (error != 0) { + emergency("failed to retrieve kern.init_path: %s", + strerror(errno)); + goto out; + } + } + + /* + * Repeat the init search logic from sys/kern/init_path.c + */ + path_component = init_path; + while ((path = strsep(&path_component, ":")) != NULL) { + /* + * Execute init(8) from the new rootfs. + */ + execl(path, path, NULL); + } + emergency("cannot exec init from %s: %s", init_path, strerror(errno)); + +out: + emergency("reroot failed; going to single user mode"); + return (state_func_t) single_user; +} + /* * Bring the system up single user. */ @@ -852,8 +1095,9 @@ run_script(const char *script) if ((wpid = waitpid(-1, &status, WUNTRACED)) != -1) collect_child(wpid); if (wpid == -1) { - if (requested_transition == death_single) - return (state_func_t) death_single; + if (requested_transition == death_single || + requested_transition == reroot) + return (state_func_t) requested_transition; if (errno == EINTR) continue; warning("wait for %s on %s failed: %m; going to " @@ -1326,6 +1570,9 @@ transition_handler(int sig) current_state == multi_user || current_state == catatonia) requested_transition = catatonia; break; + case SIGEMT: + requested_transition = reroot; + break; default: requested_transition = 0; break; @@ -1498,7 +1745,6 @@ alrm_handler(int sig) static state_func_t death(void) { - session_t *sp; int block, blocked; size_t len; @@ -1515,11 +1761,7 @@ death(void) * 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); - } + revoke_ttys(); /* Try to run the rc.shutdown script within a period of time */ runshutdown(); @@ -1565,6 +1807,18 @@ death_single(void) return (state_func_t) single_user; } +static void +revoke_ttys(void) +{ + session_t *sp; + + for (sp = sessions; sp; sp = sp->se_next) { + sp->se_flags |= SE_SHUTDOWN; + kill(sp->se_process, SIGHUP); + revoke(sp->se_device); + } +} + /* * Run the system shutdown script. * diff --git a/sbin/init/pathnames.h b/sbin/init/pathnames.h index 39eed4c..ec33b45 100644 --- a/sbin/init/pathnames.h +++ b/sbin/init/pathnames.h @@ -35,7 +35,9 @@ #include -#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_REROOT "/dev/reroot" +#define _PATH_REROOT_INIT _PATH_REROOT "/init" diff --git a/sbin/reboot/reboot.8 b/sbin/reboot/reboot.8 index 84dd887..420d4f8 100644 --- a/sbin/reboot/reboot.8 +++ b/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 .Dd Jan 06, 2016 .Dt REBOOT 8 .Os @@ -43,7 +43,7 @@ .Op Fl lNnpq .Op Fl k Ar kernel .Nm -.Op Fl dlNnpq +.Op Fl dlNnpqr .Op Fl k Ar kernel .Nm fasthalt .Op Fl lNnpq @@ -122,6 +122,13 @@ the flushing of the file system cache is performed (if the .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. +After changing vfs.root.mountfrom with +.Xr kenv 8 , +.Nm Fl r +can be used to change the root filesystem while preserving kernel state. .El .Pp The @@ -139,6 +146,13 @@ Normally, the 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 , diff --git a/sbin/reboot/reboot.c b/sbin/reboot/reboot.c index 6d590ac..961ba41 100644 --- a/sbin/reboot/reboot.c +++ b/sbin/reboot/reboot.c @@ -77,7 +77,7 @@ main(int argc, char *argv[]) } else howto = 0; lflag = nflag = qflag = Nflag = 0; - while ((ch = getopt(argc, argv, "dk:lNnpq")) != -1) + while ((ch = getopt(argc, argv, "dk:lNnpqr")) != -1) switch(ch) { case 'd': howto |= RB_DUMP; @@ -102,6 +102,9 @@ main(int argc, char *argv[]) case 'q': qflag = 1; break; + case 'r': + howto |= RB_REROOT; + break; case '?': default: usage(); @@ -113,6 +116,8 @@ main(int argc, char *argv[]) errx(1, "cannot dump (-d) when halting; must reboot instead"); if (Nflag && (howto & RB_NOSYNC) != 0) errx(1, "-N cannot be used with -n"); + if ((howto & RB_REROOT) != 0 && howto != RB_REROOT) + errx(1, "-r cannot be used with -d, -n, or -p"); if (geteuid()) { errno = EPERM; err(1, NULL); @@ -143,6 +148,9 @@ main(int argc, char *argv[]) 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); @@ -176,6 +184,16 @@ main(int argc, char *argv[]) */ (void)signal(SIGPIPE, SIG_IGN); + /* + * Only 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"); -- cgit v1.1 From 8bd7436f2ba8cb82b96bb85dc75e58ed686efebb Mon Sep 17 00:00:00 2001 From: trasz Date: Tue, 12 Jan 2016 10:24:08 +0000 Subject: MFC r290689: Fix resource leaks in error cases. Sponsored by: The FreeBSD Foundation --- sbin/init/init.c | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) (limited to 'sbin') diff --git a/sbin/init/init.c b/sbin/init/init.c index e7079bd..af672a9 100644 --- a/sbin/init/init.c +++ b/sbin/init/init.c @@ -660,6 +660,7 @@ read_file(const char *path, void **bufp, size_t *bufsizep) error = fstat(fd, &sb); if (error != 0) { emergency("fstat: %s", strerror(errno)); + close(fd); return (error); } @@ -667,12 +668,14 @@ read_file(const char *path, void **bufp, size_t *bufsizep) buf = malloc(bufsize); if (buf == NULL) { emergency("malloc: %s", strerror(errno)); + close(fd); return (error); } nbytes = read(fd, buf, bufsize); if (nbytes != (ssize_t)bufsize) { emergency("read: %s", strerror(errno)); + close(fd); free(buf); return (error); } @@ -691,7 +694,7 @@ read_file(const char *path, void **bufp, size_t *bufsizep) } static int -create_file(const char *path, void *buf, size_t bufsize) +create_file(const char *path, const void *buf, size_t bufsize) { ssize_t nbytes; int error, fd; @@ -705,13 +708,13 @@ create_file(const char *path, void *buf, size_t bufsize) nbytes = write(fd, buf, bufsize); if (nbytes != (ssize_t)bufsize) { emergency("write: %s", strerror(errno)); + close(fd); return (-1); } error = close(fd); if (error != 0) { emergency("close: %s", strerror(errno)); - free(buf); return (-1); } @@ -757,6 +760,9 @@ reroot(void) size_t bufsize, init_path_len; int error, name[4]; + buf = NULL; + bufsize = 0; + name[0] = CTL_KERN; name[1] = KERN_PROC; name[2] = KERN_PROC_PATHNAME; @@ -782,12 +788,6 @@ reroot(void) } /* - * Pacify GCC. - */ - buf = NULL; - bufsize = 0; - - /* * Copy the init binary into tmpfs, so that we can unmount * the old rootfs without committing suicide. */ @@ -809,6 +809,7 @@ reroot(void) out: emergency("reroot failed; going to single user mode"); + free(buf); return (state_func_t) single_user; } -- cgit v1.1