From owner-svn-src-all@FreeBSD.ORG Thu Jun 27 18:28:48 2013 Return-Path: Delivered-To: svn-src-all@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [8.8.178.115]) by hub.freebsd.org (Postfix) with ESMTP id 82F856A7; Thu, 27 Jun 2013 18:28:48 +0000 (UTC) (envelope-from hrs@FreeBSD.org) Received: from svn.freebsd.org (svn.freebsd.org [IPv6:2001:1900:2254:2068::e6a:0]) by mx1.freebsd.org (Postfix) with ESMTP id 648F91846; Thu, 27 Jun 2013 18:28:48 +0000 (UTC) Received: from svn.freebsd.org ([127.0.1.70]) by svn.freebsd.org (8.14.7/8.14.7) with ESMTP id r5RISmQP033714; Thu, 27 Jun 2013 18:28:48 GMT (envelope-from hrs@svn.freebsd.org) Received: (from hrs@localhost) by svn.freebsd.org (8.14.7/8.14.5/Submit) id r5RISj03033702; Thu, 27 Jun 2013 18:28:45 GMT (envelope-from hrs@svn.freebsd.org) Message-Id: <201306271828.r5RISj03033702@svn.freebsd.org> From: Hiroki Sato Date: Thu, 27 Jun 2013 18:28:45 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r252310 - in head: etc/defaults etc/rc.d include sbin/swapon share/man/man5 X-SVN-Group: head MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-BeenThere: svn-src-all@freebsd.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: "SVN commit messages for the entire src tree \(except for " user" and " projects" \)" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Thu, 27 Jun 2013 18:28:48 -0000 Author: hrs Date: Thu Jun 27 18:28:45 2013 New Revision: 252310 URL: http://svnweb.freebsd.org/changeset/base/252310 Log: - Add vnode-backed swap space specification support. This is enabled when device names "md" or "md[0-9]*" and a "file" option are specified in /etc/fstab like this: md none swap sw,file=/swap.bin 0 0 - Add GBDE/GELI encrypted swap space specification support, which rc.d/encswap supported. The /etc/fstab lines are like the following: /dev/ada1p1.bde none swap sw 0 0 /dev/ada1p2.eli none swap sw 0 0 .eli devices accepts aalgo, ealgo, keylen, and sectorsize as options. swapctl(8) can understand an encrypted device in the command line like this: # swapctl -a /dev/ada2p1.bde - "-L" flag is added to support "late" option to defer swapon until rc.d/mountlate runs. - rc.d script change: rc.d/encswap -> removed rc.d/addswap -> just display a warning message if $swapfile is defined rc.d/swap1 -> renamed to rc.d/swap rc.d/swaplate -> newly added to support "late" option These changes alleviate a race condition between device creation/removal and swapon/swapoff. MFC after: 1 week Reviewed by: wblock (manual page) Added: head/etc/rc.d/swap - copied, changed from r251659, head/etc/rc.d/swap1 head/etc/rc.d/swaplate (contents, props changed) Deleted: head/etc/rc.d/encswap head/etc/rc.d/swap1 Modified: head/etc/defaults/rc.conf head/etc/rc.d/Makefile head/etc/rc.d/addswap head/etc/rc.d/fsck head/etc/rc.d/mdconfig head/include/paths.h head/sbin/swapon/swapon.8 head/sbin/swapon/swapon.c head/share/man/man5/fstab.5 Modified: head/etc/defaults/rc.conf ============================================================================== --- head/etc/defaults/rc.conf Thu Jun 27 18:24:24 2013 (r252309) +++ head/etc/defaults/rc.conf Thu Jun 27 18:28:45 2013 (r252310) @@ -32,8 +32,6 @@ early_late_divider="FILESYSTEMS" # Scrip 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 de #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 Modified: head/etc/rc.d/Makefile ============================================================================== --- head/etc/rc.d/Makefile Thu Jun 27 18:24:24 2013 (r252309) +++ head/etc/rc.d/Makefile Thu Jun 27 18:28:45 2013 (r252310) @@ -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 \ Modified: head/etc/rc.d/addswap ============================================================================== --- head/etc/rc.d/addswap Thu Jun 27 18:24:24 2013 (r252309) +++ head/etc/rc.d/addswap Thu Jun 27 18:28:45 2013 (r252310) @@ -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" Modified: head/etc/rc.d/fsck ============================================================================== --- head/etc/rc.d/fsck Thu Jun 27 18:24:24 2013 (r252309) +++ head/etc/rc.d/fsck Thu Jun 27 18:28:45 2013 (r252310) @@ -4,7 +4,7 @@ # # PROVIDE: fsck -# REQUIRE: localswap +# REQUIRE: swap # KEYWORD: nojail . /etc/rc.subr Modified: head/etc/rc.d/mdconfig ============================================================================== --- head/etc/rc.d/mdconfig Thu Jun 27 18:24:24 2013 (r252309) +++ head/etc/rc.d/mdconfig Thu Jun 27 18:28:45 2013 (r252310) @@ -28,7 +28,7 @@ # # PROVIDE: mdconfig -# REQUIRE: localswap root +# REQUIRE: swap root . /etc/rc.subr Copied and modified: head/etc/rc.d/swap (from r251659, head/etc/rc.d/swap1) ============================================================================== --- head/etc/rc.d/swap1 Wed Jun 12 16:13:05 2013 (r251659, copy source) +++ head/etc/rc.d/swap Thu Jun 27 18:28:45 2013 (r252310) @@ -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" Added: head/etc/rc.d/swaplate ============================================================================== --- /dev/null 00:00:00 1970 (empty, because file is newly added) +++ head/etc/rc.d/swaplate Thu Jun 27 18:28:45 2013 (r252310) @@ -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" Modified: head/include/paths.h ============================================================================== --- head/include/paths.h Thu Jun 27 18:24:24 2013 (r252309) +++ head/include/paths.h Thu Jun 27 18:28:45 2013 (r252310) @@ -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" Modified: head/sbin/swapon/swapon.8 ============================================================================== --- head/sbin/swapon/swapon.8 Thu Jun 27 18:24:24 2013 (r252309) +++ head/sbin/swapon/swapon.8 Thu Jun 27 18:28:45 2013 (r252310) @@ -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 Modified: head/sbin/swapon/swapon.c ============================================================================== --- head/sbin/swapon/swapon.c Thu Jun 27 18:24:24 2013 (r252309) +++ head/sbin/swapon/swapon.c Thu Jun 27 18:28:45 2013 (r252310) @@ -41,35 +41,51 @@ static char sccsid[] = "@(#)swapon.c 8.1 #include __FBSDID("$FreeBSD$"); -#include #include +#include +#include +#include #include +#include #include #include #include +#include +#include #include +#include +#include +#include +#include +#include #include #include #include #include -#include -#include 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, ...) +{ + 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) { - if ((which_prog == SWAPOFF ? swapoff(name) : swapon(name)) == -1) { + 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"); Modified: head/share/man/man5/fstab.5 ============================================================================== --- head/share/man/man5/fstab.5 Thu Jun 27 18:24:24 2013 (r252309) +++ head/share/man/man5/fstab.5 Thu Jun 27 18:28:45 2013 (r252310) @@ -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 .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 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