diff --git a/etc/mtree/BSD.tests.dist b/etc/mtree/BSD.tests.dist --- a/etc/mtree/BSD.tests.dist +++ b/etc/mtree/BSD.tests.dist @@ -509,6 +509,8 @@ .. savecore .. + swapon + .. sysctl .. .. diff --git a/sbin/swapon/Makefile b/sbin/swapon/Makefile --- a/sbin/swapon/Makefile +++ b/sbin/swapon/Makefile @@ -8,4 +8,9 @@ LIBADD= util +.include + +HAS_TESTS= +SUBDIR.${MK_TESTS}+= tests + .include diff --git a/sbin/swapon/swapon.c b/sbin/swapon/swapon.c --- a/sbin/swapon/swapon.c +++ b/sbin/swapon/swapon.c @@ -54,6 +54,8 @@ #include #include +#define DOT_ELI ".eli" + static void usage(void) __dead2; static const char *swap_on_off(const char *, int, char *); static const char *swap_on_off_geli(const char *, char *, int); @@ -231,14 +233,17 @@ fnmatch(MD_NAME "[0-9]*", name, 0) == 0 || strncmp(_PATH_DEV MD_NAME, name, sizeof(_PATH_DEV) + sizeof(MD_NAME)) == 0 || - strncmp(MD_NAME, name, sizeof(MD_NAME)) == 0)) + strncmp(MD_NAME, name, sizeof(MD_NAME)) == 0 || + strncmp(_PATH_DEV MD_NAME DOT_ELI, name, + sizeof(_PATH_DEV) + sizeof(MD_NAME) + sizeof(DOT_ELI)) == 0 || + strncmp(MD_NAME DOT_ELI, name, sizeof(MD_NAME) + sizeof(DOT_ELI)) == 0)) return (swap_on_off_md(name, mntops, doingall)); basebuf = strdup(name); base = basename(basebuf); /* Swap on encrypted device by GEOM_ELI. */ - if (fnmatch("*.eli", base, 0) == 0) { + if (fnmatch("*" DOT_ELI, base, 0) == 0) { free(basebuf); return (swap_on_off_geli(name, mntops, doingall)); } @@ -327,6 +332,8 @@ return (NULL); } Tflag = " -T "; + } else if ((p = strstr(token, "file=")) == token) { + /* ignore known option */ } else if (strcmp(token, "late") == 0) { /* ignore known option */ } else if (strcmp(token, "noauto") == 0) { @@ -416,24 +423,37 @@ char *p, *vnodefile; size_t linelen; u_long ul; + const char *suffix; + char *dname; + int name_len; fd = -1; sfd = NULL; - if (strlen(name) == (sizeof(MD_NAME) - 1)) + dname = strdup(name); + name_len = strlen(name) - strlen(DOT_ELI); + /* dname will be name without (.eli) suffix */ + if (name_len > 0 && strcmp(suffix = &name[name_len], DOT_ELI) == 0) { + suffix++; + dname[name_len] = '\0'; + } else + suffix = NULL; + if (strlen(dname) == (sizeof(MD_NAME) - 1)) mdunit = -1; else { errno = 0; - ul = strtoul(name + 2, &p, 10); + ul = strtoul(dname + 2, &p, 10); if (errno == 0) { if (*p != '\0' || ul > INT_MAX) errno = EINVAL; } if (errno) { - warn("Bad device unit: %s", name); + warn("Bad device unit: %s", dname); + free(dname); return (NULL); } mdunit = (int)ul; } + free(dname); vnodefile = NULL; if ((p = strstr(mntops, "file=")) != NULL) { @@ -573,10 +593,19 @@ } } } - snprintf(mdpath, sizeof(mdpath), "%s%s%d", _PATH_DEV, - MD_NAME, mdunit); - mdpath[sizeof(mdpath) - 1] = '\0'; - ret = swap_on_off_sfile(mdpath, doingall); + + if (suffix != NULL && strcmp("eli", suffix) == 0) { + /* Swap on encrypted device by GEOM_ELI. */ + snprintf(mdpath, sizeof(mdpath), "%s%s%d" DOT_ELI, _PATH_DEV, + MD_NAME, mdunit); + mdpath[sizeof(mdpath) - 1] = '\0'; + ret = swap_on_off_geli(mdpath, mntops, doingall); + } else { + snprintf(mdpath, sizeof(mdpath), "%s%s%d", _PATH_DEV, + MD_NAME, mdunit); + mdpath[sizeof(mdpath) - 1] = '\0'; + ret = swap_on_off_sfile(mdpath, doingall); + } if (which_prog == SWAPOFF) { if (ret != NULL) { diff --git a/sbin/swapon/tests/Makefile b/sbin/swapon/tests/Makefile new file mode 100644 --- /dev/null +++ b/sbin/swapon/tests/Makefile @@ -0,0 +1,5 @@ +ATF_TESTS_SH= swapon_test + +TEST_METADATA.swapon_test+= required_user="root" + +.include diff --git a/sbin/swapon/tests/swapon_test.sh b/sbin/swapon/tests/swapon_test.sh new file mode 100755 --- /dev/null +++ b/sbin/swapon/tests/swapon_test.sh @@ -0,0 +1,46 @@ +# Copyright (c) 2025 Ronald Klop +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +# SUCH DAMAGE. +# +# + +atf_test_case attach_md0_eli cleanup +attach_md0_eli_head() +{ + atf_set "descr" "md0.eli device should attach" +} +attach_md0_eli_body() +{ + # if the swapfile is too small (like 1k) then mdconfig hangs looking up the md + atf_check -s exit:0 -x "truncate -s 1m swapfile" + atf_check -s exit:0 -o save:fstab.out -x "echo 'md0.eli none swap sw,file=swapfile 0 0'" + atf_check -s exit:0 -o match:"swapon: adding /dev/md0.eli as swap device" -x "swapon -F fstab.out -a" +} +attach_md0_eli_cleanup() +{ + swapoff -F fstab.out -a +} + +atf_init_test_cases() +{ + atf_add_test_case attach_md0_eli +}