- 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)
This commit is contained in:
Hiroki Sato 2013-06-27 18:28:45 +00:00
parent 25fa33476b
commit 268a55bc98
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=252310
12 changed files with 629 additions and 151 deletions

View file

@ -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

View file

@ -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 \

View file

@ -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"

View file

@ -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"

View file

@ -4,7 +4,7 @@
#
# PROVIDE: fsck
# REQUIRE: localswap
# REQUIRE: swap
# KEYWORD: nojail
. /etc/rc.subr

View file

@ -28,7 +28,7 @@
#
# PROVIDE: mdconfig
# REQUIRE: localswap root
# REQUIRE: swap root
. /etc/rc.subr

View file

@ -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"

17
etc/rc.d/swaplate Executable file
View file

@ -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"

View file

@ -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"

View file

@ -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

View file

@ -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 int
swap_on_off(char *name, int doingall)
static const char *
swap_on_off(char *name, int doingall, char *mntops)
{
if ((which_prog == SWAPOFF ? swapoff(name) : swapon(name)) == -1) {
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
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)
{
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");

View file

@ -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