diff options
author | Renato Botelho <renato@netgate.com> | 2017-02-23 06:28:41 -0300 |
---|---|---|
committer | Renato Botelho <renato@netgate.com> | 2017-02-23 06:28:41 -0300 |
commit | 82ceeb2ea625cd9bff60f2863b9a0830f55b7905 (patch) | |
tree | 263ca9347bf664a4489743f9302e699ce14de1df /tests | |
parent | 4a05f5440acda223e6a0ec5157bc32ecc0f09ff9 (diff) | |
parent | d20dd8b36e7a565be7bfbb22aade51c8ffd753e9 (diff) | |
download | FreeBSD-src-82ceeb2ea625cd9bff60f2863b9a0830f55b7905.zip FreeBSD-src-82ceeb2ea625cd9bff60f2863b9a0830f55b7905.tar.gz |
Merge remote-tracking branch 'origin/stable/10' into develdevel
Diffstat (limited to 'tests')
25 files changed, 1001 insertions, 216 deletions
diff --git a/tests/etc/Makefile b/tests/etc/Makefile index 9aad25c..1e49666 100644 --- a/tests/etc/Makefile +++ b/tests/etc/Makefile @@ -4,7 +4,7 @@ TESTSDIR= ${TESTSBASE}/etc -.PATH: ${.CURDIR:H} +.PATH: ${SRCTOP}/tests KYUAFILE= yes SUBDIR+= rc.d diff --git a/tests/sys/Makefile b/tests/sys/Makefile index 18a24a4..88881f2 100644 --- a/tests/sys/Makefile +++ b/tests/sys/Makefile @@ -8,6 +8,7 @@ TESTS_SUBDIRS+= acl TESTS_SUBDIRS+= aio TESTS_SUBDIRS+= fifo TESTS_SUBDIRS+= file +TESTS_SUBDIRS+= fs TESTS_SUBDIRS+= geom TESTS_SUBDIRS+= kern TESTS_SUBDIRS+= kqueue @@ -22,6 +23,4 @@ TESTS_SUBDIRS+= vm # Items not integrated into kyua runs by default SUBDIR+= pjdfstest -SUBDIR_PARALLEL= - .include <bsd.test.mk> diff --git a/tests/sys/fs/Makefile b/tests/sys/fs/Makefile new file mode 100644 index 0000000..9ed47c0 --- /dev/null +++ b/tests/sys/fs/Makefile @@ -0,0 +1,21 @@ +# $FreeBSD$ + +TESTSDIR= ${TESTSBASE}/sys/fs + +TESTSRC= ${SRCTOP}/contrib/netbsd-tests/fs + +#TESTS_SUBDIRS+= nullfs # XXX: needs rump +TESTS_SUBDIRS+= tmpfs + +FILES+= h_funcs.subr +FILESDIR= ${TESTSDIR} + +CLEANFILES+= h_funcs.subr +CLEANFILES+= h_funcs.subr.tmp + +h_funcs.subr: ${TESTSRC}/h_funcs.subr + cat ${.ALLSRC} | \ + sed -e '/atf_require_prog mount_$${name}/d' >>${.TARGET}.tmp + mv ${.TARGET}.tmp ${.TARGET} + +.include <bsd.test.mk> diff --git a/tests/sys/fs/tmpfs/Makefile b/tests/sys/fs/tmpfs/Makefile new file mode 100644 index 0000000..78702dd --- /dev/null +++ b/tests/sys/fs/tmpfs/Makefile @@ -0,0 +1,56 @@ +# $FreeBSD$ + +PACKAGE= tests + +FILESYSTEM?= ${.CURDIR:T} + +TESTSDIR= ${TESTSBASE}/sys/fs/${FILESYSTEM} + +TESTSRC= ${SRCTOP}/contrib/netbsd-tests/fs/${FILESYSTEM} + +# XXX: uses /dev/MAKEDEV to create pseudo /dev/{null,zero} character devices +#NETBSD_ATF_TESTS_SH+= devices_test +NETBSD_ATF_TESTS_SH+= create_test +NETBSD_ATF_TESTS_SH+= read_write_test +NETBSD_ATF_TESTS_SH+= dots_test +NETBSD_ATF_TESTS_SH+= exec_test +NETBSD_ATF_TESTS_SH+= link_test +NETBSD_ATF_TESTS_SH+= mkdir_test +NETBSD_ATF_TESTS_SH+= mknod_test +NETBSD_ATF_TESTS_SH+= mount_test +# XXX: need to replace `mknod ... p` with something more sensible +#NETBSD_ATF_TESTS_SH+= pipes_test +NETBSD_ATF_TESTS_SH+= trail_slash_test +NETBSD_ATF_TESTS_SH+= readdir_test +NETBSD_ATF_TESTS_SH+= remove_test +NETBSD_ATF_TESTS_SH+= rename_test +NETBSD_ATF_TESTS_SH+= rmdir_test +NETBSD_ATF_TESTS_SH+= setattr_test +NETBSD_ATF_TESTS_SH+= sizes_test +NETBSD_ATF_TESTS_SH+= sockets_test +NETBSD_ATF_TESTS_SH+= statvfs_test +NETBSD_ATF_TESTS_SH+= symlink_test +NETBSD_ATF_TESTS_SH+= times_test +NETBSD_ATF_TESTS_SH+= truncate_test +NETBSD_ATF_TESTS_SH+= vnd_test +NETBSD_ATF_TESTS_SH+= vnode_leak_test + +FILES+= h_funcs.subr +FILESDIR= ${TESTSDIR} + +PROGS+= h_tools +BINDIR.h_tools= ${TESTSDIR} + +ATF_TESTS_SH_SED_mount_test= \ + -e 's,-o -g,-o gid=,g' \ + -e 's,-o -m,-o mode=,g' \ + -e 's,-o -s,-o size=,g' \ + -e 's,-o -u,-o uid=,g' \ + -e 's,mount_${FILESYSTEM},mount -t ${FILESYSTEM},g' +ATF_TESTS_SH_SED_sizes_test= -e 's,-o -s,-o size=,g' +ATF_TESTS_SH_SED_statvfs_test= -e 's,-o -s,-o size=,g' +ATF_TESTS_SH_SED_vnode_leak_test= -e 's,-o -s,-o size=,g' + +.include <netbsd-tests.test.mk> + +.include <bsd.test.mk> diff --git a/tests/sys/geom/class/gate/1_test.sh b/tests/sys/geom/class/gate/1_test.sh deleted file mode 100644 index ba573bb..0000000 --- a/tests/sys/geom/class/gate/1_test.sh +++ /dev/null @@ -1,63 +0,0 @@ -#!/bin/sh -# $FreeBSD$ - -. `dirname $0`/conf.sh - -echo '1..2' - -base=`basename $0` -us=0 -while [ -c /dev/ggate${us} ]; do - : $(( us += 1 )) -done -pidfile=ggated.$$.pid -conf=`mktemp $base.XXXXXX` || exit 1 -port=33080 - -work=$(attach_md -t malloc -s 1M) -src=$(attach_md -t malloc -s 1M) - -test_cleanup() -{ - ggatec destroy -f -u $us - pkill -F $pidfile - geom_test_cleanup -} -trap test_cleanup ABRT EXIT INT TERM - -dd if=/dev/random of=/dev/$work bs=1m count=1 conv=sync -dd if=/dev/random of=/dev/$src bs=1m count=1 conv=sync -src_checksum=$(md5 -q /dev/$src) - -echo "127.0.0.1 RW /dev/$work" > $conf - -if ! ggated -p $port -F $pidfile $conf; then - echo 'ggated failed to start' - echo 'Bail out!' - exit 1 -fi -sleep 1 -if ! ggatec create -p $port -u $us 127.0.0.1 /dev/$work; then - echo 'ggatec create failed' - echo 'Bail out!' - exit 1 -fi -sleep 1 - -dd if=/dev/${src} of=/dev/ggate${us} bs=1m count=1 -sleep 1 - -work_checksum=$(md5 -q /dev/$work) -if [ "$work_checksum" != "$src_checksum" ]; then - echo "not ok 1 - md5 checksums didn't match ($work_checksum != $src_checksum)" - echo "not ok 2 # SKIP" -else - echo 'ok 1 - md5 checksum' - - ggate_checksum=$(md5 -q /dev/ggate${us}) - if [ "$ggate_checksum" != "$src_checksum" ]; then - echo "not ok 2 - md5 checksums didn't match ($ggate_checksum != $src_checksum)" - else - echo 'ok 2 - md5 checksum' - fi -fi diff --git a/tests/sys/geom/class/gate/2_test.sh b/tests/sys/geom/class/gate/2_test.sh deleted file mode 100644 index be89acc..0000000 --- a/tests/sys/geom/class/gate/2_test.sh +++ /dev/null @@ -1,48 +0,0 @@ -#!/bin/sh -# $FreeBSD$ - -. `dirname $0`/conf.sh - -base=`basename $0` -us=46 -work=`mktemp -u $base.XXXXXX` || exit 1 -src=`mktemp -u $base.XXXXXX` || exit 1 - -test_cleanup() -{ - ggatel destroy -f -u $us - rm -f $work $src - - geom_test_cleanup -} -trap test_cleanup ABRT EXIT INT TERM - -dd if=/dev/random of=$work bs=1m count=1 conv=sync -dd if=/dev/random of=$src bs=1m count=1 conv=sync - -if ! ggatel create -u $us $work; then - echo 'ggatel create failed' - echo 'Bail out!' - exit 1 -fi - -dd if=${src} of=/dev/ggate${us} bs=1m count=1 -sleep 1 - -echo '1..2' - -src_checksum=$(md5 -q $src) -work_checksum=$(md5 -q $work) -if [ "$work_checksum" != "$src_checksum" ]; then - echo "not ok 1 - md5 checksums didn't match ($work_checksum != $src_checksum) # TODO: bug 204616" - echo 'not ok 2 # SKIP' -else - echo 'ok 1 - md5 checksum' - - ggate_checksum=$(md5 -q /dev/ggate${us}) - if [ "$ggate_checksum" != "$src_checksum" ]; then - echo "not ok 2 - md5 checksums didn't match ($ggate_checksum != $src_checksum)" - else - echo 'ok 2 - md5 checksum' - fi -fi diff --git a/tests/sys/geom/class/gate/3_test.sh b/tests/sys/geom/class/gate/3_test.sh deleted file mode 100644 index 3511df7..0000000 --- a/tests/sys/geom/class/gate/3_test.sh +++ /dev/null @@ -1,49 +0,0 @@ -#!/bin/sh -# $FreeBSD$ - -. `dirname $0`/conf.sh - -base=`basename $0` -us=47 - -test_cleanup() -{ - ggatel destroy -f -u $us - - geom_test_cleanup -} -trap test_cleanup ABRT EXIT INT TERM - -work=$(attach_md -t malloc -s 1M) -src=$(attach_md -t malloc -s 1M) - -dd if=/dev/random of=/dev/$work bs=1m count=1 conv=sync -dd if=/dev/random of=/dev/$src bs=1m count=1 conv=sync -src_checksum=$(md5 -q /dev/$src) - -if ! ggatel create -u $us /dev/$work; then - echo 'ggatel create failed' - echo 'Bail out!' - exit 1 -fi - -sleep 1 -dd if=/dev/${src} of=/dev/ggate${us} bs=1m count=1 conv=sync -sleep 1 - -echo '1..2' - -work_checksum=$(md5 -q /dev/$work) -if [ "$work_checksum" != "$src_checksum" ]; then - echo "not ok 1 - md5 checksums didn't match ($work_checksum != $src_checksum)" - echo 'not ok 2 # SKIP' -else - echo 'ok 1 - md5 checksum' - - ggate_checksum=$(md5 -q /dev/ggate${us}) - if [ "$ggate_checksum" != "$src_checksum" ]; then - echo "not ok 2 - md5 checksums didn't match ($ggate_checksum != $src_checksum)" - else - echo 'ok 2 - md5 checksum' - fi -fi diff --git a/tests/sys/geom/class/gate/Makefile b/tests/sys/geom/class/gate/Makefile index 11ceb94..0b84248 100644 --- a/tests/sys/geom/class/gate/Makefile +++ b/tests/sys/geom/class/gate/Makefile @@ -2,16 +2,6 @@ TESTSDIR= ${TESTSBASE}/sys/geom/class/${.CURDIR:T} -TAP_TESTS_SH+= 1_test -TAP_TESTS_SH+= 2_test -TAP_TESTS_SH+= 3_test - -FILES+= conf.sh -FILESNAME_conf.sh= conf.sh -FILESDIR= ${TESTSDIR} - -.for t in ${TAP_TESTS_SH} -TEST_METADATA.$t+= required_user="root" -.endfor +ATF_TESTS_SH+= ggate_test .include <bsd.test.mk> diff --git a/tests/sys/geom/class/gate/conf.sh b/tests/sys/geom/class/gate/conf.sh deleted file mode 100755 index 7e22ce4..0000000 --- a/tests/sys/geom/class/gate/conf.sh +++ /dev/null @@ -1,8 +0,0 @@ -#!/bin/sh -# $FreeBSD$ - -name="$(mktemp -u gate.XXXXXX)" -class="gate" -base=`basename $0` - -. `dirname $0`/../geom_subr.sh diff --git a/tests/sys/geom/class/gate/ggate_test.sh b/tests/sys/geom/class/gate/ggate_test.sh new file mode 100755 index 0000000..18b4214 --- /dev/null +++ b/tests/sys/geom/class/gate/ggate_test.sh @@ -0,0 +1,207 @@ +# $FreeBSD$ + +PIDFILE=ggated.pid +PLAINFILES=plainfiles +PORT=33080 +CONF=gg.exports + +atf_test_case ggated cleanup +ggated_head() +{ + atf_set "descr" "ggated can proxy geoms" + atf_set "require.progs" "ggatec ggated" + atf_set "require.user" "root" + atf_set "timeout" 60 +} + +ggated_body() +{ + us=$(alloc_ggate_dev) + work=$(alloc_md) + src=$(alloc_md) + + atf_check -e ignore -o ignore \ + dd if=/dev/random of=/dev/$work bs=1m count=1 conv=notrunc + atf_check -e ignore -o ignore \ + dd if=/dev/random of=/dev/$src bs=1m count=1 conv=notrunc + + echo $CONF >> $PLAINFILES + echo "127.0.0.1 RW /dev/$work" > $CONF + + atf_check ggated -p $PORT -F $PIDFILE $CONF + atf_check ggatec create -p $PORT -u $us 127.0.0.1 /dev/$work + + ggate_dev=/dev/ggate${us} + + wait_for_ggate_device ${ggate_dev} + + atf_check -e ignore -o ignore \ + dd if=/dev/${src} of=${ggate_dev} bs=1m count=1 conv=notrunc + + checksum /dev/$src /dev/$work +} + +ggated_cleanup() +{ + common_cleanup +} + +atf_test_case ggatel_file cleanup +ggatel_file_head() +{ + atf_set "descr" "ggatel can proxy files" + atf_set "require.progs" "ggatel" + atf_set "require.user" "root" + atf_set "timeout" 15 +} + +ggatel_file_body() +{ + us=$(alloc_ggate_dev) + + echo src work >> ${PLAINFILES} + dd if=/dev/random of=work bs=1m count=1 + dd if=/dev/random of=src bs=1m count=1 + + atf_check ggatel create -u $us work + + ggate_dev=/dev/ggate${us} + + wait_for_ggate_device ${ggate_dev} + + atf_check -e ignore -o ignore \ + dd if=src of=${ggate_dev} bs=1m count=1 conv=notrunc + + checksum src work +} + +ggatel_file_cleanup() +{ + common_cleanup +} + +atf_test_case ggatel_md cleanup +ggatel_md_head() +{ + atf_set "descr" "ggatel can proxy files" + atf_set "require.progs" "ggatel" + atf_set "require.user" "root" + atf_set "timeout" 15 +} + +ggatel_md_body() +{ + us=$(alloc_ggate_dev) + work=$(alloc_md) + src=$(alloc_md) + + atf_check -e ignore -o ignore \ + dd if=/dev/random of=$work bs=1m count=1 conv=notrunc + atf_check -e ignore -o ignore \ + dd if=/dev/random of=$src bs=1m count=1 conv=notrunc + + atf_check ggatel create -u $us /dev/$work + + ggate_dev=/dev/ggate${us} + + wait_for_ggate_device ${ggate_dev} + + atf_check -e ignore -o ignore \ + dd if=/dev/$src of=${ggate_dev} bs=1m count=1 conv=notrunc + + checksum /dev/$src /dev/$work +} + +ggatel_md_cleanup() +{ + common_cleanup +} + +atf_init_test_cases() +{ + atf_add_test_case ggated + atf_add_test_case ggatel_file + atf_add_test_case ggatel_md +} + +alloc_ggate_dev() +{ + local us + + us=0 + while [ -c /dev/ggate${us} ]; do + : $(( us += 1 )) + done + echo ${us} > ggate.devs + echo ${us} +} + +alloc_md() +{ + local md + + md=$(mdconfig -a -t malloc -s 1M) || \ + atf_fail "failed to allocate md device" + echo ${md} >> md.devs + echo ${md} +} + +checksum() +{ + local src work + src=$1 + work=$2 + + src_checksum=$(dd if=${src} bs=1m | md5 -q) + work_checksum=$(dd if=${work} bs=1m | md5 -q) + + if [ "$work_checksum" != "$src_checksum" ]; then + atf_fail "work md5 checksum didn't match" + fi + + ggate_checksum=$(dd if=/dev/ggate${us} bs=1m | md5 -q) + if [ "$ggate_checksum" != "$src_checksum" ]; then + atf_fail "ggate md5 checksum didn't match" + fi +} + +common_cleanup() +{ + if [ -f "ggate.devs" ]; then + while read test_ggate; do + ggatec destroy -f -u $test_ggate >/dev/null + done < ggate.devs + rm ggate.devs + fi + + if [ -f "$PIDFILE" ]; then + pkill -F "$PIDFILE" + rm $PIDFILE + fi + + if [ -f "PLAINFILES" ]; then + while read f; do + rm -f ${f} + done < ${PLAINFILES} + rm ${PLAINFILES} + fi + + if [ -f "md.devs" ]; then + while read test_md; do + mdconfig -d -u $test_md 2>/dev/null + done < md.devs + rm md.devs + fi + true +} + +# Bug 204616: ggatel(8) creates /dev/ggate* asynchronously if `ggatel create` +# isn't called with `-v`. +wait_for_ggate_device() +{ + ggate_device=$1 + + while [ ! -c $ggate_device ]; do + sleep 0.5 + done +} diff --git a/tests/sys/kqueue/Makefile b/tests/sys/kqueue/Makefile index 43277ca..40f892d 100644 --- a/tests/sys/kqueue/Makefile +++ b/tests/sys/kqueue/Makefile @@ -1,26 +1,20 @@ # $FreeBSD$ -# -# svn://mark.heily.com/libkqueue/trunk/test -# Last update: r114 -# -# libkqueue and test suite by Mark Heily <mark@heily.com> -# -TAP_TESTS_SH= kqueue_test +TESTSRC= ${SRCTOP}/contrib/netbsd-tests/kernel/kqueue TESTSDIR= ${TESTSBASE}/sys/kqueue BINDIR= ${TESTSDIR} -PROGS= kqtest +NETBSD_ATF_TESTS_C= proc1_test +# XXX: fails `ke.fflags & NOTE_TRACKERR` invariant +#NETBSD_ATF_TESTS_C+= proc2_test +NETBSD_ATF_TESTS_C+= proc3_test +NETBSD_ATF_TESTS_C+= sig_test +NETBSD_ATF_TESTS_C+= vnode_test -SRCS.kqtest= \ - main.c \ - read.c \ - timer.c \ - vnode.c \ - proc.c \ - signal.c \ - user.c -WARNS?= 2 +WARNS?= 3 +TESTS_SUBDIRS+= libkqueue + +.include <netbsd-tests.test.mk> .include <bsd.test.mk> diff --git a/tests/sys/kqueue/libkqueue/Makefile b/tests/sys/kqueue/libkqueue/Makefile new file mode 100644 index 0000000..94d198b --- /dev/null +++ b/tests/sys/kqueue/libkqueue/Makefile @@ -0,0 +1,21 @@ +# $FreeBSD$ + +TESTSDIR= ${TESTSBASE}/sys/kqueue/libkqueue +BINDIR= ${TESTSDIR} + +# libkqueue and test suite by Mark Heily <mark@heily.com> +TAP_TESTS_SH= kqueue_test + +PROGS= kqtest + +SRCS.kqtest= \ + main.c \ + read.c \ + timer.c \ + vnode.c \ + proc.c \ + signal.c \ + user.c +WARNS?= 2 + +.include <bsd.test.mk> diff --git a/tests/sys/kqueue/libkqueue/Makefile.depend b/tests/sys/kqueue/libkqueue/Makefile.depend new file mode 100644 index 0000000..3646e2e --- /dev/null +++ b/tests/sys/kqueue/libkqueue/Makefile.depend @@ -0,0 +1,18 @@ +# $FreeBSD$ +# Autogenerated - do NOT edit! + +DIRDEPS = \ + gnu/lib/csu \ + gnu/lib/libgcc \ + include \ + include/xlocale \ + lib/${CSU_DIR} \ + lib/libc \ + lib/libcompiler_rt \ + + +.include <dirdeps.mk> + +.if ${DEP_RELDIR} == ${_DEP_RELDIR} +# local dependencies - needed for -jN in clean tree +.endif diff --git a/tests/sys/kqueue/common.h b/tests/sys/kqueue/libkqueue/common.h index 89a4029..89a4029 100644 --- a/tests/sys/kqueue/common.h +++ b/tests/sys/kqueue/libkqueue/common.h diff --git a/tests/sys/kqueue/config.h b/tests/sys/kqueue/libkqueue/config.h index a204092..a204092 100644 --- a/tests/sys/kqueue/config.h +++ b/tests/sys/kqueue/libkqueue/config.h diff --git a/tests/sys/kqueue/kqueue_test.sh b/tests/sys/kqueue/libkqueue/kqueue_test.sh index 62a7e23..3185d82 100755 --- a/tests/sys/kqueue/kqueue_test.sh +++ b/tests/sys/kqueue/libkqueue/kqueue_test.sh @@ -1,8 +1,8 @@ #!/bin/sh +# $FreeBSD$ -cd $(dirname $0) i=1 -./kqtest | while read line; do +"$(dirname $0)/kqtest" | while read line; do echo $line | grep -q passed if [ $? -eq 0 ]; then echo "ok - $i $line" diff --git a/tests/sys/kqueue/libkqueue/main.c b/tests/sys/kqueue/libkqueue/main.c new file mode 100644 index 0000000..26e8f91 --- /dev/null +++ b/tests/sys/kqueue/libkqueue/main.c @@ -0,0 +1,323 @@ +/* + * Copyright (c) 2009 Mark Heily <mark@heily.com> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * $FreeBSD$ + */ + +#include <sys/types.h> + +#include "config.h" +#include "common.h" + +int testnum = 1; +char *cur_test_id = NULL; +int kqfd; + +extern void test_evfilt_read(); +extern void test_evfilt_signal(); +extern void test_evfilt_vnode(); +extern void test_evfilt_timer(); +extern void test_evfilt_proc(); +#if HAVE_EVFILT_USER +extern void test_evfilt_user(); +#endif + +/* Checks if any events are pending, which is an error. */ +void +test_no_kevents(void) +{ + int nfds; + struct timespec timeo; + struct kevent kev; + + puts("confirming that there are no events pending"); + memset(&timeo, 0, sizeof(timeo)); + nfds = kevent(kqfd, NULL, 0, &kev, 1, &timeo); + if (nfds != 0) { + puts("\nUnexpected event:"); + puts(kevent_to_str(&kev)); + errx(1, "%d event(s) pending, but none expected:", nfds); + } +} + +/* Retrieve a single kevent */ +struct kevent * +kevent_get(int kqfd) +{ + int nfds; + struct kevent *kev; + + if ((kev = calloc(1, sizeof(*kev))) == NULL) + err(1, "out of memory"); + + nfds = kevent(kqfd, NULL, 0, kev, 1, NULL); + if (nfds < 1) + err(1, "kevent(2)"); + + return (kev); +} + +/* Retrieve a single kevent, specifying a maximum time to wait for it. */ +struct kevent * +kevent_get_timeout(int kqfd, int seconds) +{ + int nfds; + struct kevent *kev; + struct timespec timeout = {seconds, 0}; + + if ((kev = calloc(1, sizeof(*kev))) == NULL) + err(1, "out of memory"); + + nfds = kevent(kqfd, NULL, 0, kev, 1, &timeout); + if (nfds < 0) { + err(1, "kevent(2)"); + } else if (nfds == 0) { + free(kev); + kev = NULL; + } + + return (kev); +} + +char * +kevent_fflags_dump(struct kevent *kev) +{ + char *buf; + +#define KEVFFL_DUMP(attrib) \ + if (kev->fflags & attrib) \ + strncat(buf, #attrib" ", 64); + + if ((buf = calloc(1, 1024)) == NULL) + abort(); + + /* Not every filter has meaningful fflags */ + if (kev->filter == EVFILT_PROC) { + snprintf(buf, 1024, "fflags = %x (", kev->fflags); + KEVFFL_DUMP(NOTE_EXIT); + KEVFFL_DUMP(NOTE_FORK); + KEVFFL_DUMP(NOTE_EXEC); + KEVFFL_DUMP(NOTE_CHILD); + KEVFFL_DUMP(NOTE_TRACKERR); + KEVFFL_DUMP(NOTE_TRACK); + buf[strlen(buf) - 1] = ')'; + } else if (kev->filter == EVFILT_VNODE) { + snprintf(buf, 1024, "fflags = %x (", kev->fflags); + KEVFFL_DUMP(NOTE_DELETE); + KEVFFL_DUMP(NOTE_WRITE); + KEVFFL_DUMP(NOTE_EXTEND); +#if HAVE_NOTE_TRUNCATE + KEVFFL_DUMP(NOTE_TRUNCATE); +#endif + KEVFFL_DUMP(NOTE_ATTRIB); + KEVFFL_DUMP(NOTE_LINK); + KEVFFL_DUMP(NOTE_RENAME); +#if HAVE_NOTE_REVOKE + KEVFFL_DUMP(NOTE_REVOKE); +#endif + buf[strlen(buf) - 1] = ')'; + } else { + snprintf(buf, 1024, "fflags = %x", kev->fflags); + } + + return (buf); +} + +char * +kevent_flags_dump(struct kevent *kev) +{ + char *buf; + +#define KEVFL_DUMP(attrib) \ + if (kev->flags & attrib) \ + strncat(buf, #attrib" ", 64); + + if ((buf = calloc(1, 1024)) == NULL) + abort(); + + snprintf(buf, 1024, "flags = %d (", kev->flags); + KEVFL_DUMP(EV_ADD); + KEVFL_DUMP(EV_ENABLE); + KEVFL_DUMP(EV_DISABLE); + KEVFL_DUMP(EV_DELETE); + KEVFL_DUMP(EV_ONESHOT); + KEVFL_DUMP(EV_CLEAR); + KEVFL_DUMP(EV_EOF); + KEVFL_DUMP(EV_ERROR); +#if HAVE_EV_DISPATCH + KEVFL_DUMP(EV_DISPATCH); +#endif +#if HAVE_EV_RECEIPT + KEVFL_DUMP(EV_RECEIPT); +#endif + buf[strlen(buf) - 1] = ')'; + + return (buf); +} + +/* Copied from ../kevent.c kevent_dump() and improved */ +const char * +kevent_to_str(struct kevent *kev) +{ + char buf[512]; + + snprintf(&buf[0], sizeof(buf), + "[ident=%d, filter=%d, %s, %s, data=%d, udata=%p]", + (u_int) kev->ident, + kev->filter, + kevent_flags_dump(kev), + kevent_fflags_dump(kev), + (int) kev->data, + kev->udata); + + return (strdup(buf)); +} + +void +kevent_add(int kqfd, struct kevent *kev, + uintptr_t ident, + short filter, + u_short flags, + u_int fflags, + intptr_t data, + void *udata) +{ + EV_SET(kev, ident, filter, flags, fflags, data, NULL); + if (kevent(kqfd, kev, 1, NULL, 0, NULL) < 0) { + printf("Unable to add the following kevent:\n%s\n", + kevent_to_str(kev)); + err(1, "kevent(): %s", strerror(errno)); + } +} + +void +kevent_cmp(struct kevent *k1, struct kevent *k2) +{ +/* XXX- + Workaround for inconsistent implementation of kevent(2) + */ +#ifdef __FreeBSD__ + if (k1->flags & EV_ADD) + k2->flags |= EV_ADD; +#endif + if (memcmp(k1, k2, sizeof(*k1)) != 0) { + printf("kevent_cmp: mismatch:\n %s !=\n %s\n", + kevent_to_str(k1), kevent_to_str(k2)); + abort(); + } +} + +void +test_begin(const char *func) +{ + if (cur_test_id) + free(cur_test_id); + cur_test_id = strdup(func); + if (!cur_test_id) + err(1, "strdup failed"); + + printf("\n\nTest %d: %s\n", testnum++, func); +} + +void +success(void) +{ + printf("%-70s %s\n", cur_test_id, "passed"); + free(cur_test_id); + cur_test_id = NULL; +} + +void +test_kqueue(void) +{ + test_begin("kqueue()"); + if ((kqfd = kqueue()) < 0) + err(1, "kqueue()"); + test_no_kevents(); + success(); +} + +void +test_kqueue_close(void) +{ + test_begin("close(kq)"); + if (close(kqfd) < 0) + err(1, "close()"); + success(); +} + +int +main(int argc, char **argv) +{ + int test_proc = 1; + int test_socket = 1; + int test_signal = 1; + int test_vnode = 1; + int test_timer = 1; +#ifdef __FreeBSD__ + int test_user = 1; +#else + /* XXX-FIXME temporary */ + int test_user = 0; +#endif + + while (argc) { + if (strcmp(argv[0], "--no-proc") == 0) + test_proc = 0; + if (strcmp(argv[0], "--no-socket") == 0) + test_socket = 0; + if (strcmp(argv[0], "--no-timer") == 0) + test_timer = 0; + if (strcmp(argv[0], "--no-signal") == 0) + test_signal = 0; + if (strcmp(argv[0], "--no-vnode") == 0) + test_vnode = 0; + if (strcmp(argv[0], "--no-user") == 0) + test_user = 0; + argv++; + argc--; + } + + /* + * Some tests fork. If output is fully buffered, + * the children inherit some buffered data and flush + * it when they exit, causing some data to be printed twice. + * Use line buffering to avoid this problem. + */ + setlinebuf(stdout); + setlinebuf(stderr); + + test_kqueue(); + test_kqueue_close(); + + if (test_socket) + test_evfilt_read(); + if (test_signal) + test_evfilt_signal(); + if (test_vnode) + test_evfilt_vnode(); +#if HAVE_EVFILT_USER + if (test_user) + test_evfilt_user(); +#endif + if (test_timer) + test_evfilt_timer(); + if (test_proc) + test_evfilt_proc(); + + printf("\n---\n" + "+OK All %d tests completed.\n", testnum - 1); + return (0); +} diff --git a/tests/sys/kqueue/proc.c b/tests/sys/kqueue/libkqueue/proc.c index 79b8d35..79b8d35 100644 --- a/tests/sys/kqueue/proc.c +++ b/tests/sys/kqueue/libkqueue/proc.c diff --git a/tests/sys/kqueue/libkqueue/read.c b/tests/sys/kqueue/libkqueue/read.c new file mode 100644 index 0000000..2837144 --- /dev/null +++ b/tests/sys/kqueue/libkqueue/read.c @@ -0,0 +1,326 @@ +/* + * Copyright (c) 2009 Mark Heily <mark@heily.com> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * $FreeBSD$ + */ + +#include "common.h" + +int kqfd; +int sockfd[2]; + +static void +kevent_socket_drain(void) +{ + char buf[1]; + + /* Drain the read buffer, then make sure there are no more events. */ + puts("draining the read buffer"); + if (read(sockfd[0], &buf[0], 1) < 1) + err(1, "read(2)"); +} + +static void +kevent_socket_fill(void) +{ + puts("filling the read buffer"); + if (write(sockfd[1], ".", 1) < 1) + err(1, "write(2)"); +} + + +void +test_kevent_socket_add(void) +{ + const char *test_id = "kevent(EVFILT_READ, EV_ADD)"; + struct kevent kev; + + test_begin(test_id); + EV_SET(&kev, sockfd[0], EVFILT_READ, EV_ADD, 0, 0, &sockfd[0]); + if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0) + err(1, "%s", test_id); + + success(); +} + +void +test_kevent_socket_get(void) +{ + const char *test_id = "kevent(EVFILT_READ) wait"; + struct kevent kev; + + test_begin(test_id); + + EV_SET(&kev, sockfd[0], EVFILT_READ, EV_ADD, 0, 0, &sockfd[0]); + if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0) + err(1, "%s", test_id); + + kevent_socket_fill(); + + kev.data = 1; + kevent_cmp(&kev, kevent_get(kqfd)); + + kevent_socket_drain(); + test_no_kevents(); + + kev.flags = EV_DELETE; + if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0) + err(1, "%s", test_id); + + success(); +} + +void +test_kevent_socket_clear(void) +{ + const char *test_id = "kevent(EVFILT_READ, EV_CLEAR)"; + struct kevent kev; + + test_begin(test_id); + + test_no_kevents(); + + EV_SET(&kev, sockfd[0], EVFILT_READ, EV_ADD | EV_CLEAR, 0, 0, &sockfd[0]); + if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0) + err(1, "%s", test_id); + + kevent_socket_fill(); + kevent_socket_fill(); + + kev.data = 2; + kevent_cmp(&kev, kevent_get(kqfd)); + + /* We filled twice, but drain once. Edge-triggered would not generate + additional events. + */ + kevent_socket_drain(); + test_no_kevents(); + + kevent_socket_drain(); + EV_SET(&kev, sockfd[0], EVFILT_READ, EV_DELETE, 0, 0, &sockfd[0]); + if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0) + err(1, "%s", test_id); + + success(); +} + +void +test_kevent_socket_disable_and_enable(void) +{ + const char *test_id = "kevent(EVFILT_READ, EV_DISABLE)"; + struct kevent kev; + + test_begin(test_id); + + /* + * Write to the socket before adding the event. This way we can verify that + * enabling a triggered kevent causes the event to be returned immediately. + */ + kevent_socket_fill(); + + /* Add a disabled event. */ + EV_SET(&kev, sockfd[0], EVFILT_READ, EV_ADD | EV_DISABLE, 0, 0, &sockfd[0]); + if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0) + err(1, "%s", test_id); + + test_no_kevents(); + + /* Re-enable the knote, then see if an event is generated */ + kev.flags = EV_ENABLE; + if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0) + err(1, "%s", test_id); + kev.flags = EV_ADD; + kev.data = 1; + kevent_cmp(&kev, kevent_get(kqfd)); + + kevent_socket_drain(); + + kev.flags = EV_DELETE; + if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0) + err(1, "%s", test_id); + + success(); +} + +void +test_kevent_socket_del(void) +{ + const char *test_id = "kevent(EVFILT_READ, EV_DELETE)"; + struct kevent kev; + + test_begin(test_id); + + EV_SET(&kev, sockfd[0], EVFILT_READ, EV_DELETE, 0, 0, &sockfd[0]); + if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0) + err(1, "%s", test_id); + + kevent_socket_fill(); + test_no_kevents(); + kevent_socket_drain(); + + success(); +} + +void +test_kevent_socket_oneshot(void) +{ + const char *test_id = "kevent(EVFILT_READ, EV_ONESHOT)"; + struct kevent kev; + + test_begin(test_id); + + /* Re-add the watch and make sure no events are pending */ + puts("-- re-adding knote"); + EV_SET(&kev, sockfd[0], EVFILT_READ, EV_ADD | EV_ONESHOT, 0, 0, &sockfd[0]); + if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0) + err(1, "%s", test_id); + test_no_kevents(); + + puts("-- getting one event"); + kevent_socket_fill(); + kev.data = 1; + kevent_cmp(&kev, kevent_get(kqfd)); + + puts("-- checking knote disabled"); + test_no_kevents(); + + /* Try to delete the knote, it should already be deleted */ + EV_SET(&kev, sockfd[0], EVFILT_READ, EV_DELETE, 0, 0, &sockfd[0]); + if (kevent(kqfd, &kev, 1, NULL, 0, NULL) == 0) + err(1, "%s", test_id); + + kevent_socket_drain(); + + success(); +} + + +#if HAVE_EV_DISPATCH +void +test_kevent_socket_dispatch(void) +{ + const char *test_id = "kevent(EVFILT_READ, EV_DISPATCH)"; + + test_begin(test_id); + + struct kevent kev; + + /* Re-add the watch and make sure no events are pending */ + puts("-- re-adding knote"); + EV_SET(&kev, sockfd[0], EVFILT_READ, EV_ADD | EV_DISPATCH, 0, 0, &sockfd[0]); + if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0) + err(1, "%s", test_id); + test_no_kevents(); + + /* The event will occur only once, even though EV_CLEAR is not + specified. */ + kevent_socket_fill(); + kev.data = 1; + kevent_cmp(&kev, kevent_get(kqfd)); + test_no_kevents(); + + /* Since the knote is disabled, the EV_DELETE operation succeeds. */ + EV_SET(&kev, sockfd[0], EVFILT_READ, EV_DELETE, 0, 0, &sockfd[0]); + if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0) + err(1, "%s", test_id); + + kevent_socket_drain(); + + success(); +} +#endif /* HAVE_EV_DISPATCH */ + +#if BROKEN +void +test_kevent_socket_lowat(void) +{ + const char *test_id = "kevent(EVFILT_READ, NOTE_LOWAT)"; + struct kevent kev; + + test_begin(test_id); + + /* Re-add the watch and make sure no events are pending */ + puts("-- re-adding knote, setting low watermark to 2 bytes"); + EV_SET(&kev, sockfd[0], EVFILT_READ, EV_ADD | EV_ONESHOT, NOTE_LOWAT, 2, &sockfd[0]); + if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0) + err(1, "%s", test_id); + test_no_kevents(); + + puts("-- checking that one byte does not trigger an event.."); + kevent_socket_fill(); + test_no_kevents(); + + puts("-- checking that two bytes triggers an event.."); + kevent_socket_fill(); + if (kevent(kqfd, NULL, 0, &kev, 1, NULL) != 1) + err(1, "%s", test_id); + KEV_CMP(kev, sockfd[0], EVFILT_READ, 0); + test_no_kevents(); + + kevent_socket_drain(); + kevent_socket_drain(); + + success(); +} +#endif + +void +test_kevent_socket_eof(void) +{ + const char *test_id = "kevent(EVFILT_READ, EV_EOF)"; + struct kevent kev; + + test_begin(test_id); + + /* Re-add the watch and make sure no events are pending */ + EV_SET(&kev, sockfd[0], EVFILT_READ, EV_ADD, 0, 0, &sockfd[0]); + if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0) + err(1, "%s", test_id); + test_no_kevents(); + + if (close(sockfd[1]) < 0) + err(1, "close(2)"); + + kev.flags |= EV_EOF; + kevent_cmp(&kev, kevent_get(kqfd)); + + /* Delete the watch */ + EV_SET(&kev, sockfd[0], EVFILT_READ, EV_DELETE, 0, 0, &sockfd[0]); + if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0) + err(1, "%s", test_id); + + success(); +} + +void +test_evfilt_read() +{ + /* Create a connected pair of full-duplex sockets for testing socket events */ + if (socketpair(AF_UNIX, SOCK_STREAM, 0, sockfd) < 0) + abort(); + + kqfd = kqueue(); + test_kevent_socket_add(); + test_kevent_socket_del(); + test_kevent_socket_get(); + test_kevent_socket_disable_and_enable(); + test_kevent_socket_oneshot(); + test_kevent_socket_clear(); +#if HAVE_EV_DISPATCH + test_kevent_socket_dispatch(); +#endif + test_kevent_socket_eof(); + close(kqfd); +} diff --git a/tests/sys/kqueue/signal.c b/tests/sys/kqueue/libkqueue/signal.c index 14e751d..14e751d 100644 --- a/tests/sys/kqueue/signal.c +++ b/tests/sys/kqueue/libkqueue/signal.c diff --git a/tests/sys/kqueue/timer.c b/tests/sys/kqueue/libkqueue/timer.c index 766125d..766125d 100644 --- a/tests/sys/kqueue/timer.c +++ b/tests/sys/kqueue/libkqueue/timer.c diff --git a/tests/sys/kqueue/user.c b/tests/sys/kqueue/libkqueue/user.c index 9ba25f9..9ba25f9 100644 --- a/tests/sys/kqueue/user.c +++ b/tests/sys/kqueue/libkqueue/user.c diff --git a/tests/sys/kqueue/vnode.c b/tests/sys/kqueue/libkqueue/vnode.c index dfa0b5e..55d5b3f 100644 --- a/tests/sys/kqueue/vnode.c +++ b/tests/sys/kqueue/libkqueue/vnode.c @@ -25,12 +25,12 @@ void test_kevent_vnode_add(void) { const char *test_id = "kevent(EVFILT_VNODE, EV_ADD)"; - const char *testfile = "/tmp/kqueue-test.tmp"; + const char *testfile = "./kqueue-test.tmp"; struct kevent kev; test_begin(test_id); - system("touch /tmp/kqueue-test.tmp"); + system("touch ./kqueue-test.tmp"); vnode_fd = open(testfile, O_RDONLY); if (vnode_fd < 0) err(1, "open of %s", testfile); @@ -57,7 +57,7 @@ test_kevent_vnode_note_delete(void) if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0) err(1, "%s", test_id); - if (unlink("/tmp/kqueue-test.tmp") < 0) + if (unlink("./kqueue-test.tmp") < 0) err(1, "unlink"); kevent_cmp(&kev, kevent_get(kqfd)); @@ -77,7 +77,7 @@ test_kevent_vnode_note_write(void) if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0) err(1, "%s", test_id); - if (system("echo hello >> /tmp/kqueue-test.tmp") < 0) + if (system("echo hello >> ./kqueue-test.tmp") < 0) err(1, "system"); /* BSD kqueue adds NOTE_EXTEND even though it was not requested */ @@ -102,7 +102,7 @@ test_kevent_vnode_note_attrib(void) if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0) err(1, "%s", test_id); - if (system("touch /tmp/kqueue-test.tmp") < 0) + if (system("touch ./kqueue-test.tmp") < 0) err(1, "system"); nfds = kevent(kqfd, NULL, 0, &kev, 1, NULL); @@ -130,7 +130,7 @@ test_kevent_vnode_note_rename(void) if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0) err(1, "%s", test_id); - if (system("mv /tmp/kqueue-test.tmp /tmp/kqueue-test2.tmp") < 0) + if (system("mv ./kqueue-test.tmp ./kqueue-test2.tmp") < 0) err(1, "system"); nfds = kevent(kqfd, NULL, 0, &kev, 1, NULL); @@ -142,7 +142,7 @@ test_kevent_vnode_note_rename(void) err(1, "%s - incorrect event (sig=%u; filt=%d; flags=%d)", test_id, (unsigned int)kev.ident, kev.filter, kev.flags); - if (system("mv /tmp/kqueue-test2.tmp /tmp/kqueue-test.tmp") < 0) + if (system("mv ./kqueue-test2.tmp ./kqueue-test.tmp") < 0) err(1, "system"); success(); @@ -183,7 +183,7 @@ test_kevent_vnode_disable_and_enable(void) err(1, "%s", test_id); /* Confirm that the watch is disabled */ - if (system("touch /tmp/kqueue-test.tmp") < 0) + if (system("touch ./kqueue-test.tmp") < 0) err(1, "system"); test_no_kevents(); @@ -191,7 +191,7 @@ test_kevent_vnode_disable_and_enable(void) kev.flags = EV_ENABLE; if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0) err(1, "%s", test_id); - if (system("touch /tmp/kqueue-test.tmp") < 0) + if (system("touch ./kqueue-test.tmp") < 0) err(1, "system"); nfds = kevent(kqfd, NULL, 0, &kev, 1, NULL); if (nfds < 1) @@ -221,7 +221,7 @@ test_kevent_vnode_dispatch(void) if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0) err(1, "%s", test_id); - if (system("touch /tmp/kqueue-test.tmp") < 0) + if (system("touch ./kqueue-test.tmp") < 0) err(1, "system"); nfds = kevent(kqfd, NULL, 0, &kev, 1, NULL); @@ -235,7 +235,7 @@ test_kevent_vnode_dispatch(void) /* Confirm that the watch is disabled automatically */ puts("-- checking that watch is disabled"); - if (system("touch /tmp/kqueue-test.tmp") < 0) + if (system("touch ./kqueue-test.tmp") < 0) err(1, "system"); test_no_kevents(); diff --git a/tests/sys/mqueue/Makefile b/tests/sys/mqueue/Makefile index 5af8b25..63741d2 100644 --- a/tests/sys/mqueue/Makefile +++ b/tests/sys/mqueue/Makefile @@ -6,7 +6,7 @@ ATF_TESTS_SH= mqueue_test BINDIR= ${TESTSDIR} -CFLAGS+= -I${.CURDIR:H:H} +CFLAGS+= -I${SRCTOP}/tests PROGS+= mqtest1 PROGS+= mqtest2 diff --git a/tests/sys/pjdfstest/tests/Makefile b/tests/sys/pjdfstest/tests/Makefile index 917b01a..95b4bbe 100644 --- a/tests/sys/pjdfstest/tests/Makefile +++ b/tests/sys/pjdfstest/tests/Makefile @@ -1,6 +1,6 @@ # $FreeBSD$ -PJDFSTEST_SRCDIR= ${.CURDIR:H:H:H:H}/contrib/pjdfstest +PJDFSTEST_SRCDIR= ${SRCTOP}/contrib/pjdfstest TESTSDIR= ${TESTSBASE}/sys/pjdfstest @@ -36,6 +36,4 @@ TESTS_SUBDIRS+= symlink TESTS_SUBDIRS+= truncate TESTS_SUBDIRS+= unlink -SUBDIR_PARALLEL= - .include <bsd.test.mk> |