summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--etc/defaults/rc.conf5
-rw-r--r--etc/rc.d/Makefile4
-rwxr-xr-xetc/rc.d/addswap55
-rwxr-xr-xetc/rc.d/encswap57
-rwxr-xr-xetc/rc.d/fsck2
-rwxr-xr-xetc/rc.d/mdconfig2
-rwxr-xr-xetc/rc.d/swap (renamed from etc/rc.d/swap1)8
-rwxr-xr-xetc/rc.d/swaplate17
-rw-r--r--include/paths.h2
-rw-r--r--sbin/swapon/swapon.828
-rw-r--r--sbin/swapon/swapon.c567
-rw-r--r--share/man/man5/fstab.531
12 files changed, 628 insertions, 150 deletions
diff --git a/etc/defaults/rc.conf b/etc/defaults/rc.conf
index 687b092..dda1855 100644
--- a/etc/defaults/rc.conf
+++ b/etc/defaults/rc.conf
@@ -32,8 +32,6 @@ early_late_divider="FILESYSTEMS" # Script that separates early/late
always_force_depends="NO" # Set to check that indicated dependencies are
# running during boot (can increase boot time).
-swapfile="NO" # Set to name of swapfile if aux swapfile desired.
-swapfile_mdunit="99" # Swapfile md(4) unit number created by mdconfig(8).
apm_enable="NO" # Set to YES to enable APM BIOS functions (or NO).
apmd_enable="NO" # Run apmd to handle APM event from userland.
apmd_flags="" # Flags to apmd (if enabled).
@@ -85,9 +83,6 @@ geli_autodetach="YES" # Automatically detach on last close.
#geli_da1_autodetach="NO"
#geli_mirror_home_flags="-k /etc/geli/home.keys"
-geli_swap_flags="-e aes -l 256 -s 4096 -d" # Options for GELI-encrypted
- # swap partitions.
-
root_rw_mount="YES" # Set to NO to inhibit remounting root read-write.
fsck_y_enable="NO" # Set to YES to do fsck -y if the initial preen fails.
fsck_y_flags="" # Additional flags for fsck -y
diff --git a/etc/rc.d/Makefile b/etc/rc.d/Makefile
index aace4b1..3defd97 100644
--- a/etc/rc.d/Makefile
+++ b/etc/rc.d/Makefile
@@ -37,7 +37,6 @@ FILES= DAEMON \
dhclient \
dmesg \
dumpon \
- encswap \
faith \
fsck \
ftp-proxy \
@@ -139,7 +138,8 @@ FILES= DAEMON \
static_arp \
static_ndp \
stf \
- swap1 \
+ swap \
+ swaplate \
syscons \
sysctl \
syslogd \
diff --git a/etc/rc.d/addswap b/etc/rc.d/addswap
index a6ff187..1758df8 100755
--- a/etc/rc.d/addswap
+++ b/etc/rc.d/addswap
@@ -13,57 +13,12 @@
. /etc/rc.subr
name="addswap"
-start_cmd="addswap_start"
-stop_cmd="addswap_stop"
+start_cmd=":"
+stop_cmd=":"
+rcvar=
-addswap_start()
-{
- case ${swapfile} in
- [Nn][Oo] | '')
- ;;
- *)
- if [ -w "${swapfile}" ]; then
- check_startmsgs && echo "Adding ${swapfile} as additional swap"
-
- if [ -n "${swapfile_mdunit}" ]; then
- mdev="/dev/md${swapfile_mdunit#md}"
- mdconfig -a -t vnode -f "${swapfile}" -u ${swapfile_mdunit}
- else
- mdev="/dev/`mdconfig -a -t vnode -f "${swapfile}"`"
- fi
-
- if [ $? -eq 0 ]; then
- swapon ${mdev}
- else
- echo "error creating swapfile device"
- fi
- fi
- ;;
- esac
-}
-
-addswap_stop()
-{
- case ${swapfile} in
- [Nn][Oo] | '')
- ;;
- *)
- if [ -n "${swapfile_mdunit}" ]; then
- mdev="/dev/md${swapfile_mdunit#md}"
- else
- mdev="/dev/`mdconfig -lv | grep "${swapfile}" | cut -f1`"
- swapfile_mdunit=${mdev#md}
- fi
- if [ -n "${swapfile_mdunit}" ]; then
- swapctl -l | grep -q ${mdev}
- if [ $? -eq 0 ]; then
- echo "Dismounting swapfile ${swapfile}"
- swapoff ${mdev} && mdconfig -d -u ${swapfile_mdunit}
- fi
- fi
- ;;
- esac
-}
+set_rcvar_obsolete swapfile
+set_rcvar_obsolete geli_swap_flags
load_rc_config $name
run_rc_command "$1"
diff --git a/etc/rc.d/encswap b/etc/rc.d/encswap
deleted file mode 100755
index 6221998..0000000
--- a/etc/rc.d/encswap
+++ /dev/null
@@ -1,57 +0,0 @@
-#!/bin/sh
-#
-# $FreeBSD$
-#
-
-# PROVIDE: disks
-# REQUIRE: initrandom
-# KEYWORD: nojail
-
-. /etc/rc.subr
-
-name="encswap"
-start_cmd="encswap_attach"
-stop_cmd="encswap_detach"
-
-encswap_attach()
-{
- while read device mountpoint type options rest ; do
- case ":${device}:${type}:${options}" in
- :#*)
- continue
- ;;
- *.bde:swap:sw)
- passphrase=`dd if=/dev/random count=1 2>/dev/null | md5 -q`
- device="${device%.bde}"
- gbde init "${device}" -P "${passphrase}" || return 1
- gbde attach "${device}" -p "${passphrase}" || return 1
- ;;
- *.eli:swap:sw)
- device="${device%.eli}"
- geli onetime ${geli_swap_flags} "${device}" || return 1
- ;;
- esac
- done < /etc/fstab
-}
-
-encswap_detach()
-{
- while read device mountpoint type options rest ; do
- case ":${device}:${type}:${options}" in
- :#*)
- continue
- ;;
- *.bde:swap:sw)
- device="${device%.bde}"
- gbde detach "${device}"
- ;;
- *.eli:swap:sw)
- # Nothing here, because geli swap devices should be
- # created with the auto-detach-on-last-close option.
- ;;
- esac
- done < /etc/fstab
-}
-
-load_rc_config $name
-run_rc_command "$1"
diff --git a/etc/rc.d/fsck b/etc/rc.d/fsck
index c1fe155..ad06106 100755
--- a/etc/rc.d/fsck
+++ b/etc/rc.d/fsck
@@ -4,7 +4,7 @@
#
# PROVIDE: fsck
-# REQUIRE: localswap
+# REQUIRE: swap
# KEYWORD: nojail
. /etc/rc.subr
diff --git a/etc/rc.d/mdconfig b/etc/rc.d/mdconfig
index c697c35..7b9ddf8 100755
--- a/etc/rc.d/mdconfig
+++ b/etc/rc.d/mdconfig
@@ -28,7 +28,7 @@
#
# PROVIDE: mdconfig
-# REQUIRE: localswap root
+# REQUIRE: swap root
. /etc/rc.subr
diff --git a/etc/rc.d/swap1 b/etc/rc.d/swap
index 71a1908..4122e61 100755
--- a/etc/rc.d/swap1
+++ b/etc/rc.d/swap
@@ -3,15 +3,15 @@
# $FreeBSD$
#
-# PROVIDE: localswap
+# PROVIDE: swap
# REQUIRE: disks
# KEYWORD: nojail shutdown
. /etc/rc.subr
-name="swap1"
-start_cmd='swapon -aq'
+name="swap"
+start_cmd='/sbin/swapon -aq'
stop_cmd=':'
-load_rc_config swap
+load_rc_config $name
run_rc_command "$1"
diff --git a/etc/rc.d/swaplate b/etc/rc.d/swaplate
new file mode 100755
index 0000000..64fa989
--- /dev/null
+++ b/etc/rc.d/swaplate
@@ -0,0 +1,17 @@
+#!/bin/sh
+#
+# $FreeBSD$
+#
+
+# PROVIDE: swaplate
+# REQUIRE: mountlate
+# KEYWORD: nojail shutdown
+
+. /etc/rc.subr
+
+name="swaplate"
+start_cmd='/sbin/swapon -aLq'
+stop_cmd='/sbin/swapoff -aq'
+
+load_rc_config swap
+run_rc_command "$1"
diff --git a/include/paths.h b/include/paths.h
index c96f37c..c0a99a5 100644
--- a/include/paths.h
+++ b/include/paths.h
@@ -57,6 +57,8 @@
#define _PATH_ETC "/etc"
#define _PATH_FTPUSERS "/etc/ftpusers"
#define _PATH_FWMEM "/dev/fwmem"
+#define _PATH_GBDE "/sbin/gbde"
+#define _PATH_GELI "/sbin/geli"
#define _PATH_HALT "/sbin/halt"
#ifdef COMPAT_32BIT
#define _PATH_I18NMODULE "/usr/lib32/i18n"
diff --git a/sbin/swapon/swapon.8 b/sbin/swapon/swapon.8
index 5602a9a..ec2ad72 100644
--- a/sbin/swapon/swapon.8
+++ b/sbin/swapon/swapon.8
@@ -28,7 +28,7 @@
.\" @(#)swapon.8 8.1 (Berkeley) 6/5/93
.\" $FreeBSD$
.\"
-.Dd June 23, 2008
+.Dd June 21, 2013
.Dt SWAPON 8
.Os
.Sh NAME
@@ -38,11 +38,11 @@
.Nm swapon
.Oo Fl F Ar fstab
.Oc
-.Fl aq | Ar
+.Fl aLq | Ar
.Nm swapoff
.Oo Fl F Ar fstab
.Oc
-.Fl aq | Ar
+.Fl aLq | Ar
.Nm swapctl
.Op Fl AghklmsU
.Oo
@@ -74,10 +74,19 @@ option is used, all swap devices in
.Pa /etc/fstab
will be added, unless their
.Dq noauto
+or
+.Dq late
option is also set.
If the
+.Fl L
+option is specified,
+swap devices with the
+.Dq late
+option will be added as well as ones with no option.
+If the
.Fl q
-option is used informational messages will not be
+option is used,
+informational messages will not be
written to standard output when a swap device is added.
.Pp
The
@@ -89,10 +98,19 @@ option is used, all swap devices in
.Pa /etc/fstab
will be removed, unless their
.Dq noauto
+or
+.Dq late
option is also set.
If the
+.Fl L
+option is specified,
+swap devices with the
+.Dq late
+option will be removed as well as ones with no option.
+If the
.Fl q
-option is used informational messages will not be
+option is used,
+informational messages will not be
written to standard output when a swap device is removed.
Note that
.Nm swapoff
diff --git a/sbin/swapon/swapon.c b/sbin/swapon/swapon.c
index 5b9a0ed..55beb5b 100644
--- a/sbin/swapon/swapon.c
+++ b/sbin/swapon/swapon.c
@@ -41,35 +41,51 @@ static char sccsid[] = "@(#)swapon.c 8.1 (Berkeley) 6/5/93";
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
-#include <sys/stat.h>
#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/mdioctl.h>
+#include <sys/stat.h>
#include <sys/sysctl.h>
+#include <sys/wait.h>
#include <vm/vm_param.h>
#include <err.h>
#include <errno.h>
+#include <fcntl.h>
+#include <fnmatch.h>
#include <fstab.h>
+#include <libgen.h>
+#include <libutil.h>
+#include <limits.h>
+#include <paths.h>
+#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
-#include <fcntl.h>
-#include <libutil.h>
static void usage(void);
-static int swap_on_off(char *name, int ignoreebusy);
+static const char *swap_on_off(char *, int, char *);
+static const char *swap_on_off_gbde(char *, int);
+static const char *swap_on_off_geli(char *, char *, int);
+static const char *swap_on_off_md(char *, char *, int);
+static const char *swap_on_off_sfile(char *, int);
static void swaplist(int, int, int);
+static int run_cmd(int *, const char *, ...) __printflike(2, 3);
static enum { SWAPON, SWAPOFF, SWAPCTL } orig_prog, which_prog = SWAPCTL;
+static int qflag;
+
int
main(int argc, char **argv)
{
struct fstab *fsp;
+ const char *swfile;
char *ptr;
int ret;
int ch, doall;
- int sflag = 0, lflag = 0, hflag = 0, qflag = 0;
+ int sflag = 0, lflag = 0, late = 0, hflag = 0;
const char *etc_fstab;
if ((ptr = strrchr(argv[0], '/')) == NULL)
@@ -82,7 +98,7 @@ main(int argc, char **argv)
doall = 0;
etc_fstab = NULL;
- while ((ch = getopt(argc, argv, "AadghklmqsUF:")) != -1) {
+ while ((ch = getopt(argc, argv, "AadghklLmqsUF:")) != -1) {
switch(ch) {
case 'A':
if (which_prog == SWAPCTL) {
@@ -116,6 +132,9 @@ main(int argc, char **argv)
case 'l':
lflag = 1;
break;
+ case 'L':
+ late = 1;
+ break;
case 'm':
hflag = 'M';
break;
@@ -145,6 +164,7 @@ main(int argc, char **argv)
argv += optind;
ret = 0;
+ swfile = NULL;
if (etc_fstab != NULL)
setfstab(etc_fstab);
if (which_prog == SWAPON || which_prog == SWAPOFF) {
@@ -154,27 +174,37 @@ main(int argc, char **argv)
continue;
if (strstr(fsp->fs_mntops, "noauto"))
continue;
- if (swap_on_off(fsp->fs_spec, 1)) {
+ if (which_prog != SWAPOFF &&
+ strstr(fsp->fs_mntops, "late") &&
+ !late)
+ continue;
+ swfile = swap_on_off(fsp->fs_spec, 1,
+ fsp->fs_mntops);
+ if (swfile == NULL) {
ret = 1;
- } else {
- if (!qflag) {
- printf("%s: %sing %s as swap device\n",
- getprogname(),
- which_prog == SWAPOFF ? "remov" : "add",
- fsp->fs_spec);
- }
+ continue;
+ }
+ if (!qflag) {
+ printf("%s: %sing %s as swap device\n",
+ getprogname(),
+ (which_prog == SWAPOFF) ?
+ "remov" : "add", swfile);
}
}
}
else if (!*argv)
usage();
for (; *argv; ++argv) {
- if (swap_on_off(*argv, 0)) {
+ swfile = swap_on_off(*argv, 0, NULL);
+ if (swfile == NULL) {
ret = 1;
- } else if (orig_prog == SWAPCTL) {
+ continue;
+ }
+ if (orig_prog == SWAPCTL) {
printf("%s: %sing %s as swap device\n",
- getprogname(), which_prog == SWAPOFF ? "remov" : "add",
- *argv);
+ getprogname(),
+ (which_prog == SWAPOFF) ? "remov" : "add",
+ swfile);
}
}
} else {
@@ -186,14 +216,503 @@ main(int argc, char **argv)
exit(ret);
}
+static const char *
+swap_on_off(char *name, int doingall, char *mntops)
+{
+ char base[PATH_MAX];
+
+ /* Swap on vnode-backed md(4) device. */
+ if (mntops != NULL &&
+ (fnmatch(_PATH_DEV MD_NAME "[0-9]*", name, 0) != FNM_NOMATCH ||
+ fnmatch(MD_NAME "[0-9]*", name, 0) != FNM_NOMATCH ||
+ strncmp(_PATH_DEV MD_NAME, name,
+ sizeof(_PATH_DEV) + sizeof(MD_NAME)) == 0 ||
+ strncmp(MD_NAME, name, sizeof(MD_NAME)) == 0))
+ return (swap_on_off_md(name, mntops, doingall));
+
+ /* Swap on encrypted device by GEOM_BDE. */
+ basename_r(name, base);
+ if (fnmatch("*.bde", base, 0) != FNM_NOMATCH)
+ return (swap_on_off_gbde(name, doingall));
+
+ /* Swap on encrypted device by GEOM_ELI. */
+ if (fnmatch("*.eli", base, 0) != FNM_NOMATCH)
+ return (swap_on_off_geli(name, mntops, doingall));
+
+ /* Swap on special file. */
+ return (swap_on_off_sfile(name, doingall));
+}
+
+static const char *
+swap_on_off_gbde(char *name, int doingall)
+{
+ const char *ret;
+ char pass[64 * 2 + 1], bpass[64];
+ char *devname, *p;
+ int i, fd, error;
+
+ devname = strdup(name);
+ p = strrchr(devname, '.');
+ if (p == NULL) {
+ warnx("%s: Malformed device name", name);
+ return (NULL);
+ }
+ *p = '\0';
+
+ fd = -1;
+ switch (which_prog) {
+ case SWAPON:
+ arc4random_buf(bpass, sizeof(bpass));
+ for (i = 0; i < (int)sizeof(bpass); i++)
+ sprintf(&pass[2 * i], "%02x", bpass[i]);
+ pass[sizeof(pass) - 1] = '\0';
+
+ error = run_cmd(&fd, "%s init %s -P %s", _PATH_GBDE,
+ devname, pass);
+ if (error) {
+ /* bde device found. Ignore it. */
+ close(fd);
+ if (!qflag)
+ warnx("%s: Device already in use", name);
+ return (NULL);
+ }
+ close(fd);
+ error = run_cmd(&fd, "%s attach %s -p %s", _PATH_GBDE,
+ devname, pass);
+ if (error) {
+ close(fd);
+ warnx("gbde (attach) error: %s", name);
+ return (NULL);
+ }
+ break;
+ case SWAPOFF:
+ break;
+ default:
+ return (NULL);
+ break;
+ }
+ if (fd != -1)
+ close(fd);
+ ret = swap_on_off_sfile(name, doingall);
+
+ fd = -1;
+ switch (which_prog) {
+ case SWAPOFF:
+ error = run_cmd(&fd, "%s detach %s", _PATH_GBDE, devname);
+ if (error) {
+ /* bde device not found. Ignore it. */
+ if (!qflag)
+ warnx("%s: Device not found", devname);
+ return (NULL);
+ }
+ break;
+ default:
+ return (NULL);
+ break;
+ }
+
+ if (fd != -1)
+ close(fd);
+ return (ret);
+}
+
+static const char *
+swap_on_off_geli(char *name, char *mntops, int doingall)
+{
+ const char *ops, *aalgo, *ealgo, *keylen_str, *sectorsize_str;
+ char *devname, *p;
+ char args[4096];
+ struct stat sb;
+ int fd, error, keylen, sectorsize;
+ u_long ul;
+
+ devname = strdup(name);
+ p = strrchr(devname, '.');
+ if (p == NULL) {
+ warnx("%s: Malformed device name", name);
+ return (NULL);
+ }
+ *p = '\0';
+
+ ops = strdup(mntops);
+
+ /* Default parameters for geli(8). */
+ aalgo = "hmac/sha256";
+ ealgo = "aes";
+ keylen = 256;
+ sectorsize = 4096;
+
+ if ((p = strstr(ops, "aalgo=")) != NULL) {
+ aalgo = p + sizeof("aalgo=") - 1;
+ p = strchr(aalgo, ',');
+ if (p != NULL)
+ *p = '\0';
+ }
+ if ((p = strstr(ops, "ealgo=")) != NULL) {
+ ealgo = p + sizeof("ealgo=") - 1;
+ p = strchr(ealgo, ',');
+ if (p != NULL)
+ *p = '\0';
+ }
+ if ((p = strstr(ops, "keylen=")) != NULL) {
+ keylen_str = p + sizeof("keylen=") - 1;
+ p = strchr(keylen_str, ',');
+ if (p != NULL)
+ *p = '\0';
+ errno = 0;
+ ul = strtoul(keylen_str, &p, 10);
+ if (errno == 0) {
+ if (*p != '\0' || ul > INT_MAX)
+ errno = EINVAL;
+ }
+ if (errno) {
+ warn("Invalid keylen: %s", keylen_str);
+ return (NULL);
+ }
+ keylen = (int)ul;
+ }
+ if ((p = strstr(ops, "sectorsize=")) != NULL) {
+ sectorsize_str = p + sizeof("sectorsize=") - 1;
+ p = strchr(sectorsize_str, ',');
+ if (p != NULL)
+ *p = '\0';
+ errno = 0;
+ ul = strtoul(sectorsize_str, &p, 10);
+ if (errno == 0) {
+ if (*p != '\0' || ul > INT_MAX)
+ errno = EINVAL;
+ }
+ if (errno) {
+ warn("Invalid sectorsize: %s", sectorsize_str);
+ return (NULL);
+ }
+ sectorsize = (int)ul;
+ }
+ snprintf(args, sizeof(args), "-a %s -e %s -l %d -s %d -d",
+ aalgo, ealgo, keylen, sectorsize);
+ args[sizeof(args) - 1] = '\0';
+ free((void *)ops);
+
+ fd = -1;
+ switch (which_prog) {
+ case SWAPON:
+ error = run_cmd(&fd, "%s onetime %s %s", _PATH_GELI, args,
+ devname);
+ if (error) {
+ /* eli device found. Ignore it. */
+ close(fd);
+ if (!qflag)
+ warnx("%s: Device already in use "
+ "or invalid parameters", name);
+ return (NULL);
+ }
+ break;
+ case SWAPOFF:
+ if (stat(name, &sb) == -1 && errno == ENOENT) {
+ if (!qflag)
+ warnx("%s: Device not found", name);
+ return (NULL);
+ }
+ break;
+ default:
+ return (NULL);
+ break;
+ }
+ if (fd != -1)
+ close(fd);
+
+ return (swap_on_off_sfile(name, doingall));
+}
+
+static const char *
+swap_on_off_md(char *name, char *mntops, int doingall)
+{
+ FILE *sfd;
+ int fd, mdunit, error;
+ const char *ret;
+ char mdpath[PATH_MAX], linebuf[PATH_MAX];
+ char *p, *vnodefile;
+ size_t linelen;
+ u_long ul;
+
+ fd = -1;
+ sfd = NULL;
+ if (strlen(name) == (sizeof(MD_NAME) - 1))
+ mdunit = -1;
+ else {
+ errno = 0;
+ ul = strtoul(name + 2, &p, 10);
+ if (errno == 0) {
+ if (*p != '\0' || ul > INT_MAX)
+ errno = EINVAL;
+ }
+ if (errno) {
+ warn("Bad device unit: %s", name);
+ return (NULL);
+ }
+ mdunit = (int)ul;
+ }
+
+ vnodefile = NULL;
+ if ((p = strstr(mntops, "file=")) != NULL) {
+ vnodefile = strdup(p + sizeof("file=") - 1);
+ p = strchr(vnodefile, ',');
+ if (p != NULL)
+ *p = '\0';
+ }
+ if (vnodefile == NULL) {
+ warnx("file option not found for %s", name);
+ return (NULL);
+ }
+
+ switch (which_prog) {
+ case SWAPON:
+ if (mdunit == -1) {
+ error = run_cmd(&fd, "%s -l -n -f %s",
+ _PATH_MDCONFIG, vnodefile);
+ if (error == 0) {
+ /* md device found. Ignore it. */
+ close(fd);
+ if (!qflag)
+ warnx("%s: Device already in use",
+ vnodefile);
+ return (NULL);
+ }
+ error = run_cmd(&fd, "%s -a -t vnode -n -f %s",
+ _PATH_MDCONFIG, vnodefile);
+ if (error) {
+ warnx("mdconfig (attach) error: file=%s",
+ vnodefile);
+ return (NULL);
+ }
+ sfd = fdopen(fd, "r");
+ if (sfd == NULL) {
+ warn("mdconfig (attach) fdopen error");
+ ret = NULL;
+ goto err;
+ }
+ p = fgetln(sfd, &linelen);
+ if (p == NULL &&
+ (linelen < 2 || linelen > sizeof(linebuf))) {
+ warn("mdconfig (attach) unexpected output");
+ ret = NULL;
+ goto err;
+ }
+ strncpy(linebuf, p, linelen);
+ linebuf[linelen - 1] = '\0';
+ errno = 0;
+ ul = strtoul(linebuf, &p, 10);
+ if (errno == 0) {
+ if (*p != '\0' || ul > INT_MAX)
+ errno = EINVAL;
+ }
+ if (errno) {
+ warn("mdconfig (attach) unexpected output: %s",
+ linebuf);
+ ret = NULL;
+ goto err;
+ }
+ mdunit = (int)ul;
+ } else {
+ error = run_cmd(&fd, "%s -l -n -f %s -u %d",
+ _PATH_MDCONFIG, vnodefile, mdunit);
+ if (error == 0) {
+ /* md device found. Ignore it. */
+ close(fd);
+ if (!qflag)
+ warnx("md%d on %s: Device already "
+ "in use", mdunit, vnodefile);
+ return (NULL);
+ }
+ error = run_cmd(NULL, "%s -a -t vnode -u %d -f %s",
+ _PATH_MDCONFIG, mdunit, vnodefile);
+ if (error) {
+ warnx("mdconfig (attach) error: "
+ "md%d on file=%s", mdunit, vnodefile);
+ return (NULL);
+ }
+ }
+ break;
+ case SWAPOFF:
+ if (mdunit == -1) {
+ error = run_cmd(&fd, "%s -l -n -f %s",
+ _PATH_MDCONFIG, vnodefile);
+ if (error) {
+ /* md device not found. Ignore it. */
+ close(fd);
+ if (!qflag)
+ warnx("md on %s: Device not found",
+ vnodefile);
+ return (NULL);
+ }
+ sfd = fdopen(fd, "r");
+ if (sfd == NULL) {
+ warn("mdconfig (list) fdopen error");
+ ret = NULL;
+ goto err;
+ }
+ p = fgetln(sfd, &linelen);
+ if (p == NULL &&
+ (linelen < 2 || linelen > sizeof(linebuf) - 1)) {
+ warn("mdconfig (list) unexpected output");
+ ret = NULL;
+ goto err;
+ }
+ strncpy(linebuf, p, linelen);
+ linebuf[linelen - 1] = '\0';
+ p = strchr(linebuf, ' ');
+ if (p != NULL)
+ *p = '\0';
+ errno = 0;
+ ul = strtoul(linebuf, &p, 10);
+ if (errno == 0) {
+ if (*p != '\0' || ul > INT_MAX)
+ errno = EINVAL;
+ }
+ if (errno) {
+ warn("mdconfig (list) unexpected output: %s",
+ linebuf);
+ ret = NULL;
+ goto err;
+ }
+ mdunit = (int)ul;
+ } else {
+ error = run_cmd(&fd, "%s -l -n -f %s -u %d",
+ _PATH_MDCONFIG, vnodefile, mdunit);
+ if (error) {
+ /* md device not found. Ignore it. */
+ close(fd);
+ if (!qflag)
+ warnx("md%d on %s: Device not found",
+ mdunit, vnodefile);
+ return (NULL);
+ }
+ }
+ break;
+ default:
+ return (NULL);
+ }
+ snprintf(mdpath, sizeof(mdpath), "%s%s%d", _PATH_DEV,
+ MD_NAME, mdunit);
+ mdpath[sizeof(mdpath) - 1] = '\0';
+ ret = swap_on_off_sfile(mdpath, doingall);
+
+ switch (which_prog) {
+ case SWAPOFF:
+ if (ret != NULL) {
+ error = run_cmd(NULL, "%s -d -u %d",
+ _PATH_MDCONFIG, mdunit);
+ if (error)
+ warn("mdconfig (detach) detach failed: %s%s%d",
+ _PATH_DEV, MD_NAME, mdunit);
+ }
+ break;
+ default:
+ break;
+ }
+err:
+ if (sfd != NULL)
+ fclose(sfd);
+ if (fd != -1)
+ close(fd);
+ return (ret);
+}
+
static int
-swap_on_off(char *name, int doingall)
+run_cmd(int *ofd, const char *cmdline, ...)
{
- if ((which_prog == SWAPOFF ? swapoff(name) : swapon(name)) == -1) {
+ va_list ap;
+ char **argv, **argvp, *cmd, *p;
+ int argc, pid, status, rv;
+ int pfd[2], nfd, dup2dn;
+
+ va_start(ap, cmdline);
+ rv = vasprintf(&cmd, cmdline, ap);
+ if (rv == -1) {
+ warn("%s", __func__);
+ return (rv);
+ }
+ va_end(ap);
+
+ for (argc = 1, p = cmd; (p = strchr(p, ' ')) != NULL; p++)
+ argc++;
+ argv = (char **)malloc(sizeof(*argv) * (argc + 1));
+ for (p = cmd, argvp = argv; (*argvp = strsep(&p, " ")) != NULL;)
+ if (**argvp != '\0' && (++argvp > &argv[argc])) {
+ *argvp = NULL;
+ break;
+ }
+ /* The argv array ends up NULL-terminated here. */
+#if 0
+ {
+ int i;
+
+ fprintf(stderr, "DEBUG: running:");
+ /* Should be equivalent to 'cmd' (before strsep, of course). */
+ for (i = 0; argv[i] != NULL; i++)
+ fprintf(stderr, " %s", argv[i]);
+ fprintf(stderr, "\n");
+ }
+#endif
+ dup2dn = 1;
+ if (ofd != NULL) {
+ if (pipe(&pfd[0]) == -1) {
+ warn("%s: pipe", __func__);
+ return (-1);
+ }
+ *ofd = pfd[0];
+ dup2dn = 0;
+ }
+ pid = fork();
+ switch (pid) {
+ case 0:
+ /* Child process. */
+ if (ofd != NULL)
+ if (dup2(pfd[1], STDOUT_FILENO) < 0)
+ err(1, "dup2 in %s", __func__);
+ nfd = open(_PATH_DEVNULL, O_RDWR);
+ if (nfd == -1)
+ err(1, "%s: open %s", __func__, _PATH_DEVNULL);
+ if (dup2(nfd, STDIN_FILENO) < 0)
+ err(1, "%s: dup2", __func__);
+ if (dup2dn && dup2(nfd, STDOUT_FILENO) < 0)
+ err(1, "%s: dup2", __func__);
+ if (dup2(nfd, STDERR_FILENO) < 0)
+ err(1, "%s: dup2", __func__);
+ execv(argv[0], argv);
+ warn("exec: %s", argv[0]);
+ _exit(-1);
+ case -1:
+ err(1, "%s: fork", __func__);
+ }
+ free(cmd);
+ free(argv);
+ while (waitpid(pid, &status, 0) != pid)
+ ;
+ return (WEXITSTATUS(status));
+}
+
+static const char *
+swap_on_off_sfile(char *name, int doingall)
+{
+ int error;
+
+ switch (which_prog) {
+ case SWAPON:
+ error = swapon(name);
+ break;
+ case SWAPOFF:
+ error = swapoff(name);
+ break;
+ default:
+ error = 0;
+ break;
+ }
+ if (error == -1) {
switch (errno) {
case EBUSY:
if (!doingall)
- warnx("%s: device already in use", name);
+ warnx("%s: Device already in use", name);
break;
case EINVAL:
if (which_prog == SWAPON)
@@ -205,9 +724,9 @@ swap_on_off(char *name, int doingall)
warn("%s", name);
break;
}
- return(1);
+ return (NULL);
}
- return(0);
+ return (name);
}
static void
@@ -217,7 +736,7 @@ usage(void)
switch(orig_prog) {
case SWAPON:
case SWAPOFF:
- fprintf(stderr, "[-F fstab] -aq | file ...\n");
+ fprintf(stderr, "[-F fstab] -aLq | file ...\n");
break;
case SWAPCTL:
fprintf(stderr, "[-AghklmsU] [-a file ... | -d file ...]\n");
diff --git a/share/man/man5/fstab.5 b/share/man/man5/fstab.5
index d516767..7daacf2 100644
--- a/share/man/man5/fstab.5
+++ b/share/man/man5/fstab.5
@@ -32,7 +32,7 @@
.\" @(#)fstab.5 8.1 (Berkeley) 6/5/93
.\" $FreeBSD$
.\"
-.Dd October 11, 2012
+.Dd June 21, 2013
.Dt FSTAB 5
.Os
.Sh NAME
@@ -185,6 +185,15 @@ variable must be used to extend the
.Xr rc 8
startup script's list of network file system types.
.Pp
+If the option
+.Dq late
+is specified, the file system will be automatically mounted
+at a stage of system startup after remote mount points are mounted.
+For more detail about this option,
+see the
+.Xr mount 8
+manual page.
+.Pp
The type of the mount is extracted from the
.Fa fs_mntops
field and stored separately in the
@@ -202,6 +211,7 @@ then the file system whose name is given in the
.Fa fs_file
field is normally mounted read-write or read-only on the
specified special file.
+.Pp
If
.Fa fs_type
is
@@ -210,6 +220,25 @@ then the special file is made available as a piece of swap
space by the
.Xr swapon 8
command at the end of the system reboot procedure.
+For vnode-backed swap spaces,
+.Dq file
+is supported in the
+.Fa fs_mntops
+field.
+When
+.Fa fs_spec
+is an
+.Xr md 4
+device file
+.Pq Do md Dc or Do md[0-9]* Dc
+and
+.Dq file
+is specified in
+.Fa fs_mntopts ,
+an
+.Xr md 4
+device is created with the specified file used as backing store,
+and then the new device is used as swap space.
The fields other than
.Fa fs_spec
and
OpenPOWER on IntegriCloud