diff options
Diffstat (limited to 'contrib/netbsd-tests/fs')
105 files changed, 16380 insertions, 0 deletions
diff --git a/contrib/netbsd-tests/fs/cd9660/pr_48787.image.bz2.uue b/contrib/netbsd-tests/fs/cd9660/pr_48787.image.bz2.uue new file mode 100644 index 000000000000..d8f7488f36d2 --- /dev/null +++ b/contrib/netbsd-tests/fs/cd9660/pr_48787.image.bz2.uue @@ -0,0 +1,103 @@ +begin 644 pr_48787.image.bz2 +M0EIH.3%!62936>D^3`0``+M_V?_7U17T!W_H/^_?8..V$"1DB`0``B$`0I-H +MP`+N-!HLI8)131H4](]3TC(VH`S4;4````T&@R&C0R:!*$1D(8B:C!,(Q-&3 +M-`!,``"&:`FC'&AH&C3(TT:9`8F"``&@-`:9`8$R`J1(A&A$R&391FA#TC0V +MHQ'J8@&T@VHT`QII&Z!"B5;S7YT+1"ZB8Y+5"M,5_J`!]Y:[$2%,%W`ZAA2@ +MVE)'DK^*?'3QU`DFQ4@22)(B[N3GZN?E<)`DDB.C)7\X71*B1K*2))(DD1HI +MU5$TUVF[4JP89^FHY$B*FEBC(RN$5"8O'XO]1++(._=;ZKXR%:QK3^W7/>RT +M8EODZ#MX53U8C0F]6O.G4J/9YNQA$B2))$<[<CT.C.)G[#NK)A3#\KM]#AP, +M*V*=Z35CIY9O/Q-6T7&8=_%R-%>H5(]"2=])+_3RW)O*AI[)<ZVSDZ"I-3B2 +M3;T^%)3LM2^.3I+<>9@D^JV5RK3?43-;"G;69#AH8,(5;:7UN,<5%98$9;9; +M\G*RT*37_9[;D'P/`1(R-$D.!36\S6N:_M>!][4*&3?'S858VCD+-3PINFR8 +M,C9?J+9ME:9.,_OR\C;3K'27W:K<<&>MMC;<YN*;!H83)Y-+"BCM6:&H"OT2 +M-]XWT/ZSW69R8]UG%S8IV5)$%2X)\%PF)G>HS".>68$Y&.B608>JM?)+3$:Z +MY539A<7-E*'_YY..1'ECZBIG5%1%U93-9*1-5T_C!\)&2@?*CQB>(Q\0G(J< +M6%PDB4L,2$>Q4IM%6A+%4K/0-!7*348,9!&#<9@JNP&+LBI>+9&*JC6ZE293 +MY%-8H^HI12#5$9J;"0@$DA.](1+1.SH#B10&H6C48:PMPI7=#M2A@I%'\J2P +M.Y(+0C:B.&>F(^[(>)1+M\+QH%@O#4OE(\RE*14IZ7+9R*G8IYV^O=Y<=4HY +M1C@SCIZ=$<UY5X+M6FT2)(DD1O#AYE/_]9B@K),IK(<$\6^`K\<@`&````00 +M`!A`)J,A4!+4A4!+F*"LDRFLAP3Q;X"OQR``8```!!``&$`FHR%0$M2%0$N8 +MH*R3*:R'!/%O@*_'(`!@```$$``80":C(5`2U(5`2YB@K),IK(<$\6^`K\<@ +M`&````00`!A`)J,A4!+4A4!+F*"LDRFLAP3Q;X"OQR``8```!!``&$`FHR%0 +M$M2%0$N8H*R3*:R'!/%O@*_'(`!@```$$``80":C(5`2U(5`2YB@K),IK(<$ +M\6^`K\<@`&````00`!A`)J,A4!+4A4!+F*"LDRFLAP3Q;X"OQR``8```!!`` +M&$`FHR%0$M2%0$N8H*R3*:R'!/%O@*_'(`!@```$$``80":C(5`2U(5`2YB@ +MK),IK(<$\6^`K\<@`&````00`!A`)J,A4!+4A4!+F*"LDRFLAP3Q;X"OQR`` +M8```!!``&$`FHR%0$M2%0$N8H*R3*:R'!/%O@*_'(`!@```$$``80":C(5`2 +MU(5`2YB@K),IK(<$\6^`K\<@`&````00`!A`)J,A4!+4A4!+F*"LDRFLAP3Q +M;X"OQR``8```!!``&$`FHR%0$M2%0$N8H*R3*:R'!/%O@*_'(`!@```$$``8 +M0":C(5`2U(5`2YB@K),IK(<$\6^`K\<@`&````00`!A`)J,A4!+4A4!+F*"L +MDRFLAP3Q;X"OQR``8```!!``&$`FHR%0$M2%0$N8H*R3*:R'!/%O@*_'(`!@ +M```$$``80":C(5`2U(5`2YB@K),IK(<$\6^`K\<@`&````00`!A`)J,A4!+4 +MA4!+F*"LDRFLAP3Q;X"OQR``8```!!``&$`FHR%0$M2%0$N8H*R3*:R'!/%O +M@*_'(`!@```$$``80":C(5`2U(5`2YB@K),IK(<$\6^`K\<@`&````00`!A` +M)J,A4!+4A4!+F*"LDRFLAP3Q;X"OQR``8```!!``&$`FHR%0$M2%0$N8H*R3 +M*:R'!/%O@*_'(`!@```$$``80":C(5`2U(5`2YB@K),IK(<$\6^`K\<@`&`` +M``00`!A`)J,A4!+4A4!+F*"LDRFLAP3Q;X"OQR``8```!!``&$`FHR%0$M2% +M0$N8H*R3*:R'!/%O@*_'(`!@```$$``80":C(5`2U(5`2YB@K),IK(<$\6^` +MK\<@`&````00`!A`)J,A4!+4A4!+F*"LDRFLAP3Q;X"OQR``8```!!``&$`F +MHR%0$M2%0$N8H*R3*:R'!/%O@*_'(`!@```$$``80":C(5`2U(5`2YB@K),I +MK(<$\6^`K\<@`&````00`!A`)J,A4!+4A4!+F*"LDRFLAP3Q;X"OQR``8``` +M!!``&$`FHR%0$M2%0$N8H*R3*:R'!/%O@*_'(`!@```$$``80":C(5`2U(5` +M2YB@K),IK(<$\6^`K\<@`&````00`!A`)J,A4!+4A4!+F*"LDRFLAP3Q;X"O +MQR``8```!!``&$`FHR%0$M2%0$N8H*R3*:R'!/%O@*_'(`!@```$$``80":C +M(5`2U(5`2YB@K),IK(<$\6^`K\<@`&````00`!A`)J,A4!+4A4!+F*"LDRFL +MAP3Q;X"OQR``8```!!``&$`FHR%0$M2%0$N8H*R3*:R'!/%O@*_'(`!@```$ +M$``80":C(5`2U(5`2YB@K),IK(<$\6^`K\<@`&````00`!A`)J,A4!+4A4!+ +MF*"LDRFLAP3Q;X"OQR``8```!!``&$`FHR%0$M2%0$N8H*R3*:R'!/%O@*_' +M(`!@```$$``80":C(5`2U(5`2YB@K),IK(<$\6^`K\<@`&````00`!A`)J,A +M4!+4A4!+F*"LDRFLAP3Q;X"OQR``8```!!``&$`FHR%0$M2%0$N8H*R3*:R' +M!/%O@*_'(`!@```$$``80":C(5`2U(5`2YB@K),IK(<$\6^`K\<@`&````00 +M`!A`)J,A4!+4A4!+F*"LDRFLAP3Q;X"OQR``8```!!``&$`FHR%0$M2%0$N8 +MH*R3*:R'!/%O@*_'(`!@```$$``80":C(5`2U(5`2YB@K),IK(<$\6^`K\<@ +M`&````00`!A`)J,A4!+4A4!+F*"LDRFLAP3Q;X"OQR``8```!!``&$`FHR%0 +M$M2%0$N8H*R3*:R'!/%O@*_'(`!@```$$``80":C(5`2U(5`2YB@K),IK(<$ +M\6^`K\<@`&````00`!A`)J,A4!+4A4!+F*"LDRFLAP3Q;X"OQR``8```!!`` +M&$`FHR%0$M2%0$N8H*R3*:R'!/%O@*_'(`!@```$$``80":C(5`2U(5`2YB@ +MK),IK(<$\6^`K\<@`&````00`!A`)J,A4!+4A4!+F*"LDRFLAP3Q;X"OQR`` +M8```!!``&$`FHR%0$M2%0$N8H*R3*:R'!/%O@*_'(`!@```$$``80":C(5`2 +MU(5`2YB@K),IK(<$\6^`K\<@`&````00`!A`)J,A4!+4A4!+F*"LDRFLAP3Q +M;X"OQR``8```!!``&$`FHR%0$M2%0$N8H*R3*:R'!/%O@*_'(`!@```$$``8 +M0":C(5`2U(5`2YB@K),IK(<$\6^`K\<@`&````00`!A`)J,A4!+4A4!+F*"L +MDRFLAP3Q;X"OQR``8```!!``&$`FHR%0$M2%0$N8H*R3*:R'!/%O@*_'(`!@ +M```$$``80":C(5`2U(5`2YB@K),IK(<$\6^`K\<@`&````00`!A`)J,A4!+4 +MA4!+F*"LDRFLAP3Q;X"OQR``8```!!``&$`FHR%0$M2%0$N8H*R3*:R'!/%O +M@*_'(`!@```$$``80":C(5`2U(5`2YB@K),IK(<$\6^`K\<@`&````00`!A` +M)J,A4!+4A4!+F*"LDRFLAP3Q;X"OQR``8```!!``&$`FHR%0$M2%0$N8H*R3 +M*:R'!/%O@*_'(`!@```$$``80":C(5`2U(5`2YB@K),IK(<$\6^`K\<@`&`` +M``00`!A`)J,A4!+4A4!+F*"LDRFLAP3Q;X"OQR``8```!!``&$`FHR%0$M2% +M0$N8H*R3*:R'!/%O@*_'(`!@```$$``80":C(5`2U(5`2YB@K),IK(<$\6^` +MK\<@`&````00`!A`)J,A4!+4A4!+F*"LDRFLAP3Q;X"OQR``8```!!``&$`F +MHR%0$M2%0$N8H*R3*:R'!/%O@*_'(`!@```$$``80":C(5`2U(5`2YB@K),I +MK(<$\6^`K\<@`&````00`!A`)J,A4!+4A4!+F*"LDRFLAP3Q;X"OQR``8``` +M!!``&$`FHR%0$M2%0$N8H*R3*:R'!/%O@*_'(`!@```$$``80":C(5`2U(5` +M2YB@K),IK(<$\6^`K\<@`&````00`!A`)J,A4!+4A4!+F*"LDRFLAP3Q;X"O +MQR``8```!!``&$`FHR%0$M2%0$N8H*R3*:R'!/%O@*_'(`!@```$$``80":C +M(5`2U(5`2YB@K),IK(<$\6^`K\<@`&````00`!A`)J,A4!+4A4!+F*"LDRFL +MAP3Q;X"OQR``8```!!``&$`FHR%0$M2%0$N8H*R3*:R'!/%O@*_'(`!@```$ +M$``80":C(5`2U(5`2YB@K),IK(<$\6^`K\<@`&````00`!A`)J,A4!+4A4!+ +MF*"LDRFLAP3Q;X"OQR``8```!!``&$`FHR%0$M2%0$N8H*R3*:R'!/%O@*_' +M(`!@```$$``80":C(5`2U(5`2YB@K),IK(<$\6^`K\<@`&````00`!A`)J,A +M4!+4A4!+F*"LDRFLAP3Q;X"OQR``8```!!``&$`FHR%0$M2%0$N8H*R3*:R' +M!/%O@*_'(`!@```$$``80":C(5`2U(5`2YB@K),IK(<$\6^`K\<@`&````00 +M`!A`)J,A4!+4A4!+F*"LDRFLAP3Q;X"OQR``8```!!``&$`FHR%0$M2%0$N8 +MH*R3*:R'!/%O@*_'(`!@```$$``80":C(5`2U(5`2YB@K),IK(KI-J(`.S;_ +M[O_KZIKZ`[_T'_?OL''[3!(R1`(```"`(``A3^1@`6=-9:!3`DD(:)ZC%)Z9 +M33:@>DT]"`>IH&@`#1Z)M3"-#(T#$4:I[4U`/4T-````````````!PT-&31H +MT::&1D,(`R`&0::``!D#(`D4IZIZ0-`T````````````]&II7`12+EV$9U/B +MB!*_@T]?CB(F_;A17-%[AD,R8`JV@70VUC,Y6`FQ"$@1<L2$)(`2[M+DHCF` +M0)`D)8!-P/',(82"IS(@R>@M3"$@0)"3F`Y&Q/<D<N339,\$GB`#`Q1SK=@R +M<HD1R!2\A(3.H3EOJB05)8.6&%6&J\9CF>$XJBC2?^*)EA9:/'NE+<&E/_K^ +M-Z0($"0E11*I%KQK=*`$'<N+G-F@9[YHI1'6M:8%.$2785901!%"0`U7%A/< +MPA@I4`8&N@"3L[Y!8V2Y*M8>NO&"YPP%*V4`5T>42;8B[:=M@:9#;@')!UFD +M8$)CB(&5G68PD`TD`[D"*AV+N\79)G^Q/SOS[CLC2P3T;\WCMH#X(5\++`-# +ML-+?DXEFS9H@P06,,HP2-X<1W%B*AY`JW`=,R?NG%O?)8;N6134$BXK2#F&& +M*"8&QUDIX$R\2.;XAFVSP/=K'6.!M8;%=UGWD84CA7$<.IJ0]NS'LEV@J(Q[ +MA='$&9W%-><1MMG8-JCG-DG+D,4"H>!`EJIEKV61?:5TW2M97U?>B%$S@N0G +M4!Q5$=A,ES!<J\):&C=5);/*T,$9.=>Z%;4P):4`FG@`X=YHB%#"PIU084Y4 +M<J@33)%J*]&*'15=HQ"PK3%#K"--<BB@FF*H%$2]4Y]`\FT7`^32RN'76OEC +M>@/JFD\8E9G8Y\8:0TJYP'=17J(:!3R>)1/FE%'Z2XBYRI259/935.OC-50: +M#[&,:!IG0R$A"P8>:89+I+'"&$B")A'5G8B+ZJ14JXH:'.:@IH0&T(0($A+" +/#6J,VO\7<D4X4)!E$I5" +` +end diff --git a/contrib/netbsd-tests/fs/cd9660/t_high_ino_big_file.sh b/contrib/netbsd-tests/fs/cd9660/t_high_ino_big_file.sh new file mode 100755 index 000000000000..c38f10300bb9 --- /dev/null +++ b/contrib/netbsd-tests/fs/cd9660/t_high_ino_big_file.sh @@ -0,0 +1,118 @@ +# $NetBSD: t_high_ino_big_file.sh,v 1.4 2014/07/07 22:06:02 pgoyette Exp $ +# +# Copyright (c) 2014 The NetBSD Foundation, Inc. +# All rights reserved. +# +# 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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. +# + +# The image used in these tests has been provided by Thomas Schmitt under +# the following license (see PR kern/48787 for details how to recreate it): +# +# Copyright (c) 1999 - 2008, Thomas Schmitt (scdbackup@gmx.net) +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# Redistributions of source code must retain the above copyright notice, +# this list of conditions and the following disclaimer. +# +# 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. +# +# Neither the name of Thomas Schmitt nor the names of his contributors +# may be used to endorse or promote products derived from this software without +# specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 REGENTS 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. +# +# ------------------------------------------------------------------------ +# This is the BSD license as stated July 22 1999 with +# <OWNER>="Thomas Schmitt (scdbackup@gmx.net)", +# <ORGANIZATION>="Thomas Schmitt" and <YEAR>="1999" +# an Open Source license approved by opensource.org +# + +mntpnt="" + +atf_test_case pr_kern_48787 cleanup +pr_kern_48787_head() { + atf_set "descr" "Verifies 32bit overflow isssues from PR kern/48787 are fixed" + atf_set "require.user" "root" + atf_set "require.progs" "rump_cd9660 bunzip2 stat" + atf_set "timeout" 6000 +} + +pr_kern_48787_body() { + avail=$( df -Pk . | awk '{if (NR==2) print $4}' ) + if [ $avail -lt 4500000 ]; then + atf_skip "not enough free disk space, have ${avail} Kbytes, need ~ 4500000 Kbytes" + fi + bunzip2 < $(atf_get_srcdir)/pr_48787.image.bz2 > pr_48787.image + mntpnt=$(pwd)/mnt + mkdir ${mntpnt} + rump_cd9660 -o norrip ./pr_48787.image ${mntpnt} + if [ ! -r ${mntpnt}/small_file ]; then + atf_fail "${mntpnt}/small_file does not exist" + fi + if [ ! -r ${mntpnt}/my/large_file ]; then + atf_fail "${mntpnt}/my/large_file does not exist" + fi + umount ${mntpnt} + rump_cd9660 ./pr_48787.image ${mntpnt} + if [ ! -r ${mntpnt}/small_file ]; then + atf_fail "${mntpnt}/small_file does not exist" + fi + if [ ! -r ${mntpnt}/my/large_file ]; then + atf_fail "${mntpnt}/my/large_file does not exist" + fi + echo "this assumes current cd9660 inode encoding - adapt on changes" + atf_check -o match:"^4329541966$" stat -f "%i" ${mntpnt}/small_file + atf_check -o match:"^4329545920$" stat -f "%i" ${mntpnt}/my/large_file + umount ${mntpnt} + touch "done" +} + +pr_kern_48787_cleanup() { + if [ ! -f done ]; then + if [ "x${mntpnt}" != "x" ]; then + umount -f ${mntpnt} || true + fi + fi +} + +atf_init_test_cases() { + atf_add_test_case pr_kern_48787 +} diff --git a/contrib/netbsd-tests/fs/common/fstest_ext2fs.c b/contrib/netbsd-tests/fs/common/fstest_ext2fs.c new file mode 100644 index 000000000000..85bb79f7ebd0 --- /dev/null +++ b/contrib/netbsd-tests/fs/common/fstest_ext2fs.c @@ -0,0 +1,139 @@ +/* $NetBSD: fstest_ext2fs.c,v 1.2 2010/07/30 16:15:05 pooka Exp $ */ + +/*- + * Copyright (c) 2010 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Nicolas Joly. + * + * 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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. + */ + +#include <sys/mount.h> +#include <sys/stat.h> + +#include <atf-c.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +#include <ufs/ufs/ufsmount.h> + +#include <rump/rump.h> +#include <rump/rump_syscalls.h> + +#include "h_fsmacros.h" + +struct ext2fstestargs { + struct ufs_args ta_uargs; + char ta_devpath[MAXPATHLEN]; + char ta_imgpath[MAXPATHLEN]; +}; + +int +ext2fs_fstest_newfs(const atf_tc_t *tc, void **buf, const char *image, + off_t size, void *fspriv) +{ + char cmd[1024]; + int res; + static unsigned int num = 0; + struct ext2fstestargs *args; + + size /= 512; + snprintf(cmd, 1024, "newfs_ext2fs -F -s %"PRId64" %s >/dev/null", + size, image); + res = system(cmd); + if (res != 0) + return res; + + res = rump_init(); + if (res != 0) + return res; + + args = calloc(1, sizeof(*args)); + if (args == NULL) + return -1; + + snprintf(args->ta_devpath, MAXPATHLEN, "/dev/device%d.ext2fs", num); + snprintf(args->ta_imgpath, MAXPATHLEN, "%s", image); + args->ta_uargs.fspec = args->ta_devpath; + + res = rump_pub_etfs_register(args->ta_devpath, image, RUMP_ETFS_BLK); + if (res != 0) { + free(args); + return res; + } + + *buf = args; + num++; + + return res; +} + +int +ext2fs_fstest_delfs(const atf_tc_t *tc, void *buf) +{ + int res; + struct ext2fstestargs *args = buf; + + res = rump_pub_etfs_remove(args->ta_devpath); + if (res != 0) + return res; + + res = unlink(args->ta_imgpath); + if (res != 0) + return res; + + free(args); + + return 0; +} + +int +ext2fs_fstest_mount(const atf_tc_t *tc, void *buf, const char *path, int flags) +{ + int res; + struct ext2fstestargs *args = buf; + + res = rump_sys_mkdir(path, 0777); + if (res == -1) + return res; + + res = rump_sys_mount(MOUNT_EXT2FS, path, flags, &args->ta_uargs, + sizeof(args->ta_uargs)); + return res; +} + +int +ext2fs_fstest_unmount(const atf_tc_t *tc, const char *path, int flags) +{ + int res; + + res = rump_sys_unmount(path, flags); + if (res == -1) + return res; + + res = rump_sys_rmdir(path); + return res; +} diff --git a/contrib/netbsd-tests/fs/common/fstest_ffs.c b/contrib/netbsd-tests/fs/common/fstest_ffs.c new file mode 100644 index 000000000000..7ae4e8f5970c --- /dev/null +++ b/contrib/netbsd-tests/fs/common/fstest_ffs.c @@ -0,0 +1,156 @@ +/* $NetBSD: fstest_ffs.c,v 1.6 2012/08/05 02:03:05 riastradh Exp $ */ + +/*- + * Copyright (c) 2010 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Nicolas Joly. + * + * 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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. + */ + +#include <sys/mount.h> +#include <sys/stat.h> + +#include <atf-c.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <signal.h> + +#include <ufs/ufs/ufsmount.h> + +#include <rump/rump.h> +#include <rump/rump_syscalls.h> + +#include "h_fsmacros.h" + +struct ffstestargs { + struct ufs_args ta_uargs; + char ta_devpath[MAXPATHLEN]; + char ta_imgpath[MAXPATHLEN]; +}; + +int +ffs_fstest_newfs(const atf_tc_t *tc, void **buf, const char *image, off_t size, + void *fspriv) +{ + char cmd[1024]; + int res; + static unsigned int num = 0; + struct ffstestargs *args; + struct sigaction act, oact; + + size /= 512; + snprintf(cmd, 1024, "newfs -F -s %"PRId64" %s >/dev/null", size, image); + memset(&act, 0, sizeof(act)); + act.sa_handler = SIG_DFL; + sigaction(SIGCHLD, &act, &oact); + res = system(cmd); + sigaction(SIGCHLD, &oact, NULL); + if (res != 0) + return res; + + res = rump_init(); + if (res != 0) + return res; + + args = calloc(1, sizeof(*args)); + if (args == NULL) + return -1; + + snprintf(args->ta_devpath, MAXPATHLEN, "/dev/device%d.ffs", num); + snprintf(args->ta_imgpath, MAXPATHLEN, "%s", image); + args->ta_uargs.fspec = args->ta_devpath; + + res = rump_pub_etfs_register(args->ta_devpath, image, RUMP_ETFS_BLK); + if (res != 0) { + free(args); + return res; + } + + *buf = args; + num++; + + return 0; +} +__strong_alias(ffslog_fstest_newfs,ffs_fstest_newfs); + +int +ffs_fstest_delfs(const atf_tc_t *tc, void *buf) +{ + int res; + struct ffstestargs *args = buf; + + res = rump_pub_etfs_remove(args->ta_devpath); + if (res != 0) { + errno = res; + return -1; + } + + res = unlink(args->ta_imgpath); + if (res != 0) + return res; + + free(args); + + return 0; +} +__strong_alias(ffslog_fstest_delfs,ffs_fstest_delfs); + +int +ffs_fstest_mount(const atf_tc_t *tc, void *buf, const char *path, int flags) +{ + int res; + struct ffstestargs *args = buf; + + res = rump_sys_mkdir(path, 0777); + if (res == -1) + return res; + + res = rump_sys_mount(MOUNT_FFS, path, flags, &args->ta_uargs, + sizeof(args->ta_uargs)); + return res; +} + +int +ffslog_fstest_mount(const atf_tc_t *tc, void *buf, const char *path, int flags) +{ + + return ffs_fstest_mount(tc, buf, path, flags | MNT_LOG); +} + +int +ffs_fstest_unmount(const atf_tc_t *tc, const char *path, int flags) +{ + int res; + + res = rump_sys_unmount(path, flags); + if (res == -1) + return res; + + res = rump_sys_rmdir(path); + return res; +} +__strong_alias(ffslog_fstest_unmount,ffs_fstest_unmount); diff --git a/contrib/netbsd-tests/fs/common/fstest_lfs.c b/contrib/netbsd-tests/fs/common/fstest_lfs.c new file mode 100644 index 000000000000..597ca23bbaa8 --- /dev/null +++ b/contrib/netbsd-tests/fs/common/fstest_lfs.c @@ -0,0 +1,190 @@ +/* $NetBSD: fstest_lfs.c,v 1.5 2015/08/30 18:27:26 dholland Exp $ */ + +/*- + * Copyright (c) 2010 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Nicolas Joly. + * + * 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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. + */ + +#include <sys/mount.h> +#include <sys/stat.h> + +#include <atf-c.h> +#include <pthread.h> +#include <semaphore.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +#include <ufs/ufs/ufsmount.h> + +#include <rump/rump.h> +#include <rump/rump_syscalls.h> + +#include "h_fsmacros.h" +#include "mount_lfs.h" + +struct lfstestargs { + struct ufs_args ta_uargs; + pthread_t ta_cleanerthread; + sem_t ta_cleanerloop; + char ta_devpath[MAXPATHLEN]; + char ta_imgpath[MAXPATHLEN]; + char ta_mntpath[MAXPATHLEN]; + char ta_hostpath[MAXPATHLEN]; +}; + +int +lfs_fstest_newfs(const atf_tc_t *tc, void **buf, const char *image, off_t size, + void *fspriv) +{ + char cmd[1024]; + int res; + static unsigned int num = 0; + struct lfstestargs *args; + + size /= 512; + snprintf(cmd, 1024, "newfs_lfs -D -F -s %"PRId64" ./%s >/dev/null", + size, image); + res = system(cmd); + if (res != 0) + return res; + + res = rump_init(); + if (res != 0) + return res; + + args = calloc(1, sizeof(*args)); + if (args == NULL) + return -1; + + strcpy(args->ta_hostpath, image); + snprintf(args->ta_devpath, MAXPATHLEN, "/dev/device%d.lfs", num); + snprintf(args->ta_imgpath, MAXPATHLEN, "%s", image); + args->ta_uargs.fspec = args->ta_devpath; + sem_init(&args->ta_cleanerloop, 0, 0); + + res = rump_pub_etfs_register(args->ta_devpath, image, RUMP_ETFS_BLK); + if (res != 0) { + free(args); + return res; + } + + *buf = args; + num++; + + return 0; +} + +int +lfs_fstest_delfs(const atf_tc_t *tc, void *buf) +{ + int res; + struct lfstestargs *args = buf; + + res = rump_pub_etfs_remove(args->ta_devpath); + if (res != 0) + return res; + + res = unlink(args->ta_imgpath); + if (res != 0) + return res; + + pthread_join(args->ta_cleanerthread, NULL); + free(args); + + return 0; +} + +static void * +cleaner(void *arg) +{ + char thepath[MAXPATHLEN]; + struct lfstestargs *args = arg; + const char *the_argv[7]; + char buf[64]; + + /* this inspired by the cleaner code. fixme */ + sprintf(thepath, "/dev/r%s", args->ta_devpath+5); + rump_pub_etfs_register(thepath, args->ta_hostpath, RUMP_ETFS_CHR); + sprintf(buf, "%p", &args->ta_cleanerloop); + + the_argv[0] = "megamaid"; + the_argv[1] = "-D"; /* don't fork() & detach */ + the_argv[2] = "-S"; + the_argv[3] = buf; + the_argv[4] = args->ta_mntpath; + the_argv[5] = NULL; + + /* xxxatf */ + optind = 1; + opterr = 1; + + lfs_cleaner_main(5, __UNCONST(the_argv)); + + return NULL; +} + +int +lfs_fstest_mount(const atf_tc_t *tc, void *buf, const char *path, int flags) +{ + struct lfstestargs *args = buf; + int res; + + res = rump_sys_mkdir(path, 0777); + if (res == -1) + return res; + + res = rump_sys_mount(MOUNT_LFS, path, flags, &args->ta_uargs, + sizeof(args->ta_uargs)); + if (res == -1) + return res; + + strcpy(args->ta_mntpath, path); + res = pthread_create(&args->ta_cleanerthread, NULL, cleaner, args); + if (res) + return res; + + /* wait for cleaner to initialize */ + sem_wait(&args->ta_cleanerloop); + + return 0; +} + +int +lfs_fstest_unmount(const atf_tc_t *tc, const char *path, int flags) +{ + int res; + + res = rump_sys_unmount(path, flags); + if (res == -1) { + return res; + } + + res = rump_sys_rmdir(path); + return res; +} diff --git a/contrib/netbsd-tests/fs/common/fstest_msdosfs.c b/contrib/netbsd-tests/fs/common/fstest_msdosfs.c new file mode 100644 index 000000000000..2c94e3f92fa8 --- /dev/null +++ b/contrib/netbsd-tests/fs/common/fstest_msdosfs.c @@ -0,0 +1,140 @@ +/* $NetBSD: fstest_msdosfs.c,v 1.3 2012/03/26 15:10:26 njoly Exp $ */ + +/*- + * Copyright (c) 2010 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Nicolas Joly. + * + * 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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. + */ + +#include <sys/mount.h> +#include <sys/stat.h> + +#include <atf-c.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +#include <msdosfs/msdosfsmount.h> + +#include <rump/rump.h> +#include <rump/rump_syscalls.h> + +#include "h_fsmacros.h" + +struct msdosfstestargs { + struct msdosfs_args ta_uargs; + char ta_devpath[MAXPATHLEN]; + char ta_imgpath[MAXPATHLEN]; +}; + +int +msdosfs_fstest_newfs(const atf_tc_t *tc, void **buf, const char *image, + off_t size, void *fspriv) +{ + char cmd[1024]; + int res; + static unsigned int num = 0; + struct msdosfstestargs *args; + + size /= 512; size -= (size % 63); + snprintf(cmd, 1024, "newfs_msdos -C %"PRId64"s %s >/dev/null", + size, image); + res = system(cmd); + if (res != 0) + return res; + + res = rump_init(); + if (res != 0) + return res; + + args = calloc(1, sizeof(*args)); + if (args == NULL) + return -1; + + snprintf(args->ta_devpath, MAXPATHLEN, "/dev/device%d.msdosfs", num); + snprintf(args->ta_imgpath, MAXPATHLEN, "%s", image); + args->ta_uargs.fspec = args->ta_devpath; + args->ta_uargs.mask = 0755; + + res = rump_pub_etfs_register(args->ta_devpath, image, RUMP_ETFS_BLK); + if (res != 0) { + free(args); + return res; + } + + *buf = args; + num++; + + return 0; +} + +int +msdosfs_fstest_delfs(const atf_tc_t *tc, void *buf) +{ + int res; + struct msdosfstestargs *args = buf; + + res = rump_pub_etfs_remove(args->ta_devpath); + if (res != 0) + return res; + + res = unlink(args->ta_imgpath); + if (res != 0) + return res; + + free(args); + + return 0; +} + +int +msdosfs_fstest_mount(const atf_tc_t *tc, void *buf, const char *path, int flags) +{ + int res; + struct msdosfstestargs *args = buf; + + res = rump_sys_mkdir(path, 0777); + if (res == -1) + return res; + + res = rump_sys_mount(MOUNT_MSDOS, path, flags, &args->ta_uargs, + sizeof(args->ta_uargs)); + return res; +} + +int +msdosfs_fstest_unmount(const atf_tc_t *tc, const char *path, int flags) +{ + int res; + + res = rump_sys_unmount(path, flags); + if (res == -1) + return res; + + res = rump_sys_rmdir(path); + return res; +} diff --git a/contrib/netbsd-tests/fs/common/fstest_nfs.c b/contrib/netbsd-tests/fs/common/fstest_nfs.c new file mode 100644 index 000000000000..5ef256f1be41 --- /dev/null +++ b/contrib/netbsd-tests/fs/common/fstest_nfs.c @@ -0,0 +1,326 @@ +/* $NetBSD: fstest_nfs.c,v 1.9 2011/02/28 21:08:46 pooka Exp $ */ + +/* + * Copyright (c) 2010 The NetBSD Foundation, Inc. + * + * 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 ``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. + */ + +#include <sys/types.h> +#include <sys/mount.h> +#include <sys/socket.h> +#include <sys/statvfs.h> +#include <sys/wait.h> + +#include <assert.h> +#include <atf-c.h> +#include <err.h> +#include <errno.h> +#include <fcntl.h> +#include <libgen.h> +#include <pthread.h> +#include <puffs.h> +#include <puffsdump.h> +#include <stdio.h> +#include <unistd.h> +#include <string.h> +#include <stdlib.h> + +#include <rump/rump.h> +#include <rump/rump_syscalls.h> + +#include "h_fsmacros.h" +#include "mount_nfs.h" +#include "../../net/config/netconfig.c" + +#define SERVERADDR "10.3.2.1" +#define SERVERROADDR "10.4.2.1" +#define CLIENTADDR "10.3.2.2" +#define CLIENTROADDR "10.4.2.2" +#define NETNETMASK "255.255.255.0" +#define EXPORTPATH "/myexport" + +static void +childfail(int status) +{ + + atf_tc_fail("child died"); +} + +/* fork rump nfsd, configure interface */ +static int +donewfs(const atf_tc_t *tc, void **argp, + const char *image, off_t size, void *fspriv) +{ + const char *srcdir; + char *nfsdargv[16]; + char nfsdpath[MAXPATHLEN]; + char imagepath[MAXPATHLEN]; + char ethername[MAXPATHLEN], ethername_ro[MAXPATHLEN]; + char ifname[IFNAMSIZ], ifname_ro[IFNAMSIZ]; + char cwd[MAXPATHLEN]; + struct nfstestargs *args; + pid_t childpid; + int pipes[2]; + int devnull; + + /* + * First, we start the nfs service. + */ + srcdir = atf_tc_get_config_var(tc, "srcdir"); + sprintf(nfsdpath, "%s/../nfs/nfsservice/rumpnfsd", srcdir); + sprintf(ethername, "/%s/%s.etherbus", getcwd(cwd, sizeof(cwd)), image); + sprintf(ethername_ro, "%s_ro", ethername); + sprintf(imagepath, "/%s/%s", cwd, image); + + nfsdargv[0] = nfsdpath; + nfsdargv[1] = ethername; + nfsdargv[2] = ethername_ro; + nfsdargv[3] = __UNCONST(SERVERADDR); + nfsdargv[4] = __UNCONST(SERVERROADDR); + nfsdargv[5] = __UNCONST(NETNETMASK); + nfsdargv[6] = __UNCONST(EXPORTPATH); + nfsdargv[7] = imagepath; + nfsdargv[8] = NULL; + + signal(SIGCHLD, childfail); + if (pipe(pipes) == -1) + return errno; + + switch ((childpid = fork())) { + case 0: + if (chdir(dirname(nfsdpath)) == -1) + err(1, "chdir"); + close(pipes[0]); + if (dup2(pipes[1], 3) == -1) + err(1, "dup2"); + if (execvp(nfsdargv[0], nfsdargv) == -1) + err(1, "execvp"); + case -1: + return errno; + default: + close(pipes[1]); + break; + } + + /* + * Ok, nfsd has been run. The following sleep helps with the + * theoretical problem that nfsd can't start fast enough to + * process our mount request and we end up doing a timeout + * before the mount. This would take several seconds. So + * try to make sure nfsd is up&running already at this stage. + */ + if (read(pipes[0], &devnull, 4) == -1) + return errno; + + /* + * Configure our networking interface. + */ + rump_init(); + netcfg_rump_makeshmif(ethername, ifname); + netcfg_rump_if(ifname, CLIENTADDR, NETNETMASK); + netcfg_rump_makeshmif(ethername_ro, ifname_ro); + netcfg_rump_if(ifname_ro, CLIENTROADDR, NETNETMASK); + + /* + * That's it. The rest is done in mount, since we don't have + * the mountpath available here. + */ + args = malloc(sizeof(*args)); + if (args == NULL) + return errno; + memset(args, 0, sizeof(*args)); + args->ta_childpid = childpid; + strcpy(args->ta_ethername, ethername); + + *argp = args; + + return 0; +} + +int +nfs_fstest_newfs(const atf_tc_t *tc, void **argp, + const char *image, off_t size, void *fspriv) +{ + + return donewfs(tc, argp, image, size, fspriv); +} + +int +nfsro_fstest_newfs(const atf_tc_t *tc, void **argp, + const char *image, off_t size, void *fspriv) +{ + + return donewfs(tc, argp, image, size, fspriv); +} + +/* mount the file system */ +static int +domount(const atf_tc_t *tc, void *arg, const char *serverpath, + const char *path, int flags) +{ + char canon_dev[MAXPATHLEN], canon_dir[MAXPATHLEN]; + const char *nfscliargs[] = { + "nfsclient", + serverpath, + path, + NULL, + }; + struct nfs_args args; + int mntflags; + + if (rump_sys_mkdir(path, 0777) == -1) + return errno; + + /* XXX: atf does not reset values */ + optind = 1; + opterr = 1; + + /* + * We use nfs parseargs here, since as a side effect it + * takes care of the RPC hulabaloo. + */ + mount_nfs_parseargs(__arraycount(nfscliargs)-1, __UNCONST(nfscliargs), + &args, &mntflags, canon_dev, canon_dir); + + if (rump_sys_mount(MOUNT_NFS, path, flags, &args, sizeof(args)) == -1) { + return errno; + } + + return 0; +} + +int +nfs_fstest_mount(const atf_tc_t *tc, void *arg, const char *path, int flags) +{ + + return domount(tc, arg, SERVERADDR ":" EXPORTPATH, path, flags); +} + +/* + * This is where the magic happens! + * + * If we are mounting r/w, do the normal thing. However, if we are + * doing a r/o mount, switch use the r/o server export address + * and do a r/w mount. This way we end up testing the r/o export policy + * of the server! (yes, slightly questionable semantics, but at least + * we notice very quickly if our assumption is broken in the future ;) + */ +int +nfsro_fstest_mount(const atf_tc_t *tc, void *arg, const char *path, int flags) +{ + + if (flags & MNT_RDONLY) { + flags &= ~MNT_RDONLY; + return domount(tc, arg, SERVERROADDR":"EXPORTPATH, path, flags); + } else { + return domount(tc, arg, SERVERADDR":"EXPORTPATH, path, flags); + } +} + +static int +dodelfs(const atf_tc_t *tc, void *arg) +{ + + /* + * XXX: no access to "args" since we're called from "cleanup". + * Trust atf to kill nfsd process and remove etherfile. + */ +#if 0 + /* + * It's highly expected that the child will die next, so we + * don't need that information anymore thank you very many. + */ + signal(SIGCHLD, SIG_IGN); + + /* + * Just KILL it. Sending it SIGTERM first causes it to try + * to send some unmount RPCs, leading to sticky situations. + */ + kill(args->ta_childpid, SIGKILL); + wait(&status); + + /* remove ethernet bus */ + if (unlink(args->ta_ethername) == -1) + atf_tc_fail_errno("unlink ethername"); +#endif + + return 0; +} + +int +nfs_fstest_delfs(const atf_tc_t *tc, void *arg) +{ + + return dodelfs(tc, arg); +} + +int +nfsro_fstest_delfs(const atf_tc_t *tc, void *arg) +{ + + return dodelfs(tc, arg); +} + +static int +dounmount(const atf_tc_t *tc, const char *path, int flags) +{ + int status, i, sverrno; + + /* + * NFS handles sillyrenames in an workqueue. Some of them might + * be still in the queue even if all user activity has ceased. + * We try to unmount for 2 seconds to give them a chance + * to flush out. + * + * PR kern/43799 + */ + for (i = 0; i < 20; i++) { + if ((status = rump_sys_unmount(path, flags)) == 0) + break; + sverrno = errno; + if (sverrno != EBUSY) + break; + usleep(100000); + } + if (status == -1) + return sverrno; + + if (rump_sys_rmdir(path) == -1) + return errno; + + return 0; +} + +int +nfs_fstest_unmount(const atf_tc_t *tc, const char *path, int flags) +{ + + return dounmount(tc, path, flags); +} + +int +nfsro_fstest_unmount(const atf_tc_t *tc, const char *path, int flags) +{ + + return dounmount(tc, path, flags); +} diff --git a/contrib/netbsd-tests/fs/common/fstest_puffs.c b/contrib/netbsd-tests/fs/common/fstest_puffs.c new file mode 100644 index 000000000000..14e4bfba43ba --- /dev/null +++ b/contrib/netbsd-tests/fs/common/fstest_puffs.c @@ -0,0 +1,452 @@ +/* $NetBSD: fstest_puffs.c,v 1.11 2013/09/09 19:47:38 pooka Exp $ */ + +/* + * Copyright (c) 2010, 2011 The NetBSD Foundation, Inc. + * + * 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 ``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. + */ + +#include <sys/types.h> +#include <sys/mount.h> +#include <sys/socket.h> +#include <sys/statvfs.h> +#include <sys/wait.h> + +#include <assert.h> +#include <atf-c.h> +#include <err.h> +#include <errno.h> +#include <fcntl.h> +#include <pthread.h> +#include <puffs.h> +#include <puffsdump.h> +#include <signal.h> +#include <stdio.h> +#include <unistd.h> +#include <string.h> +#include <stdlib.h> + +#include <rump/rump.h> +#include <rump/rump_syscalls.h> + +#include "h_fsmacros.h" + +#define BUFSIZE (128*1024) +#define DTFS_DUMP "-o","dump" + +static bool mayquit = false; + +static ssize_t +xread(int fd, void *vp, size_t n) +{ + size_t left; + + left = n; + do { + ssize_t ssz; + + ssz = read(fd, vp, left); + if (ssz == -1) { + return ssz; + } + left -= ssz; + vp = (char *)vp + ssz; + } while (left > 0); + return n; +} + +static ssize_t +xwrite(int fd, const void *vp, size_t n) +{ + size_t left; + + left = n; + do { + ssize_t ssz; + + ssz = write(fd, vp, left); + if (ssz == -1) { + return ssz; + } + left -= ssz; + vp = (const char *)vp + ssz; + } while (left > 0); + return n; +} + +/* + * Threads which shovel data between comfd and /dev/puffs. + * (cannot use polling since fd's are in different namespaces) + */ +static void * +readshovel(void *arg) +{ + struct putter_hdr *phdr; + struct puffs_req *preq; + struct puffstestargs *args = arg; + char buf[BUFSIZE]; + ssize_t n; + int comfd, puffsfd; + + comfd = args->pta_servfd; + puffsfd = args->pta_rumpfd; + + phdr = (void *)buf; + preq = (void *)buf; + + rump_pub_lwproc_newlwp(1); + + for (;;) { + n = rump_sys_read(puffsfd, buf, sizeof(*phdr)); + if (n <= 0) { + fprintf(stderr, "readshovel r1 %zd / %d\n", n, errno); + break; + } + + assert(phdr->pth_framelen < BUFSIZE); + n = rump_sys_read(puffsfd, buf+sizeof(*phdr), + phdr->pth_framelen - sizeof(*phdr)); + if (n <= 0) { + fprintf(stderr, "readshovel r2 %zd / %d\n", n, errno); + break; + } + + /* Analyze request */ + if (PUFFSOP_OPCLASS(preq->preq_opclass) == PUFFSOP_VFS) { + assert(preq->preq_optype < PUFFS_VFS_MAX); + args->pta_vfs_toserv_ops[preq->preq_optype]++; + } else if (PUFFSOP_OPCLASS(preq->preq_opclass) == PUFFSOP_VN) { + assert(preq->preq_optype < PUFFS_VN_MAX); + args->pta_vn_toserv_ops[preq->preq_optype]++; + } + + n = phdr->pth_framelen; + if (xwrite(comfd, buf, n) != n) { + fprintf(stderr, "readshovel write %zd / %d\n", n, errno); + break; + } + } + + if (n != 0 && mayquit == false) + abort(); + return NULL; +} + +static void * +writeshovel(void *arg) +{ + struct puffstestargs *args = arg; + struct putter_hdr *phdr; + struct puffs_req *preq; + char buf[BUFSIZE]; + size_t toread; + ssize_t n; + int comfd, puffsfd; + + rump_pub_lwproc_newlwp(1); + + comfd = args->pta_servfd; + puffsfd = args->pta_rumpfd; + + phdr = (struct putter_hdr *)buf; + preq = (void *)buf; + + for (;;) { + uint64_t off; + + /* + * Need to write everything to the "kernel" in one chunk, + * so make sure we have it here. + */ + off = 0; + toread = sizeof(struct putter_hdr); + assert(toread < BUFSIZE); + do { + n = xread(comfd, buf+off, toread); + if (n <= 0) { + fprintf(stderr, "writeshovel read %zd / %d\n", + n, errno); + goto out; + } + off += n; + if (off >= sizeof(struct putter_hdr)) + toread = phdr->pth_framelen - off; + else + toread = off - sizeof(struct putter_hdr); + } while (toread); + + if (__predict_false( + PUFFSOP_OPCLASS(preq->preq_opclass) == PUFFSOP_VFS + && preq->preq_optype == PUFFS_VFS_UNMOUNT)) { + if (preq->preq_rv == 0) + mayquit = true; + } + + n = rump_sys_write(puffsfd, buf, phdr->pth_framelen); + if ((size_t)n != phdr->pth_framelen) { + fprintf(stderr, "writeshovel wr %zd / %d\n", n, errno); + break; + } + } + + out: + if (n != 0) + abort(); + return NULL; +} + +static void +rumpshovels(struct puffstestargs *args) +{ + pthread_t pt; + int rv; + + if ((rv = rump_init()) == -1) + err(1, "rump_init"); + + if (pthread_create(&pt, NULL, readshovel, args) == -1) + err(1, "read shovel"); + pthread_detach(pt); + + if (pthread_create(&pt, NULL, writeshovel, args) == -1) + err(1, "write shovel"); + pthread_detach(pt); +} + +static void +childfail(int sign) +{ + + atf_tc_fail("child died"); /* almost signal-safe */ +} + +struct puffstestargs *theargs; /* XXX */ + +/* XXX: we don't support size */ +static int +donewfs(const atf_tc_t *tc, void **argp, + const char *image, off_t size, void *fspriv, char **theargv) +{ + struct puffstestargs *args; + pid_t childpid; + int *pflags; + char comfd[16]; + int sv[2]; + int mntflags; + size_t len; + ssize_t n; + + *argp = NULL; + + args = malloc(sizeof(*args)); + if (args == NULL) + return errno; + memset(args, 0, sizeof(*args)); + + pflags = &args->pta_pflags; + + /* Create sucketpair for communication with the real file server */ + if (socketpair(PF_LOCAL, SOCK_STREAM, 0, sv) == -1) + return errno; + + signal(SIGCHLD, childfail); + + switch ((childpid = fork())) { + case 0: + close(sv[1]); + snprintf(comfd, sizeof(sv[0]), "%d", sv[0]); + if (setenv("PUFFS_COMFD", comfd, 1) == -1) + return errno; + + if (execvp(theargv[0], theargv) == -1) + return errno; + case -1: + return errno; + default: + close(sv[0]); + break; + } + + /* read args */ + if ((n = xread(sv[1], &len, sizeof(len))) != sizeof(len)) + err(1, "mp 1 %zd", n); + if (len > MAXPATHLEN) + err(1, "mntpath > MAXPATHLEN"); + if ((size_t)xread(sv[1], args->pta_dir, len) != len) + err(1, "mp 2"); + if (xread(sv[1], &len, sizeof(len)) != sizeof(len)) + err(1, "fn 1"); + if (len > MAXPATHLEN) + err(1, "devpath > MAXPATHLEN"); + if ((size_t)xread(sv[1], args->pta_dev, len) != len) + err(1, "fn 2"); + if (xread(sv[1], &mntflags, sizeof(mntflags)) != sizeof(mntflags)) + err(1, "mntflags"); + if (xread(sv[1], &args->pta_pargslen, sizeof(args->pta_pargslen)) + != sizeof(args->pta_pargslen)) + err(1, "puffstest_args len"); + args->pta_pargs = malloc(args->pta_pargslen); + if (args->pta_pargs == NULL) + err(1, "malloc"); + if (xread(sv[1], args->pta_pargs, args->pta_pargslen) + != (ssize_t)args->pta_pargslen) + err(1, "puffstest_args"); + if (xread(sv[1], pflags, sizeof(*pflags)) != sizeof(*pflags)) + err(1, "pflags"); + + args->pta_childpid = childpid; + args->pta_servfd = sv[1]; + strlcpy(args->pta_dev, image, sizeof(args->pta_dev)); + + *argp = theargs = args; + + return 0; +} + +int +puffs_fstest_newfs(const atf_tc_t *tc, void **argp, + const char *image, off_t size, void *fspriv) +{ + char dtfs_path[MAXPATHLEN]; + char *dtfsargv[6]; + char **theargv; + + /* build dtfs exec path from atf test dir */ + sprintf(dtfs_path, "%s/../puffs/h_dtfs/h_dtfs", + atf_tc_get_config_var(tc, "srcdir")); + + if (fspriv) { + theargv = fspriv; + theargv[0] = dtfs_path; + } else { + dtfsargv[0] = dtfs_path; + dtfsargv[1] = __UNCONST("-i"); + dtfsargv[2] = __UNCONST("-s"); + dtfsargv[3] = __UNCONST("dtfs"); + dtfsargv[4] = __UNCONST("fictional"); + dtfsargv[5] = NULL; + + theargv = dtfsargv; + } + + return donewfs(tc, argp, image, size, fspriv, theargv); +} + +int +p2k_ffs_fstest_newfs(const atf_tc_t *tc, void **argp, + const char *image, off_t size, void *fspriv) +{ + char *rumpffs_argv[5]; + int rv; + + rump_init(); + if ((rv = ffs_fstest_newfs(tc, argp, image, size, fspriv)) != 0) + return rv; + if (mkdir("p2kffsfake", 0777) == -1 && errno != EEXIST) + return errno; + + setenv("P2K_NODETACH", "1", 1); + rumpffs_argv[0] = __UNCONST("rump_ffs"); + rumpffs_argv[1] = __UNCONST(image); + rumpffs_argv[2] = __UNCONST("p2kffsfake"); /* NOTUSED */ + rumpffs_argv[3] = NULL; + + if ((rv = donewfs(tc, argp, image, size, fspriv, rumpffs_argv)) != 0) + ffs_fstest_delfs(tc, argp); + return rv; +} + +int +puffs_fstest_mount(const atf_tc_t *tc, void *arg, const char *path, int flags) +{ + struct puffstestargs *pargs = arg; + int fd; + + rump_init(); + fd = rump_sys_open("/dev/puffs", O_RDWR); + if (fd == -1) + return fd; + + if (rump_sys_mkdir(path, 0777) == -1) + return -1; + + if (rump_sys_mount(MOUNT_PUFFS, path, flags, + pargs->pta_pargs, pargs->pta_pargslen) == -1) { + /* apply "to kill a child" to avoid atf hang (kludge) */ + kill(pargs->pta_childpid, SIGKILL); + return -1; + } + + pargs->pta_rumpfd = fd; + rumpshovels(pargs); + + return 0; +} +__strong_alias(p2k_ffs_fstest_mount,puffs_fstest_mount); + +int +puffs_fstest_delfs(const atf_tc_t *tc, void *arg) +{ + + /* useless ... */ + return 0; +} + +int +p2k_ffs_fstest_delfs(const atf_tc_t *tc, void *arg) +{ + + return ffs_fstest_delfs(tc, arg); +} + +int +puffs_fstest_unmount(const atf_tc_t *tc, const char *path, int flags) +{ + struct puffstestargs *pargs = theargs; + int status; + int rv; + + /* ok, child might exit here */ + signal(SIGCHLD, SIG_IGN); + + rv = rump_sys_unmount(path, flags); + if (rv) + return rv; + + if ((rv = rump_sys_rmdir(path)) != 0) + return rv; + + if (waitpid(pargs->pta_childpid, &status, WNOHANG) > 0) + return 0; + kill(pargs->pta_childpid, SIGTERM); + usleep(10); + if (waitpid(pargs->pta_childpid, &status, WNOHANG) > 0) + return 0; + kill(pargs->pta_childpid, SIGKILL); + usleep(500); + wait(&status); + + rmdir("p2kffsfake"); + + return 0; +} +__strong_alias(p2k_ffs_fstest_unmount,puffs_fstest_unmount); diff --git a/contrib/netbsd-tests/fs/common/fstest_rumpfs.c b/contrib/netbsd-tests/fs/common/fstest_rumpfs.c new file mode 100644 index 000000000000..e4003db3d026 --- /dev/null +++ b/contrib/netbsd-tests/fs/common/fstest_rumpfs.c @@ -0,0 +1,90 @@ +/* $NetBSD: fstest_rumpfs.c,v 1.2 2014/03/16 10:28:03 njoly Exp $ */ + +/*- + * Copyright (c) 2010 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Nicolas Joly. + * + * 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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. + */ + +#include <sys/mount.h> +#include <sys/stat.h> + +#include <atf-c.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +#include <rump/rump.h> +#include <rump/rump_syscalls.h> + +#include "h_fsmacros.h" + +int +rumpfs_fstest_newfs(const atf_tc_t *tc, void **buf, const char *image, + off_t size, void *fspriv) +{ + char tmp[64]; + int res; + + snprintf(tmp, sizeof(tmp), "%"PRId64, size); + res = setenv("RUMP_MEMLIMIT", tmp, 0); + if (res == -1) + return res; + + return rump_init(); +} + +int +rumpfs_fstest_delfs(const atf_tc_t *tc, void *buf) +{ + + return 0; +} + +int +rumpfs_fstest_mount(const atf_tc_t *tc, void *buf, const char *path, int flags) +{ + int res; + + res = rump_sys_mkdir(path, 0777); + if (res == -1) + return res; + + return rump_sys_mount(MOUNT_RUMPFS, path, flags, NULL, 0); +} + +int +rumpfs_fstest_unmount(const atf_tc_t *tc, const char *path, int flags) +{ + int res; + + res = rump_sys_unmount(path, flags); + if (res == -1) + return res; + + return rump_sys_rmdir(path); +} diff --git a/contrib/netbsd-tests/fs/common/fstest_sysvbfs.c b/contrib/netbsd-tests/fs/common/fstest_sysvbfs.c new file mode 100644 index 000000000000..a7cf7f4cd8e1 --- /dev/null +++ b/contrib/netbsd-tests/fs/common/fstest_sysvbfs.c @@ -0,0 +1,139 @@ +/* $NetBSD: fstest_sysvbfs.c,v 1.2 2010/07/30 16:15:05 pooka Exp $ */ + +/*- + * Copyright (c) 2010 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Nicolas Joly. + * + * 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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. + */ + +#include <sys/mount.h> +#include <sys/stat.h> + +#include <atf-c.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +#include <ufs/ufs/ufsmount.h> + +#include <rump/rump.h> +#include <rump/rump_syscalls.h> + +#include "h_fsmacros.h" + +struct sysvbfstestargs { + struct ufs_args ta_uargs; + char ta_devpath[MAXPATHLEN]; + char ta_imgpath[MAXPATHLEN]; +}; + +int +sysvbfs_fstest_newfs(const atf_tc_t *tc, void **buf, const char *image, + off_t size, void *fspriv) +{ + char cmd[1024]; + int res; + static unsigned int num = 0; + struct sysvbfstestargs *args; + + size /= 512; + snprintf(cmd, 1024, "newfs_sysvbfs -F -s %"PRId64" %s >/dev/null", + size, image); + res = system(cmd); + if (res != 0) + return res; + + res = rump_init(); + if (res != 0) + return res; + + args = calloc(1, sizeof(*args)); + if (args == NULL) + return -1; + + snprintf(args->ta_devpath, MAXPATHLEN, "/dev/device%d.sysvbfs", num); + snprintf(args->ta_imgpath, MAXPATHLEN, "%s", image); + args->ta_uargs.fspec = args->ta_devpath; + + res = rump_pub_etfs_register(args->ta_devpath, image, RUMP_ETFS_BLK); + if (res != 0) { + free(args); + return res; + } + + *buf = args; + num++; + + return 0; +} + +int +sysvbfs_fstest_delfs(const atf_tc_t *tc, void *buf) +{ + int res; + struct sysvbfstestargs *args = buf; + + res = rump_pub_etfs_remove(args->ta_devpath); + if (res != 0) + return res; + + res = unlink(args->ta_imgpath); + if (res != 0) + return res; + + free(args); + + return 0; +} + +int +sysvbfs_fstest_mount(const atf_tc_t *tc, void *buf, const char *path, int flags) +{ + int res; + struct sysvbfstestargs *args = buf; + + res = rump_sys_mkdir(path, 0777); + if (res == -1) + return res; + + res = rump_sys_mount(MOUNT_SYSVBFS, path, flags, &args->ta_uargs, + sizeof(args->ta_uargs)); + return res; +} + +int +sysvbfs_fstest_unmount(const atf_tc_t *tc, const char *path, int flags) +{ + int res; + + res = rump_sys_unmount(path, flags); + if (res == -1) + return res; + + res = rump_sys_rmdir(path); + return res; +} diff --git a/contrib/netbsd-tests/fs/common/fstest_tmpfs.c b/contrib/netbsd-tests/fs/common/fstest_tmpfs.c new file mode 100644 index 000000000000..83848432e21f --- /dev/null +++ b/contrib/netbsd-tests/fs/common/fstest_tmpfs.c @@ -0,0 +1,112 @@ +/* $NetBSD: fstest_tmpfs.c,v 1.2 2010/07/30 16:15:05 pooka Exp $ */ + +/*- + * Copyright (c) 2010 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Nicolas Joly. + * + * 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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. + */ + +#include <sys/mount.h> +#include <sys/stat.h> + +#include <atf-c.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +#include <fs/tmpfs/tmpfs_args.h> + +#include <rump/rump.h> +#include <rump/rump_syscalls.h> + +#include "h_fsmacros.h" + +struct tmpfstestargs { + struct tmpfs_args ta_uargs; +}; + +int +tmpfs_fstest_newfs(const atf_tc_t *tc, void **buf, const char *image, + off_t size, void *fspriv) +{ + int res; + struct tmpfstestargs *args; + + res = rump_init(); + if (res != 0) + return res; + + args = calloc(1, sizeof(*args)); + if (args == NULL) + return -1; + + args->ta_uargs.ta_version = TMPFS_ARGS_VERSION; + args->ta_uargs.ta_root_mode = 0777; + args->ta_uargs.ta_size_max = size; + + *buf = args; + + return 0; +} + +int +tmpfs_fstest_delfs(const atf_tc_t *tc, void *buf) +{ + struct tmpfstestargs *args = buf; + + free(args); + + return 0; +} + +int +tmpfs_fstest_mount(const atf_tc_t *tc, void *buf, const char *path, int flags) +{ + int res; + struct tmpfstestargs *args = buf; + + res = rump_sys_mkdir(path, 0777); + if (res == -1) + return res; + + res = rump_sys_mount(MOUNT_TMPFS, path, flags, &args->ta_uargs, + sizeof(args->ta_uargs)); + return res; +} + +int +tmpfs_fstest_unmount(const atf_tc_t *tc, const char *path, int flags) +{ + int res; + + res = rump_sys_unmount(path, flags); + if (res == -1) + return res; + + res = rump_sys_rmdir(path); + return res; +} diff --git a/contrib/netbsd-tests/fs/common/fstest_udf.c b/contrib/netbsd-tests/fs/common/fstest_udf.c new file mode 100644 index 000000000000..3c9e017f388f --- /dev/null +++ b/contrib/netbsd-tests/fs/common/fstest_udf.c @@ -0,0 +1,153 @@ +/* $NetBSD: fstest_udf.c,v 1.4 2013/07/02 15:00:55 reinoud Exp $ */ + +/*- + * Copyright (c) 2010 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Nicolas Joly. + * + * 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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. + */ + +#include <sys/mount.h> +#include <sys/stat.h> + +#include <atf-c.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <signal.h> + +#include <fs/udf/udf_mount.h> + +#include <rump/rump.h> +#include <rump/rump_syscalls.h> + +#include "h_fsmacros.h" + +struct udftestargs { + struct udf_args ta_uargs; + char ta_devpath[MAXPATHLEN]; + char ta_imgpath[MAXPATHLEN]; +}; + +int +udf_fstest_newfs(const atf_tc_t *tc, void **buf, const char *image, off_t size, + void *fspriv) +{ + char cmd[1024]; + int res; + static unsigned int num = 0; + struct udftestargs *args; + struct sigaction act, oact; + + /* + * Sectorsize can be specified with -S, as a multiple of 512. + * newfs_udf takes humanized number as size in bytes as -s parameter! + */ + snprintf(cmd, 1024, "newfs_udf -F -s %"PRId64" %s >/dev/null", size, image); + memset(&act, 0, sizeof(act)); + act.sa_handler = SIG_DFL; + sigaction(SIGCHLD, &act, &oact); + res = system(cmd); + sigaction(SIGCHLD, &oact, NULL); + if (res != 0) + return res; + + res = rump_init(); + if (res != 0) + return res; + + args = calloc(1, sizeof(*args)); + if (args == NULL) + return -1; + + snprintf(args->ta_devpath, MAXPATHLEN, "/dev/device%d.udf", num); + snprintf(args->ta_imgpath, MAXPATHLEN, "%s", image); + args->ta_uargs.fspec = args->ta_devpath; + args->ta_uargs.version = UDFMNT_VERSION; + + res = rump_pub_etfs_register(args->ta_devpath, image, RUMP_ETFS_BLK); + if (res != 0) { + free(args); + return res; + } + + *buf = args; + num++; + + return 0; +} +__strong_alias(udflog_fstest_newfs,udf_fstest_newfs); + +int +udf_fstest_delfs(const atf_tc_t *tc, void *buf) +{ + int res; + struct udftestargs *args = buf; + + res = rump_pub_etfs_remove(args->ta_devpath); + if (res != 0) { + errno = res; + return -1; + } + + res = unlink(args->ta_imgpath); + if (res != 0) + return res; + + free(args); + + return 0; +} +__strong_alias(udflog_fstest_delfs,udf_fstest_delfs); + +int +udf_fstest_mount(const atf_tc_t *tc, void *buf, const char *path, int flags) +{ + int res; + struct udftestargs *args = buf; + + res = rump_sys_mkdir(path, 0777); + if (res == -1) + return res; + + res = rump_sys_mount(MOUNT_UDF, path, flags, &args->ta_uargs, + sizeof(args->ta_uargs)); + return res; +} + +int +udf_fstest_unmount(const atf_tc_t *tc, const char *path, int flags) +{ + int res; + + res = rump_sys_unmount(path, flags); + if (res == -1) + return res; + + res = rump_sys_rmdir(path); + return res; +} +__strong_alias(udflog_fstest_unmount,udf_fstest_unmount); diff --git a/contrib/netbsd-tests/fs/common/fstest_v7fs.c b/contrib/netbsd-tests/fs/common/fstest_v7fs.c new file mode 100644 index 000000000000..92110e430e83 --- /dev/null +++ b/contrib/netbsd-tests/fs/common/fstest_v7fs.c @@ -0,0 +1,140 @@ +/* $NetBSD: fstest_v7fs.c,v 1.1 2011/08/11 10:52:12 uch Exp $ */ + +/*- + * Copyright (c) 2011 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Nicolas Joly. + * + * 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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. + */ + +#include <sys/mount.h> +#include <sys/stat.h> + +#include <atf-c.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +#include <fs/v7fs/v7fs_args.h> + +#include <rump/rump.h> +#include <rump/rump_syscalls.h> + +#include "h_fsmacros.h" + +struct v7fstestargs { + struct v7fs_args ta_uargs; + char ta_devpath[MAXPATHLEN]; + char ta_imgpath[MAXPATHLEN]; +}; + +int +v7fs_fstest_newfs(const atf_tc_t *tc, void **buf, const char *image, + off_t size, void *fspriv) +{ + char cmd[1024]; + int res; + static unsigned int num = 0; + struct v7fstestargs *args; + + size /= 512; + snprintf(cmd, 1024, "newfs_v7fs -F -s %"PRId64" %s >/dev/null", + size, image); + res = system(cmd); + if (res != 0) + return res; + + res = rump_init(); + if (res != 0) + return res; + + args = calloc(1, sizeof(*args)); + if (args == NULL) + return -1; + + snprintf(args->ta_devpath, MAXPATHLEN, "/dev/device%d.v7fs", num); + snprintf(args->ta_imgpath, MAXPATHLEN, "%s", image); + args->ta_uargs.fspec = args->ta_devpath; + args->ta_uargs.endian = _BYTE_ORDER; + + res = rump_pub_etfs_register(args->ta_devpath, image, RUMP_ETFS_BLK); + if (res != 0) { + free(args); + return res; + } + + *buf = args; + num++; + + return 0; +} + +int +v7fs_fstest_delfs(const atf_tc_t *tc, void *buf) +{ + int res; + struct v7fstestargs *args = buf; + + res = rump_pub_etfs_remove(args->ta_devpath); + if (res != 0) + return res; + + res = unlink(args->ta_imgpath); + if (res != 0) + return res; + + free(args); + + return 0; +} + +int +v7fs_fstest_mount(const atf_tc_t *tc, void *buf, const char *path, int flags) +{ + int res; + struct v7fstestargs *args = buf; + + res = rump_sys_mkdir(path, 0777); + if (res == -1) + return res; + + res = rump_sys_mount(MOUNT_V7FS, path, flags, &args->ta_uargs, + sizeof(args->ta_uargs)); + return res; +} + +int +v7fs_fstest_unmount(const atf_tc_t *tc, const char *path, int flags) +{ + int res; + + res = rump_sys_unmount(path, flags); + if (res == -1) + return res; + + res = rump_sys_rmdir(path); + return res; +} diff --git a/contrib/netbsd-tests/fs/common/fstest_zfs.c b/contrib/netbsd-tests/fs/common/fstest_zfs.c new file mode 100644 index 000000000000..88aa05f28ff7 --- /dev/null +++ b/contrib/netbsd-tests/fs/common/fstest_zfs.c @@ -0,0 +1,134 @@ +/* $NetBSD: fstest_zfs.c,v 1.1 2012/08/20 16:37:35 pooka Exp $ */ + +/*- + * Copyright (c) 2010, 2011 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Nicolas Joly. + * + * 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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. + */ + +#include <sys/mount.h> +#include <sys/stat.h> + +#include <atf-c.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +#include <rump/rump.h> +#include <rump/rump_syscalls.h> + +#include "h_fsmacros.h" + +#define SRVPATH "zfssurvo" +#define SRVURL "unix://" SRVPATH +#define ZFSDEV "/zfsdev" + +int +zfs_fstest_newfs(const atf_tc_t *tc, void **buf, const char *image, + off_t size, void *fspriv) +{ + int res; + int fd; + + /* XXX: hardcoded zfs minimum size */ + size = MAX(64*1024*1024, size); + + res = rump_init(); + if (res != 0) { + errno = res; + return -1; + } + + /* create backing image, sparse file is enough */ + if ((fd = open(image, O_RDWR | O_CREAT, 0777)) == -1) + return -1; + if (ftruncate(fd, size) == -1) { + close(fd); + return -1; + } + close(fd); + + res = rump_pub_etfs_register(ZFSDEV, image, RUMP_ETFS_BLK); + if (res != 0) { + errno = res; + return -1; + } + + res = rump_init_server(SRVURL); + if (res != 0) { + errno = res; + return -1; + } + *buf = NULL; + + return 0; +} + +int +zfs_fstest_delfs(const atf_tc_t *tc, void *buf) +{ + + unlink(SRVPATH); + return 0; +} + +int +zfs_fstest_mount(const atf_tc_t *tc, void *buf, const char *path, int flags) +{ + char tmpbuf[128]; + int error; + + /* set up the hijack env for running zpool */ + setenv("RUMP_SERVER", SRVURL, 1); + snprintf(tmpbuf, sizeof(tmpbuf)-1, "blanket=/dev/zfs:%s:%s", + ZFSDEV, path); + setenv("RUMPHIJACK", tmpbuf, 1); + setenv("LD_PRELOAD", "/usr/lib/librumphijack.so", 1); + + while (*path == '/') + path++; + + /* run zpool create */ + snprintf(tmpbuf, sizeof(tmpbuf)-1, "zpool create %s %s", + path, ZFSDEV); + if ((error = system(tmpbuf)) != 0) { + errno = error; + return -1; + } + + return 0; +} + +int +zfs_fstest_unmount(const atf_tc_t *tc, const char *path, int flags) +{ + + unmount(path, flags); + unlink(SRVPATH); + + return 0; +} diff --git a/contrib/netbsd-tests/fs/common/h_fsmacros.h b/contrib/netbsd-tests/fs/common/h_fsmacros.h new file mode 100644 index 000000000000..eb8376873b2f --- /dev/null +++ b/contrib/netbsd-tests/fs/common/h_fsmacros.h @@ -0,0 +1,329 @@ +/* $NetBSD: h_fsmacros.h,v 1.41 2017/01/13 21:30:39 christos Exp $ */ + +/*- + * Copyright (c) 2010 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Nicolas Joly. + * + * 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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. + */ + +#ifndef __H_FSMACROS_H_ +#define __H_FSMACROS_H_ + +#include <sys/mount.h> + +#include <atf-c.h> +#include <puffsdump.h> +#include <string.h> + +#include <rump/rump.h> + +#include "h_macros.h" + +#define FSPROTOS(_fs_) \ +int _fs_##_fstest_newfs(const atf_tc_t *, void **, const char *, \ + off_t, void *); \ +int _fs_##_fstest_delfs(const atf_tc_t *, void *); \ +int _fs_##_fstest_mount(const atf_tc_t *, void *, const char *, int); \ +int _fs_##_fstest_unmount(const atf_tc_t *, const char *, int); + +FSPROTOS(ext2fs); +FSPROTOS(ffs); +FSPROTOS(ffslog); +FSPROTOS(lfs); +FSPROTOS(msdosfs); +FSPROTOS(nfs); +FSPROTOS(nfsro); +FSPROTOS(p2k_ffs); +FSPROTOS(puffs); +FSPROTOS(rumpfs); +FSPROTOS(sysvbfs); +FSPROTOS(tmpfs); +FSPROTOS(udf); +FSPROTOS(v7fs); +FSPROTOS(zfs); + +#ifndef FSTEST_IMGNAME +#define FSTEST_IMGNAME "image.fs" +#endif +#ifndef FSTEST_IMGSIZE +#define FSTEST_IMGSIZE (10000 * 512) +#endif +#ifndef FSTEST_MNTNAME +#define FSTEST_MNTNAME "/mnt" +#endif + +#define FSTEST_CONSTRUCTOR(_tc_, _fs_, _args_) \ +do { \ + if (_fs_##_fstest_newfs(_tc_, &_args_, \ + FSTEST_IMGNAME, FSTEST_IMGSIZE, NULL) != 0) \ + atf_tc_fail_errno("newfs failed"); \ + if (_fs_##_fstest_mount(_tc_, _args_, FSTEST_MNTNAME, 0) != 0) \ + atf_tc_fail_errno("mount failed"); \ +} while (/*CONSTCOND*/0); + +#define FSTEST_CONSTRUCTOR_FSPRIV(_tc_, _fs_, _args_, _privargs_) \ +do { \ + if (_fs_##_fstest_newfs(_tc_, &_args_, \ + FSTEST_IMGNAME, FSTEST_IMGSIZE, _privargs_) != 0) \ + atf_tc_fail_errno("newfs failed"); \ + if (_fs_##_fstest_mount(_tc_, _args_, FSTEST_MNTNAME, 0) != 0) \ + atf_tc_fail_errno("mount failed"); \ +} while (/*CONSTCOND*/0); + +#define FSTEST_DESTRUCTOR(_tc_, _fs_, _args_) \ +do { \ + if (_fs_##_fstest_unmount(_tc_, FSTEST_MNTNAME, 0) != 0) { \ + rump_pub_vfs_mount_print(FSTEST_MNTNAME, 1); \ + atf_tc_fail_errno("unmount failed"); \ + } \ + if (_fs_##_fstest_delfs(_tc_, _args_) != 0) \ + atf_tc_fail_errno("delfs failed"); \ +} while (/*CONSTCOND*/0); + +#define ATF_TC_FSADD(fs,type,func,desc) \ + ATF_TC(fs##_##func); \ + ATF_TC_HEAD(fs##_##func,tc) \ + { \ + atf_tc_set_md_var(tc, "descr", type " test for " desc); \ + atf_tc_set_md_var(tc, "X-fs.type", #fs); \ + atf_tc_set_md_var(tc, "X-fs.mntname", type); \ + } \ + void *fs##func##tmp; \ + \ + ATF_TC_BODY(fs##_##func,tc) \ + { \ + if (!atf_check_fstype(tc, #fs)) \ + atf_tc_skip("filesystem not selected"); \ + FSTEST_CONSTRUCTOR(tc,fs,fs##func##tmp); \ + func(tc,FSTEST_MNTNAME); \ + if (fs##_fstest_unmount(tc, FSTEST_MNTNAME, 0) != 0) { \ + rump_pub_vfs_mount_print(FSTEST_MNTNAME, 1); \ + atf_tc_fail_errno("unmount failed"); \ + } \ + } + +#define ATF_TC_FSADD_RO(_fs_,_type_,_func_,_desc_,_gen_) \ + ATF_TC(_fs_##_##_func_); \ + ATF_TC_HEAD(_fs_##_##_func_,tc) \ + { \ + atf_tc_set_md_var(tc, "descr",_type_" test for "_desc_);\ + atf_tc_set_md_var(tc, "X-fs.type", #_fs_); \ + atf_tc_set_md_var(tc, "X-fs.mntname", _type_); \ + } \ + void *_fs_##_func_##tmp; \ + \ + ATF_TC_BODY(_fs_##_##_func_,tc) \ + { \ + if (!atf_check_fstype(tc, #_fs_)) \ + atf_tc_skip("filesystem not selected"); \ + FSTEST_CONSTRUCTOR(tc,_fs_,_fs_##_func_##tmp); \ + _gen_(tc,FSTEST_MNTNAME); \ + if (_fs_##_fstest_unmount(tc, FSTEST_MNTNAME, 0) != 0) \ + atf_tc_fail_errno("unmount r/w failed"); \ + if (_fs_##_fstest_mount(tc, _fs_##_func_##tmp, \ + FSTEST_MNTNAME, MNT_RDONLY) != 0) \ + atf_tc_fail_errno("mount ro failed"); \ + _func_(tc,FSTEST_MNTNAME); \ + if (_fs_##_fstest_unmount(tc, FSTEST_MNTNAME, 0) != 0) {\ + rump_pub_vfs_mount_print(FSTEST_MNTNAME, 1); \ + atf_tc_fail_errno("unmount failed"); \ + } \ + } + +#define ATF_TP_FSADD(fs,func) \ + ATF_TP_ADD_TC(tp,fs##_##func) + +#define ATF_TC_FSAPPLY_NOZFS(func,desc) \ + ATF_TC_FSADD(ext2fs,MOUNT_EXT2FS,func,desc) \ + ATF_TC_FSADD(ffs,MOUNT_FFS,func,desc) \ + ATF_TC_FSADD(ffslog,MOUNT_FFS,func,desc) \ + ATF_TC_FSADD(lfs,MOUNT_LFS,func,desc) \ + ATF_TC_FSADD(msdosfs,MOUNT_MSDOS,func,desc) \ + ATF_TC_FSADD(nfs,MOUNT_NFS,func,desc) \ + ATF_TC_FSADD(puffs,MOUNT_PUFFS,func,desc) \ + ATF_TC_FSADD(p2k_ffs,MOUNT_PUFFS,func,desc) \ + ATF_TC_FSADD(rumpfs,MOUNT_RUMPFS,func,desc) \ + ATF_TC_FSADD(sysvbfs,MOUNT_SYSVBFS,func,desc) \ + ATF_TC_FSADD(tmpfs,MOUNT_TMPFS,func,desc) \ + ATF_TC_FSADD(udf,MOUNT_UDF,func,desc) \ + ATF_TC_FSADD(v7fs,MOUNT_V7FS,func,desc) + +#define ATF_TP_FSAPPLY_NOZFS(func) \ + ATF_TP_FSADD(ext2fs,func); \ + ATF_TP_FSADD(ffs,func); \ + ATF_TP_FSADD(ffslog,func); \ + ATF_TP_FSADD(lfs,func); \ + ATF_TP_FSADD(msdosfs,func); \ + ATF_TP_FSADD(nfs,func); \ + ATF_TP_FSADD(puffs,func); \ + ATF_TP_FSADD(p2k_ffs,func); \ + ATF_TP_FSADD(rumpfs,func); \ + ATF_TP_FSADD(sysvbfs,func); \ + ATF_TP_FSADD(tmpfs,func); \ + ATF_TP_FSADD(udf,func); \ + ATF_TP_FSADD(v7fs,func); + +/* XXX: this will not scale */ +#ifdef WANT_ZFS_TESTS +#define ATF_TC_FSAPPLY(func,desc) \ + ATF_TC_FSAPPLY_NOZFS(func,desc) \ + ATF_TC_FSADD(zfs,MOUNT_ZFS,func,desc) +#define ATF_TP_FSAPPLY(func) \ + ATF_TP_FSAPPLY_NOZFS(func) \ + ATF_TP_FSADD(zfs,func); + +#else /* !WANT_ZFS_TESTS */ + +#define ATF_TC_FSAPPLY(func,desc) \ + ATF_TC_FSAPPLY_NOZFS(func,desc) +#define ATF_TP_FSAPPLY(func) \ + ATF_TP_FSAPPLY_NOZFS(func) + +#endif /* WANT_ZFS_TESTS */ + +/* + * Same as above, but generate a file system image first and perform + * tests for a r/o mount. + * + * Missing the following file systems: + * + lfs (fstest_lfs routines cannot handle remount. FIXME!) + * + tmpfs (memory backend) + * + rumpfs (memory backend) + * + puffs (memory backend, but could be run in theory) + */ + +#define ATF_TC_FSAPPLY_RO(func,desc,gen) \ + ATF_TC_FSADD_RO(ext2fs,MOUNT_EXT2FS,func,desc,gen) \ + ATF_TC_FSADD_RO(ffs,MOUNT_FFS,func,desc,gen) \ + ATF_TC_FSADD_RO(ffslog,MOUNT_FFS,func,desc,gen) \ + ATF_TC_FSADD_RO(msdosfs,MOUNT_MSDOS,func,desc,gen) \ + ATF_TC_FSADD_RO(nfs,MOUNT_NFS,func,desc,gen) \ + ATF_TC_FSADD_RO(nfsro,MOUNT_NFS,func,desc,gen) \ + ATF_TC_FSADD_RO(sysvbfs,MOUNT_SYSVBFS,func,desc,gen) \ + ATF_TC_FSADD_RO(udf,MOUNT_UDF,func,desc,gen) \ + ATF_TC_FSADD_RO(v7fs,MOUNT_V7FS,func,desc,gen) + +#define ATF_TP_FSAPPLY_RO(func) \ + ATF_TP_FSADD(ext2fs,func); \ + ATF_TP_FSADD(ffs,func); \ + ATF_TP_FSADD(ffslog,func); \ + ATF_TP_FSADD(msdosfs,func); \ + ATF_TP_FSADD(nfs,func); \ + ATF_TP_FSADD(nfsro,func); \ + ATF_TP_FSADD(sysvbfs,func); \ + ATF_TP_FSADD(udf,func); \ + ATF_TP_FSADD(v7fs,func); + +#define ATF_FSAPPLY(func,desc) \ + ATF_TC_FSAPPLY(func,desc); \ + ATF_TP_ADD_TCS(tp) \ + { \ + ATF_TP_FSAPPLY(func); \ + return atf_no_error(); \ + } + +static __inline bool +atf_check_fstype(const atf_tc_t *tc, const char *fs) +{ + const char *fstype; + + if (!atf_tc_has_config_var(tc, "fstype")) + return true; + + fstype = atf_tc_get_config_var(tc, "fstype"); + if (strcmp(fstype, fs) == 0) + return true; + return false; +} + +#define FSTYPE_EXT2FS(tc)\ + (strcmp(atf_tc_get_md_var(tc, "X-fs.type"), "ext2fs") == 0) +#define FSTYPE_FFS(tc)\ + (strcmp(atf_tc_get_md_var(tc, "X-fs.type"), "ffs") == 0) +#define FSTYPE_FFSLOG(tc)\ + (strcmp(atf_tc_get_md_var(tc, "X-fs.type"), "ffslog") == 0) +#define FSTYPE_LFS(tc)\ + (strcmp(atf_tc_get_md_var(tc, "X-fs.type"), "lfs") == 0) +#define FSTYPE_MSDOS(tc)\ + (strcmp(atf_tc_get_md_var(tc, "X-fs.type"), "msdosfs") == 0) +#define FSTYPE_NFS(tc)\ + (strcmp(atf_tc_get_md_var(tc, "X-fs.type"), "nfs") == 0) +#define FSTYPE_NFSRO(tc)\ + (strcmp(atf_tc_get_md_var(tc, "X-fs.type"), "nfsro") == 0) +#define FSTYPE_P2K_FFS(tc)\ + (strcmp(atf_tc_get_md_var(tc, "X-fs.type"), "p2k_ffs") == 0) +#define FSTYPE_PUFFS(tc)\ + (strcmp(atf_tc_get_md_var(tc, "X-fs.type"), "puffs") == 0) +#define FSTYPE_RUMPFS(tc)\ + (strcmp(atf_tc_get_md_var(tc, "X-fs.type"), "rumpfs") == 0) +#define FSTYPE_SYSVBFS(tc)\ + (strcmp(atf_tc_get_md_var(tc, "X-fs.type"), "sysvbfs") == 0) +#define FSTYPE_TMPFS(tc)\ + (strcmp(atf_tc_get_md_var(tc, "X-fs.type"), "tmpfs") == 0) +#define FSTYPE_UDF(tc)\ + (strcmp(atf_tc_get_md_var(tc, "X-fs.type"), "udf") == 0) +#define FSTYPE_V7FS(tc)\ + (strcmp(atf_tc_get_md_var(tc, "X-fs.type"), "v7fs") == 0) +#define FSTYPE_ZFS(tc)\ + (strcmp(atf_tc_get_md_var(tc, "X-fs.type"), "zfs") == 0) + +#define FSTEST_ENTER() \ + if (rump_sys_chdir(FSTEST_MNTNAME) == -1) \ + atf_tc_fail_errno("failed to cd into test mount") + +#define FSTEST_EXIT() \ + if (rump_sys_chdir("/") == -1) \ + atf_tc_fail_errno("failed to cd out of test mount") + +/* + * file system args structures + */ + +struct nfstestargs { + pid_t ta_childpid; + char ta_ethername[MAXPATHLEN]; +}; + +struct puffstestargs { + uint8_t *pta_pargs; + size_t pta_pargslen; + + int pta_pflags; + pid_t pta_childpid; + + int pta_rumpfd; + int pta_servfd; + + char pta_dev[MAXPATHLEN]; + char pta_dir[MAXPATHLEN]; + + int pta_mntflags; + + int pta_vfs_toserv_ops[PUFFS_VFS_MAX]; + int pta_vn_toserv_ops[PUFFS_VN_MAX]; +}; + +#endif /* __H_FSMACROS_H_ */ diff --git a/contrib/netbsd-tests/fs/common/snapshot.c b/contrib/netbsd-tests/fs/common/snapshot.c new file mode 100644 index 000000000000..7baf611b6ed6 --- /dev/null +++ b/contrib/netbsd-tests/fs/common/snapshot.c @@ -0,0 +1,228 @@ +/* $NetBSD: snapshot.c,v 1.7 2013/02/06 09:05:01 hannken Exp $ */ + +#include <sys/types.h> +#include <sys/ioctl.h> +#include <sys/mount.h> + +#include <dev/fssvar.h> + +#include <atf-c.h> +#include <fcntl.h> +#include <pthread.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +ATF_TC_WITH_CLEANUP(snapshot); +ATF_TC_HEAD(snapshot, tc) +{ + + atf_tc_set_md_var(tc, "descr", "basic snapshot features"); +} + +static void +makefile(const char *path) +{ + int fd; + + fd = rump_sys_open(path, O_CREAT | O_RDWR, 0777); + if (fd == -1) + atf_tc_fail_errno("create %s", path); + rump_sys_close(fd); +} + +ATF_TC_BODY(snapshot, tc) +{ + char buf[1024]; + struct fss_set fss; + int fssfd; + int fd, fd2, i; + + if (system(NEWFS) == -1) + atf_tc_fail_errno("cannot create file system"); + + rump_init(); + begin(); + + if (rump_sys_mkdir("/mnt", 0777) == -1) + atf_tc_fail_errno("mount point create"); + if (rump_sys_mkdir("/snap", 0777) == -1) + atf_tc_fail_errno("mount point 2 create"); + + rump_pub_etfs_register("/diskdev", IMGNAME, RUMP_ETFS_BLK); + + mount_diskfs("/diskdev", "/mnt"); + +#define TESTSTR1 "huihai\n" +#define TESTSZ1 (sizeof(TESTSTR1)-1) +#define TESTSTR2 "baana liten\n" +#define TESTSZ2 (sizeof(TESTSTR2)-1) + + fd = rump_sys_open("/mnt/myfile", O_RDWR | O_CREAT, 0777); + if (fd == -1) + atf_tc_fail_errno("create file"); + if (rump_sys_write(fd, TESTSTR1, TESTSZ1) != TESTSZ1) + atf_tc_fail_errno("write fail"); + + fssfd = rump_sys_open("/dev/rfss0", O_RDWR); + if (fssfd == -1) + atf_tc_fail_errno("cannot open fss"); + makefile(BAKNAME); + memset(&fss, 0, sizeof(fss)); + fss.fss_mount = __UNCONST("/mnt"); + fss.fss_bstore = __UNCONST(BAKNAME); + fss.fss_csize = 0; + if (rump_sys_ioctl(fssfd, FSSIOCSET, &fss) == -1) + atf_tc_fail_errno("create snapshot"); + + for (i = 0; i < 10000; i++) { + if (rump_sys_write(fd, TESTSTR2, TESTSZ2) != TESTSZ2) + atf_tc_fail_errno("write fail"); + } + rump_sys_sync(); + + /* technically we should fsck it first? */ + mount_diskfs("/dev/fss0", "/snap"); + + /* check for old contents */ + fd2 = rump_sys_open("/snap/myfile", O_RDONLY); + if (fd2 == -1) + atf_tc_fail_errno("fail"); + memset(buf, 0, sizeof(buf)); + if (rump_sys_read(fd2, buf, sizeof(buf)) == -1) + atf_tc_fail_errno("read snap"); + ATF_CHECK(strcmp(buf, TESTSTR1) == 0); + + /* check that new files are invisible in the snapshot */ + makefile("/mnt/newfile"); + if (rump_sys_open("/snap/newfile", O_RDONLY) != -1) + atf_tc_fail("newfile exists in snapshot"); + if (errno != ENOENT) + atf_tc_fail_errno("newfile open should fail with ENOENT"); + + /* check that removed files are still visible in the snapshot */ + rump_sys_unlink("/mnt/myfile"); + if (rump_sys_open("/snap/myfile", O_RDONLY) == -1) + atf_tc_fail_errno("unlinked file no longer in snapshot"); + + /* done for now */ +} + +ATF_TC_CLEANUP(snapshot, tc) +{ + + unlink(IMGNAME); +} + +ATF_TC_WITH_CLEANUP(snapshotstress); +ATF_TC_HEAD(snapshotstress, tc) +{ + + atf_tc_set_md_var(tc, "descr", "snapshot on active file system"); +} + +#define NACTIVITY 4 + +static bool activity_stop = false; +static pid_t wrkpid; + +static void * +fs_activity(void *arg) +{ + int di, fi; + char *prefix = arg, path[128]; + + rump_pub_lwproc_newlwp(wrkpid); + + RL(rump_sys_mkdir(prefix, 0777)); + while (! activity_stop) { + for (di = 0; di < 5; di++) { + snprintf(path, sizeof(path), "%s/d%d", prefix, di); + RL(rump_sys_mkdir(path, 0777)); + for (fi = 0; fi < 5; fi++) { + snprintf(path, sizeof(path), "%s/d%d/f%d", + prefix, di, fi); + makefile(path); + } + } + for (di = 0; di < 5; di++) { + for (fi = 0; fi < 5; fi++) { + snprintf(path, sizeof(path), "%s/d%d/f%d", + prefix, di, fi); + RL(rump_sys_unlink(path)); + } + snprintf(path, sizeof(path), "%s/d%d", prefix, di); + RL(rump_sys_rmdir(path)); + } + } + RL(rump_sys_rmdir(prefix)); + + rump_pub_lwproc_releaselwp(); + + return NULL; +} + +ATF_TC_BODY(snapshotstress, tc) +{ + pthread_t at[NACTIVITY]; + struct fss_set fss; + char prefix[NACTIVITY][128]; + int i, fssfd; + + if (system(NEWFS) == -1) + atf_tc_fail_errno("cannot create file system"); + /* Force SMP so the stress makes sense. */ + RL(setenv("RUMP_NCPU", "4", 1)); + RZ(rump_init()); + /* Prepare for fsck to use the RUMP /dev/fss0. */ + RL(rump_init_server("unix://commsock")); + RL(setenv("LD_PRELOAD", "/usr/lib/librumphijack.so", 1)); + RL(setenv("RUMP_SERVER", "unix://commsock", 1)); + RL(setenv("RUMPHIJACK", "blanket=/dev/rfss0", 1)); + begin(); + + RL(rump_sys_mkdir("/mnt", 0777)); + + rump_pub_etfs_register("/diskdev", IMGNAME, RUMP_ETFS_BLK); + + mount_diskfs("/diskdev", "/mnt"); + + /* Start file system activity. */ + RL(wrkpid = rump_sys_getpid()); + for (i = 0; i < NACTIVITY; i++) { + snprintf(prefix[i], sizeof(prefix[i]), "/mnt/a%d", i); + RL(pthread_create(&at[i], NULL, fs_activity, prefix[i])); + sleep(1); + } + + fssfd = rump_sys_open("/dev/rfss0", O_RDWR); + if (fssfd == -1) + atf_tc_fail_errno("cannot open fss"); + makefile(BAKNAME); + memset(&fss, 0, sizeof(fss)); + fss.fss_mount = __UNCONST("/mnt"); + fss.fss_bstore = __UNCONST(BAKNAME); + fss.fss_csize = 0; + if (rump_sys_ioctl(fssfd, FSSIOCSET, &fss) == -1) + atf_tc_fail_errno("create snapshot"); + + activity_stop = true; + for (i = 0; i < NACTIVITY; i++) + RL(pthread_join(at[i], NULL)); + + RL(system(FSCK " /dev/rfss0")); +} + +ATF_TC_CLEANUP(snapshotstress, tc) +{ + + unlink(IMGNAME); +} + +ATF_TP_ADD_TCS(tp) +{ + ATF_TP_ADD_TC(tp, snapshot); + ATF_TP_ADD_TC(tp, snapshotstress); + return 0; +} diff --git a/contrib/netbsd-tests/fs/ffs/ffs_common.sh b/contrib/netbsd-tests/fs/ffs/ffs_common.sh new file mode 100755 index 000000000000..ee94a15f994a --- /dev/null +++ b/contrib/netbsd-tests/fs/ffs/ffs_common.sh @@ -0,0 +1,99 @@ +# $NetBSD: ffs_common.sh,v 1.3 2016/10/08 13:23:53 gson Exp $ + +create_ffs() +{ + local endian=$1; shift + local vers=$1; shift + local type=$1; shift + local op; + if [ ${type} = "both" ]; then + op="-q user -q group" + else + op="-q ${type}" + fi + atf_check -o ignore -e ignore newfs ${op} \ + -B ${endian} -O ${vers} -s 4000 -F ${IMG} +} + +create_ffs_server() +{ + local sarg=$1; shift + create_ffs $* + atf_check -o ignore -e ignore $(atf_get_srcdir)/h_ffs_server \ + ${sarg} ${IMG} ${RUMP_SERVER} +} + +rump_shutdown() +{ + for s in ${RUMP_SOCKETS_LIST}; do + atf_check -s exit:0 env RUMP_SERVER=unix://${s} rump.halt; + done +# check that the quota inode creation didn't corrupt the filesystem + atf_check -s exit:0 -o "match:already clean" \ + -o "match:Phase 6 - Check Quotas" \ + fsck_ffs -nf -F ${IMG} +} + +# from tests/ipf/h_common.sh via tests/sbin/resize_ffs +test_case() +{ + local name="${1}"; shift + local check_function="${1}"; shift + local descr="${1}"; shift + + atf_test_case "${name}" cleanup + + eval "${name}_head() { \ + atf_set "descr" "${descr}" + atf_set "timeout" "120" + }" + eval "${name}_body() { \ + RUMP_SOCKETS_LIST=\${RUMP_SOCKET}; \ + export RUMP_SERVER=unix://\${RUMP_SOCKET}; \ + ${check_function} " "${@}" "; \ + }" + eval "${name}_cleanup() { \ + for s in \${RUMP_SOCKETS_LIST}; do \ + export RUMP_SERVER=unix://\${s}; \ + atf_check -s exit:1 -o ignore -e ignore rump.halt; \ + done; \ + }" + tests="${tests} ${name}" +} + +test_case_root() +{ + local name="${1}"; shift + local check_function="${1}"; shift + local descr="${1}"; shift + + atf_test_case "${name}" cleanup + + eval "${name}_head() { \ + atf_set "descr" "${descr}" + atf_set "require.user" "root" + atf_set "timeout" "360" + }" + eval "${name}_body() { \ + RUMP_SOCKETS_LIST=\${RUMP_SOCKET}; \ + export RUMP_SERVER=unix://\${RUMP_SOCKET}; \ + ${check_function} " "${@}" "; \ + }" + eval "${name}_cleanup() { \ + for s in \${RUMP_SOCKETS_LIST}; do \ + export RUMP_SERVER=unix://\${s}; \ + atf_check -s exit:1 -o ignore -e ignore rump.halt; \ + done; \ + }" + tests="${tests} ${name}" +} + +atf_init_test_cases() +{ + IMG=fsimage + DIR=target + RUMP_SOCKET=test; + for i in ${tests}; do + atf_add_test_case $i + done +} diff --git a/contrib/netbsd-tests/fs/ffs/h_ffs_server.c b/contrib/netbsd-tests/fs/ffs/h_ffs_server.c new file mode 100644 index 000000000000..dd22d9faf1d8 --- /dev/null +++ b/contrib/netbsd-tests/fs/ffs/h_ffs_server.c @@ -0,0 +1,113 @@ +/* $NetBSD: h_ffs_server.c,v 1.2 2012/08/24 20:25:50 jmmv Exp $ */ + +/* + * rump server for advanced quota tests + */ + +#include "../common/h_fsmacros.h" + +#include <err.h> +#include <semaphore.h> +#include <sys/types.h> +#include <sys/mount.h> + +#include <stdlib.h> +#include <unistd.h> + +#include <ufs/ufs/ufsmount.h> + +#include <rump/rump.h> +#include <rump/rump_syscalls.h> + +int background = 0; + +static void +usage(void) +{ + fprintf(stderr, "usage: %s [-b] [-l] diskimage bindurl\n", + getprogname()); + exit(1); +} + +static void +die(const char *reason, int error) +{ + + warnx("%s: %s", reason, strerror(error)); + if (background) + rump_daemonize_done(error); + exit(1); +} + +static sem_t sigsem; +static void +sigreboot(int sig) +{ + + sem_post(&sigsem); +} + +int +main(int argc, char **argv) +{ + int error; + struct ufs_args uargs; + const char *filename; + const char *serverurl; + int log = 0; + int ch; + + while ((ch = getopt(argc, argv, "bl")) != -1) { + switch(ch) { + case 'b': + background = 1; + break; + case 'l': + log = 1; + break; + default: + usage(); + } + } + argc -= optind; + argv += optind; + + if (argc != 2) + usage(); + + filename = argv[0]; + serverurl = argv[1]; + + if (background) { + error = rump_daemonize_begin(); + if (error) + errx(1, "rump daemonize: %s", strerror(error)); + } + + error = rump_init(); + if (error) + die("rump init failed", error); + + if (rump_sys_mkdir(FSTEST_MNTNAME, 0777) == -1) + die("mount point create", errno); + rump_pub_etfs_register("/diskdev", filename, RUMP_ETFS_BLK); + uargs.fspec = __UNCONST("/diskdev"); + if (rump_sys_mount(MOUNT_FFS, FSTEST_MNTNAME, (log) ? MNT_LOG : 0, + &uargs, sizeof(uargs)) == -1) + die("mount ffs", errno); + + error = rump_init_server(serverurl); + if (error) + die("rump server init failed", error); + if (background) + rump_daemonize_done(RUMP_DAEMONIZE_SUCCESS); + + sem_init(&sigsem, 0, 0); + signal(SIGTERM, sigreboot); + signal(SIGINT, sigreboot); + sem_wait(&sigsem); + + rump_sys_reboot(0, NULL); + /*NOTREACHED*/ + return 0; +} diff --git a/contrib/netbsd-tests/fs/ffs/h_quota2_tests.c b/contrib/netbsd-tests/fs/ffs/h_quota2_tests.c new file mode 100644 index 000000000000..71cf3b4958f1 --- /dev/null +++ b/contrib/netbsd-tests/fs/ffs/h_quota2_tests.c @@ -0,0 +1,468 @@ +/* $NetBSD: h_quota2_tests.c,v 1.5 2017/01/13 21:30:39 christos Exp $ */ + +/* + * rump server for advanced quota tests + * this one includes functions to run against the filesystem before + * starting to handle rump requests from clients. + */ + +#include "../common/h_fsmacros.h" + +#include <err.h> +#include <semaphore.h> +#include <sys/types.h> +#include <sys/mount.h> + +#include <stdlib.h> +#include <unistd.h> + +#include <ufs/ufs/ufsmount.h> +#include <dev/fssvar.h> + +#include <rump/rump.h> +#include <rump/rump_syscalls.h> + +#include "h_macros.h" + +int background = 0; + +#define TEST_NONROOT_ID 1 + +static int +quota_test0(const char *testopts) +{ + static char buf[512]; + int fd; + int error; + unsigned int i; + int chowner = 1; + for (i =0; testopts && i < strlen(testopts); i++) { + switch(testopts[i]) { + case 'C': + chowner = 0; + break; + default: + errx(1, "test4: unknown option %c", testopts[i]); + } + } + if (chowner) + rump_sys_chown(".", TEST_NONROOT_ID, TEST_NONROOT_ID); + rump_sys_chmod(".", 0777); + if (rump_sys_setegid(TEST_NONROOT_ID) != 0) { + error = errno; + warn("rump_sys_setegid"); + return error; + } + if (rump_sys_seteuid(TEST_NONROOT_ID) != 0) { + error = errno; + warn("rump_sys_seteuid"); + return error; + } + fd = rump_sys_open("test_fillup", O_CREAT | O_RDWR, 0644); + if (fd < 0) { + error = errno; + warn("rump_sys_open"); + } else { + while (rump_sys_write(fd, buf, sizeof(buf)) == sizeof(buf)) + error = 0; + error = errno; + } + rump_sys_close(fd); + rump_sys_seteuid(0); + rump_sys_setegid(0); + return error; +} + +static int +quota_test1(const char *testopts) +{ + static char buf[512]; + int fd; + int error; + rump_sys_chown(".", TEST_NONROOT_ID, TEST_NONROOT_ID); + rump_sys_chmod(".", 0777); + if (rump_sys_setegid(TEST_NONROOT_ID) != 0) { + error = errno; + warn("rump_sys_setegid"); + return error; + } + if (rump_sys_seteuid(TEST_NONROOT_ID) != 0) { + error = errno; + warn("rump_sys_seteuid"); + return error; + } + fd = rump_sys_open("test_fillup", O_CREAT | O_RDWR, 0644); + if (fd < 0) { + error = errno; + warn("rump_sys_open"); + } else { + /* + * write up to the soft limit, wait a bit, an try to + * keep on writing + */ + int i; + + /* write 2k: with the directory this makes 2.5K */ + for (i = 0; i < 4; i++) { + error = rump_sys_write(fd, buf, sizeof(buf)); + if (error != sizeof(buf)) + err(1, "write failed early"); + } + sleep(2); + /* now try to write an extra .5k */ + if (rump_sys_write(fd, buf, sizeof(buf)) != sizeof(buf)) + error = errno; + else + error = 0; + } + rump_sys_close(fd); + rump_sys_seteuid(0); + rump_sys_setegid(0); + return error; +} + +static int +quota_test2(const char *testopts) +{ + static char buf[512]; + int fd; + int error; + int i; + rump_sys_chown(".", TEST_NONROOT_ID, TEST_NONROOT_ID); + rump_sys_chmod(".", 0777); + if (rump_sys_setegid(TEST_NONROOT_ID) != 0) { + error = errno; + warn("rump_sys_setegid"); + return error; + } + if (rump_sys_seteuid(TEST_NONROOT_ID) != 0) { + error = errno; + warn("rump_sys_seteuid"); + return error; + } + + for (i = 0; ; i++) { + sprintf(buf, "file%d", i); + fd = rump_sys_open(buf, O_CREAT | O_RDWR, 0644); + if (fd < 0) + break; + sprintf(buf, "test file no %d", i); + rump_sys_write(fd, buf, strlen(buf)); + rump_sys_close(fd); + } + error = errno; + + rump_sys_close(fd); + rump_sys_seteuid(0); + rump_sys_setegid(0); + return error; +} + +static int +quota_test3(const char *testopts) +{ + static char buf[512]; + int fd; + int error; + int i; + rump_sys_chown(".", TEST_NONROOT_ID, TEST_NONROOT_ID); + rump_sys_chmod(".", 0777); + if (rump_sys_setegid(TEST_NONROOT_ID) != 0) { + error = errno; + warn("rump_sys_setegid"); + return error; + } + if (rump_sys_seteuid(TEST_NONROOT_ID) != 0) { + error = errno; + warn("rump_sys_seteuid"); + return error; + } + + /* + * create files one past the soft limit: one less as we already own the + * root directory + */ + for (i = 0; i < 4; i++) { + sprintf(buf, "file%d", i); + fd = rump_sys_open(buf, O_EXCL| O_CREAT | O_RDWR, 0644); + if (fd < 0) + err(1, "file create failed early"); + sprintf(buf, "test file no %d", i); + rump_sys_write(fd, buf, strlen(buf)); + rump_sys_close(fd); + } + /* now create an extra file after grace time: this should fail */ + sleep(2); + sprintf(buf, "file%d", i); + fd = rump_sys_open(buf, O_EXCL| O_CREAT | O_RDWR, 0644); + if (fd < 0) + error = errno; + else + error = 0; + + rump_sys_close(fd); + rump_sys_seteuid(0); + rump_sys_setegid(0); + return error; +} + +static int +quota_test4(const char *testopts) +{ + static char buf[512]; + int fd, fssfd; + struct fss_set fss; + unsigned int i; + int unl=0; + int unconf=0; + + /* + * take an internal snapshot of the filesystem, and create a new + * file with some data + */ + rump_sys_chown(".", 0, 0); + rump_sys_chmod(".", 0777); + + for (i =0; testopts && i < strlen(testopts); i++) { + switch(testopts[i]) { + case 'L': + unl++; + break; + case 'C': + unconf++; + break; + default: + errx(1, "test4: unknown option %c", testopts[i]); + } + } + + /* first create the snapshot */ + + fd = rump_sys_open(FSTEST_MNTNAME "/le_snap", O_CREAT | O_RDWR, 0777); + if (fd == -1) + err(1, "create " FSTEST_MNTNAME "/le_snap"); + rump_sys_close(fd); + fssfd = rump_sys_open("/dev/rfss0", O_RDWR); + if (fssfd == -1) + err(1, "cannot open fss"); + memset(&fss, 0, sizeof(fss)); + fss.fss_mount = __UNCONST("/mnt"); + fss.fss_bstore = __UNCONST(FSTEST_MNTNAME "/le_snap"); + fss.fss_csize = 0; + if (rump_sys_ioctl(fssfd, FSSIOCSET, &fss) == -1) + err(1, "create snapshot"); + if (unl) { + if (rump_sys_unlink(FSTEST_MNTNAME "/le_snap") == -1) + err(1, "unlink snapshot"); + } + + /* now create some extra files */ + + for (i = 0; i < 4; i++) { + sprintf(buf, "file%d", i); + fd = rump_sys_open(buf, O_EXCL| O_CREAT | O_RDWR, 0644); + if (fd < 0) + err(1, "create %s", buf); + sprintf(buf, "test file no %d", i); + rump_sys_write(fd, buf, strlen(buf)); + rump_sys_close(fd); + } + if (unconf) + if (rump_sys_ioctl(fssfd, FSSIOCCLR, NULL) == -1) + err(1, "unconfigure snapshot"); + return 0; +} + +static int +quota_test5(const char *testopts) +{ + static char buf[512]; + int fd; + int remount = 0; + int unlnk = 0; + int log = 0; + unsigned int i; + + for (i =0; testopts && i < strlen(testopts); i++) { + switch(testopts[i]) { + case 'L': + log++; + break; + case 'R': + remount++; + break; + case 'U': + unlnk++; + break; + default: + errx(1, "test4: unknown option %c", testopts[i]); + } + } + if (remount) { + struct ufs_args uargs; + uargs.fspec = __UNCONST("/diskdev"); + /* remount the fs read/write */ + if (rump_sys_mount(MOUNT_FFS, FSTEST_MNTNAME, + MNT_UPDATE | (log ? MNT_LOG : 0), + &uargs, sizeof(uargs)) == -1) + err(1, "mount ffs rw %s", FSTEST_MNTNAME); + } + + if (unlnk) { + /* + * open and unlink a file + */ + + fd = rump_sys_open("unlinked_file", + O_EXCL| O_CREAT | O_RDWR, 0644); + if (fd < 0) + err(1, "create %s", "unlinked_file"); + sprintf(buf, "test unlinked_file"); + rump_sys_write(fd, buf, strlen(buf)); + if (rump_sys_unlink("unlinked_file") == -1) + err(1, "unlink unlinked_file"); + if (rump_sys_fsync(fd) == -1) + err(1, "fsync unlinked_file"); + rump_sys_reboot(RUMP_RB_NOSYNC, NULL); + errx(1, "reboot failed"); + return 1; + } + return 0; +} + +struct quota_test { + int (*func)(const char *); + const char *desc; +}; + +struct quota_test quota_tests[] = { + { quota_test0, "write up to hard limit"}, + { quota_test1, "write beyond the soft limit after grace time"}, + { quota_test2, "create file up to hard limit"}, + { quota_test3, "create file beyond the soft limit after grace time"}, + { quota_test4, "take a snapshot and add some data"}, + { quota_test5, "open and unlink a file"}, +}; + +static void +usage(void) +{ + unsigned int test; + fprintf(stderr, "usage: %s [-b] [-l] test# diskimage bindurl\n", + getprogname()); + fprintf(stderr, "available tests:\n"); + for (test = 0; test < sizeof(quota_tests) / sizeof(quota_tests[0]); + test++) + fprintf(stderr, "\t%d: %s\n", test, quota_tests[test].desc); + exit(1); +} + +static void +die(const char *reason, int error) +{ + + warnx("%s: %s", reason, strerror(error)); + if (background) + rump_daemonize_done(error); + exit(1); +} + +static sem_t sigsem; +static void +sigreboot(int sig) +{ + + sem_post(&sigsem); +} + +int +main(int argc, char **argv) +{ + int error; + u_long test; + char *end; + struct ufs_args uargs; + const char *filename; + const char *serverurl; + const char *topts = NULL; + int mntopts = 0; + int ch; + + while ((ch = getopt(argc, argv, "blo:r")) != -1) { + switch(ch) { + case 'b': + background = 1; + break; + case 'l': + mntopts |= MNT_LOG; + break; + case 'r': + mntopts |= MNT_RDONLY; + break; + case 'o': + topts = optarg; + break; + default: + usage(); + } + } + argc -= optind; + argv += optind; + + if (argc != 3) + usage(); + + filename = argv[1]; + serverurl = argv[2]; + + test = strtoul(argv[0], &end, 10); + if (*end != '\0') { + usage(); + } + if (test > sizeof(quota_tests) / sizeof(quota_tests[0])) { + usage(); + } + + if (background) { + error = rump_daemonize_begin(); + if (error) + errx(1, "rump daemonize: %s", strerror(error)); + } + + error = rump_init(); + if (error) + die("rump init failed", error); + + if (rump_sys_mkdir(FSTEST_MNTNAME, 0777) == -1) + err(1, "mount point create"); + rump_pub_etfs_register("/diskdev", filename, RUMP_ETFS_BLK); + uargs.fspec = __UNCONST("/diskdev"); + if (rump_sys_mount(MOUNT_FFS, FSTEST_MNTNAME, mntopts, + &uargs, sizeof(uargs)) == -1) + die("mount ffs", errno); + + if (rump_sys_chdir(FSTEST_MNTNAME) == -1) + err(1, "cd %s", FSTEST_MNTNAME); + error = quota_tests[test].func(topts); + if (error) { + fprintf(stderr, " test %lu: %s returned %d: %s\n", + test, quota_tests[test].desc, error, strerror(error)); + } + if (rump_sys_chdir("/") == -1) + err(1, "cd /"); + + error = rump_init_server(serverurl); + if (error) + die("rump server init failed", error); + if (background) + rump_daemonize_done(RUMP_DAEMONIZE_SUCCESS); + + sem_init(&sigsem, 0, 0); + signal(SIGTERM, sigreboot); + signal(SIGINT, sigreboot); + sem_wait(&sigsem); + + rump_sys_reboot(0, NULL); + /*NOTREACHED*/ + return 0; +} diff --git a/contrib/netbsd-tests/fs/ffs/quotas_common.sh b/contrib/netbsd-tests/fs/ffs/quotas_common.sh new file mode 100755 index 000000000000..0ad002f54ad5 --- /dev/null +++ b/contrib/netbsd-tests/fs/ffs/quotas_common.sh @@ -0,0 +1,12 @@ +# $NetBSD: quotas_common.sh,v 1.4 2012/01/18 20:51:23 bouyer Exp $ + +rump_quota_shutdown() +{ + for s in ${RUMP_SOCKETS_LIST}; do + atf_check -s exit:0 env RUMP_SERVER=unix://${s} rump.halt; + done +# check that the quota inode creation didn't corrupt the filesystem + atf_check -s exit:0 -o "match:already clean" \ + -o "match:Phase 6 - Check Quotas" \ + fsck_ffs -nf -F ${IMG} +} diff --git a/contrib/netbsd-tests/fs/ffs/t_clearquota.sh b/contrib/netbsd-tests/fs/ffs/t_clearquota.sh new file mode 100755 index 000000000000..f62a494730cd --- /dev/null +++ b/contrib/netbsd-tests/fs/ffs/t_clearquota.sh @@ -0,0 +1,91 @@ +# $NetBSD: t_clearquota.sh,v 1.4 2012/01/18 20:51:23 bouyer Exp $ +# +# Copyright (c) 2011 Manuel Bouyer +# All rights reserved. +# +# 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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. +# + +for e in le be; do + for v in 1 2; do + for q in "user" "group"; do + test_case_root clear_${e}_${v}_${q} clear_quota \ + "clear quota with ${q} enabled" -b ${e} ${v} ${q} + done + test_case_root clear_${e}_${v}_"both" clear_quota \ + "clear quota with both enabled" -b ${e} ${v} "both" + test_case_root clear_${e}_${v}_"both_log" clear_quota \ + "clear quota for new id with both enabled, WAPBL" -bl ${e} ${v} "both" + done +done + +clear_quota() +{ + create_ffs_server $* + local q=$4 + local expect + local fail + local id=1 + + case ${q} in + user) + expect=u + fail=g + ;; + group) + expect=g + fail=u + ;; + both) + expect="u g" + fail="" + ;; + *) + atf_fail "wrong quota type" + ;; + esac + +#set and check the expected quota + for q in ${expect} ; do + atf_check -s exit:0 \ + env LD_PRELOAD=/usr/lib/librumphijack.so RUMPHIJACK=vfs=getvfsstat,blanket=/mnt edquota -$q -s10k/20 -h40M/50k \ + -t 2W/3D ${id} + atf_check -s exit:0 \ +-o "match:/mnt 0 10 40960 2weeks 0 20 51200 3days" \ +-o "match:Disk quotas for .*: $" \ + env LD_PRELOAD=/usr/lib/librumphijack.so RUMPHIJACK=vfs=getvfsstat,blanket=/mnt quota -${q} -v ${id} + done +#now clear the quotas + for q in ${expect} ; do + atf_check -s exit:0 \ + env LD_PRELOAD=/usr/lib/librumphijack.so RUMPHIJACK=vfs=getvfsstat,blanket=/mnt edquota -$q -c ${id} + done; + +#check that we do not get positive reply for any quota type + for q in u g ; do + atf_check -s exit:0 -o "not-match:/mnt" \ + -o "not-match:Disk quotas for .*: $" \ + -o "match:Disk quotas for .*: none$" \ + env LD_PRELOAD=/usr/lib/librumphijack.so RUMPHIJACK=vfs=getvfsstat,blanket=/mnt quota -${q} -v ${id} + done + rump_quota_shutdown +} diff --git a/contrib/netbsd-tests/fs/ffs/t_fifos.c b/contrib/netbsd-tests/fs/ffs/t_fifos.c new file mode 100644 index 000000000000..10b50bbd792d --- /dev/null +++ b/contrib/netbsd-tests/fs/ffs/t_fifos.c @@ -0,0 +1,158 @@ +/* $NetBSD: t_fifos.c,v 1.6 2017/01/13 21:30:39 christos Exp $ */ + +#include <sys/types.h> +#include <sys/mount.h> + +#include <atf-c.h> +#include <errno.h> +#include <fcntl.h> +#include <pthread.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> + +#include <rump/rump.h> +#include <rump/rump_syscalls.h> + +#include <ufs/ufs/ufsmount.h> + +#include "h_macros.h" + +ATF_TC_WITH_CLEANUP(fifos); +ATF_TC_HEAD(fifos, tc) +{ + atf_tc_set_md_var(tc, "descr", "test fifo support in ffs"); + atf_tc_set_md_var(tc, "timeout", "5"); +} + +#define teststr1 "raving & drooling" +#define teststr2 "haha, charade" + +static void * +w1(void *arg) +{ + int fd; + + fd = rump_sys_open("sheep", O_WRONLY); + if (fd == -1) + atf_tc_fail_errno("w1 open"); + if (rump_sys_write(fd, teststr1, sizeof(teststr1)) != sizeof(teststr1)) + atf_tc_fail_errno("w1 write"); + rump_sys_close(fd); + + return NULL; +} + +static void * +w2(void *arg) +{ + int fd; + + fd = rump_sys_open("pigs", O_WRONLY); + if (fd == -1) + atf_tc_fail_errno("w2 open"); + if (rump_sys_write(fd, teststr2, sizeof(teststr2)) != sizeof(teststr2)) + atf_tc_fail_errno("w2 write"); + rump_sys_close(fd); + + return NULL; +} + +static void * +r1(void *arg) +{ + char buf[32]; + int fd; + + fd = rump_sys_open("sheep", O_RDONLY); + if (fd == -1) + atf_tc_fail_errno("r1 open"); + if (rump_sys_read(fd, buf, sizeof(buf)) != sizeof(teststr1)) + atf_tc_fail_errno("r1 read"); + rump_sys_close(fd); + + if (strcmp(teststr1, buf) != 0) + atf_tc_fail("got invalid str, %s vs. %s", buf, teststr1); + + return NULL; +} + +static void * +r2(void *arg) +{ + char buf[32]; + int fd; + + fd = rump_sys_open("pigs", O_RDONLY); + if (fd == -1) + atf_tc_fail_errno("r2 open"); + if (rump_sys_read(fd, buf, sizeof(buf)) != sizeof(teststr2)) + atf_tc_fail_errno("r2 read"); + rump_sys_close(fd); + + if (strcmp(teststr2, buf) != 0) + atf_tc_fail("got invalid str, %s vs. %s", buf, teststr2); + + return NULL; +} + +#define IMGNAME "atf.img" + +const char *newfs = "newfs -F -s 10000 " IMGNAME; +#define FAKEBLK "/dev/sp00ka" + +ATF_TC_BODY(fifos, tc) +{ + struct ufs_args args; + pthread_t ptw1, ptw2, ptr1, ptr2; + + if (system(newfs) == -1) + atf_tc_fail_errno("newfs failed"); + + memset(&args, 0, sizeof(args)); + args.fspec = __UNCONST(FAKEBLK); + + rump_init(); + if (rump_sys_mkdir("/animals", 0777) == -1) + atf_tc_fail_errno("cannot create mountpoint"); + rump_pub_etfs_register(FAKEBLK, IMGNAME, RUMP_ETFS_BLK); + if (rump_sys_mount(MOUNT_FFS, "/animals", 0, &args, sizeof(args))==-1) + atf_tc_fail_errno("rump_sys_mount failed"); + + /* create fifos */ + if (rump_sys_chdir("/animals") == 1) + atf_tc_fail_errno("chdir"); + if (rump_sys_mkfifo("pigs", S_IFIFO | 0777) == -1) + atf_tc_fail_errno("mknod1"); + if (rump_sys_mkfifo("sheep", S_IFIFO | 0777) == -1) + atf_tc_fail_errno("mknod2"); + + pthread_create(&ptw1, NULL, w1, NULL); + pthread_create(&ptw2, NULL, w2, NULL); + pthread_create(&ptr1, NULL, r1, NULL); + pthread_create(&ptr2, NULL, r2, NULL); + + pthread_join(ptw1, NULL); + pthread_join(ptw2, NULL); + pthread_join(ptr1, NULL); + pthread_join(ptr2, NULL); + + if (rump_sys_chdir("/") == 1) + atf_tc_fail_errno("chdir"); + + if (rump_sys_unmount("/animals", 0) == -1) + atf_tc_fail_errno("unmount failed"); +} + +ATF_TC_CLEANUP(fifos, tc) +{ + + unlink(IMGNAME); +} + +ATF_TP_ADD_TCS(tp) +{ + ATF_TP_ADD_TC(tp, fifos); + return 0; +} diff --git a/contrib/netbsd-tests/fs/ffs/t_getquota.sh b/contrib/netbsd-tests/fs/ffs/t_getquota.sh new file mode 100755 index 000000000000..80f3cc7a6e76 --- /dev/null +++ b/contrib/netbsd-tests/fs/ffs/t_getquota.sh @@ -0,0 +1,112 @@ +# $NetBSD: t_getquota.sh,v 1.4 2012/01/18 20:51:23 bouyer Exp $ +# +# Copyright (c) 2011 Manuel Bouyer +# All rights reserved. +# +# 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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. +# + +for e in le be; do + for v in 1 2; do + for q in "user" "group"; do + test_case get_${e}_${v}_${q} get_quota \ + "get quota with ${q} enabled" -b ${e} ${v} ${q} + done + test_case get_${e}_${v}_"both" get_quota \ + "get quota with both enabled" -b ${e} ${v} "both" + done +done + +get_quota() +{ + create_ffs_server $* + local q=$4 + local expect + local fail + + case ${q} in + user) + expect=u + fail=g + ;; + group) + expect=g + fail=u + ;; + both) + expect="u g" + fail="" + ;; + *) + atf_fail "wrong quota type" + ;; + esac + +#check that we can get the expected quota + for q in ${expect} ; do + atf_check -s exit:0 \ +-o "match:/mnt 0 - - 7days 1 - - 7days" \ +-o "match:Disk quotas for .*: $" \ + env LD_PRELOAD=/usr/lib/librumphijack.so RUMPHIJACK=vfs=getvfsstat,blanket=/mnt quota -${q} -v + atf_check -s exit:0 \ +-o "match:-- 0 - - 1 - -" \ +-o "not-match:\+\+" \ + env LD_PRELOAD=/usr/lib/librumphijack.so RUMPHIJACK=vfs=getvfsstat,blanket=/mnt repquota -${q} /mnt + done + +#check that we do not get positive reply for non-expected quota + for q in ${fail} ; do + atf_check -s exit:0 -o "not-match:/mnt" \ + -o "not-match:Disk quotas for .*: $" \ + -o "match:Disk quotas for .*: none$" \ + env LD_PRELOAD=/usr/lib/librumphijack.so RUMPHIJACK=vfs=getvfsstat,blanket=/mnt quota -${q} -v + atf_check -s exit:0 \ +-o "not-match:-- 0 - - 1 - -" \ + env LD_PRELOAD=/usr/lib/librumphijack.so RUMPHIJACK=vfs=getvfsstat,blanket=/mnt repquota -${q} /mnt + done + rump_quota_shutdown +} + +quota_walk_list() +{ + create_ffs_server $* + local q=$4 + local expect + + case ${q} in + user) + expect=u + fail=g + ;; + group) + expect=g + fail=u + ;; + both) + expect="u g" + fail="" + ;; + *) + atf_fail "wrong quota type" + ;; + esac +} diff --git a/contrib/netbsd-tests/fs/ffs/t_miscquota.sh b/contrib/netbsd-tests/fs/ffs/t_miscquota.sh new file mode 100755 index 000000000000..904ea37f8f6c --- /dev/null +++ b/contrib/netbsd-tests/fs/ffs/t_miscquota.sh @@ -0,0 +1,213 @@ +# $NetBSD: t_miscquota.sh,v 1.8 2013/01/22 06:24:11 dholland Exp $ +# +# Copyright (c) 2011 Manuel Bouyer +# All rights reserved. +# +# 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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. +# + +test_case_root walk_list_user quota_walk_list \ + "walk user quota list over several disk blocks" -b le 1 user + +test_case_root psnapshot_user quota_snap \ + "create a persistent shapshot of quota-enabled fs, and do some writes" \ + -b le 1 user + +test_case_root npsnapshot_user quota_snap \ + "create a non-persistent shapshot of quota-enabled fs, and do some writes" \ + -boL le 1 user + +test_case_root psnapshot_unconf_user quota_snap \ + "create a persistent shapshot of quota-enabled fs, and do some writes and unconf" \ + -boC le 1 user + +test_case_root npsnapshot_unconf_user quota_snap \ + "create a non-persistent shapshot of quota-enabled fs, and do some writes and unconf" \ + -boLC le 1 user + +test_case log_unlink quota_log \ + "an unlinked file cleaned by the log replay should update quota" \ + -l le 1 user + +test_case log_unlink_remount quota_log \ + "an unlinked file cleaned by the log replay after remount" \ + -oRL le 1 user + + +test_case_root default_deny_user quota_default_deny \ + "new quota entry denied by default entry" 5 -b le 1 user + +test_case_root default_deny_user_big quota_default_deny \ + "new quota entry denied by default entry, with list on more than one block" 5000 -b le 1 user + + +quota_walk_list() +{ + create_ffs_server $* + local q=$4 + local expect + + case ${q} in + user) + expect=u + fail=g + ;; + group) + expect=g + fail=u + ;; + *) + atf_fail "wrong quota type" + ;; + esac + + # create 100 users, all in the same hash list + local i=1; + while [ $i -lt 101 ]; do + atf_check -s exit:0 \ + env LD_PRELOAD=/usr/lib/librumphijack.so RUMPHIJACK=vfs=getvfsstat,blanket=/mnt edquota -${expect} \ + -s10k/20 -h40M/50k -t 2W/3D $((i * 4096)) + i=$((i + 1)) + done + # do a repquota + atf_check -s exit:0 -o 'match:user 409600 block *81920 20 0' \ + env LD_PRELOAD=/usr/lib/librumphijack.so RUMPHIJACK=vfs=getvfsstat,blanket=/mnt repquota -x -${expect} /mnt + rump_quota_shutdown +} + +quota_snap() +{ + local flag=$1; shift + create_ffs $* + local q=$3 + local expect + + case ${q} in + user) + expect=u + fail=g + ;; + group) + expect=g + fail=u + ;; + *) + atf_fail "wrong quota type" + ;; + esac + + #start our server which takes a snapshot + atf_check -s exit:0 -o ignore \ + $(atf_get_srcdir)/h_quota2_tests ${flag} 4 ${IMG} ${RUMP_SERVER} + # create a few users + local i=1; + while [ $i -lt 11 ]; do + atf_check -s exit:0 \ + env LD_PRELOAD=/usr/lib/librumphijack.so RUMPHIJACK=vfs=getvfsstat,blanket=/mnt edquota -${expect} \ + -s10k/20 -h40M/50k -t 2W/3D $i + i=$((i + 1)) + done + # we should have 5 files (root + 4 regular files) + atf_check -s exit:0 \ + -o 'match:- - 7days 5 - - 7days' \ + env LD_PRELOAD=/usr/lib/librumphijack.so RUMPHIJACK=vfs=getvfsstat,blanket=/mnt repquota -av + #shutdown and check filesystem + rump_quota_shutdown +} + +quota_log() +{ + local srv2args=$1; shift + create_ffs $* + local q=$3 + local expect + + case ${q} in + user) + expect=u + fail=g + ;; + group) + expect=g + fail=u + ;; + *) + atf_fail "wrong quota type" + ;; + esac + + #start our server which create a file and unlink while keeping + # it open. The server halts itself without flush + atf_check -s exit:0 -o ignore \ + $(atf_get_srcdir)/h_quota2_tests -loU 5 ${IMG} ${RUMP_SERVER} + # we should have one unlinked file, but the log covers it. + atf_check -s exit:0 -o match:'3 files' -e ignore \ + fsck_ffs -nf -F ${IMG} + # have a kernel mount the fs again; it should cleanup the + # unlinked file + atf_check -o ignore -e ignore $(atf_get_srcdir)/h_quota2_tests \ + ${srv2args} -b 5 ${IMG} ${RUMP_SERVER} + #shutdown and check filesystem + rump_quota_shutdown +} + +quota_default_deny() +{ + local nusers=$1; shift + create_ffs_server $* + local q=$4 + local expect + + case ${q} in + user) + expect=u + fail=g + ;; + group) + expect=g + fail=u + ;; + *) + atf_fail "wrong quota type" + ;; + esac + + # create $nusers users, so we are sure the free list has entries + # from block 1. Start from 10, as non-root id is 1. + # set default to deny all + ( echo "@format netbsd-quota-dump v1" + echo "# idtype id objtype hard soft usage expire grace" + echo "$q default block 0 0 0 0 0" + echo "$q default file 0 0 0 0 0" + local i=10; + while [ $i -lt $(($nusers + 10)) ]; do + echo "$q $i block 0 0 0 0 0" + echo "$q $i file 0 0 0 0 0" + i=$((i + 1)) + done + ) | atf_check -s exit:0 \ + env LD_PRELOAD=/usr/lib/librumphijack.so RUMPHIJACK=vfs=getvfsstat,blanket=/mnt quotarestore -d /mnt + atf_check -s exit:0 rump.halt + #now start the server which does the limits tests + $(atf_get_srcdir)/h_quota2_tests -oC -b 0 ${IMG} ${RUMP_SERVER} + rump_quota_shutdown +} diff --git a/contrib/netbsd-tests/fs/ffs/t_mount.c b/contrib/netbsd-tests/fs/ffs/t_mount.c new file mode 100644 index 000000000000..20960953406b --- /dev/null +++ b/contrib/netbsd-tests/fs/ffs/t_mount.c @@ -0,0 +1,138 @@ +/* $NetBSD: t_mount.c,v 1.14 2017/01/13 21:30:39 christos Exp $ */ + +/* + * Basic tests for mounting + */ + +/* + * 48Kimage: + * Adapted for rump and atf from a testcase supplied + * by Hubert Feyrer on netbsd-users@ + */ + +#include <atf-c.h> + +#define FSTEST_IMGSIZE (96 * 512) +#include "../common/h_fsmacros.h" + +#include <sys/types.h> +#include <sys/mount.h> + +#include <stdlib.h> + +#include <ufs/ufs/ufsmount.h> + +#include <rump/rump.h> +#include <rump/rump_syscalls.h> + +#include "h_macros.h" + +ATF_TC(48Kimage); +ATF_TC_HEAD(48Kimage, tc) +{ + atf_tc_set_md_var(tc, "descr", "mount small 48K ffs image"); +} + +ATF_TC_BODY(48Kimage, tc) +{ + void *tmp; + + atf_tc_expect_fail("PR kern/43573"); + FSTEST_CONSTRUCTOR(tc, ffs, tmp); + atf_tc_expect_pass(); + + FSTEST_DESTRUCTOR(tc, ffs, tmp); +} + +ATF_TC(fsbsizeovermaxphys); +ATF_TC_HEAD(fsbsizeovermaxphys, tc) +{ + + atf_tc_set_md_var(tc, "descr", "mounts file system with " + "blocksize > MAXPHYS"); + /* PR kern/43727 */ +} + +ATF_TC_BODY(fsbsizeovermaxphys, tc) +{ + char cmd[1024]; + struct ufs_args args; + struct statvfs svb; + + /* + * We cannot pass newfs parameters via the fstest interface, + * so do things the oldfashioned manual way. + */ + snprintf(cmd, sizeof(cmd), "newfs -G -b %d -F -s 10000 " + "ffs.img > /dev/null", MAXPHYS * 2); + if (system(cmd)) + atf_tc_fail("cannot create file system"); + + rump_init(); + if (rump_pub_etfs_register("/devdisk", "ffs.img", RUMP_ETFS_BLK)) + atf_tc_fail("cannot register rump fake device"); + + args.fspec = __UNCONST("/devdisk"); + + if (rump_sys_mkdir("/mp", 0777) == -1) + atf_tc_fail_errno("create mountpoint"); + + /* mount succeeded? bad omen. confirm we're in trouble. */ + if (rump_sys_mount(MOUNT_FFS, "/mp", 0, &args, sizeof(args)) != -1) { + rump_sys_statvfs1("/mp", &svb, ST_WAIT); + atf_tc_fail("not expecting to be alive"); + } + + /* otherwise we're do-ne */ +} + +ATF_TC(fsbsizeovermaxbsize); +ATF_TC_HEAD(fsbsizeovermaxbsize, tc) +{ + + atf_tc_set_md_var(tc, "descr", "mounts file system with " + "blocksize > MAXBSIZE"); +} + +ATF_TC_BODY(fsbsizeovermaxbsize, tc) +{ + char cmd[1024]; + struct ufs_args args; + struct statvfs svb; + + /* + * We cannot pass newfs parameters via the fstest interface, + * so do things the oldfashioned manual way. + */ + snprintf(cmd, sizeof(cmd), "newfs -G -b %d -F -s 10000 " + "ffs.img > /dev/null", MAXBSIZE * 2); + if (system(cmd)) + atf_tc_fail("cannot create file system"); + + rump_init(); + if (rump_pub_etfs_register("/devdisk", "ffs.img", RUMP_ETFS_BLK)) + atf_tc_fail("cannot register rump fake device"); + + args.fspec = __UNCONST("/devdisk"); + + if (rump_sys_mkdir("/mp", 0777) == -1) + atf_tc_fail_errno("create mountpoint"); + + /* mount succeeded? bad omen. confirm we're in trouble. */ + if (rump_sys_mount(MOUNT_FFS, "/mp", 0, &args, sizeof(args)) != -1) { + rump_sys_statvfs1("/mp", &svb, ST_WAIT); + atf_tc_fail("not expecting to be alive"); + } + + /* otherwise we're do-ne */ +} + +ATF_TP_ADD_TCS(tp) +{ + + ATF_TP_ADD_TC(tp, 48Kimage); + ATF_TP_ADD_TC(tp, fsbsizeovermaxphys); + ATF_TP_ADD_TC(tp, fsbsizeovermaxbsize); + + return atf_no_error(); +} diff --git a/contrib/netbsd-tests/fs/ffs/t_quota2_1.c b/contrib/netbsd-tests/fs/ffs/t_quota2_1.c new file mode 100644 index 000000000000..22cd5d24512a --- /dev/null +++ b/contrib/netbsd-tests/fs/ffs/t_quota2_1.c @@ -0,0 +1,114 @@ +/* $NetBSD: t_quota2_1.c,v 1.5 2017/01/13 21:30:39 christos Exp $ */ + +/* + * Basic tests for quota2 + */ + +#include <atf-c.h> + +#include "../common/h_fsmacros.h" + +#include <sys/types.h> +#include <sys/mount.h> + +#include <stdlib.h> + +#include <ufs/ufs/ufsmount.h> + +#include <rump/rump.h> +#include <rump/rump_syscalls.h> + +#include "h_macros.h" + +static void +do_quota(const atf_tc_t *tc, int n, const char *newfs_opts, int log) +{ + int i; + char buf[1024]; + int res; + int fd; + struct ufs_args uargs; + + snprintf(buf, sizeof(buf), "newfs -q user -q group -F -s 4000 -n %d " + "%s %s", (n + 3), newfs_opts, FSTEST_IMGNAME); + if (system(buf) == -1) + atf_tc_fail_errno("cannot create file system"); + + rump_init(); + if (rump_sys_mkdir(FSTEST_MNTNAME, 0777) == -1) + atf_tc_fail_errno("mount point create"); + + rump_pub_etfs_register("/diskdev", FSTEST_IMGNAME, RUMP_ETFS_BLK); + + uargs.fspec = __UNCONST("/diskdev"); + if (rump_sys_mount(MOUNT_FFS, FSTEST_MNTNAME, (log) ? MNT_LOG : 0, + &uargs, sizeof(uargs)) == -1) + atf_tc_fail_errno("mount ffs %s", FSTEST_MNTNAME); + + atf_tc_expect_pass(); + FSTEST_ENTER(); + RL(rump_sys_chown(".", 0, 0)); + for (i = 0 ; i < n; i++) { + sprintf(buf, "file%d", i); + RL(fd = rump_sys_open(buf, O_CREAT | O_RDWR, 0755)); + sprintf(buf, "test file no %d", i); + RL(rump_sys_write(fd, buf, strlen(buf))); + RL(rump_sys_fchown(fd, i, i+80000)); + rump_sys_close(fd); + } + FSTEST_EXIT(); + if (rump_sys_unmount(FSTEST_MNTNAME, 0) != 0) { + rump_pub_vfs_mount_print(FSTEST_MNTNAME, 1); + atf_tc_fail_errno("unmount failed"); + } + snprintf(buf, 1024, "fsck_ffs -fn -F %s", FSTEST_IMGNAME); + res = system(buf); + if (res != 0) + atf_tc_fail("fsck returned %d", res); +} + +#define DECL_TEST(nent, newops, name, descr, log) \ +ATF_TC(quota_##name); \ + \ +ATF_TC_HEAD(quota_##name, tc) \ +{ \ + atf_tc_set_md_var(tc, "descr", \ + "test quotas with %d users and groups, %s", \ + nent, descr); \ +} \ + \ +ATF_TC_BODY(quota_##name, tc) \ +{ \ + do_quota(tc, nent, newops, log); \ +} + +DECL_TEST(40, "-O1 -B le", 40_O1_le, "UFS1 little-endian", 0) +DECL_TEST(40, "-O1 -B be", 40_O1_be, "UFS1 big-endian", 0) + +DECL_TEST(40, "-O2 -B le", 40_O2_le, "UFS2 little-endian", 0) +DECL_TEST(40, "-O2 -B be", 40_O2_be, "UFS2 big-endian", 0) + +DECL_TEST(40, "-O1", 40_O1_log, "UFS1 log", 1) +DECL_TEST(40, "-O2", 40_O2_log, "UFS2 log", 1) + +DECL_TEST(1000, "-O1 -B le", 1000_O1_le, "UFS1 little-endian", 0) +DECL_TEST(1000, "-O1 -B be", 1000_O1_be, "UFS1 big-endian", 0) + +DECL_TEST(1000, "-O2 -B le", 1000_O2_le, "UFS2 little-endian", 0) +DECL_TEST(1000, "-O2 -B be", 1000_O2_be, "UFS2 big-endian", 0) + +ATF_TP_ADD_TCS(tp) +{ + + ATF_TP_ADD_TC(tp, quota_40_O1_le); + ATF_TP_ADD_TC(tp, quota_40_O1_be); + ATF_TP_ADD_TC(tp, quota_40_O2_le); + ATF_TP_ADD_TC(tp, quota_40_O2_be); + ATF_TP_ADD_TC(tp, quota_40_O1_log); + ATF_TP_ADD_TC(tp, quota_40_O2_log); + ATF_TP_ADD_TC(tp, quota_1000_O1_le); + ATF_TP_ADD_TC(tp, quota_1000_O1_be); + ATF_TP_ADD_TC(tp, quota_1000_O2_le); + ATF_TP_ADD_TC(tp, quota_1000_O2_be); + return atf_no_error(); +} diff --git a/contrib/netbsd-tests/fs/ffs/t_quota2_remount.c b/contrib/netbsd-tests/fs/ffs/t_quota2_remount.c new file mode 100644 index 000000000000..d843cf891b4b --- /dev/null +++ b/contrib/netbsd-tests/fs/ffs/t_quota2_remount.c @@ -0,0 +1,139 @@ +/* $NetBSD: t_quota2_remount.c,v 1.5 2017/01/13 21:30:39 christos Exp $ */ + +/* + * Basic tests for quota2 + */ + +#include <atf-c.h> + +#include "../common/h_fsmacros.h" + +#include <sys/types.h> +#include <sys/mount.h> +#include <sys/statvfs.h> + +#include <stdlib.h> + +#include <ufs/ufs/ufsmount.h> + +#include <rump/rump.h> +#include <rump/rump_syscalls.h> + +#include "h_macros.h" + +static void +do_quota(const atf_tc_t *tc, int n, const char *newfs_opts, int log) +{ + int i; + char buf[1024]; + int res; + int fd; + struct ufs_args uargs; + struct statvfs fst; + + snprintf(buf, sizeof(buf), "newfs -q user -q group -F -s 4000 -n %d " + "%s %s", (n + 3), newfs_opts, FSTEST_IMGNAME); + if (system(buf) == -1) + atf_tc_fail_errno("cannot create file system"); + + rump_init(); + if (rump_sys_mkdir(FSTEST_MNTNAME, 0777) == -1) + atf_tc_fail_errno("mount point create"); + + rump_pub_etfs_register("/diskdev", FSTEST_IMGNAME, RUMP_ETFS_BLK); + + uargs.fspec = __UNCONST("/diskdev"); + + /* read-only doens't have quota enabled */ + if (rump_sys_mount(MOUNT_FFS, FSTEST_MNTNAME, MNT_RDONLY, + &uargs, sizeof(uargs)) == -1) + atf_tc_fail_errno("mount ffs ro %s", FSTEST_MNTNAME); + + if (rump_sys_statvfs1(FSTEST_MNTNAME, &fst, 0) != 0) + atf_tc_fail_errno("statbfs %s (1)", FSTEST_MNTNAME); + + if ((fst.f_flag & ST_QUOTA) != 0) + atf_tc_fail("R/O filesystem has quota"); + + /* updating to read-write enables quota */ + if (rump_sys_mount(MOUNT_FFS, FSTEST_MNTNAME, + MNT_UPDATE | (log ? MNT_LOG : 0), &uargs, sizeof(uargs)) == -1) + atf_tc_fail_errno("mount ffs rw %s", FSTEST_MNTNAME); + + if (rump_sys_statvfs1(FSTEST_MNTNAME, &fst, 0) != 0) + atf_tc_fail_errno("statbfs %s (2)", FSTEST_MNTNAME); + + if ((fst.f_flag & ST_QUOTA) == 0) + atf_tc_fail("R/W filesystem has no quota"); + + /* we can update a second time */ + if (rump_sys_mount(MOUNT_FFS, FSTEST_MNTNAME, + MNT_UPDATE | (log ? MNT_LOG : 0), &uargs, sizeof(uargs)) == -1) + atf_tc_fail_errno("mount ffs rw(2) %s", FSTEST_MNTNAME); + + if (rump_sys_statvfs1(FSTEST_MNTNAME, &fst, 0) != 0) + atf_tc_fail_errno("statbfs %s (3)", FSTEST_MNTNAME); + + if ((fst.f_flag & ST_QUOTA) == 0) + atf_tc_fail("R/W filesystem has no quota"); + + /* create some files so fsck has something to check */ + FSTEST_ENTER(); + RL(rump_sys_chown(".", 0, 0)); + for (i = 0 ; i < n; i++) { + sprintf(buf, "file%d", i); + RL(fd = rump_sys_open(buf, O_CREAT | O_RDWR, 0755)); + sprintf(buf, "test file no %d", i); + RL(rump_sys_write(fd, buf, strlen(buf))); + RL(rump_sys_fchown(fd, i, i+80000)); + rump_sys_close(fd); + } + FSTEST_EXIT(); + if (rump_sys_unmount(FSTEST_MNTNAME, 0) != 0) { + rump_pub_vfs_mount_print(FSTEST_MNTNAME, 1); + atf_tc_fail_errno("unmount failed"); + } + snprintf(buf, 1024, "fsck_ffs -fn -F %s", FSTEST_IMGNAME); + res = system(buf); + if (res != 0) + atf_tc_fail("fsck returned %d", res); +} + +#define DECL_TEST(nent, newops, name, descr, log) \ +ATF_TC(quota_##name); \ + \ +ATF_TC_HEAD(quota_##name, tc) \ +{ \ + atf_tc_set_md_var(tc, "descr", \ + "test filesystem remount with quotas, %s", descr); \ +} \ + \ +ATF_TC_BODY(quota_##name, tc) \ +{ \ + do_quota(tc, nent, newops, log); \ +} + +DECL_TEST(10, "-O1 -B le", 10_O1_le, "UFS1 little-endian", 0) +DECL_TEST(10, "-O1 -B be", 10_O1_be, "UFS1 big-endian", 0) + +#if 0 +/* + * this cause fsck to complain about summaries at the end. + * This sems to be related to -o log (reproductible on a fs with no + * quota enabled). not reproductible with a real kernel ... + */ +DECL_TEST(10, "-O1", 10_O1_log, "UFS1 log", 1) +DECL_TEST(10, "-O2", 10_O2_log, "UFS2 log", 1) +#endif + +ATF_TP_ADD_TCS(tp) +{ + + ATF_TP_ADD_TC(tp, quota_10_O1_le); + ATF_TP_ADD_TC(tp, quota_10_O1_be); +#if 0 + ATF_TP_ADD_TC(tp, quota_10_O1_log); + ATF_TP_ADD_TC(tp, quota_10_O2_log); +#endif + return atf_no_error(); +} diff --git a/contrib/netbsd-tests/fs/ffs/t_quotalimit.sh b/contrib/netbsd-tests/fs/ffs/t_quotalimit.sh new file mode 100755 index 000000000000..16e47b7a8fb8 --- /dev/null +++ b/contrib/netbsd-tests/fs/ffs/t_quotalimit.sh @@ -0,0 +1,345 @@ +# $NetBSD: t_quotalimit.sh,v 1.4 2012/01/18 20:51:23 bouyer Exp $ +# +# Copyright (c) 2011 Manuel Bouyer +# All rights reserved. +# +# 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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. +# + +for e in le; do + for v in 1; do + for q in "user" "group"; do + test_case_root limit_${e}_${v}_${q} limit_quota \ + "hit hard limit quota with ${q} enabled" -b ${e} ${v} ${q} + test_case_root limit_${e}_${v}_${q}_log limit_quota \ + "hit hard limit quota with ${q} enabled, WAPBL" -bl ${e} ${v} ${q} + test_case_root slimit_${e}_${v}_${q} limit_softquota \ + "hit soft limit quota with ${q} enabled after grace time" \ + -b ${e} ${v} ${q} + test_case_root inolimit_${e}_${v}_${q} limit_iquota \ + "hit hard limit ino quota with ${q} enabled" -b ${e} ${v} ${q} + test_case_root inolimit_${e}_${v}_${q}_log limit_iquota \ + "hit hard limit ino quota with ${q} enabled, WAPBL" -bl ${e} ${v} ${q} + test_case_root sinolimit_${e}_${v}_${q} limit_softiquota \ + "hit soft limit ino quota with ${q} enabled after grace time" \ + -b ${e} ${v} ${q} + test_case_root herit_defq_${e}_${v}_${q} inherit_defaultquota \ + "new id herit from default for ${q} quota" -b ${e} ${v} ${q} + test_case_root herit_defq_${e}_${v}_${q}_log inherit_defaultquota \ + "new id herit from default for ${q} quota, WAPBL" -bl ${e} ${v} ${q} + test_case_root herit_idefq_${e}_${v}_${q}_log inherit_defaultiquota \ + "new id herit from default for ${q} ino quota, WAPBL" -bl ${e} ${v} ${q} + done + done +done + +limit_quota() +{ + create_ffs_server $* + local q=$4 + local expect + local id=1 + + case ${q} in + user) + expect=u + fail=g + ;; + group) + expect=g + fail=u + ;; + both) + expect="u g" + fail="" + ;; + *) + atf_fail "wrong quota type" + ;; + esac + + for q in ${expect} ; do + atf_check -s exit:0 \ + env LD_PRELOAD=/usr/lib/librumphijack.so RUMPHIJACK=vfs=getvfsstat,blanket=/mnt edquota -$q -s2k/4 -h3k/6 \ + -t 2h/2h ${id} + done + atf_check -s exit:0 rump.halt + + #now start the server which does the limits tests + atf_check -s exit:0 -o ignore \ +-e match:'test 0: write up to hard limit returned 69: Disc quota exceeded' \ + $(atf_get_srcdir)/h_quota2_tests -b 0 ${IMG} ${RUMP_SERVER} + for q in ${expect} ; do + atf_check -s exit:0 \ + -o match:'/mnt 3072 B\* 2048 B 3072 B 2:0 2 4 6 ' \ + env LD_PRELOAD=/usr/lib/librumphijack.so RUMPHIJACK=vfs=getvfsstat,blanket=/mnt quota -$q -h ${id} + atf_check -s exit:0 \ + -o match:'daemon \+- 3 2 3 2:0 2 4 6' \ + env LD_PRELOAD=/usr/lib/librumphijack.so RUMPHIJACK=vfs=getvfsstat,blanket=/mnt repquota -$q /mnt + done + rump_quota_shutdown +} + +limit_softquota() +{ + create_ffs_server $* + local q=$4 + local expect + local id=1 + + case ${q} in + user) + expect=u + fail=g + ;; + group) + expect=g + fail=u + ;; + both) + expect="u g" + fail="" + ;; + *) + atf_fail "wrong quota type" + ;; + esac + + for q in ${expect} ; do + atf_check -s exit:0 \ + env LD_PRELOAD=/usr/lib/librumphijack.so RUMPHIJACK=vfs=getvfsstat,blanket=/mnt edquota -$q -s2k/4 -h3k/6 \ + -t 1s/1d ${id} + done + atf_check -s exit:0 rump.halt + + #now start the server which does the limits tests + atf_check -s exit:0 -o ignore \ +-e match:'test 1: write beyond the soft limit after grace time returned 69: Disc quota exceeded' \ + $(atf_get_srcdir)/h_quota2_tests -b 1 ${IMG} ${RUMP_SERVER} + for q in ${expect} ; do + atf_check -s exit:0 \ + -o match:'/mnt 2560 B\* 2048 B 3072 B none 2 4 6 ' \ + env LD_PRELOAD=/usr/lib/librumphijack.so RUMPHIJACK=vfs=getvfsstat,blanket=/mnt quota -$q -h ${id} + atf_check -s exit:0 \ + -o match:'daemon \+- 2 2 3 none 2 4 6' \ + env LD_PRELOAD=/usr/lib/librumphijack.so RUMPHIJACK=vfs=getvfsstat,blanket=/mnt repquota -$q /mnt + done + rump_quota_shutdown +} + +limit_iquota() +{ + create_ffs_server $* + local q=$4 + local expect + local id=1 + + case ${q} in + user) + expect=u + fail=g + ;; + group) + expect=g + fail=u + ;; + both) + expect="u g" + fail="" + ;; + *) + atf_fail "wrong quota type" + ;; + esac + + for q in ${expect} ; do + atf_check -s exit:0 \ + env LD_PRELOAD=/usr/lib/librumphijack.so RUMPHIJACK=vfs=getvfsstat,blanket=/mnt edquota -$q -s2m/4 -h3m/6 \ + -t 2h/2h ${id} + done + atf_check -s exit:0 rump.halt + + #now start the server which does the limits tests + atf_check -s exit:0 -o ignore \ +-e match:'test 2: create file up to hard limit returned 69: Disc quota exceeded' \ + $(atf_get_srcdir)/h_quota2_tests -b 2 ${IMG} ${RUMP_SERVER} + for q in ${expect} ; do + atf_check -s exit:0 \ + -o match:'/mnt 3072 B 2048 K 3072 K 6 \* 4 6 2:0' \ + env LD_PRELOAD=/usr/lib/librumphijack.so RUMPHIJACK=vfs=getvfsstat,blanket=/mnt quota -$q -h ${id} + atf_check -s exit:0 \ + -o match:'daemon -\+ 3 2048 3072 6 4 6 2:0' \ + env LD_PRELOAD=/usr/lib/librumphijack.so RUMPHIJACK=vfs=getvfsstat,blanket=/mnt repquota -$q /mnt + done + rump_quota_shutdown +} + +limit_softiquota() +{ + create_ffs_server $* + local q=$4 + local expect + local id=1 + + case ${q} in + user) + expect=u + fail=g + ;; + group) + expect=g + fail=u + ;; + both) + expect="u g" + fail="" + ;; + *) + atf_fail "wrong quota type" + ;; + esac + + for q in ${expect} ; do + atf_check -s exit:0 \ + env LD_PRELOAD=/usr/lib/librumphijack.so RUMPHIJACK=vfs=getvfsstat,blanket=/mnt edquota -$q -s2m/4 -h3m/6 \ + -t 1d/1s ${id} + done + atf_check -s exit:0 rump.halt + + #now start the server which does the limits tests + atf_check -s exit:0 -o ignore \ +-e match:'test 3: create file beyond the soft limit after grace time returned 69: Disc quota exceeded' \ + $(atf_get_srcdir)/h_quota2_tests -b 3 ${IMG} ${RUMP_SERVER} + for q in ${expect} ; do + atf_check -s exit:0 \ + -o match:'/mnt 2560 B 2048 K 3072 K 5 \* 4 6 none' \ + env LD_PRELOAD=/usr/lib/librumphijack.so RUMPHIJACK=vfs=getvfsstat,blanket=/mnt quota -$q -h ${id} + atf_check -s exit:0 \ + -o match:'daemon -\+ 2 2048 3072 5 4 6 none' \ + env LD_PRELOAD=/usr/lib/librumphijack.so RUMPHIJACK=vfs=getvfsstat,blanket=/mnt repquota -$q /mnt + done + rump_quota_shutdown +} + +inherit_defaultquota() +{ + create_ffs_server $* + local q=$4 + local expect + local id=1 + + case ${q} in + user) + expect=u + fail=g + ;; + group) + expect=g + fail=u + ;; + both) + expect="u g" + fail="" + ;; + *) + atf_fail "wrong quota type" + ;; + esac + + for q in ${expect} ; do + atf_check -s exit:0 \ + env LD_PRELOAD=/usr/lib/librumphijack.so RUMPHIJACK=vfs=getvfsstat,blanket=/mnt edquota -$q -s2k/4 -h3k/6 \ + -t 2h/2h -d + done + for q in ${expect} ; do + atf_check -s exit:0 \ + -o match:'Disk quotas for .*id 1\): none' \ + env LD_PRELOAD=/usr/lib/librumphijack.so RUMPHIJACK=vfs=getvfsstat,blanket=/mnt quota -$q -v ${id} + done + atf_check -s exit:0 rump.halt + + #now start the server which does the limits tests + atf_check -s exit:0 -o ignore \ +-e match:'test 0: write up to hard limit returned 69: Disc quota exceeded' \ + $(atf_get_srcdir)/h_quota2_tests -b 0 ${IMG} ${RUMP_SERVER} + for q in ${expect} ; do + atf_check -s exit:0 \ + -o match:'/mnt 3072 B\* 2048 B 3072 B 2:0 2 4 6 ' \ + env LD_PRELOAD=/usr/lib/librumphijack.so RUMPHIJACK=vfs=getvfsstat,blanket=/mnt quota -$q -h ${id} + atf_check -s exit:0 \ + -o match:'daemon \+- 3 2 3 2:0 2 4 6' \ + env LD_PRELOAD=/usr/lib/librumphijack.so RUMPHIJACK=vfs=getvfsstat,blanket=/mnt repquota -$q /mnt + done + rump_quota_shutdown +} + +inherit_defaultiquota() +{ + create_ffs_server $* + local q=$4 + local expect + local id=1 + + case ${q} in + user) + expect=u + fail=g + ;; + group) + expect=g + fail=u + ;; + both) + expect="u g" + fail="" + ;; + *) + atf_fail "wrong quota type" + ;; + esac + + for q in ${expect} ; do + atf_check -s exit:0 \ + env LD_PRELOAD=/usr/lib/librumphijack.so RUMPHIJACK=vfs=getvfsstat,blanket=/mnt edquota -$q -s2m/4 -h3m/6 \ + -t 2h/2h -d + done + for q in ${expect} ; do + atf_check -s exit:0 \ + -o match:'Disk quotas for .*id 1\): none' \ + env LD_PRELOAD=/usr/lib/librumphijack.so RUMPHIJACK=vfs=getvfsstat,blanket=/mnt quota -$q -v ${id} + done + atf_check -s exit:0 rump.halt + + #now start the server which does the limits tests + atf_check -s exit:0 -o ignore \ +-e match:'test 2: create file up to hard limit returned 69: Disc quota exceeded' \ + $(atf_get_srcdir)/h_quota2_tests -b 2 ${IMG} ${RUMP_SERVER} + for q in ${expect} ; do + atf_check -s exit:0 \ + -o match:'/mnt 3072 B 2048 K 3072 K 6 \* 4 6 2:0' \ + env LD_PRELOAD=/usr/lib/librumphijack.so RUMPHIJACK=vfs=getvfsstat,blanket=/mnt quota -$q -h ${id} + atf_check -s exit:0 \ + -o match:'daemon -\+ 3 2048 3072 6 4 6 2:0' \ + env LD_PRELOAD=/usr/lib/librumphijack.so RUMPHIJACK=vfs=getvfsstat,blanket=/mnt repquota -$q /mnt + done + rump_quota_shutdown +} diff --git a/contrib/netbsd-tests/fs/ffs/t_setquota.sh b/contrib/netbsd-tests/fs/ffs/t_setquota.sh new file mode 100755 index 000000000000..5795fe4d46b6 --- /dev/null +++ b/contrib/netbsd-tests/fs/ffs/t_setquota.sh @@ -0,0 +1,203 @@ +# $NetBSD: t_setquota.sh,v 1.4 2012/01/18 20:51:23 bouyer Exp $ +# +# Copyright (c) 2011 Manuel Bouyer +# All rights reserved. +# +# 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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. +# + +for e in le be; do + for v in 1 2; do + for q in "user" "group"; do + test_case_root set_${e}_${v}_${q} set_quota \ + "set quota with ${q} enabled" -b ${e} ${v} ${q} + test_case_root set_new_${e}_${v}_${q} set_quota_new \ + "set quota for new id with ${q} enabled" -b ${e} ${v} ${q} + test_case_root set_default_${e}_${v}_${q} set_quota_default \ + "set default quota with ${q} enabled" -b ${e} ${v} ${q} + done + test_case_root set_${e}_${v}_"both" set_quota \ + "set quota with both enabled" -b ${e} ${v} "both" + test_case_root set_new_${e}_${v}_"both" set_quota_new \ + "set quota for new id with both enabled" -b ${e} ${v} "both" + test_case_root set_new_${e}_${v}_"both_log" set_quota_new \ + "set quota for new id with both enabled, WAPBL" -bl ${e} ${v} "both" + test_case_root set_default_${e}_${v}_"both" set_quota_default \ + "set default quota with both enabled" -b ${e} ${v} "both" + done +done + +set_quota() +{ + create_ffs_server $* + local q=$4 + local expect + local fail + + case ${q} in + user) + expect=u + fail=g + ;; + group) + expect=g + fail=u + ;; + both) + expect="u g" + fail="" + ;; + *) + atf_fail "wrong quota type" + ;; + esac + +#check that we can set the expected quota + for q in ${expect} ; do + local id=$(id -${q}) + atf_check -s exit:0 \ + env LD_PRELOAD=/usr/lib/librumphijack.so RUMPHIJACK=vfs=getvfsstat,blanket=/mnt edquota -$q -s10k/20 -h40M/50k \ + -t 2W/3D ${id} + atf_check -s exit:0 \ +-o "match:/mnt 0 10 40960 2weeks 1 20 51200 3days" \ +-o "match:Disk quotas for .*: $" \ + env LD_PRELOAD=/usr/lib/librumphijack.so RUMPHIJACK=vfs=getvfsstat,blanket=/mnt quota -${q} -v + atf_check -s exit:0 \ +-o "match:-- 0 10 40960 1 20 51200" \ + env LD_PRELOAD=/usr/lib/librumphijack.so RUMPHIJACK=vfs=getvfsstat,blanket=/mnt repquota -${q} /mnt + done + +#check that we do not get positive reply for non-expected quota + for q in ${fail} ; do + local id=$(id -${q}) + atf_check -s exit:0 \ + env LD_PRELOAD=/usr/lib/librumphijack.so RUMPHIJACK=vfs=getvfsstat,blanket=/mnt edquota -$q -s10k/20 -h40M/50k ${id} + atf_check -s exit:0 -o "not-match:/mnt" \ + -o "not-match:Disk quotas for .*: $" \ + -o "match:Disk quotas for .*: none$" \ + env LD_PRELOAD=/usr/lib/librumphijack.so RUMPHIJACK=vfs=getvfsstat,blanket=/mnt quota -${q} -v + atf_check -s exit:0 \ +-o "not-match:-- 0 - -" \ + env LD_PRELOAD=/usr/lib/librumphijack.so RUMPHIJACK=vfs=getvfsstat,blanket=/mnt repquota -${q} /mnt + done + rump_quota_shutdown +} + +set_quota_new() +{ + create_ffs_server $* + local q=$4 + local expect + local fail + + case ${q} in + user) + expect=u + fail=g + ;; + group) + expect=g + fail=u + ;; + both) + expect="u g" + fail="" + ;; + *) + atf_fail "wrong quota type" + ;; + esac + +#check that we can set the expected quota + for q in ${expect} ; do + local id=1 + atf_check -s exit:0 \ + env LD_PRELOAD=/usr/lib/librumphijack.so RUMPHIJACK=vfs=getvfsstat,blanket=/mnt edquota -$q -s10k/20 -h40M/50k \ + -t 120W/255D ${id} + atf_check -s exit:0 \ +-o "match:/mnt 0 10 40960 2years 0 20 51200 9months" \ +-o "match:Disk quotas for .*: $" \ + env LD_PRELOAD=/usr/lib/librumphijack.so RUMPHIJACK=vfs=getvfsstat,blanket=/mnt quota -${q} -v ${id} + done + +#check that we do not get positive reply for non-expected quota + for q in ${fail} ; do + local id=$(id -${q}) + atf_check -s exit:0 \ + env LD_PRELOAD=/usr/lib/librumphijack.so RUMPHIJACK=vfs=getvfsstat,blanket=/mnt edquota -$q -s10k/20 -h40M/50k ${id} + atf_check -s exit:0 -o "not-match:/mnt" \ + -o "not-match:Disk quotas for .*: $" \ + -o "match:Disk quotas for .*: none$" \ + env LD_PRELOAD=/usr/lib/librumphijack.so RUMPHIJACK=vfs=getvfsstat,blanket=/mnt quota -${q} -v ${id} + done + rump_quota_shutdown +} + +set_quota_default() +{ + create_ffs_server $* + local q=$4 + local expect + local fail + + case ${q} in + user) + expect=u + fail=g + ;; + group) + expect=g + fail=u + ;; + both) + expect="u g" + fail="" + ;; + *) + atf_fail "wrong quota type" + ;; + esac + +#check that we can set the expected quota + for q in ${expect} ; do + local id="-d" + atf_check -s exit:0 \ + env LD_PRELOAD=/usr/lib/librumphijack.so RUMPHIJACK=vfs=getvfsstat,blanket=/mnt edquota -$q -s10k/20 -h40M/50k \ + -t 2H2M/3540 ${id} + atf_check -s exit:0 \ +-o "match:/mnt 0 10 40960 2:2 0 20 51200 59" \ +-o "match:Default (user|group) disk quotas: $" \ + env LD_PRELOAD=/usr/lib/librumphijack.so RUMPHIJACK=vfs=getvfsstat,blanket=/mnt quota -${q} -v ${id} + done + +#check that we do not get positive reply for non-expected quota + for q in ${fail} ; do + local id="-d" + atf_check -s exit:0 \ + env LD_PRELOAD=/usr/lib/librumphijack.so RUMPHIJACK=vfs=getvfsstat,blanket=/mnt edquota -$q -s10k/20 -h40M/50k ${id} + atf_check -s exit:0 -o "not-match:/mnt" \ + -o "not-match:Default (user|group) disk quotas: $" \ + -o "match:Default (user|group) disk quotas: none$" \ + env LD_PRELOAD=/usr/lib/librumphijack.so RUMPHIJACK=vfs=getvfsstat,blanket=/mnt quota -${q} -v ${id} + done + rump_quota_shutdown +} diff --git a/contrib/netbsd-tests/fs/ffs/t_snapshot.c b/contrib/netbsd-tests/fs/ffs/t_snapshot.c new file mode 100644 index 000000000000..f661bec2634c --- /dev/null +++ b/contrib/netbsd-tests/fs/ffs/t_snapshot.c @@ -0,0 +1,43 @@ +/* $NetBSD: t_snapshot.c,v 1.7 2017/01/13 21:30:39 christos Exp $ */ + +#include <sys/types.h> +#include <sys/mount.h> + +#include <rump/rump.h> +#include <rump/rump_syscalls.h> + +#include <ufs/ufs/ufsmount.h> + +#include <atf-c.h> +#include <fcntl.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +#include "h_macros.h" + +#define IMGNAME "ffs.img" +#define NEWFS "newfs -F -s 10000 " IMGNAME +#define FSCK "fsck_ffs -fn -F" +#define BAKNAME "/mnt/le_snapp" + +static void +mount_diskfs(const char *fspec, const char *path) +{ + struct ufs_args uargs; + + uargs.fspec = __UNCONST(fspec); + + if (rump_sys_mount(MOUNT_FFS, path, 0, &uargs, sizeof(uargs)) == -1) + atf_tc_fail_errno("mount ffs %s", path); +} + +static void +begin(void) +{ + + /* empty */ +} + +#include "../common/snapshot.c" diff --git a/contrib/netbsd-tests/fs/ffs/t_snapshot_log.c b/contrib/netbsd-tests/fs/ffs/t_snapshot_log.c new file mode 100644 index 000000000000..31b28e53df2d --- /dev/null +++ b/contrib/netbsd-tests/fs/ffs/t_snapshot_log.c @@ -0,0 +1,46 @@ +/* $NetBSD: t_snapshot_log.c,v 1.3 2017/01/13 21:30:39 christos Exp $ */ + +#include <sys/types.h> +#include <sys/mount.h> + +#include <rump/rump.h> +#include <rump/rump_syscalls.h> + +#include <ufs/ufs/ufsmount.h> + +#include <atf-c.h> +#include <fcntl.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +#include "h_macros.h" + +#define IMGNAME "ffs.img" +#define NEWFS "newfs -F -s 10000 " IMGNAME +#define FSCK "fsck_ffs -fn -F" +#define BAKNAME "/mnt/le_snapp" + +static void +mount_diskfs(const char *fspec, const char *path) +{ + struct ufs_args uargs; + static int flags = MNT_LOG; + + uargs.fspec = __UNCONST(fspec); + + if (rump_sys_mount(MOUNT_FFS, + path, flags, &uargs, sizeof(uargs)) == -1) + atf_tc_fail_errno("mount ffs %s", path); + flags = 0; +} + +static void +begin(void) +{ + + /* empty */ +} + +#include "../common/snapshot.c" diff --git a/contrib/netbsd-tests/fs/ffs/t_snapshot_v2.c b/contrib/netbsd-tests/fs/ffs/t_snapshot_v2.c new file mode 100644 index 000000000000..b27929cb12d8 --- /dev/null +++ b/contrib/netbsd-tests/fs/ffs/t_snapshot_v2.c @@ -0,0 +1,43 @@ +/* $NetBSD: t_snapshot_v2.c,v 1.3 2017/01/13 21:30:39 christos Exp $ */ + +#include <sys/types.h> +#include <sys/mount.h> + +#include <rump/rump.h> +#include <rump/rump_syscalls.h> + +#include <ufs/ufs/ufsmount.h> + +#include <atf-c.h> +#include <fcntl.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +#include "h_macros.h" + +#define IMGNAME "ffs.img" +#define NEWFS "newfs -F -s 10000 -O 2 " IMGNAME +#define FSCK "fsck_ffs -fn -F" +#define BAKNAME "/mnt/le_snapp" + +static void +mount_diskfs(const char *fspec, const char *path) +{ + struct ufs_args uargs; + + uargs.fspec = __UNCONST(fspec); + + if (rump_sys_mount(MOUNT_FFS, path, 0, &uargs, sizeof(uargs)) == -1) + atf_tc_fail_errno("mount ffs %s", path); +} + +static void +begin(void) +{ + + /* empty */ +} + +#include "../common/snapshot.c" diff --git a/contrib/netbsd-tests/fs/fifofs/t_fifo.c b/contrib/netbsd-tests/fs/fifofs/t_fifo.c new file mode 100644 index 000000000000..4b37bb85b8c2 --- /dev/null +++ b/contrib/netbsd-tests/fs/fifofs/t_fifo.c @@ -0,0 +1,238 @@ +/* Test case written by Bharat Joshi */ +#include <sys/cdefs.h> +__RCSID("$NetBSD: t_fifo.c,v 1.2 2017/01/10 22:36:29 christos Exp $"); + +#include <sys/types.h> +#include <sys/wait.h> +#include <sys/stat.h> + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <fcntl.h> +#include <errno.h> +#include <string.h> +#include <err.h> +#include <signal.h> + +#ifndef STANDALONE +#include <atf-c.h> +#endif + +#define FIFO_FILE_PATH "./fifo_file" +#define NUM_MESSAGES 20 +#define MSG_SIZE 240 +#define MESSAGE "I am fine" + +static int verbose = 0; + +/* + * child_writer + * + * Function that runs in child context and opens and write to the FIFO. + */ +static void +child_writer(void) +{ + ssize_t rv; + int fd; + size_t count; + char message[MSG_SIZE] = MESSAGE; + static const struct timespec ts = { 0, 10000 }; + + /* Open the fifo in write-mode */ + for (;;) { + fd = open(FIFO_FILE_PATH, O_WRONLY, 0); + if (fd == -1) { + if (errno == EINTR) + continue; + err(1, "Child: can't open fifo in write mode"); + } + break; + } + + for (count = 0; count < NUM_MESSAGES; count++) { + rv = write(fd, message, MSG_SIZE); + if (rv == -1) { + warn("Child: Failed to write"); + break; + } + if (rv != MSG_SIZE) + warnx("Child: wrote only %zd", rv); + nanosleep(&ts, NULL); + } + + close(fd); + if (verbose) { + printf("Child: Closed the fifo file\n"); + fflush(stdout); + } +} + +/* + * _sigchild_handler + * + * Called when a sigchild is delivered + */ +static void +sigchild_handler(int signo) +{ + if (verbose) { + if (signo == SIGCHLD) { + printf("Got sigchild\n"); + } else { + printf("Got %d signal\n", signo); + } + fflush(stdout); + } + +} + +static int +run(void) +{ + pid_t pid; + ssize_t rv; + int fd, status; + size_t buf_size = MSG_SIZE; + char buf[MSG_SIZE]; + struct sigaction action; + static const struct timespec ts = { 0, 500000000 }; + + /* Catch sigchild Signal */ + memset(&action, 0, sizeof(action)); + action.sa_handler = sigchild_handler; + sigemptyset(&action.sa_mask); + + if (sigaction(SIGCHLD, &action, NULL) == -1) + err(1, "sigaction"); + + (void)unlink(FIFO_FILE_PATH); + /* First create a fifo */ + if (mkfifo(FIFO_FILE_PATH, S_IRUSR | S_IWUSR) == -1) + err(1, "mkfifo"); + + switch ((pid = fork())) { + case -1: + err(1, "fork"); + case 0: + /* Open the file in write mode so that subsequent read + * from parent side does not block the parent.. + */ + if ((fd = open(FIFO_FILE_PATH, O_WRONLY, 0)) == -1) + err(1, "failed to open fifo"); + + /* In child */ + child_writer(); + return 0; + + default: + break; + } + + if (verbose) { + printf("Child pid is %d\n", pid ); + fflush(stdout); + } + + /* In parent */ + for (;;) { + if ((fd = open(FIFO_FILE_PATH, O_RDONLY, 0)) == -1) { + if (errno == EINTR) + continue; + else + err(1, "Failed to open the fifo in read mode"); + } + /* Read mode is opened */ + break; + + } + + nanosleep(&ts, NULL); + if (verbose) { + printf("Was sleeping...\n"); + fflush(stdout); + } + + for (;;) { + rv = read(fd, buf, buf_size); + + if (rv == -1) { + warn("Failed to read"); + if (errno == EINTR) { + if (verbose) { + printf("Parent interrupted, " + "continuing...\n"); + fflush(stdout); + } + continue; + } + + break; + } + + if (rv == 0) { + if (verbose) { + printf("Writers have closed, looks like we " + "are done\n"); + fflush(stdout); + } + break; + } + + if (verbose) { + printf("Received %zd bytes message '%s'\n", rv, buf); + fflush(stdout); + } + } + + close(fd); + + if (verbose) { + printf("We are done.. now reap the child"); + fflush(stdout); + } + + // Read the child... + while (waitpid(pid, &status, 0) == -1) + if (errno != EINTR) { + warn("Failed to reap the child"); + return 1; + } + + if (verbose) { + printf("We are done completely\n"); + fflush(stdout); + } + return 0; +} + +#ifndef STANDALONE +ATF_TC(parent_child); + +ATF_TC_HEAD(parent_child, tc) +{ + atf_tc_set_md_var(tc, "descr", "Checks that when a fifo is shared " + "between a reader parent and a writer child, that read will " + "return EOF, and not get stuck after the child exits"); +} + +ATF_TC_BODY(parent_child, tc) +{ + ATF_REQUIRE(run() == 0); +} + +ATF_TP_ADD_TCS(tp) +{ + ATF_TP_ADD_TC(tp, parent_child); + + return atf_no_error(); +} +#else +int +main(void) +{ + verbose = 1; + return run(); +} +#endif diff --git a/contrib/netbsd-tests/fs/h_funcs.subr b/contrib/netbsd-tests/fs/h_funcs.subr new file mode 100644 index 000000000000..8da43cc95160 --- /dev/null +++ b/contrib/netbsd-tests/fs/h_funcs.subr @@ -0,0 +1,75 @@ +#!/bin/sh +# +# $NetBSD: h_funcs.subr,v 1.3 2010/06/23 11:19:17 pooka Exp $ +# +# Copyright (c) 2007 The NetBSD Foundation, Inc. +# All rights reserved. +# +# 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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. +# + +# +# require_fs name +# +# Checks that the given file system is built into the kernel and +# that its corresponding mount(8) utility is available. Otherwise +# skips the test. +# +require_fs() { + local name + local autoload + name="${1}" + + atf_require_prog mount + atf_require_prog mount_${name} + atf_require_prog umount + + # Begin FreeBSD + if true; then + if kldstat -qm ${name} || kldload -n ${name}; then + found=yes + else + found=no + fi + else + # End FreeBSD + # if we have autoloadable modules, just assume the file system + atf_require_prog sysctl + autoload=$(sysctl -n kern.module.autoload) + [ "${autoload}" = "1" ] && return 0 + + set -- $(sysctl -n vfs.generic.fstypes) + found=no + while [ ${#} -gt 1 ]; do + if [ ${1} = ${name} ]; then + found=yes + break + fi + shift + done + # Begin FreeBSD + fi + # End FreeBSD + [ ${found} = yes ] || \ + atf_skip "The kernel does not include support the " \ + "\`${name}' file system" +} diff --git a/contrib/netbsd-tests/fs/hfs/colon.hfs.bz2.uue b/contrib/netbsd-tests/fs/hfs/colon.hfs.bz2.uue new file mode 100644 index 000000000000..9240e7befa80 --- /dev/null +++ b/contrib/netbsd-tests/fs/hfs/colon.hfs.bz2.uue @@ -0,0 +1,35 @@ +begin 644 colon.hfs.bz2 +M0EIH.3%!629363%?)5P``$+____[_UOQ>_]__^_O\+____1K30045,CBA$'P +M'DA:2!KIT`3V\VRA*<ZPAUVK`E%-)E,IME3T33U--DFRCU,T33T@]-1HQ&1M +M(/2&@&TGI&@9#1B#0&F@TT:``R9/4$I$4PTF$Q,B8T)IY(VD:9&`3(80T>B& +M`$,"8C$P$T9!HR:81B,":`D20A3T:GI`9``#(>H-`:-```:````````````` +M08!#1B:`R:83)ID`&$:-,`F`)A!H9`Q,@#``"8F3`3`30%241HC(4_4GJ>U- +M1Y31IM)ID`]3(T>H`#0#0T`:!H!A&@!H`````*9A\>L.>@+P;@Y:4C2%YM29 +M)Z`H>8SU&'"0U30JHOQ^.'A/7!GQK%#<GT'!B0OU+G:^>A5RVH"2$4VDL&T@ +M65#T*A/GU+(_VI$+*$`TJ"4J1(B1S&-YV+\J^"\Z6EK+@TU[0OQJ+;*HW.MN +M=HTL,CQHCE$C3#EW'>#8!IGYY[*)]U$!0W6L;#U:*4X6IT<@^*5!16E)%(:* +MA["$B&JX1022R8T4#20D@+ZHA_2_9$72HDSJ-FJ"7Z15%U2`@<>BJGD5'+*A +M@M6>?K^MS^LOC8I)EI6[`O3`#CCKU:M6F6A00-$/:LH+!E7(G33<)<I*5Q&T +M4[$M.$5OJZQKO59^7&LNANB-1PEMLB*TT\<[=;@7C@EYFG#:K@GL&R8^48"Y +MU*QN%C56,Q?,.BW;"R9.7;9Z;2,+07U,QGK13C,!FYO^3/?)>)OZ27I4`@;= +M4C<-$,N=UX98G_0DK)BTS-^)R+8NZ,B3JU:@85&-MM@</$$"."U>FCNQW/?= +M'ZL4BR[\&3S\>.K"S#1Z&>2I>^+16EM54PV3%K7M$"E`.N2"E*,8-@V.E<3$ +M,K\RU$&5E//5.'K6A+44]9=\"WF$J@Q1!43!WLA!?"XLR2GOU6G-,W]92)1` +MC@M4A4'FVAA`Q&&_%1B@L_`Z;T`0>[W6SCI%W&=H%Y>2"#E>IN[R<S>3+(:S +MLMC<>N$1&APB(&6_#U<"!5*#IDA;MLNX`J(:/B8I,UNWB3CDPU2.@"(ORCKK +MK(1*"RZ+9V>$I2"PLER`U4BFIY'VTJ#\NYN2-9DRCIP1([QBLNKT:%1K"-P5 +MY)2NL9KM8=ACP>MLBS&J(00HA*QYRUL:'A%8F5]&22@@@D,;3[C,4.9$P)DK +M>\N+DK'4TLDI*LD&>8DE<M`B3!)=Z,E/#BSM)O*_$9Z"ZPSI%3*/=47CG8DJ +MD]U*[RTUH7SC41(FD1>V@DT9B\,_CR;`,Y-E8*MM?Z*?BPU`I[I5^G-B$$A. +M\7&8DC*:*',@VKX0HL8O)DL<-9GG!8>NK.2XS2I.;Z3%Q9OIL8?(6-*DEGHW +MX^&A?%APXI:C@,A/&<6=)7#$UI;1Y6A'C<#/EW-*T(8WC9=`B`%\)M5HIS[\ +MV1%+H,,()X19<,:)U:Y?V\-T!^]'A\%%%+Z6.PQ"QI$]3#11IRB<#.9-L)^! +MB-WJYVQVMP^;7V<DK?-[M;DQF]<[:M3)$-F@*(CXT128KESC.#OPP+`$D`G- +MA6$DKT2V\;3+*:U+2]66T]'1$A`=33.FMDA1G\MA$1V_"/+2]%!GTQI'8E03 +M=?AO,S0#0V,9IS,&;8KGKL_$RKJFE62392;]B2933`4\$VJ""-0$;")-/A]R +M[D"*/0:F1=%1R!B9&8=^RD4B^;4O-6'*J4J)EVNWN[+!_$)1\;@+#>*W5MG' +MKUWYE^[,*T:U)Y]NUI,00H%8>74G/?LJ0K)51^BXZ+AI*2O[PI`V*%Q@X\YV +M!V?D08"^;*TYO4R)T6G5:M;_M5M*;H4V)1IKCL$01$`#1R%N5,'_B[DBG"A( +%&*^2K@"^ +` +end diff --git a/contrib/netbsd-tests/fs/hfs/t_pathconvert.c b/contrib/netbsd-tests/fs/hfs/t_pathconvert.c new file mode 100644 index 000000000000..056726a1a6c2 --- /dev/null +++ b/contrib/netbsd-tests/fs/hfs/t_pathconvert.c @@ -0,0 +1,83 @@ +/* $NetBSD: t_pathconvert.c,v 1.6 2017/01/13 21:30:40 christos Exp $ */ + +#include <sys/types.h> +#include <sys/mount.h> + +#include <atf-c.h> +#include <dirent.h> +#include <errno.h> +#include <fcntl.h> +#include <limits.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> + +#include <rump/rump.h> +#include <rump/rump_syscalls.h> + +#include <fs/hfs/hfs.h> + +#include "h_macros.h" + +ATF_TC(colonslash); +ATF_TC_HEAD(colonslash, tc) +{ + atf_tc_set_md_var(tc, "descr", "HFS+ colons/slashes (PR kern/44523)"); + atf_tc_set_md_var(tc, "timeout", "20"); +} + +#define IMGNAME "colon.hfs" +#define FAKEBLK "/dev/blk" +#define FUNNY_FILENAME "foo:bar" +ATF_TC_BODY(colonslash, tc) +{ + struct hfs_args args; + int dirfd, fd; + char thecmd[1024]; + char buf[DIRBLKSIZ]; + struct dirent *dirent; + int offset, nbytes; + bool ok = false; + + snprintf(thecmd, sizeof(thecmd), "uudecode %s/colon.hfs.bz2.uue", + atf_tc_get_config_var(tc, "srcdir")); + RZ(system(thecmd)); + + snprintf(thecmd, sizeof(thecmd), "bunzip2 " IMGNAME ".bz2"); + RZ(system(thecmd)); + + memset(&args, 0, sizeof args); + args.fspec = __UNCONST(FAKEBLK); + RZ(rump_init()); + + RL(rump_sys_mkdir("/mp", 0777)); + RZ(rump_pub_etfs_register(FAKEBLK, IMGNAME, RUMP_ETFS_BLK)); + RL(rump_sys_mount(MOUNT_HFS, "/mp", 0, &args, sizeof args)); + + RL(dirfd = rump_sys_open("/mp", O_RDONLY)); + + RL(nbytes = rump_sys_getdents(dirfd, buf, sizeof buf)); + + for (offset = 0; offset < nbytes; offset += dirent->d_reclen) { + dirent = (struct dirent *)(buf + offset); + if (strchr(dirent->d_name, '/')) + atf_tc_fail("dirent with slash: %s", dirent->d_name); + if (0 == strcmp(FUNNY_FILENAME, dirent->d_name)) + ok = true; + } + + if (!ok) + atf_tc_fail("no dirent for file: %s", FUNNY_FILENAME); + + RL(rump_sys_close(dirfd)); + RL(fd = rump_sys_open("/mp/" FUNNY_FILENAME, O_RDONLY)); + RL(rump_sys_close(fd)); + RL(rump_sys_unmount("/mp", 0)); +} + +ATF_TP_ADD_TCS(tp) +{ + ATF_TP_ADD_TC(tp, colonslash); + return 0; +} diff --git a/contrib/netbsd-tests/fs/kernfs/t_basic.c b/contrib/netbsd-tests/fs/kernfs/t_basic.c new file mode 100644 index 000000000000..77acd1149c66 --- /dev/null +++ b/contrib/netbsd-tests/fs/kernfs/t_basic.c @@ -0,0 +1,133 @@ +/* $NetBSD: t_basic.c,v 1.4 2017/01/13 21:30:40 christos Exp $ */ + +#include <sys/types.h> +#include <sys/mount.h> +#include <sys/module.h> +#include <sys/dirent.h> +#include <sys/sysctl.h> + +#include <atf-c.h> +#include <err.h> +#include <errno.h> +#include <fcntl.h> +#include <stdio.h> +#include <unistd.h> +#include <string.h> +#include <stdlib.h> + +#include <rump/rump.h> +#include <rump/rump_syscalls.h> + +#include <miscfs/kernfs/kernfs.h> + +#include "h_macros.h" + +ATF_TC(getdents); +ATF_TC_HEAD(getdents, tc) +{ + + atf_tc_set_md_var(tc, "descr", "kernfs directory contains files"); +} + +static void +mountkernfs(void) +{ + + rump_init(); + + if (rump_sys_mkdir("/kern", 0777) == -1) + atf_tc_fail_errno("mkdir /kern"); + if (rump_sys_mount(MOUNT_KERNFS, "/kern", 0, NULL, 0) == -1) + atf_tc_fail_errno("could not mount kernfs"); +} + +ATF_TC_BODY(getdents, tc) +{ + struct dirent *dent; + char buf[8192]; + int dfd; + + mountkernfs(); + + if ((dfd = rump_sys_open("/kern", O_RDONLY)) == -1) + atf_tc_fail_errno("can't open directory"); + if (rump_sys_getdents(dfd, buf, sizeof(buf)) == -1) + atf_tc_fail_errno("getdents"); + + /* + * Check that we get the first three values (., .., boottime). + * Make more complete by autogenerating list from kernfs_vnops.c? + */ + dent = (void *)buf; + ATF_REQUIRE_STREQ(dent->d_name, "."); + dent = _DIRENT_NEXT(dent); + ATF_REQUIRE_STREQ(dent->d_name, ".."); + dent = _DIRENT_NEXT(dent); + ATF_REQUIRE_STREQ(dent->d_name, "boottime"); + + /* done */ +} + +ATF_TC(hostname); +ATF_TC_HEAD(hostname, tc) +{ + + atf_tc_set_md_var(tc, "descr", "/kern/hostname changes hostname"); +} + +static char * +getthehost(void) +{ + static char buf[8192]; + int mib[2]; + size_t blen; + + mib[0] = CTL_KERN; + mib[1] = KERN_HOSTNAME; + blen = sizeof(buf); + if (rump_sys___sysctl(mib, 2, buf, &blen, NULL, 0) == -1) + atf_tc_fail_errno("sysctl gethostname"); + + return buf; +} + +#define NEWHOSTNAME "turboton roos-berg" +ATF_TC_BODY(hostname, tc) +{ + char buf[8192]; + char *shost, *p; + int fd; + + mountkernfs(); + if ((fd = rump_sys_open("/kern/hostname", O_RDWR)) == -1) + atf_tc_fail_errno("open hostname"); + + /* check initial match */ + shost = getthehost(); + buf[0] = '\0'; + if (rump_sys_read(fd, buf, sizeof(buf)) == -1) + atf_tc_fail_errno("read hostname"); + p = strchr(buf, '\n'); + if (p) + *p = '\0'; + ATF_REQUIRE_STREQ_MSG(buf, shost, "initial hostname mismatch"); + + /* check changing hostname works */ + if (rump_sys_pwrite(fd, NEWHOSTNAME, strlen(NEWHOSTNAME), 0) + != strlen(NEWHOSTNAME)) { + atf_tc_fail_errno("write new hostname"); + } + + shost = getthehost(); + ATF_REQUIRE_STREQ_MSG(NEWHOSTNAME, shost, "modified hostname mismatch"); + + /* done */ +} + +ATF_TP_ADD_TCS(tp) +{ + ATF_TP_ADD_TC(tp, hostname); + ATF_TP_ADD_TC(tp, getdents); + + return atf_no_error(); +} diff --git a/contrib/netbsd-tests/fs/lfs/t_pr.c b/contrib/netbsd-tests/fs/lfs/t_pr.c new file mode 100644 index 000000000000..ed676d8bf9b0 --- /dev/null +++ b/contrib/netbsd-tests/fs/lfs/t_pr.c @@ -0,0 +1,60 @@ +/* $NetBSD: t_pr.c,v 1.7 2017/01/13 21:30:40 christos Exp $ */ + +#include <sys/types.h> +#include <sys/mount.h> + +#include <atf-c.h> +#include <errno.h> +#include <fcntl.h> +#include <limits.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> + +#include <rump/rump.h> +#include <rump/rump_syscalls.h> + +#include <ufs/ufs/ufsmount.h> + +#include "h_macros.h" + +ATF_TC(mknod); +ATF_TC_HEAD(mknod, tc) +{ + + atf_tc_set_md_var(tc, "descr", "mknod(2) hangs on LFS (PR kern/43503)"); + atf_tc_set_md_var(tc, "timeout", "20"); +} + +#define IMGNAME "disk.img" +#define FAKEBLK "/dev/blk" +ATF_TC_BODY(mknod, tc) +{ + struct ufs_args args; + + /* hmm, maybe i should fix newfs_lfs instead? */ + if (system("newfs_lfs -D -F -s 10000 ./" IMGNAME) == -1) + atf_tc_fail_errno("newfs failed"); + + memset(&args, 0, sizeof(args)); + args.fspec = __UNCONST(FAKEBLK); + + rump_init(); + if (rump_sys_mkdir("/mp", 0777) == -1) + atf_tc_fail_errno("cannot create mountpoint"); + rump_pub_etfs_register(FAKEBLK, IMGNAME, RUMP_ETFS_BLK); + if (rump_sys_mount(MOUNT_LFS, "/mp", 0, &args, sizeof(args)) == -1) + atf_tc_fail_errno("rump_sys_mount failed"); + + //atf_tc_expect_timeout("PR kern/43503"); + if (rump_sys_mknod("/mp/node", S_IFCHR | 0777, 0) == -1) + atf_tc_fail_errno("mknod failed"); +} + +ATF_TP_ADD_TCS(tp) +{ + + ATF_TP_ADD_TC(tp, mknod); + return 0; +} diff --git a/contrib/netbsd-tests/fs/msdosfs/t_snapshot.c b/contrib/netbsd-tests/fs/msdosfs/t_snapshot.c new file mode 100644 index 000000000000..449e62545ab7 --- /dev/null +++ b/contrib/netbsd-tests/fs/msdosfs/t_snapshot.c @@ -0,0 +1,51 @@ +/* $NetBSD: t_snapshot.c,v 1.4 2017/01/13 21:30:40 christos Exp $ */ + +#include <sys/types.h> +#include <sys/mount.h> + +#include <rump/rump.h> +#include <rump/rump_syscalls.h> + +#include <fs/tmpfs/tmpfs_args.h> +#include <msdosfs/msdosfsmount.h> + +#include <atf-c.h> +#include <err.h> +#include <fcntl.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +#include "h_macros.h" + +#define IMGNAME "msdosfs.img" +#define NEWFS "newfs_msdos -C 5M " IMGNAME +#define FSCK "fsck_msdos -fn" +#define BAKNAME "/stor/snap" + +static void +mount_diskfs(const char *fspec, const char *path) +{ + struct msdosfs_args margs; + + memset(&margs, 0, sizeof(margs)); + margs.fspec = __UNCONST(fspec); + margs.version = MSDOSFSMNT_VERSION; + + if (rump_sys_mount(MOUNT_MSDOS, path, 0, &margs, sizeof(margs)) == -1) + err(1, "mount msdosfs %s", path); +} + +static void +begin(void) +{ + struct tmpfs_args targs = { .ta_version = TMPFS_ARGS_VERSION, }; + + if (rump_sys_mkdir("/stor", 0777) == -1) + atf_tc_fail_errno("mkdir /stor"); + if (rump_sys_mount(MOUNT_TMPFS, "/stor", 0, &targs,sizeof(targs)) == -1) + atf_tc_fail_errno("mount storage"); +} + +#include "../common/snapshot.c" diff --git a/contrib/netbsd-tests/fs/nfs/nfsservice/README b/contrib/netbsd-tests/fs/nfs/nfsservice/README new file mode 100644 index 000000000000..8cfa8af62949 --- /dev/null +++ b/contrib/netbsd-tests/fs/nfs/nfsservice/README @@ -0,0 +1,16 @@ + $NetBSD: README,v 1.1 2010/07/26 15:53:00 pooka Exp $ + +This directory contains the necessary bits to get an NFS server +running in a rump kernel. In essence, it's: + + * rpcbind + * mountd + * nfsd + +Additionally, you need the libc rpc code which is in +tests/fs/common/nfsrpc. + +TODO: make the standard nfs userspace services usable (the challenge +comes from rpc being in libc). + +questions? ==> pooka@netbsd.org diff --git a/contrib/netbsd-tests/fs/nfs/nfsservice/exports b/contrib/netbsd-tests/fs/nfs/nfsservice/exports new file mode 100644 index 000000000000..6cc8c5fb80e9 --- /dev/null +++ b/contrib/netbsd-tests/fs/nfs/nfsservice/exports @@ -0,0 +1,12 @@ +# $NetBSD: exports,v 1.2 2010/12/31 18:11:27 pooka Exp $ +# + +# +# The export dir is currently hardcoded and is exposed to the +# world, where "world" in this case means inside the rump shmif +# IP network, i.e. not a very big world. Probably needs some +# adjustments if we want to test NFS features more carefully, +# but this is enough for the current VFS level tests. +# +/myexport -noresvport -noresvmnt -maproot=0:0 10.3.2.2 +/myexport -ro -noresvport -noresvmnt -maproot=0:0 10.4.2.2 diff --git a/contrib/netbsd-tests/fs/nfs/nfsservice/getmntinfo.c b/contrib/netbsd-tests/fs/nfs/nfsservice/getmntinfo.c new file mode 100644 index 000000000000..0c0587a7aba5 --- /dev/null +++ b/contrib/netbsd-tests/fs/nfs/nfsservice/getmntinfo.c @@ -0,0 +1,85 @@ +/* $NetBSD: getmntinfo.c,v 1.1 2010/07/26 15:53:00 pooka Exp $ */ + +/* + * Copyright (c) 1989, 1993 + * The Regents of the University of California. All rights reserved. + * + * 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. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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. + */ + +#include <sys/cdefs.h> +#if defined(LIBC_SCCS) && !defined(lint) +#if 0 +static char sccsid[] = "@(#)getmntinfo.c 8.1 (Berkeley) 6/4/93"; +#else +__RCSID("$NetBSD: getmntinfo.c,v 1.1 2010/07/26 15:53:00 pooka Exp $"); +#endif +#endif /* LIBC_SCCS and not lint */ + +#include <sys/param.h> +#include <sys/ucred.h> +#include <sys/mount.h> + +#include <rump/rump.h> +#include <rump/rump_syscalls.h> + +#include <assert.h> +#include <errno.h> +#include <stdlib.h> + +#define getvfsstat(a,b,c) rump_sys_getvfsstat(a,b,c) + +/* + * Return information about mounted filesystems. + */ +int +getmntinfo(mntbufp, flags) + struct statvfs **mntbufp; + int flags; +{ + static struct statvfs *mntbuf; + static int mntsize; + static size_t bufsize; + + _DIAGASSERT(mntbufp != NULL); + + if (mntsize <= 0 && + (mntsize = getvfsstat(NULL, (size_t)0, MNT_NOWAIT)) == -1) + return (0); + if (bufsize > 0 && + (mntsize = getvfsstat(mntbuf, bufsize, flags)) == -1) + return (0); + while (bufsize <= mntsize * sizeof(struct statvfs)) { + if (mntbuf) + free(mntbuf); + bufsize = (mntsize + 1) * sizeof(struct statvfs); + if ((mntbuf = malloc(bufsize)) == NULL) + return (0); + if ((mntsize = getvfsstat(mntbuf, bufsize, flags)) == -1) + return (0); + } + *mntbufp = mntbuf; + return (mntsize); +} diff --git a/contrib/netbsd-tests/fs/nfs/nfsservice/pathnames.h b/contrib/netbsd-tests/fs/nfs/nfsservice/pathnames.h new file mode 100644 index 000000000000..3985af93850b --- /dev/null +++ b/contrib/netbsd-tests/fs/nfs/nfsservice/pathnames.h @@ -0,0 +1,37 @@ +/* $NetBSD: pathnames.h,v 1.1 2010/07/26 15:53:00 pooka Exp $ */ + +/* + * Copyright (c) 1989, 1993 + * The Regents of the University of California. All rights reserved. + * + * 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. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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. + * + * @(#)pathnames.h 8.1 (Berkeley) 6/5/93 + */ + +#include <paths.h> + +#define _PATH_EXPORTS "/etc/exports" +#define _PATH_RMOUNTLIST "/var/db/mountdtab" diff --git a/contrib/netbsd-tests/fs/nfs/nfsservice/rumpnfsd.c b/contrib/netbsd-tests/fs/nfs/nfsservice/rumpnfsd.c new file mode 100644 index 000000000000..5f8e15250532 --- /dev/null +++ b/contrib/netbsd-tests/fs/nfs/nfsservice/rumpnfsd.c @@ -0,0 +1,166 @@ +/* $NetBSD: rumpnfsd.c,v 1.9 2015/11/08 02:45:16 christos Exp $ */ + +/*- + * Copyright (c) 2010 The NetBSD Foundation, Inc. + * + * 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 ``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. + */ + +#include <sys/types.h> + +#include <dlfcn.h> +#include <err.h> +#include <errno.h> +#include <pthread.h> +#include <semaphore.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <syslog.h> +#include <unistd.h> +#include <rpc/rpc.h> + +void *mountd_main(void *); +void *rpcbind_main(void *); +int nfsd_main(int, char **); + +sem_t gensem; + +#include "../../../net/config/netconfig.c" +#include "../../common/h_fsmacros.h" +#include "svc_fdset.h" + +#include <rump/rump.h> +#include <rump/rump_syscalls.h> + +int +main(int argc, char *argv[]) +{ + const char *ethername, *ethername_ro; + const char *serveraddr, *serveraddr_ro; + const char *netmask; + const char *exportpath; + const char *imagename; + char ifname[IFNAMSIZ], ifname_ro[IFNAMSIZ]; + void *fsarg; + pthread_t t; + int rv; + + /* for netcfg */ + noatf = 1; + + /* use defaults? */ + if (argc == 1) { + ethername = "etherbus"; + ethername_ro = "etherbus_ro"; + serveraddr = "10.3.2.1"; + serveraddr_ro = "10.4.2.1"; + netmask = "255.255.255.0"; + exportpath = "/myexport"; + imagename = "ffs.img"; + } else { + ethername = argv[1]; + ethername_ro = argv[2]; + serveraddr = argv[3]; + serveraddr_ro = argv[4]; + netmask = argv[5]; + exportpath = argv[6]; + imagename = argv[7]; + } + + rump_init(); + svc_fdset_init(SVC_FDSET_MT); + + rv = rump_pub_etfs_register("/etc/exports", "./exports", RUMP_ETFS_REG); + if (rv) { + errx(1, "register /etc/exports: %s", strerror(rv)); + } + + /* mini-mtree for mountd */ + static const char *const dirs[] = { "/var", "/var/run", "/var/db" }; + for (size_t i = 0; i < __arraycount(dirs); i++) + if (rump_sys_mkdir(dirs[i], 0777) == -1) + err(1, "can't mkdir `%s'", dirs[i]); + + if (ffs_fstest_newfs(NULL, &fsarg, + imagename, FSTEST_IMGSIZE, NULL) != 0) + err(1, "newfs failed"); + if (ffs_fstest_mount(NULL, fsarg, exportpath, 0) != 0) + err(1, "mount failed"); + +#if 0 + /* + * Serve from host instead of dedicated mount? + * THIS IS MORE EVIL THAN MURRAY THE DEMONIC TALKING SKULL! + */ + + if (ukfs_modload("/usr/lib/librumpfs_syspuffs.so") < 1) + errx(1, "modload"); + + mount_syspuffs_parseargs(__arraycount(pnullarg), pnullarg, + &args, &mntflags, canon_dev, canon_dir); + if ((ukfs = ukfs_mount(MOUNT_PUFFS, "/", UKFS_DEFAULTMP, MNT_RDONLY, + &args, sizeof(args))) == NULL) + err(1, "mount"); + + if (ukfs_modload("/usr/lib/librumpfs_nfsserver.so") < 1) + errx(1, "modload"); +#endif + + if (sem_init(&gensem, 1, 0) == -1) + err(1, "gensem init"); + + /* create interface */ + netcfg_rump_makeshmif(ethername, ifname); + netcfg_rump_if(ifname, serveraddr, netmask); + + netcfg_rump_makeshmif(ethername_ro, ifname_ro); + netcfg_rump_if(ifname_ro, serveraddr_ro, netmask); + + /* + * No syslogging, thanks. + * XXX: "0" does not modify the mask, so pick something + * which is unlikely to cause any logging + */ + setlogmask(0x10000000); + + if (pthread_create(&t, NULL, rpcbind_main, NULL) == -1) + err(1, "rpcbind"); + sem_wait(&gensem); + + if (pthread_create(&t, NULL, mountd_main, NULL) == -1) + err(1, "mountd"); + sem_wait(&gensem); + + rv = 0; + /* signal the other process we're almost done */ + if (write(3, &rv, 4) != 4) + errx(1, "magic write failed"); + + { + char *nfsargv[] = { __UNCONST("nfsd"), NULL }; + nfsd_main(1, nfsargv); + } + /*NOTREACHED*/ + + return 0; +} diff --git a/contrib/netbsd-tests/fs/nfs/t_mountd.c b/contrib/netbsd-tests/fs/nfs/t_mountd.c new file mode 100644 index 000000000000..6272587d71a0 --- /dev/null +++ b/contrib/netbsd-tests/fs/nfs/t_mountd.c @@ -0,0 +1,121 @@ +/* $NetBSD: t_mountd.c,v 1.6 2017/01/13 21:30:40 christos Exp $ */ + +/*- + * Copyright (c) 2010 The NetBSD Foundation, Inc. + * + * 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 ``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. + */ + +#include <sys/types.h> +#include <sys/mount.h> + +#include <atf-c.h> +#include <errno.h> +#include <fcntl.h> +#include <pthread.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> +#include <signal.h> + +#include <rump/rump.h> +#include <rump/rump_syscalls.h> + +#include "h_macros.h" +#include "../common/h_fsmacros.h" + +ATF_TC(mountdhup); +ATF_TC_HEAD(mountdhup, tc) +{ + + atf_tc_set_md_var(tc, "descr", "test for service interrupt while " + "mountd handles SIGHUP"); +} + +static volatile int quit; + +static void * +wrkwrkwrk(void *unused) +{ + int fd, fail; + + fail = 0; + + rump_sys_chdir(FSTEST_MNTNAME); + while (!quit) { + fd = rump_sys_open("file", O_RDWR | O_CREAT); + if (fd == -1) { + if (errno == EACCES) { + fail++; + break; + } + } + rump_sys_close(fd); + if (rump_sys_unlink("file") == -1) { + if (errno == EACCES) { + fail++; + break; + } + } + } + rump_sys_chdir("/"); + quit = 1; + + return fail ? wrkwrkwrk : NULL; +} + +ATF_TC_BODY(mountdhup, tc) +{ + pthread_t pt; + struct nfstestargs *nfsargs; + void *voidargs; + int attempts; + void *fail; + + FSTEST_CONSTRUCTOR(tc, nfs, voidargs); + nfsargs = voidargs; + + pthread_create(&pt, NULL, wrkwrkwrk, NULL); + for (attempts = 100; attempts && !quit; attempts--) { + usleep(100000); + kill(nfsargs->ta_childpid, SIGHUP); + } + quit = 1; + pthread_join(pt, &fail); + + FSTEST_DESTRUCTOR(tc, nfs, voidargs); + + atf_tc_expect_fail("PR kern/5844"); + if (fail) + atf_tc_fail("op failed with EACCES"); + else + atf_tc_fail("race did not trigger this time"); +} + +ATF_TP_ADD_TCS(tp) +{ + + ATF_TP_ADD_TC(tp, mountdhup); + + return atf_no_error(); +} diff --git a/contrib/netbsd-tests/fs/nfs/t_rquotad.sh b/contrib/netbsd-tests/fs/nfs/t_rquotad.sh new file mode 100755 index 000000000000..dc9226ce17cc --- /dev/null +++ b/contrib/netbsd-tests/fs/nfs/t_rquotad.sh @@ -0,0 +1,142 @@ +# $NetBSD: t_rquotad.sh,v 1.5 2016/08/10 23:25:39 kre Exp $ +# +# Copyright (c) 2011 Manuel Bouyer +# All rights reserved. +# +# 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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. +# +for e in le be; do + for v in 1; do + for q in "user" "group" "both"; do + test_case_root get_nfs_${e}_${v}_${q} get_nfs_quota \ + "get NFS quota with ${q} enabled" ${e} ${v} ${q} + done + done +done + +get_nfs_quota() +{ + create_ffs $* + local q=$3 + local expect + + case ${q} in + user) + expect=u + ;; + group) + expect=g + ;; + both) + expect="u g" + ;; + *) + atf_fail "wrong quota type" + ;; + esac + +#start a a nfs server + + atf_check -s exit:0 rump_server -lrumpvfs -lrumpdev -lrumpnet \ + -lrumpnet_net -lrumpnet_netinet -lrumpnet_netinet6 \ + -lrumpnet_local -lrumpnet_shmif -lrumpdev_disk -lrumpfs_ffs \ + -lrumpfs_nfs -lrumpfs_nfsserver \ + -d key=/dk,hostpath=${IMG},size=host ${RUMP_SERVER} + + atf_check -s exit:0 rump.ifconfig shmif0 create + atf_check -s exit:0 rump.ifconfig shmif0 linkstr shmbus + atf_check -s exit:0 rump.ifconfig shmif0 inet 10.1.1.1 + + export RUMPHIJACK_RETRYCONNECT=die + export LD_PRELOAD=/usr/lib/librumphijack.so + + atf_check -s exit:0 mkdir /rump/etc + atf_check -s exit:0 mkdir /rump/export + atf_check -s exit:0 mkdir -p /rump/var/run + atf_check -s exit:0 mkdir -p /rump/var/db + atf_check -s exit:0 touch /rump/var/db/mountdtab + + /bin/echo "/export -noresvport -noresvmnt 10.1.1.100" | \ + dd of=/rump/etc/exports 2> /dev/null + + atf_check -s exit:0 -e ignore mount_ffs /dk /rump/export + +#set a quota limit (and check that we can read it back) + for q in ${expect} ; do + local id=$(id -${q}) + atf_check -s exit:0 \ + env LD_PRELOAD=/usr/lib/librumphijack.so RUMPHIJACK=vfs=getvfsstat,blanket=/export edquota -$q -s10k/20 -h40M/50k \ + -t 2W/3D ${id} + atf_check -s exit:0 \ +-o "match:0 10 40960 2weeks 1 20 51200 3days" \ +-o "match:Disk quotas for .*: $" \ + env LD_PRELOAD=/usr/lib/librumphijack.so RUMPHIJACK=vfs=getvfsstat,blanket=/export quota -${q} -v + done + + # start rpcbind. we want /var/run/rpcbind.sock + export RUMPHIJACK='blanket=/var/run,socket=all' + atf_check -s exit:0 rpcbind + + # ok, then we want mountd in the similar fashion + export RUMPHIJACK='blanket=/var/run:/var/db:/export,socket=all,path=/rump,vfs=all' + atf_check -s exit:0 mountd /rump/etc/exports + + # and nfs + export RUMPHIJACK='blanket=/var/run,socket=all,vfs=all' + atf_check -s exit:0 nfsd + + #finally, rpc.rquotad + export RUMPHIJACK='blanket=/var/run:/export,vfs=getvfsstat,socket=all' + atf_check -s exit:0 /usr/libexec/rpc.rquotad + + # now start a client server + export RUMP_SERVER=unix://clientsock + RUMP_SOCKETS_LIST="${RUMP_SOCKETS_LIST} clientsock" + unset RUMPHIJACK + unset LD_PRELOAD + + atf_check -s exit:0 rump_server -lrumpvfs -lrumpnet -lrumpdev \ + -lrumpnet_net -lrumpnet_netinet -lrumpnet_shmif -lrumpfs_nfs\ + ${RUMP_SERVER} + + atf_check -s exit:0 rump.ifconfig shmif0 create + atf_check -s exit:0 rump.ifconfig shmif0 linkstr shmbus + atf_check -s exit:0 rump.ifconfig shmif0 inet 10.1.1.100 + + export LD_PRELOAD=/usr/lib/librumphijack.so + + atf_check -s exit:0 mkdir /rump/mnt + atf_check -s exit:0 mount_nfs 10.1.1.1:/export /rump/mnt + + #now try a quota(8) call + export RUMPHIJACK='blanket=/mnt,socket=all,path=/rump,vfs=getvfsstat' + for q in ${expect} ; do + local id=$(id -${q}) + atf_check -s exit:0 \ +-o "match:/mnt 0 10 40960 1 20 51200 " \ +-o "match:Disk quotas for .*: $" \ + quota -${q} -v + done + + unset LD_PRELOAD + rump_quota_shutdown +} diff --git a/contrib/netbsd-tests/fs/nullfs/t_basic.c b/contrib/netbsd-tests/fs/nullfs/t_basic.c new file mode 100644 index 000000000000..d54f7739bafc --- /dev/null +++ b/contrib/netbsd-tests/fs/nullfs/t_basic.c @@ -0,0 +1,174 @@ +/* $NetBSD: t_basic.c,v 1.4 2017/01/13 21:30:40 christos Exp $ */ + +#include <sys/types.h> +#include <sys/mount.h> + +#include <atf-c.h> +#include <err.h> +#include <errno.h> +#include <fcntl.h> +#include <stdio.h> +#include <unistd.h> +#include <string.h> +#include <stdlib.h> + +#include <rump/rump.h> +#include <rump/rump_syscalls.h> + +#include <miscfs/nullfs/null.h> +#include <fs/tmpfs/tmpfs_args.h> + +#include "h_macros.h" + +ATF_TC(basic); +ATF_TC_HEAD(basic, tc) +{ + atf_tc_set_md_var(tc, "descr", "basic nullfs functionality"); +} + +#define MSTR "magic bus" + +static void +xput_tfile(const char *path, const char *mstr) +{ + int fd; + + fd = rump_sys_open(path, O_CREAT | O_RDWR, 0777); + if (fd == -1) + atf_tc_fail_errno("create %s", path); + if (rump_sys_write(fd, MSTR, sizeof(MSTR)) != sizeof(MSTR)) + atf_tc_fail_errno("write to testfile"); + rump_sys_close(fd); +} + +static int +xread_tfile(const char *path, const char *mstr) +{ + char buf[128]; + int fd; + + fd = rump_sys_open(path, O_RDONLY); + if (fd == -1) + return errno; + if (rump_sys_read(fd, buf, sizeof(buf)) == -1) + atf_tc_fail_errno("read tfile"); + rump_sys_close(fd); + if (strcmp(buf, MSTR) == 0) + return 0; + return EPROGMISMATCH; +} + +static void +mountnull(const char *what, const char *mp, int flags) +{ + struct null_args nargs; + + memset(&nargs, 0, sizeof(nargs)); + nargs.nulla_target = __UNCONST(what); + if (rump_sys_mount(MOUNT_NULL, mp, flags, &nargs, sizeof(nargs)) == -1) + atf_tc_fail_errno("could not mount nullfs"); + +} + +ATF_TC_BODY(basic, tc) +{ + struct tmpfs_args targs; + struct stat sb; + int error; + + rump_init(); + if (rump_sys_mkdir("/td1", 0777) == -1) + atf_tc_fail_errno("mp1"); + if (rump_sys_mkdir("/td2", 0777) == -1) + atf_tc_fail_errno("mp1"); + + /* use tmpfs because rumpfs doesn't support regular files */ + memset(&targs, 0, sizeof(targs)); + targs.ta_version = TMPFS_ARGS_VERSION; + targs.ta_root_mode = 0777; + if (rump_sys_mount(MOUNT_TMPFS, "/td1", 0, &targs, sizeof(targs)) == -1) + atf_tc_fail_errno("could not mount tmpfs td1"); + + mountnull("/td1", "/td2", 0); + + /* test unnull -> null */ + xput_tfile("/td1/tensti", "jeppe"); + error = xread_tfile("/td2/tensti", "jeppe"); + if (error != 0) + atf_tc_fail("null compare failed: %d (%s)", + error, strerror(error)); + + /* test null -> unnull */ + xput_tfile("/td2/kiekko", "keppi"); + error = xread_tfile("/td1/kiekko", "keppi"); + if (error != 0) + atf_tc_fail("unnull compare failed: %d (%s)", + error, strerror(error)); + + /* test unnull -> null overwrite */ + xput_tfile("/td1/tensti", "se oolannin sota"); + error = xread_tfile("/td2/tensti", "se oolannin sota"); + if (error != 0) + atf_tc_fail("unnull compare failed: %d (%s)", + error, strerror(error)); + + /* test that /td2 is unaffected in "real life" */ + if (rump_sys_unmount("/td2", 0) == -1) + atf_tc_fail_errno("cannot unmount nullfs"); + if ((error = rump_sys_stat("/td2/tensti", &sb)) != -1 + || errno != ENOENT) { + atf_tc_fail("stat tensti should return ENOENT, got %d", error); + } + if ((error = rump_sys_stat("/td2/kiekko", &sb)) != -1 + || errno != ENOENT) { + atf_tc_fail("stat kiekko should return ENOENT, got %d", error); + } + + /* done */ +} + +ATF_TC(twistymount); +ATF_TC_HEAD(twistymount, tc) +{ + + /* this is expected to fail until the PR is fixed */ + atf_tc_set_md_var(tc, "descr", "\"recursive\" mounts deadlock" + " (kern/43439)"); +} + +/* + * Mapping to identifiers in kern/43439: + * /td = /home/current/pkgsrc + * /td/dist = /home/current/pkgsrc/distiles + * /mp = /usr/pkgsrc + * /mp/dist = /usr/pkgsrc/distfiles -- "created" by first null mount + */ + +ATF_TC_BODY(twistymount, tc) +{ + int mkd = 0; + + rump_init(); + + if (rump_sys_mkdir("/td", 0777) == -1) + atf_tc_fail_errno("mkdir %d", mkd++); + if (rump_sys_mkdir("/td/dist", 0777) == -1) + atf_tc_fail_errno("mkdir %d", mkd++); + if (rump_sys_mkdir("/mp", 0777) == -1) + atf_tc_fail_errno("mkdir %d", mkd++); + + /* MNT_RDONLY doesn't matter, but just for compat with the PR */ + mountnull("/td", "/mp", MNT_RDONLY); + mountnull("/td/dist", "/mp/dist", 0); + + /* if we didn't get a locking-against-meself panic, we passed */ +} + +ATF_TP_ADD_TCS(tp) +{ + + ATF_TP_ADD_TC(tp, basic); + ATF_TP_ADD_TC(tp, twistymount); + + return atf_no_error(); +} diff --git a/contrib/netbsd-tests/fs/psshfs/h_have_puffs.c b/contrib/netbsd-tests/fs/psshfs/h_have_puffs.c new file mode 100644 index 000000000000..9d349508ca97 --- /dev/null +++ b/contrib/netbsd-tests/fs/psshfs/h_have_puffs.c @@ -0,0 +1,58 @@ +/* $NetBSD: h_have_puffs.c,v 1.1 2010/07/06 14:06:22 pooka Exp $ */ +/* + * Copyright (c) 2007 The NetBSD Foundation, Inc. + * All rights reserved. + * + * 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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. + */ + +#include <errno.h> +#include <fcntl.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> + +int +main(void) +{ + int exitcode, fd; + + fd = open("/dev/puffs", O_RDWR); + if (fd != -1) { + printf("yes\n"); + close(fd); + exitcode = EXIT_SUCCESS; + } else { + if (errno == ENXIO) { + printf("enxio\n"); + exitcode = EXIT_SUCCESS; + } else if (errno == EACCES) { + printf("eacces\n"); + exitcode = EXIT_SUCCESS; + } else { + printf("failed\n"); + exitcode = EXIT_FAILURE; + } + } + + return exitcode; +} diff --git a/contrib/netbsd-tests/fs/psshfs/ssh_config.in b/contrib/netbsd-tests/fs/psshfs/ssh_config.in new file mode 100644 index 000000000000..3ebd68b3fdac --- /dev/null +++ b/contrib/netbsd-tests/fs/psshfs/ssh_config.in @@ -0,0 +1,14 @@ +# $NetBSD: ssh_config.in,v 1.1 2010/07/06 14:06:22 pooka Exp $ + +# Basic settings. +Port 10000 +Protocol 2 + +# The temporary key used for login. +IdentityFile @WORKDIR@/ssh_user_key + +# Prevent the client from complaining about unknown host keys. +GlobalKnownHostsFile @WORKDIR@/known_hosts + +# Do not attempt password authentication in case keys fail. +IdentitiesOnly yes diff --git a/contrib/netbsd-tests/fs/psshfs/ssh_host_key b/contrib/netbsd-tests/fs/psshfs/ssh_host_key new file mode 100644 index 000000000000..ebdbc8b44171 --- /dev/null +++ b/contrib/netbsd-tests/fs/psshfs/ssh_host_key @@ -0,0 +1,15 @@ +-----BEGIN RSA PRIVATE KEY----- +MIICWwIBAAKBgQDJnMpSG1lGmApk8F7ZH7TGtjjP/WUs+vqHyFsyS2lilJzereen +a/ME6S0d0HTOeCdKldjbtDpfNXbh+XnJMlJMEgEs4Mg1jluuEV0GOJoMt7cGzku2 +gAYGx++2+wqYw6Y+M8Tb1M4AO+PcxD/3BkdUyIKO63v6STl2VQn1BzsTQwIBIwKB +gAuFTWPHDGpvFols0jhK9GMgWwSSIwnidLdNRwowMehgQ3pwVmFWoCwqlN0h2sn4 +PMJu9nL0WxtiJAzprzARgQuPI25t9LiKTF7scC/cNUiHPplUjvoDXA9ccY1eIf4R +e6wwZz1jfCWen0eRsvMyoYvFmEH8hILAk1bY9heymOGLAkEA/WhC49n+gtloVMow +iKQOO6+u3ouxTOTQ3sV2wCaLaO2pEbHP2//5SlUJLp6QrjC7bg9Kr+f56+zT2he9 +f6GCwwJBAMus3XizmZdJyJLnkCJRiT0/3Kf57fhWKRdnFkuRLyjET9MEWavRdJmr +bx/lxmILi1iKwXiFEDM6MqYfmNImJYECQQCtw9YYlXtSaTGZOi/oqwJyEhGCqO6b +II85q/moVPHhjQY4BOZNttbT4on0FPV+wlSjPa+OkHDcSp/mAaaDZ2+bAkEAujel +6rLVkaKLfv+ZuPoXE22WivMityo0Mqdk12ArHfVQS+a4YpOdzlOYzLTSosi56o19 +sAShGOTAl+Jf1hQ/iwJAKpPviX5w292H/m5T0m4l0NRdQ3pRujOLMSVmY+/HFZTW +GJMYLr1eBKNfLsKzJgB88GzuF2O/O8hNi3XSiOP+9w== +-----END RSA PRIVATE KEY----- diff --git a/contrib/netbsd-tests/fs/psshfs/ssh_host_key.pub b/contrib/netbsd-tests/fs/psshfs/ssh_host_key.pub new file mode 100644 index 000000000000..8d087959c4ab --- /dev/null +++ b/contrib/netbsd-tests/fs/psshfs/ssh_host_key.pub @@ -0,0 +1 @@ +ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAIEAyZzKUhtZRpgKZPBe2R+0xrY4z/1lLPr6h8hbMktpYpSc3q3np2vzBOktHdB0zngnSpXY27Q6XzV24fl5yTJSTBIBLODINY5brhFdBjiaDLe3Bs5LtoAGBsfvtvsKmMOmPjPE29TOADvj3MQ/9wZHVMiCjut7+kk5dlUJ9Qc7E0M= test@test.example.net diff --git a/contrib/netbsd-tests/fs/psshfs/sshd_config.in b/contrib/netbsd-tests/fs/psshfs/sshd_config.in new file mode 100644 index 000000000000..a7f86b1d3388 --- /dev/null +++ b/contrib/netbsd-tests/fs/psshfs/sshd_config.in @@ -0,0 +1,40 @@ +# $NetBSD: sshd_config.in,v 1.2 2011/02/11 13:19:46 pooka Exp $ + +# Basic settings. +Port 10000 +Protocol 2 + +# Provide information to the user in case something goes wrong. +LogLevel DEBUG1 + +# The host key. It lives in the work directory because we need to set +# very strict permissions on it and cannot modify the copy on the source +# directory. +HostKey @WORKDIR@/ssh_host_key + +# The authorized keys file we set up during the test to allow the client +# to safely log in. We need to disable strict modes because ATF_WORKDIR +# usually lives in /tmp, which has 1777 permissions and are not liked by +# sshd. +AuthorizedKeysFile @WORKDIR@/authorized_keys +StrictModes no + +# Some settings to allow user runs of sshd. +PidFile @WORKDIR@/sshd.pid +Subsystem sftp @WORKDIR@/sftp-server +UsePam no +UsePrivilegeSeparation no + +# The root user should also be able to run the tests. +PermitRootLogin yes + +# Be restrictive about access to the temporary server. Only allow key-based +# authentication. +ChallengeResponseAuthentication no +GSSAPIAuthentication no +HostbasedAuthentication no +KerberosAuthentication no +MaxAuthTries 1 +MaxStartups 1 +PasswordAuthentication no +PubkeyAuthentication yes diff --git a/contrib/netbsd-tests/fs/psshfs/t_psshfs.sh b/contrib/netbsd-tests/fs/psshfs/t_psshfs.sh new file mode 100755 index 000000000000..4d8fede15494 --- /dev/null +++ b/contrib/netbsd-tests/fs/psshfs/t_psshfs.sh @@ -0,0 +1,295 @@ +# $NetBSD: t_psshfs.sh,v 1.8 2016/09/05 08:53:57 christos Exp $ +# +# Copyright (c) 2007, 2008 The NetBSD Foundation, Inc. +# All rights reserved. +# +# 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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. +# + +# ------------------------------------------------------------------------- +# Auxiliary functions. +# ------------------------------------------------------------------------- + +# +# Skips the calling test case if puffs is not supported in the kernel +# or if the calling user does not have the necessary permissions to mount +# file systems. +# +require_puffs() { + case "$($(atf_get_srcdir)/h_have_puffs)" in + eacces) + atf_skip "Cannot open /dev/puffs for read/write access" + ;; + enxio) + atf_skip "puffs support not built into the kernel" + ;; + failed) + atf_skip "Unknown error trying to access /dev/puffs" + ;; + yes) + ;; + *) + atf_fail "Unknown value returned by h_have_puffs" + ;; + esac + + if [ $(id -u) -ne 0 -a $(sysctl -n vfs.generic.usermount) -eq 0 ] + then + atf_skip "Regular users cannot mount file systems" \ + "(vfs.generic.usermount is set to 0)" + fi +} + +# +# Starts a SSH server and sets up the client to access it. +# Authentication is allowed and done using an RSA key exclusively, which +# is generated on the fly as part of the test case. +# XXX: Ideally, all the tests in this test program should be able to share +# the generated key, because creating it can be a very slow process on some +# machines. +# +start_ssh() { + echo "Setting up SSH server configuration" + sed -e "s,@SRCDIR@,$(atf_get_srcdir),g" -e "s,@WORKDIR@,$(pwd),g" \ + $(atf_get_srcdir)/sshd_config.in >sshd_config || \ + atf_fail "Failed to create sshd_config" + atf_check -s eq:0 -o empty -e empty cp /usr/libexec/sftp-server . + atf_check -s eq:0 -o empty -e empty \ + cp $(atf_get_srcdir)/ssh_host_key . + atf_check -s eq:0 -o empty -e empty \ + cp $(atf_get_srcdir)/ssh_host_key.pub . + atf_check -s eq:0 -o empty -e empty chmod 400 ssh_host_key + atf_check -s eq:0 -o empty -e empty chmod 444 ssh_host_key.pub + + /usr/sbin/sshd -e -f ./sshd_config >sshd.log 2>&1 & + while [ ! -f sshd.pid ]; do + sleep 0.01 + done + echo "SSH server started (pid $(cat sshd.pid))" + + echo "Setting up SSH client configuration" + atf_check -s eq:0 -o empty -e empty \ + ssh-keygen -f ssh_user_key -t rsa -b 1024 -N "" -q + atf_check -s eq:0 -o empty -e empty \ + cp ssh_user_key.pub authorized_keys + echo "[localhost]:10000,[127.0.0.1]:10000,[::1]:10000" \ + "$(cat $(atf_get_srcdir)/ssh_host_key.pub)" >known_hosts || \ + atf_fail "Failed to create known_hosts" + atf_check -s eq:0 -o empty -e empty chmod 600 authorized_keys + sed -e "s,@SRCDIR@,$(atf_get_srcdir),g" -e "s,@WORKDIR@,$(pwd),g" \ + $(atf_get_srcdir)/ssh_config.in >ssh_config || \ + atf_fail "Failed to create ssh_config" +} + +# +# Stops the SSH server spawned by start_ssh and prints diagnosis data. +# +stop_ssh() { + if [ -f sshd.pid ]; then + echo "Stopping SSH server (pid $(cat sshd.pid))" + kill $(cat sshd.pid) + fi + if [ -f sshd.log ]; then + echo "Server output was:" + sed -e 's,^, ,' sshd.log + fi +} + +# +# Mounts the given source directory on the target directory using psshfs. +# Both directories are supposed to live on the current directory. +# +mount_psshfs() { + atf_check -s eq:0 -o empty -e empty \ + mount -t psshfs -o -F=$(pwd)/ssh_config localhost:$(pwd)/${1} ${2} +} + +# ------------------------------------------------------------------------- +# The test cases. +# ------------------------------------------------------------------------- + +atf_test_case inode_nos cleanup +inode_nos_head() { + atf_set "descr" "Checks that different files get different inode" \ + "numbers" +} +inode_nos_body() { + require_puffs + + start_ssh + + mkdir root + mkdir root/dir + touch root/dir/file1 + touch root/dir/file2 + touch root/file3 + touch root/file4 + + cat >ne_inodes.sh <<EOF +#! /bin/sh +# +# Compares the inodes of the two given files and returns true if they are +# different; false otherwise. +# +set -e +ino1=\$(stat -f %i \${1}) +ino2=\$(stat -f %i \${2}) +test \${ino1} -ne \${ino2} +EOF + chmod +x ne_inodes.sh + + mkdir mnt + mount_psshfs root mnt + atf_check -s eq:0 -o empty -e empty \ + ./ne_inodes.sh root/dir root/dir/file1 + atf_check -s eq:0 -o empty -e empty \ + ./ne_inodes.sh root/dir root/dir/file2 + atf_check -s eq:0 -o empty -e empty \ + ./ne_inodes.sh root/dir/file1 root/dir/file2 + atf_check -s eq:0 -o empty -e empty \ + ./ne_inodes.sh root/file3 root/file4 +} +inode_nos_cleanup() { + umount mnt + stop_ssh +} + +atf_test_case pwd cleanup +pwd_head() { + atf_set "descr" "Checks that pwd works correctly" +} +pwd_body() { + require_puffs + + start_ssh + + mkdir root + mkdir root/dir + + mkdir mnt + atf_check -s eq:0 -o save:stdout -e empty \ + -x 'echo $(cd mnt && /bin/pwd)/dir' + mv stdout expout + mount_psshfs root mnt + atf_check -s eq:0 -o file:expout -e empty \ + -x 'cd mnt/dir && ls .. >/dev/null && /bin/pwd' +} +pwd_cleanup() { + umount mnt + stop_ssh +} + +atf_test_case ls cleanup +ls_head() { + atf_set "descr" "Uses ls, attempts to exercise puffs_cc" +} +ls_body() { + require_puffs + + start_ssh + + mkdir mnt + mkdir root + mkdir root/dir + touch root/dir/file1 + touch root/dir/file2 + touch root/file3 + touch root/file4 + + mount_psshfs root mnt + + ls -l mnt & + + IFS=' ' +lsout='dir +file3 +file4 + +mnt/dir: +file1 +file2 +' + atf_check -s exit:0 -o inline:"$lsout" ls -R mnt +} +ls_cleanup() { + umount mnt + stop_ssh +} + +atf_test_case setattr_cache cleanup +setattr_cache_head() { + atf_set "descr" "Checks that setattr caches" + # Don't wait for the eternity that atf usually waits. Twenty + # seconds should be good enough, except maybe on a VAX... + atf_set "timeout" 20 +} +setattr_cache_body() { + require_puffs + start_ssh + atf_check -s exit:0 mkdir root + atf_check -s exit:0 mkdir mnt + mount_psshfs root mnt + atf_check -s exit:0 -x ': > mnt/loser' + atf_check -s exit:0 -o save:stat stat mnt/loser + # Oops -- this doesn't work. We need to stop the child of the + # sshd that is handling the sftp session. + atf_check -s exit:0 kill -STOP $(cat sshd.pid) + atf_check -s exit:0 -x ': > mnt/loser' + atf_check -s exit:0 -o file:stat stat mnt/loser +} +setattr_cache_cleanup() { + umount mnt + kill -CONT $(cat sshd.pid) + stop_ssh +} + +atf_test_case read_empty_file cleanup +read_empty_file_head() { + atf_set "descr" "Checks whether an empty file can be read" + # This test is supposed to make sure psshfs does not hang + # when reading from an empty file, hence the timeout. + atf_set "timeout" 8 +} +read_empty_file_body() { + require_puffs + start_ssh + atf_check mkdir root mnt + atf_check -x ': > root/empty' + mount_psshfs root mnt + atf_check cat mnt/empty +} +read_empty_file_cleanup() { + umount mnt + stop_ssh +} + +# ------------------------------------------------------------------------- +# Initialization. +# ------------------------------------------------------------------------- + +atf_init_test_cases() { + atf_add_test_case inode_nos + atf_add_test_case pwd + atf_add_test_case ls + #atf_add_test_case setattr_cache + atf_add_test_case read_empty_file +} diff --git a/contrib/netbsd-tests/fs/ptyfs/t_nullpts.c b/contrib/netbsd-tests/fs/ptyfs/t_nullpts.c new file mode 100644 index 000000000000..fcc7e47f6215 --- /dev/null +++ b/contrib/netbsd-tests/fs/ptyfs/t_nullpts.c @@ -0,0 +1,128 @@ +/* $NetBSD: t_nullpts.c,v 1.6 2017/01/13 21:30:40 christos Exp $ */ + +#include <sys/types.h> +#include <sys/mount.h> +#include <sys/ioctl.h> + +#include <atf-c.h> +#include <err.h> +#include <errno.h> +#include <fcntl.h> +#include <stdio.h> +#include <unistd.h> +#include <string.h> +#include <stdlib.h> + +#include <rump/rump.h> +#include <rump/rump_syscalls.h> + +#include <fs/ptyfs/ptyfs.h> +#include <miscfs/nullfs/null.h> + +#include "h_macros.h" + +static void +mountptyfs(const char *mp, int flags) +{ + struct ptyfs_args args; + + if (rump_sys_mkdir(mp, 0777) == -1) { + if (errno != EEXIST) + atf_tc_fail_errno("null create %s", mp); + } + memset(&args, 0, sizeof(args)); + args.version = PTYFS_ARGSVERSION; + args.mode = 0777; + if (rump_sys_mount(MOUNT_PTYFS, mp, flags, &args, sizeof(args)) == -1) + atf_tc_fail_errno("could not mount ptyfs"); +} + +static void +mountnull(const char *what, const char *mp, int flags) +{ + struct null_args nargs; + + if (rump_sys_mkdir(what, 0777) == -1) { + if (errno != EEXIST) + atf_tc_fail_errno("null create %s", what); + } + if (rump_sys_mkdir(mp, 0777) == -1) { + if (errno != EEXIST) + atf_tc_fail_errno("null create %s", mp); + } + memset(&nargs, 0, sizeof(nargs)); + nargs.nulla_target = __UNCONST(what); + if (rump_sys_mount(MOUNT_NULL, mp, flags, &nargs, sizeof(nargs)) == -1) + atf_tc_fail_errno("could not mount nullfs"); +} + +ATF_TC(nullrevoke); +ATF_TC_HEAD(nullrevoke, tc) +{ + atf_tc_set_md_var(tc, "descr", "null mount ptyfs and revoke"); +} + +ATF_TC_BODY(nullrevoke, tc) +{ + char path[MAXPATHLEN]; + struct ptmget ptg; + int ptm; + + rump_init(); + + /* + * mount /dev/pts + */ + mountptyfs("/dev/pts", 0); + + /* + * null mount /dev/pts to /null/dev/pts + */ + if (rump_sys_mkdir("/null", 0777) == -1) { + if (errno != EEXIST) + atf_tc_fail_errno("null create /null"); + } + if (rump_sys_mkdir("/null/dev", 0777) == -1) { + if (errno != EEXIST) + atf_tc_fail_errno("null create /null/dev"); + } + + mountnull("/dev/pts", "/null/dev/pts", 0); + + /* + * get slave/master pair. + */ + ptm = rump_sys_open("/dev/ptm", O_RDWR); + if (rump_sys_ioctl(ptm, TIOCPTMGET, &ptg) == -1) + atf_tc_fail_errno("get pty"); + + /* + * Build nullfs path to slave. + */ + strcpy(path, "/null"); + strcat(path, ptg.sn); + + /* + * Open slave tty via nullfs. + */ + if (rump_sys_open(path, O_RDWR) == -1) + atf_tc_fail_errno("slave null open"); + + /* + * Close slave opened with /dev/ptm. Need purely non-null refs to it. + */ + rump_sys_close(ptg.sfd); + + /* revoke slave tty. */ + rump_sys_revoke(path); + + /* done */ +} + +ATF_TP_ADD_TCS(tp) +{ + + ATF_TP_ADD_TC(tp, nullrevoke); + + return atf_no_error(); +} diff --git a/contrib/netbsd-tests/fs/ptyfs/t_ptyfs.c b/contrib/netbsd-tests/fs/ptyfs/t_ptyfs.c new file mode 100644 index 000000000000..108c344c343c --- /dev/null +++ b/contrib/netbsd-tests/fs/ptyfs/t_ptyfs.c @@ -0,0 +1,62 @@ +/* $NetBSD: t_ptyfs.c,v 1.2 2017/01/13 21:30:40 christos Exp $ */ + +#include <sys/types.h> +#include <sys/mount.h> + +#include <atf-c.h> +#include <err.h> +#include <errno.h> +#include <fcntl.h> +#include <stdio.h> +#include <unistd.h> +#include <string.h> +#include <stdlib.h> + +#include <rump/rump.h> +#include <rump/rump_syscalls.h> + +#include <fs/ptyfs/ptyfs.h> + +#include "h_macros.h" + +static void +mountptyfs(const char *mp, int flags) +{ + struct ptyfs_args args; + + if (rump_sys_mkdir("/mp", 0777) == -1) { + if (errno != EEXIST) + atf_tc_fail_errno("mp1"); + } + memset(&args, 0, sizeof(args)); + args.version = PTYFS_ARGSVERSION; + args.mode = 0777; + if (rump_sys_mount(MOUNT_PTYFS, mp, flags, &args, sizeof(args)) == -1) + atf_tc_fail_errno("could not mount ptyfs"); +} + +ATF_TC(basic); +ATF_TC_HEAD(basic, tc) +{ + atf_tc_set_md_var(tc, "descr", "mount ptyfs"); +} + +ATF_TC_BODY(basic, tc) +{ + + rump_init(); + + mountptyfs("/mp", 0); + if (rump_sys_unmount("/mp", 0) == -1) + atf_tc_fail_errno("unmount failed"); + + /* done */ +} + +ATF_TP_ADD_TCS(tp) +{ + + ATF_TP_ADD_TC(tp, basic); + + return atf_no_error(); +} diff --git a/contrib/netbsd-tests/fs/puffs/h_dtfs/dtfs.c b/contrib/netbsd-tests/fs/puffs/h_dtfs/dtfs.c new file mode 100644 index 000000000000..c625f90ab24b --- /dev/null +++ b/contrib/netbsd-tests/fs/puffs/h_dtfs/dtfs.c @@ -0,0 +1,255 @@ +/* $NetBSD: dtfs.c,v 1.2 2010/07/21 06:58:25 pooka Exp $ */ + +/* + * Copyright (c) 2006 Antti Kantee. All Rights Reserved. + * + * 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 ``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. + */ + +/* + * Delectable Test File System: a simple in-memory file system which + * demonstrates the use of puffs. + * (a.k.a. Detrempe FS ...) + */ + +#include <sys/types.h> + +#include <err.h> +#include <mntopts.h> +#include <paths.h> +#include <puffs.h> +#include <signal.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +#include "dtfs.h" + +#ifdef DEEP_ROOTED_CLUE +#define FSNAME "detrempe" +#else +#define FSNAME "dt" +#endif +#define MAXREQMAGIC -37 + +static struct puffs_usermount *gpu; +static struct dtfs_mount gdtm; +int dynamicfh; +int straightflush; + +static void usage(void); + +static void +usage() +{ + + fprintf(stderr, "usage: %s [-bsdftl] [-c hashbuckets] [-m maxreqsize] " + "[-n typename]\n [-o mntopt] [-o puffsopt] [-p prot] " + "[-r rootnodetype]\n detrempe /mountpoint\n", getprogname()); + exit(1); +} + +static void +wipe_the_sleep_out_of_my_eyes(int v) +{ + + gdtm.dtm_needwakeup++; +} + +static void +loopfun(struct puffs_usermount *pu) +{ + struct dtfs_mount *dtm = puffs_getspecific(pu); + struct dtfs_poll *dp; + + while (dtm->dtm_needwakeup) { + dtm->dtm_needwakeup--; + dp = LIST_FIRST(&dtm->dtm_pollent); + if (dp == NULL) + return; + + LIST_REMOVE(dp, dp_entries); + puffs_cc_continue(dp->dp_pcc); + } +} + +int +main(int argc, char *argv[]) +{ + extern char *optarg; + extern int optind; + struct puffs_usermount *pu; + struct puffs_pathobj *po_root; + struct puffs_ops *pops; + struct timespec ts; + const char *typename; + char *rtstr; + mntoptparse_t mp; + int pflags, detach, mntflags; + int ch; + int khashbuckets; + int maxreqsize; + + setprogname(argv[0]); + + rtstr = NULL; + detach = 1; + mntflags = 0; + khashbuckets = 256; + pflags = PUFFS_KFLAG_IAONDEMAND; + typename = FSNAME; + maxreqsize = MAXREQMAGIC; + gdtm.dtm_allowprot = VM_PROT_ALL; + while ((ch = getopt(argc, argv, "bc:dfilm:n:o:p:r:st")) != -1) { + switch (ch) { + case 'b': /* build paths, for debugging the feature */ + pflags |= PUFFS_FLAG_BUILDPATH; + break; + case 'c': + khashbuckets = atoi(optarg); + break; + case 'd': + dynamicfh = 1; + break; + case 'f': + pflags |= PUFFS_KFLAG_LOOKUP_FULLPNBUF; + break; + case 'i': + pflags &= ~PUFFS_KFLAG_IAONDEMAND; + break; + case 'l': + straightflush = 1; + break; + case 'm': + maxreqsize = atoi(optarg); + break; + case 'n': + typename = optarg; + break; + case 'o': + mp = getmntopts(optarg, puffsmopts, &mntflags, &pflags); + if (mp == NULL) + err(1, "getmntopts"); + freemntopts(mp); + break; + case 'p': + gdtm.dtm_allowprot = atoi(optarg); + if ((gdtm.dtm_allowprot | VM_PROT_ALL) != VM_PROT_ALL) + usage(); + break; + case 'r': + rtstr = optarg; + break; + case 's': /* stay on top */ + detach = 0; + break; + case 't': + pflags |= PUFFS_KFLAG_WTCACHE; + break; + default: + usage(); + /*NOTREACHED*/ + } + } + if (pflags & PUFFS_FLAG_OPDUMP) + detach = 0; + argc -= optind; + argv += optind; + + if (argc != 2) + usage(); + + PUFFSOP_INIT(pops); + + PUFFSOP_SET(pops, dtfs, fs, statvfs); + PUFFSOP_SET(pops, dtfs, fs, unmount); + PUFFSOP_SETFSNOP(pops, sync); + PUFFSOP_SET(pops, dtfs, fs, fhtonode); + PUFFSOP_SET(pops, dtfs, fs, nodetofh); + + PUFFSOP_SET(pops, dtfs, node, lookup); + PUFFSOP_SET(pops, dtfs, node, access); + PUFFSOP_SET(pops, puffs_genfs, node, getattr); + PUFFSOP_SET(pops, dtfs, node, setattr); + PUFFSOP_SET(pops, dtfs, node, create); + PUFFSOP_SET(pops, dtfs, node, remove); + PUFFSOP_SET(pops, dtfs, node, readdir); + PUFFSOP_SET(pops, dtfs, node, poll); + PUFFSOP_SET(pops, dtfs, node, mmap); + PUFFSOP_SET(pops, dtfs, node, mkdir); + PUFFSOP_SET(pops, dtfs, node, rmdir); + PUFFSOP_SET(pops, dtfs, node, rename); + PUFFSOP_SET(pops, dtfs, node, read); + PUFFSOP_SET(pops, dtfs, node, write); + PUFFSOP_SET(pops, dtfs, node, link); + PUFFSOP_SET(pops, dtfs, node, symlink); + PUFFSOP_SET(pops, dtfs, node, readlink); + PUFFSOP_SET(pops, dtfs, node, mknod); + PUFFSOP_SET(pops, dtfs, node, inactive); + PUFFSOP_SET(pops, dtfs, node, pathconf); + PUFFSOP_SET(pops, dtfs, node, reclaim); + + srandom(time(NULL)); /* for random generation numbers */ + + pu = puffs_init(pops, _PATH_PUFFS, typename, &gdtm, pflags); + if (pu == NULL) + err(1, "init"); + gpu = pu; + + puffs_setfhsize(pu, sizeof(struct dtfs_fid), + PUFFS_FHFLAG_NFSV2 | PUFFS_FHFLAG_NFSV3 + | (dynamicfh ? PUFFS_FHFLAG_DYNAMIC : 0)); + puffs_setncookiehash(pu, khashbuckets); + + if (signal(SIGALRM, wipe_the_sleep_out_of_my_eyes) == SIG_ERR) + warn("cannot set alarm sighandler"); + + /* init */ + if (dtfs_domount(pu, rtstr) != 0) + errx(1, "dtfs_domount failed"); + + po_root = puffs_getrootpathobj(pu); + po_root->po_path = argv[0]; + po_root->po_len = strlen(argv[0]); + + /* often enough for testing poll */ + ts.tv_sec = 1; + ts.tv_nsec = 0; + puffs_ml_setloopfn(pu, loopfun); + puffs_ml_settimeout(pu, &ts); + + if (maxreqsize != MAXREQMAGIC) + puffs_setmaxreqlen(pu, maxreqsize); + + puffs_set_errnotify(pu, puffs_kernerr_abort); + if (detach) + if (puffs_daemon(pu, 1, 1) == -1) + err(1, "puffs_daemon"); + + if (puffs_mount(pu, argv[1], mntflags, puffs_getroot(pu)) == -1) + err(1, "mount"); + if (puffs_mainloop(pu) == -1) + err(1, "mainloop"); + + return 0; +} diff --git a/contrib/netbsd-tests/fs/puffs/h_dtfs/dtfs.h b/contrib/netbsd-tests/fs/puffs/h_dtfs/dtfs.h new file mode 100644 index 000000000000..de4d9589e5e1 --- /dev/null +++ b/contrib/netbsd-tests/fs/puffs/h_dtfs/dtfs.h @@ -0,0 +1,127 @@ +/* $NetBSD: dtfs.h,v 1.2 2010/07/14 13:09:52 pooka Exp $ */ + +/* + * Copyright (c) 2006 Antti Kantee. All Rights Reserved. + * + * 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 ``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. + */ + +#ifndef DTFS_H_ +#define DTFS_H_ + +#include <sys/types.h> + +#include <puffs.h> + +PUFFSOP_PROTOS(dtfs); +int dtfs_domount(struct puffs_usermount *, const char *); + +#define DTFS_BLOCKSHIFT (12) +#define DTFS_BLOCKSIZE (1<<DTFS_BLOCKSHIFT) + +#define ROUNDUP(a,b) ((a) & ((b)-1)) +#define BLOCKNUM(a,b) (((a) & ~((1<<(b))-1)) >> (b)) + +struct dtfs_fid; +struct dtfs_mount { + ino_t dtm_nextfileid; /* running number for file id */ + + size_t dtm_fsizes; /* sum of file sizes in bytes */ + fsfilcnt_t dtm_nfiles; /* number of files */ + + LIST_HEAD(, dtfs_poll) dtm_pollent; + int dtm_needwakeup; + vm_prot_t dtm_allowprot; +}; + +struct dtfs_file { + union { + struct { + uint8_t **blocks; + size_t numblocks; + size_t datalen; + } reg; + struct { + struct puffs_node *dotdot; + LIST_HEAD(, dtfs_dirent) dirents; + } dir; + struct { + char *target; + } link; + } u; +#define df_blocks u.reg.blocks +#define df_numblocks u.reg.numblocks +#define df_datalen u.reg.datalen +#define df_dotdot u.dir.dotdot +#define df_dirents u.dir.dirents +#define df_linktarget u.link.target +}; + +struct dtfs_dirent { + struct puffs_node *dfd_node; + struct puffs_node *dfd_parent; + char *dfd_name; + size_t dfd_namelen; + + LIST_ENTRY(dtfs_dirent) dfd_entries; +}; + +struct dtfs_fid { + struct puffs_node *dfid_addr; + + /* best^Wsome-effort extra sanity check */ + ino_t dfid_fileid; + u_long dfid_gen; +}; +#define DTFS_FIDSIZE (sizeof(struct dtfs_fid)) + +struct dtfs_poll { + struct puffs_cc *dp_pcc; + LIST_ENTRY(dtfs_poll) dp_entries; +}; + +struct puffs_node * dtfs_genfile(struct puffs_node *, + const struct puffs_cn *, enum vtype); +struct dtfs_file * dtfs_newdir(void); +struct dtfs_file * dtfs_newfile(void); +struct dtfs_dirent * dtfs_dirgetnth(struct dtfs_file *, int); +struct dtfs_dirent * dtfs_dirgetbyname(struct dtfs_file *, + const char *, size_t); + +void dtfs_nukenode(struct puffs_node *, struct puffs_node *, + const char *, size_t); +void dtfs_freenode(struct puffs_node *); +void dtfs_setsize(struct puffs_node *, off_t); + +void dtfs_adddent(struct puffs_node *, struct dtfs_dirent *); +void dtfs_removedent(struct puffs_node *, struct dtfs_dirent *); + +void dtfs_baseattrs(struct vattr *, enum vtype, ino_t); +void dtfs_updatetimes(struct puffs_node *, int, int, int); + +bool dtfs_isunder(struct puffs_node *, struct puffs_node *); + + +#define DTFS_CTOF(a) ((struct dtfs_file *)(((struct puffs_node *)a)->pn_data)) +#define DTFS_PTOF(a) ((struct dtfs_file *)(a->pn_data)) + +#endif /* DTFS_H_ */ diff --git a/contrib/netbsd-tests/fs/puffs/h_dtfs/dtfs_subr.c b/contrib/netbsd-tests/fs/puffs/h_dtfs/dtfs_subr.c new file mode 100644 index 000000000000..fcb817680b91 --- /dev/null +++ b/contrib/netbsd-tests/fs/puffs/h_dtfs/dtfs_subr.c @@ -0,0 +1,358 @@ +/* $NetBSD: dtfs_subr.c,v 1.4 2013/10/19 17:45:00 christos Exp $ */ + +/* + * Copyright (c) 2006 Antti Kantee. All Rights Reserved. + * + * 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 ``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. + */ + +#include <sys/types.h> +#include <sys/time.h> + +#include <assert.h> +#include <err.h> +#include <errno.h> +#include <puffs.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <util.h> + +#include "dtfs.h" + +void +dtfs_baseattrs(struct vattr *vap, enum vtype type, ino_t id) +{ + struct timeval tv; + struct timespec ts; + + gettimeofday(&tv, NULL); + TIMEVAL_TO_TIMESPEC(&tv, &ts); + + vap->va_type = type; + if (type == VDIR) { + vap->va_mode = 0777; + vap->va_nlink = 1; /* n + 1 after adding dent */ + } else { + vap->va_mode = 0666; + vap->va_nlink = 0; /* n + 1 */ + } + vap->va_uid = 0; + vap->va_gid = 0; + vap->va_fileid = id; + vap->va_size = 0; + vap->va_blocksize = getpagesize(); + vap->va_gen = random(); + vap->va_flags = 0; + vap->va_rdev = PUFFS_VNOVAL; + vap->va_bytes = 0; + vap->va_filerev = 1; + vap->va_vaflags = 0; + + vap->va_atime = vap->va_mtime = vap->va_ctime = vap->va_birthtime = ts; +} + +/* + * Well, as you can probably see, this interface has the slight problem + * of assuming file creation will always be succesful, or at least not + * giving a reason for the failure. Be sure to do better when you + * implement your own fs. + */ +struct puffs_node * +dtfs_genfile(struct puffs_node *dir, const struct puffs_cn *pcn, + enum vtype type) +{ + struct dtfs_file *dff; + struct dtfs_dirent *dfd; + struct dtfs_mount *dtm; + struct puffs_node *newpn; + uid_t uid; + int rv; + + assert(dir->pn_va.va_type == VDIR); + assert(dir->pn_mnt != NULL); + + uid = 0; + rv = puffs_cred_getuid(pcn->pcn_cred, &uid); + assert(rv == 0); + + if (type == VDIR) { + dff = dtfs_newdir(); + dff->df_dotdot = dir; + } else + dff = dtfs_newfile(); + + dtm = puffs_pn_getmntspecific(dir); + newpn = puffs_pn_new(dir->pn_mnt, dff); + if (newpn == NULL) + errx(1, "getnewpnode"); + dtfs_baseattrs(&newpn->pn_va, type, dtm->dtm_nextfileid++); + + dfd = emalloc(sizeof(struct dtfs_dirent)); + dfd->dfd_node = newpn; + dfd->dfd_name = estrndup(pcn->pcn_name, pcn->pcn_namelen); + dfd->dfd_namelen = strlen(dfd->dfd_name); + dfd->dfd_parent = dir; + dtfs_adddent(dir, dfd); + + newpn->pn_va.va_uid = uid; + newpn->pn_va.va_gid = dir->pn_va.va_gid; + + return newpn; +} + +struct dtfs_file * +dtfs_newdir() +{ + struct dtfs_file *dff; + + dff = emalloc(sizeof(struct dtfs_file)); + memset(dff, 0, sizeof(struct dtfs_file)); + LIST_INIT(&dff->df_dirents); + + return dff; +} + +struct dtfs_file * +dtfs_newfile() +{ + struct dtfs_file *dff; + + dff = emalloc(sizeof(struct dtfs_file)); + memset(dff, 0, sizeof(struct dtfs_file)); + + return dff; +} + +struct dtfs_dirent * +dtfs_dirgetnth(struct dtfs_file *searchdir, int n) +{ + struct dtfs_dirent *dirent; + int i; + + i = 0; + LIST_FOREACH(dirent, &searchdir->df_dirents, dfd_entries) { + if (i == n) + return dirent; + i++; + } + + return NULL; +} + +struct dtfs_dirent * +dtfs_dirgetbyname(struct dtfs_file *searchdir, const char *fname, size_t fnlen) +{ + struct dtfs_dirent *dirent; + + LIST_FOREACH(dirent, &searchdir->df_dirents, dfd_entries) + if (dirent->dfd_namelen == fnlen + && strncmp(dirent->dfd_name, fname, fnlen) == 0) + return dirent; + + return NULL; +} + +/* + * common nuke, kill dirent from parent node + */ +void +dtfs_nukenode(struct puffs_node *nukeme, struct puffs_node *pn_parent, + const char *fname, size_t fnlen) +{ + struct dtfs_dirent *dfd; + struct dtfs_mount *dtm; + + assert(pn_parent->pn_va.va_type == VDIR); + + dfd = dtfs_dirgetbyname(DTFS_PTOF(pn_parent), fname, fnlen); + assert(dfd); + + dtm = puffs_pn_getmntspecific(nukeme); + dtm->dtm_nfiles--; + assert(dtm->dtm_nfiles >= 1); + + dtfs_removedent(pn_parent, dfd); + free(dfd); +} + +/* free lingering information */ +void +dtfs_freenode(struct puffs_node *pn) +{ + struct dtfs_file *df = DTFS_PTOF(pn); + struct dtfs_mount *dtm; + int i; + + assert(pn->pn_va.va_nlink == 0); + dtm = puffs_pn_getmntspecific(pn); + + switch (pn->pn_va.va_type) { + case VREG: + assert(dtm->dtm_fsizes >= pn->pn_va.va_size); + dtm->dtm_fsizes -= pn->pn_va.va_size; + for (i = 0; i < BLOCKNUM(df->df_datalen, DTFS_BLOCKSHIFT); i++) + free(df->df_blocks[i]); + if (df->df_datalen > i << DTFS_BLOCKSHIFT) + free(df->df_blocks[i]); + break; + case VLNK: + free(df->df_linktarget); + break; + case VCHR: + case VBLK: + case VDIR: + case VSOCK: + case VFIFO: + break; + default: + assert(0); + break; + } + + free(df); + puffs_pn_put(pn); +} + +void +dtfs_setsize(struct puffs_node *pn, off_t newsize) +{ + struct dtfs_file *df = DTFS_PTOF(pn); + struct dtfs_mount *dtm; + size_t newblocks; + int needalloc, shrinks; + int i; + + needalloc = newsize > ROUNDUP(df->df_datalen, DTFS_BLOCKSIZE); + shrinks = newsize < pn->pn_va.va_size; + + if (needalloc || shrinks) { + newblocks = BLOCKNUM(newsize, DTFS_BLOCKSHIFT) + 1; + + if (shrinks) + for (i = newblocks; i < df->df_numblocks; i++) + free(df->df_blocks[i]); + + df->df_blocks = erealloc(df->df_blocks, + newblocks * sizeof(uint8_t *)); + /* + * if extended, set storage to zero + * to match correct behaviour + */ + if (!shrinks) { + for (i = df->df_numblocks; i < newblocks; i++) { + df->df_blocks[i] = emalloc(DTFS_BLOCKSIZE); + memset(df->df_blocks[i], 0, DTFS_BLOCKSIZE); + } + } + + df->df_datalen = newsize; + df->df_numblocks = newblocks; + } + + dtm = puffs_pn_getmntspecific(pn); + if (!shrinks) { + dtm->dtm_fsizes += newsize - pn->pn_va.va_size; + } else { + dtm->dtm_fsizes -= pn->pn_va.va_size - newsize; + } + + pn->pn_va.va_size = newsize; + pn->pn_va.va_bytes = BLOCKNUM(newsize,DTFS_BLOCKSHIFT)>>DTFS_BLOCKSHIFT; +} + +/* add & bump link count */ +void +dtfs_adddent(struct puffs_node *pn_dir, struct dtfs_dirent *dent) +{ + struct dtfs_file *dir = DTFS_PTOF(pn_dir); + struct puffs_node *pn_file = dent->dfd_node; + struct dtfs_file *file = DTFS_PTOF(pn_file); + struct dtfs_mount *dtm; + + assert(pn_dir->pn_va.va_type == VDIR); + LIST_INSERT_HEAD(&dir->df_dirents, dent, dfd_entries); + pn_file->pn_va.va_nlink++; + + dtm = puffs_pn_getmntspecific(pn_file); + dtm->dtm_nfiles++; + + dent->dfd_parent = pn_dir; + if (dent->dfd_node->pn_va.va_type == VDIR) { + file->df_dotdot = pn_dir; + pn_dir->pn_va.va_nlink++; + } + + dtfs_updatetimes(pn_dir, 0, 1, 1); +} + +/* remove & lower link count */ +void +dtfs_removedent(struct puffs_node *pn_dir, struct dtfs_dirent *dent) +{ + struct puffs_node *pn_file = dent->dfd_node; + + assert(pn_dir->pn_va.va_type == VDIR); + LIST_REMOVE(dent, dfd_entries); + if (pn_file->pn_va.va_type == VDIR) { + struct dtfs_file *df = DTFS_PTOF(pn_file); + + pn_dir->pn_va.va_nlink--; + df->df_dotdot = NULL; + } + pn_file->pn_va.va_nlink--; + assert(pn_dir->pn_va.va_nlink >= 2); + + dtfs_updatetimes(pn_dir, 0, 1, 1); +} + +void +dtfs_updatetimes(struct puffs_node *pn, int doatime, int doctime, int domtime) +{ + struct timeval tv; + struct timespec ts; + + gettimeofday(&tv, NULL); + TIMEVAL_TO_TIMESPEC(&tv, &ts); + + if (doatime) + pn->pn_va.va_atime = ts; + if (doctime) + pn->pn_va.va_ctime = ts; + if (domtime) + pn->pn_va.va_mtime = ts; +} + +bool +dtfs_isunder(struct puffs_node *pn, struct puffs_node *pn_parent) +{ + struct dtfs_file *df; + + while (pn) { + if (pn == pn_parent) + return true; + df = DTFS_CTOF(pn); + pn = df->df_dotdot; + } + + return false; +} diff --git a/contrib/netbsd-tests/fs/puffs/h_dtfs/dtfs_vfsops.c b/contrib/netbsd-tests/fs/puffs/h_dtfs/dtfs_vfsops.c new file mode 100644 index 000000000000..6f0c72ee3510 --- /dev/null +++ b/contrib/netbsd-tests/fs/puffs/h_dtfs/dtfs_vfsops.c @@ -0,0 +1,298 @@ +/* $NetBSD: dtfs_vfsops.c,v 1.3 2012/11/04 23:37:02 christos Exp $ */ + +/* + * Copyright (c) 2006 Antti Kantee. All Rights Reserved. + * + * 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 ``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. + */ + +#include <sys/types.h> +#include <sys/resource.h> + +#include <stdio.h> +#include <assert.h> +#include <err.h> +#include <errno.h> +#include <puffs.h> +#include <string.h> +#include <stdlib.h> +#include <unistd.h> +#include <util.h> + +#include "dtfs.h" + +static int +rtstr(struct puffs_usermount *pu, const char *str, enum vtype vt) +{ + struct puffs_node *pn = puffs_getroot(pu); + struct vattr *va = &pn->pn_va; + struct dtfs_file *df = DTFS_PTOF(pn); + char ltarg[256+1]; + + if (sscanf(str, "%*s %256s", ltarg) != 1) + return 1; + + dtfs_baseattrs(va, vt, 2); + df->df_linktarget = estrdup(ltarg); + + va->va_nlink = 1; + va->va_size = strlen(df->df_linktarget); + + puffs_setrootinfo(pu, vt, 0, 0); + + return 0; +} + +static int +rtdev(struct puffs_usermount *pu, const char *str, enum vtype vt) +{ + struct puffs_node *pn = puffs_getroot(pu); + struct vattr *va = &pn->pn_va; + int major, minor; + + if (sscanf(str, "%*s %d %d", &major, &minor) != 2) + return 1; + + dtfs_baseattrs(va, vt, 2); + va->va_nlink = 1; + va->va_rdev = makedev(major, minor); + + if (vt == VBLK) + va->va_mode |= S_IFBLK; + else + va->va_mode |= S_IFCHR; + + puffs_setrootinfo(pu, vt, 0, va->va_rdev); + + return 0; +} + +static int +rtnorm(struct puffs_usermount *pu, const char *str, enum vtype vt) +{ + struct puffs_node *pn = puffs_getroot(pu); + struct vattr *va = &pn->pn_va; + + dtfs_baseattrs(va, vt, 2); + if (vt == VDIR) + va->va_nlink = 2; + else + va->va_nlink = 1; + + puffs_setrootinfo(pu, vt, 0, 0); + + return 0; +} + +struct rtype { + char *tstr; + enum vtype vt; + int (*pfunc)(struct puffs_usermount *, const char *, enum vtype); +} rtypes[] = { + { "reg", VREG, rtnorm }, + { "dir", VDIR, rtnorm }, + { "blk", VBLK, rtdev }, + { "chr", VCHR, rtdev }, + { "lnk", VLNK, rtstr }, + { "sock", VSOCK, rtnorm }, + { "fifo", VFIFO, rtnorm } +}; +#define NTYPES (sizeof(rtypes) / sizeof(rtypes[0])) + +int +dtfs_domount(struct puffs_usermount *pu, const char *typestr) +{ + struct dtfs_mount *dtm; + struct dtfs_file *dff; + struct puffs_node *pn; + int i; + + /* create mount-local thingie */ + dtm = puffs_getspecific(pu); + dtm->dtm_nextfileid = 3; + dtm->dtm_nfiles = 1; + dtm->dtm_fsizes = 0; + LIST_INIT(&dtm->dtm_pollent); + + /* + * create root directory, do it "by hand" to avoid special-casing + * dtfs_genfile() + */ + dff = dtfs_newdir(); + dff->df_dotdot = NULL; + pn = puffs_pn_new(pu, dff); + if (!pn) + errx(1, "puffs_newpnode"); + puffs_setroot(pu, pn); + + if (!typestr) { + rtnorm(pu, NULL, VDIR); + } else { + for (i = 0; i < NTYPES; i++) { + if (strncmp(rtypes[i].tstr, typestr, + strlen(rtypes[i].tstr)) == 0) { + if (rtypes[i].pfunc(pu, typestr, + rtypes[i].vt) != 0) { + fprintf(stderr, "failed to parse " + "\"%s\"\n", typestr); + return 1; + } + break; + } + } + if (i == NTYPES) { + fprintf(stderr, "no maching type for %s\n", typestr); + return 1; + } + } + + return 0; +} + +/* + * statvfs() should fill in the following members of struct statvfs: + * + * unsigned long f_bsize; file system block size + * unsigned long f_frsize; fundamental file system block size + * unsigned long f_iosize; optimal file system block size + * fsblkcnt_t f_blocks; number of blocks in file system, + * (in units of f_frsize) + * + * fsblkcnt_t f_bfree; free blocks avail in file system + * fsblkcnt_t f_bavail; free blocks avail to non-root + * fsblkcnt_t f_bresvd; blocks reserved for root + * + * fsfilcnt_t f_files; total file nodes in file system + * fsfilcnt_t f_ffree; free file nodes in file system + * fsfilcnt_t f_favail; free file nodes avail to non-root + * fsfilcnt_t f_fresvd; file nodes reserved for root + * + * + * The rest are filled in by the kernel. + */ +#define ROUND(a,b) (((a) + ((b)-1)) & ~((b)-1)) +#define NFILES 1024*1024 +int +dtfs_fs_statvfs(struct puffs_usermount *pu, struct statvfs *sbp) +{ + struct rlimit rlim; + struct dtfs_mount *dtm; + off_t btot, bfree; + int pgsize; + + dtm = puffs_getspecific(pu); + pgsize = getpagesize(); + memset(sbp, 0, sizeof(struct statvfs)); + + /* + * Use datasize rlimit as an _approximation_ for free size. + * This, of course, is not accurate due to overhead and not + * accounting for metadata. + */ + if (getrlimit(RLIMIT_DATA, &rlim) == 0) + btot = rlim.rlim_cur; + else + btot = 16*1024*1024; + bfree = btot - dtm->dtm_fsizes; + + sbp->f_blocks = ROUND(btot, pgsize) / pgsize; + sbp->f_files = NFILES; + + sbp->f_bsize = sbp->f_frsize = sbp->f_iosize = pgsize; + sbp->f_bfree = sbp->f_bavail = ROUND(bfree, pgsize) / pgsize; + sbp->f_ffree = sbp->f_favail = NFILES - dtm->dtm_nfiles; + + sbp->f_bresvd = sbp->f_fresvd = 0; + + return 0; +} +#undef ROUND + +static void * +addrcmp(struct puffs_usermount *pu, struct puffs_node *pn, void *arg) +{ + + if (pn == arg) + return pn; + + return NULL; +} + +int +dtfs_fs_fhtonode(struct puffs_usermount *pu, void *fid, size_t fidsize, + struct puffs_newinfo *pni) +{ + struct dtfs_fid *dfid; + struct puffs_node *pn; + + assert(fidsize == sizeof(struct dtfs_fid)); + dfid = fid; + + pn = puffs_pn_nodewalk(pu, addrcmp, dfid->dfid_addr); + if (pn == NULL) + return ESTALE; + + if (pn->pn_va.va_fileid != dfid->dfid_fileid + || pn->pn_va.va_gen != dfid->dfid_gen) + return ESTALE; + + puffs_newinfo_setcookie(pni, pn); + puffs_newinfo_setvtype(pni, pn->pn_va.va_type); + puffs_newinfo_setsize(pni, pn->pn_va.va_size); + puffs_newinfo_setrdev(pni, pn->pn_va.va_rdev); + + return 0; +} + +int +dtfs_fs_nodetofh(struct puffs_usermount *pu, void *cookie, + void *fid, size_t *fidsize) +{ + struct puffs_node *pn = cookie; + struct dtfs_fid *dfid; + extern int dynamicfh; + + if (dynamicfh == 0) { + assert(*fidsize >= sizeof(struct dtfs_fid)); + } else { + if (*fidsize < sizeof(struct dtfs_fid)) { + *fidsize = sizeof(struct dtfs_fid); + return E2BIG; + } + *fidsize = sizeof(struct dtfs_fid); + } + + dfid = fid; + + dfid->dfid_addr = pn; + dfid->dfid_fileid = pn->pn_va.va_fileid; + dfid->dfid_gen = pn->pn_va.va_gen; + + return 0; +} + +int +dtfs_fs_unmount(struct puffs_usermount *pu, int flags) +{ + + return 0; +} diff --git a/contrib/netbsd-tests/fs/puffs/h_dtfs/dtfs_vnops.c b/contrib/netbsd-tests/fs/puffs/h_dtfs/dtfs_vnops.c new file mode 100644 index 000000000000..875109cb35b6 --- /dev/null +++ b/contrib/netbsd-tests/fs/puffs/h_dtfs/dtfs_vnops.c @@ -0,0 +1,586 @@ +/* $NetBSD: dtfs_vnops.c,v 1.10 2013/10/19 17:45:00 christos Exp $ */ + +/* + * Copyright (c) 2006 Antti Kantee. All Rights Reserved. + * + * 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 ``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. + */ + +#include <sys/types.h> +#include <sys/poll.h> + +#include <assert.h> +#include <errno.h> +#include <puffs.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <util.h> + +#include "dtfs.h" + +int +dtfs_node_lookup(struct puffs_usermount *pu, void *opc, + struct puffs_newinfo *pni, const struct puffs_cn *pcn) +{ + struct puffs_node *pn_dir = opc; + struct dtfs_file *df = DTFS_CTOF(opc); + struct dtfs_dirent *dfd; + extern int straightflush; + int rv; + + /* parent dir? */ + if (PCNISDOTDOT(pcn)) { + if (df->df_dotdot == NULL) + return ENOENT; + + assert(df->df_dotdot->pn_va.va_type == VDIR); + puffs_newinfo_setcookie(pni, df->df_dotdot); + puffs_newinfo_setvtype(pni, df->df_dotdot->pn_va.va_type); + + return 0; + } + + dfd = dtfs_dirgetbyname(df, pcn->pcn_name, pcn->pcn_namelen); + if (dfd) { + if ((pcn->pcn_flags & NAMEI_ISLASTCN) && + (pcn->pcn_nameiop == NAMEI_DELETE)) { + rv = puffs_access(VDIR, pn_dir->pn_va.va_mode, + pn_dir->pn_va.va_uid, pn_dir->pn_va.va_gid, + PUFFS_VWRITE, pcn->pcn_cred); + if (rv) + return rv; + } + puffs_newinfo_setcookie(pni, dfd->dfd_node); + puffs_newinfo_setvtype(pni, dfd->dfd_node->pn_va.va_type); + puffs_newinfo_setsize(pni, dfd->dfd_node->pn_va.va_size); + puffs_newinfo_setrdev(pni, dfd->dfd_node->pn_va.va_rdev); + + if (straightflush) + puffs_flush_pagecache_node(pu, dfd->dfd_node); + + return 0; + } + + if ((pcn->pcn_flags & NAMEI_ISLASTCN) + && (pcn->pcn_nameiop == NAMEI_CREATE || + pcn->pcn_nameiop == NAMEI_RENAME)) { + rv = puffs_access(VDIR, pn_dir->pn_va.va_mode, + pn_dir->pn_va.va_uid, pn_dir->pn_va.va_gid, + PUFFS_VWRITE, pcn->pcn_cred); + if (rv) + return rv; + } + + return ENOENT; +} + +int +dtfs_node_access(struct puffs_usermount *pu, void *opc, int acc_mode, + const struct puffs_cred *pcr) +{ + struct puffs_node *pn = opc; + + return puffs_access(pn->pn_va.va_type, pn->pn_va.va_mode, + pn->pn_va.va_uid, pn->pn_va.va_gid, acc_mode, pcr); +} + +int +dtfs_node_setattr(struct puffs_usermount *pu, void *opc, + const struct vattr *va, const struct puffs_cred *pcr) +{ + struct puffs_node *pn = opc; + int rv; + + /* check permissions */ + if (va->va_flags != PUFFS_VNOVAL) + return EOPNOTSUPP; + + if (va->va_uid != PUFFS_VNOVAL || va->va_gid != PUFFS_VNOVAL) { + rv = puffs_access_chown(pn->pn_va.va_uid, pn->pn_va.va_gid, + va->va_uid, va->va_gid, pcr); + if (rv) + return rv; + } + + if (va->va_mode != PUFFS_VNOVAL) { + rv = puffs_access_chmod(pn->pn_va.va_uid, pn->pn_va.va_gid, + pn->pn_va.va_type, va->va_mode, pcr); + if (rv) + return rv; + } + + if ((va->va_atime.tv_sec != PUFFS_VNOVAL + && va->va_atime.tv_nsec != PUFFS_VNOVAL) + || (va->va_mtime.tv_sec != PUFFS_VNOVAL + && va->va_mtime.tv_nsec != PUFFS_VNOVAL)) { + rv = puffs_access_times(pn->pn_va.va_uid, pn->pn_va.va_gid, + pn->pn_va.va_mode, va->va_vaflags & VA_UTIMES_NULL, pcr); + if (rv) + return rv; + } + + if (va->va_size != PUFFS_VNOVAL) { + switch (pn->pn_va.va_type) { + case VREG: + dtfs_setsize(pn, va->va_size); + pn->pn_va.va_bytes = va->va_size; + break; + case VBLK: + case VCHR: + case VFIFO: + break; + case VDIR: + return EISDIR; + default: + return EOPNOTSUPP; + } + } + + puffs_setvattr(&pn->pn_va, va); + + return 0; +} + +/* create a new node in the parent directory specified by opc */ +int +dtfs_node_create(struct puffs_usermount *pu, void *opc, + struct puffs_newinfo *pni, const struct puffs_cn *pcn, + const struct vattr *va) +{ + struct puffs_node *pn_parent = opc; + struct puffs_node *pn_new; + + if (!(va->va_type == VREG || va->va_type == VSOCK)) + return ENODEV; + + pn_new = dtfs_genfile(pn_parent, pcn, va->va_type); + puffs_setvattr(&pn_new->pn_va, va); + + puffs_newinfo_setcookie(pni, pn_new); + + return 0; +} + +int +dtfs_node_remove(struct puffs_usermount *pu, void *opc, void *targ, + const struct puffs_cn *pcn) +{ + struct puffs_node *pn_parent = opc; + struct puffs_node *pn = targ; + + if (pn->pn_va.va_type == VDIR) + return EPERM; + + dtfs_nukenode(targ, pn_parent, pcn->pcn_name, pcn->pcn_namelen); + + if (pn->pn_va.va_nlink == 0) + puffs_setback(puffs_cc_getcc(pu), PUFFS_SETBACK_NOREF_N2); + + return 0; +} + +int +dtfs_node_mkdir(struct puffs_usermount *pu, void *opc, + struct puffs_newinfo *pni, const struct puffs_cn *pcn, + const struct vattr *va) +{ + struct puffs_node *pn_parent = opc; + struct puffs_node *pn_new; + + pn_new = dtfs_genfile(pn_parent, pcn, VDIR); + puffs_setvattr(&pn_new->pn_va, va); + + puffs_newinfo_setcookie(pni, pn_new); + + return 0; +} + +int +dtfs_node_rmdir(struct puffs_usermount *pu, void *opc, void *targ, + const struct puffs_cn *pcn) +{ + struct puffs_node *pn_parent = opc; + struct dtfs_file *df = DTFS_CTOF(targ); + + if (!LIST_EMPTY(&df->df_dirents)) + return ENOTEMPTY; + + dtfs_nukenode(targ, pn_parent, pcn->pcn_name, pcn->pcn_namelen); + puffs_setback(puffs_cc_getcc(pu), PUFFS_SETBACK_NOREF_N2); + + return 0; +} + +int +dtfs_node_readdir(struct puffs_usermount *pu, void *opc, + struct dirent *dent, off_t *readoff, size_t *reslen, + const struct puffs_cred *pcr, + int *eofflag, off_t *cookies, size_t *ncookies) +{ + struct puffs_node *pn = opc; + struct puffs_node *pn_nth; + struct dtfs_dirent *dfd_nth; + + if (pn->pn_va.va_type != VDIR) + return ENOTDIR; + + dtfs_updatetimes(pn, 1, 0, 0); + + *ncookies = 0; + again: + if (*readoff == DENT_DOT || *readoff == DENT_DOTDOT) { + puffs_gendotdent(&dent, pn->pn_va.va_fileid, *readoff, reslen); + (*readoff)++; + PUFFS_STORE_DCOOKIE(cookies, ncookies, *readoff); + goto again; + } + + for (;;) { + dfd_nth = dtfs_dirgetnth(pn->pn_data, DENT_ADJ(*readoff)); + if (!dfd_nth) { + *eofflag = 1; + break; + } + pn_nth = dfd_nth->dfd_node; + + if (!puffs_nextdent(&dent, dfd_nth->dfd_name, + pn_nth->pn_va.va_fileid, + puffs_vtype2dt(pn_nth->pn_va.va_type), + reslen)) + break; + + (*readoff)++; + PUFFS_STORE_DCOOKIE(cookies, ncookies, *readoff); + } + + return 0; +} + +int +dtfs_node_poll(struct puffs_usermount *pu, void *opc, int *events) +{ + struct dtfs_mount *dtm = puffs_getspecific(pu); + struct dtfs_poll dp; + struct itimerval it; + + memset(&it, 0, sizeof(struct itimerval)); + it.it_value.tv_sec = 4; + if (setitimer(ITIMER_REAL, &it, NULL) == -1) + return errno; + + dp.dp_pcc = puffs_cc_getcc(pu); + LIST_INSERT_HEAD(&dtm->dtm_pollent, &dp, dp_entries); + puffs_cc_yield(dp.dp_pcc); + + *events = *events & (POLLIN | POLLOUT | POLLRDNORM | POLLWRNORM); + return 0; +} + +int +dtfs_node_mmap(struct puffs_usermount *pu, void *opc, vm_prot_t prot, + const struct puffs_cred *pcr) +{ + struct dtfs_mount *dtm = puffs_getspecific(pu); + + if ((dtm->dtm_allowprot & prot) != prot) + return EACCES; + + return 0; +} + +int +dtfs_node_rename(struct puffs_usermount *pu, void *opc, void *src, + const struct puffs_cn *pcn_src, void *targ_dir, void *targ, + const struct puffs_cn *pcn_targ) +{ + struct dtfs_dirent *dfd_src; + struct dtfs_file *df_targ; + struct puffs_node *pn_sdir = opc; + struct puffs_node *pn_sfile = src; + struct puffs_node *pn_tdir = targ_dir; + struct puffs_node *pn_tfile = targ; + + /* check that we don't do the old amigados trick */ + if (pn_sfile->pn_va.va_type == VDIR) { + if (dtfs_isunder(pn_tdir, pn_sfile)) + return EINVAL; + + if ((pcn_src->pcn_namelen == 1 && pcn_src->pcn_name[0]=='.') || + opc == src || + PCNISDOTDOT(pcn_src) || + PCNISDOTDOT(pcn_targ)) { + return EINVAL; + } + } + + dfd_src = dtfs_dirgetbyname(DTFS_PTOF(pn_sdir), + pcn_src->pcn_name, pcn_src->pcn_namelen); + + /* does it still exist, or did someone race us here? */ + if (dfd_src == NULL) { + return ENOENT; + } + + /* if there's a target file, nuke it for atomic replacement */ + if (pn_tfile) { + if (pn_tfile->pn_va.va_type == VDIR) { + df_targ = DTFS_CTOF(pn_tfile); + if (!LIST_EMPTY(&df_targ->df_dirents)) + return ENOTEMPTY; + } + dtfs_nukenode(pn_tfile, pn_tdir, + pcn_targ->pcn_name, pcn_targ->pcn_namelen); + } + + /* out with the old */ + dtfs_removedent(pn_sdir, dfd_src); + /* and in with the new */ + dtfs_adddent(pn_tdir, dfd_src); + + /* update name */ + free(dfd_src->dfd_name); + dfd_src->dfd_name = estrndup(pcn_targ->pcn_name,pcn_targ->pcn_namelen); + dfd_src->dfd_namelen = strlen(dfd_src->dfd_name); + + dtfs_updatetimes(src, 0, 1, 0); + + return 0; +} + +int +dtfs_node_link(struct puffs_usermount *pu, void *opc, void *targ, + const struct puffs_cn *pcn) +{ + struct puffs_node *pn_dir = opc; + struct dtfs_dirent *dfd; + + dfd = emalloc(sizeof(struct dtfs_dirent)); + dfd->dfd_node = targ; + dfd->dfd_name = estrndup(pcn->pcn_name, pcn->pcn_namelen); + dfd->dfd_namelen = strlen(dfd->dfd_name); + dtfs_adddent(pn_dir, dfd); + + dtfs_updatetimes(targ, 0, 1, 0); + + return 0; +} + +int +dtfs_node_symlink(struct puffs_usermount *pu, void *opc, + struct puffs_newinfo *pni, const struct puffs_cn *pcn_src, + const struct vattr *va, const char *link_target) +{ + struct puffs_node *pn_parent = opc; + struct puffs_node *pn_new; + struct dtfs_file *df_new; + + if (va->va_type != VLNK) + return ENODEV; + + pn_new = dtfs_genfile(pn_parent, pcn_src, VLNK); + puffs_setvattr(&pn_new->pn_va, va); + df_new = DTFS_PTOF(pn_new); + df_new->df_linktarget = estrdup(link_target); + pn_new->pn_va.va_size = strlen(df_new->df_linktarget); + + puffs_newinfo_setcookie(pni, pn_new); + + return 0; +} + +int +dtfs_node_readlink(struct puffs_usermount *pu, void *opc, + const struct puffs_cred *cred, char *linkname, size_t *linklen) +{ + struct dtfs_file *df = DTFS_CTOF(opc); + struct puffs_node *pn = opc; + + assert(pn->pn_va.va_type == VLNK); + strlcpy(linkname, df->df_linktarget, *linklen); + *linklen = strlen(linkname); + + return 0; +} + +int +dtfs_node_mknod(struct puffs_usermount *pu, void *opc, + struct puffs_newinfo *pni, const struct puffs_cn *pcn, + const struct vattr *va) +{ + struct puffs_node *pn_parent = opc; + struct puffs_node *pn_new; + + if (!(va->va_type == VBLK || va->va_type == VCHR + || va->va_type == VFIFO)) + return EINVAL; + + pn_new = dtfs_genfile(pn_parent, pcn, va->va_type); + puffs_setvattr(&pn_new->pn_va, va); + + puffs_newinfo_setcookie(pni, pn_new); + + return 0; +} + +#define BLOCKOFF(a,b) ((a) & ((b)-1)) +#define BLOCKLEFT(a,b) ((b) - BLOCKOFF(a,b)) + +/* + * Read operation, used both for VOP_READ and VOP_GETPAGES + */ +int +dtfs_node_read(struct puffs_usermount *pu, void *opc, uint8_t *buf, + off_t offset, size_t *resid, const struct puffs_cred *pcr, int ioflag) +{ + struct puffs_node *pn = opc; + struct dtfs_file *df = DTFS_CTOF(opc); + quad_t xfer, origxfer; + uint8_t *src, *dest; + size_t copylen; + + if (pn->pn_va.va_type != VREG) + return EISDIR; + + xfer = MIN(*resid, df->df_datalen - offset); + if (xfer < 0) + return EINVAL; + + dest = buf; + origxfer = xfer; + while (xfer > 0) { + copylen = MIN(xfer, BLOCKLEFT(offset, DTFS_BLOCKSIZE)); + src = df->df_blocks[BLOCKNUM(offset, DTFS_BLOCKSHIFT)] + + BLOCKOFF(offset, DTFS_BLOCKSIZE); + memcpy(dest, src, copylen); + offset += copylen; + dest += copylen; + xfer -= copylen; + } + *resid -= origxfer; + + dtfs_updatetimes(pn, 1, 0, 0); + + return 0; +} + +/* + * write operation on the wing + */ +int +dtfs_node_write(struct puffs_usermount *pu, void *opc, uint8_t *buf, + off_t offset, size_t *resid, const struct puffs_cred *pcr, int ioflag) +{ + struct puffs_node *pn = opc; + struct dtfs_file *df = DTFS_CTOF(opc); + uint8_t *src, *dest; + size_t copylen; + + if (pn->pn_va.va_type != VREG) + return EISDIR; + + if (ioflag & PUFFS_IO_APPEND) + offset = pn->pn_va.va_size; + + if (*resid + offset > pn->pn_va.va_size) + dtfs_setsize(pn, *resid + offset); + + src = buf; + while (*resid > 0) { + int i; + copylen = MIN(*resid, BLOCKLEFT(offset, DTFS_BLOCKSIZE)); + i = BLOCKNUM(offset, DTFS_BLOCKSHIFT); + dest = df->df_blocks[i] + + BLOCKOFF(offset, DTFS_BLOCKSIZE); + memcpy(dest, src, copylen); + offset += copylen; + dest += copylen; + *resid -= copylen; + } + + dtfs_updatetimes(pn, 0, 1, 1); + + return 0; +} + +int +dtfs_node_pathconf(struct puffs_usermount *pu, puffs_cookie_t opc, + int name, register_t *retval) +{ + + switch (name) { + case _PC_LINK_MAX: + *retval = LINK_MAX; + return 0; + case _PC_NAME_MAX: + *retval = NAME_MAX; + return 0; + case _PC_PATH_MAX: + *retval = PATH_MAX; + return 0; + case _PC_PIPE_BUF: + *retval = PIPE_BUF; + return 0; + case _PC_CHOWN_RESTRICTED: + *retval = 1; + return 0; + case _PC_NO_TRUNC: + *retval = 1; + return 0; + case _PC_SYNC_IO: + *retval = 1; + return 0; + case _PC_FILESIZEBITS: + *retval = 43; /* this one goes to 11 */ + return 0; + case _PC_SYMLINK_MAX: + *retval = MAXPATHLEN; + return 0; + case _PC_2_SYMLINKS: + *retval = 1; + return 0; + default: + return EINVAL; + } +} + +int +dtfs_node_inactive(struct puffs_usermount *pu, puffs_cookie_t opc) +{ + struct puffs_node *pn = opc; + + if (pn->pn_va.va_nlink == 0) + puffs_setback(puffs_cc_getcc(pu), PUFFS_SETBACK_NOREF_N1); + return 0; +} + +int +dtfs_node_reclaim(struct puffs_usermount *pu, void *opc) +{ + struct puffs_node *pn = opc; + + if (pn->pn_va.va_nlink == 0) + dtfs_freenode(pn); + + return 0; +} diff --git a/contrib/netbsd-tests/fs/puffs/t_basic.c b/contrib/netbsd-tests/fs/puffs/t_basic.c new file mode 100644 index 000000000000..4b5b7b81b2a4 --- /dev/null +++ b/contrib/netbsd-tests/fs/puffs/t_basic.c @@ -0,0 +1,455 @@ +/* $NetBSD: t_basic.c,v 1.14 2017/01/13 21:30:40 christos Exp $ */ + +#include <sys/types.h> +#include <sys/mount.h> +#include <sys/socket.h> + +#include <assert.h> +#include <atf-c.h> +#include <err.h> +#include <errno.h> +#include <fcntl.h> +#include <pthread.h> +#include <puffs.h> +#include <puffsdump.h> +#include <stdio.h> +#include <unistd.h> +#include <string.h> +#include <stdlib.h> + +#include <rump/rump.h> +#include <rump/rump_syscalls.h> + +#include "h_macros.h" +#include "../common/h_fsmacros.h" + +/* + * Do a synchronous operation. When this returns, all FAF operations + * have at least been delivered to the file system. + * + * XXX: is this really good enough considering puffs(9)-issued + * callback operations? + */ +static void +syncbar(const char *fs) +{ + struct statvfs svb; + + if (rump_sys_statvfs1(fs, &svb, ST_WAIT) == -1) + atf_tc_fail_errno("statvfs"); +} + +#ifdef PUFFSDUMP +static void __unused +dumpopcount(struct puffstestargs *args) +{ + size_t i; + + printf("VFS OPS:\n"); + for (i = 0; i < MIN(puffsdump_vfsop_count, PUFFS_VFS_MAX); i++) { + printf("\t%s: %d\n", + puffsdump_vfsop_revmap[i], args->pta_vfs_toserv_ops[i]); + } + + printf("VN OPS:\n"); + for (i = 0; i < MIN(puffsdump_vnop_count, PUFFS_VN_MAX); i++) { + printf("\t%s: %d\n", + puffsdump_vnop_revmap[i], args->pta_vn_toserv_ops[i]); + } +} +#endif + +ATF_TC(mount); +ATF_TC_HEAD(mount, tc) +{ + + atf_tc_set_md_var(tc, "descr", "puffs+dtfs un/mount test"); +} + +ATF_TC_BODY(mount, tc) +{ + void *args; + + FSTEST_CONSTRUCTOR(tc, puffs, args); + FSTEST_DESTRUCTOR(tc, puffs, args); +} + +ATF_TC(root_reg); +ATF_TC_HEAD(root_reg, tc) +{ + atf_tc_set_md_var(tc, "descr", "root is a regular file"); +} + +#define MAKEOPTS(...) \ + char *theopts[] = {NULL, "-s", __VA_ARGS__, "dtfs", "n/a", NULL} + +ATF_TC_BODY(root_reg, tc) +{ + MAKEOPTS("-r", "reg"); + void *args; + int fd, rv; + + FSTEST_CONSTRUCTOR_FSPRIV(tc, puffs, args, theopts); + + fd = rump_sys_open(FSTEST_MNTNAME, O_RDWR); + if (fd == -1) + atf_tc_fail_errno("open root"); + if (rump_sys_write(fd, &fd, sizeof(fd)) != sizeof(fd)) + atf_tc_fail_errno("write to root"); + rv = rump_sys_mkdir(FSTEST_MNTNAME "/test", 0777); + ATF_REQUIRE(errno == ENOTDIR); + ATF_REQUIRE(rv == -1); + rump_sys_close(fd); + + FSTEST_DESTRUCTOR(tc, puffs, args); +} + +ATF_TC(root_lnk); +ATF_TC_HEAD(root_lnk, tc) +{ + + atf_tc_set_md_var(tc, "descr", "root is a symbolic link"); +} + +#define LINKSTR "/path/to/nowhere" +ATF_TC_BODY(root_lnk, tc) +{ + MAKEOPTS("-r", "lnk " LINKSTR); + void *args; + char buf[PATH_MAX]; + ssize_t len; + + FSTEST_CONSTRUCTOR_FSPRIV(tc, puffs, args, theopts); + + if ((len = rump_sys_readlink(FSTEST_MNTNAME, buf, sizeof(buf)-1)) == -1) + atf_tc_fail_errno("readlink"); + buf[len] = '\0'; + + ATF_REQUIRE_STREQ(buf, LINKSTR); + +#if 0 /* XXX: unmount uses FOLLOW */ + if (rump_sys_unmount("/mp", 0) == -1) + atf_tc_fail_errno("unmount"); +#endif +} + +ATF_TC(root_fifo); +ATF_TC_HEAD(root_fifo, tc) +{ + + atf_tc_set_md_var(tc, "descr", "root is a symbolic link"); +} + +#define MAGICSTR "nakit ja muusiperunat maustevoilla" +static void * +dofifow(void *arg) +{ + int fd = (int)(uintptr_t)arg; + char buf[512]; + + printf("writing\n"); + strcpy(buf, MAGICSTR); + if (rump_sys_write(fd, buf, strlen(buf)+1) != strlen(buf)+1) + atf_tc_fail_errno("write to fifo"); + + return NULL; +} + +ATF_TC_BODY(root_fifo, tc) +{ + MAKEOPTS("-r", "fifo"); + void *args; + pthread_t pt; + char buf[512]; + int fd; + + FSTEST_CONSTRUCTOR_FSPRIV(tc, puffs, args, theopts); + + fd = rump_sys_open(FSTEST_MNTNAME, O_RDWR); + if (fd == -1) + atf_tc_fail_errno("open fifo"); + + pthread_create(&pt, NULL, dofifow, (void *)(uintptr_t)fd); + + memset(buf, 0, sizeof(buf)); + if (rump_sys_read(fd, buf, sizeof(buf)) == -1) + atf_tc_fail_errno("read fifo"); + + ATF_REQUIRE_STREQ(buf, MAGICSTR); + rump_sys_close(fd); + + FSTEST_DESTRUCTOR(tc, puffs, args); +} + +ATF_TC(root_chrdev); +ATF_TC_HEAD(root_chrdev, tc) +{ + + atf_tc_set_md_var(tc, "descr", "root is /dev/null"); +} + +ATF_TC_BODY(root_chrdev, tc) +{ + MAKEOPTS("-r", "chr 2 2"); + void *args; + ssize_t rv; + char buf[512]; + int fd; + + FSTEST_CONSTRUCTOR_FSPRIV(tc, puffs, args, theopts); + + fd = rump_sys_open(FSTEST_MNTNAME, O_RDWR); + if (fd == -1) + atf_tc_fail_errno("open null"); + + rv = rump_sys_write(fd, buf, sizeof(buf)); + ATF_REQUIRE(rv == sizeof(buf)); + + rv = rump_sys_read(fd, buf, sizeof(buf)); + ATF_REQUIRE(rv == 0); + + rump_sys_close(fd); + + FSTEST_DESTRUCTOR(tc, puffs, args); +} + +/* + * Inactive/reclaim tests + */ + +ATF_TC(inactive_basic); +ATF_TC_HEAD(inactive_basic, tc) +{ + + atf_tc_set_md_var(tc, "descr", "inactive gets called"); +} + +ATF_TC_BODY(inactive_basic, tc) +{ + struct puffstestargs *pargs; + void *args; + int fd; + + FSTEST_CONSTRUCTOR(tc, puffs, args); + FSTEST_ENTER(); + pargs = args; + + fd = rump_sys_open("file", O_CREAT | O_RDWR, 0777); + if (fd == -1) + atf_tc_fail_errno("create"); + + /* none yet */ + ATF_REQUIRE_EQ(pargs->pta_vn_toserv_ops[PUFFS_VN_INACTIVE], 0); + + rump_sys_close(fd); + + /* one for file */ + ATF_REQUIRE_EQ(pargs->pta_vn_toserv_ops[PUFFS_VN_INACTIVE], 1); + + FSTEST_EXIT(); + + /* another for the mountpoint */ + ATF_REQUIRE_EQ(pargs->pta_vn_toserv_ops[PUFFS_VN_INACTIVE], 2); + + FSTEST_DESTRUCTOR(tc, puffs, args); +} + +ATF_TC(inactive_reclaim); +ATF_TC_HEAD(inactive_reclaim, tc) +{ + + atf_tc_set_md_var(tc, "descr", "inactive/reclaim gets called"); +} + +ATF_TC_BODY(inactive_reclaim, tc) +{ + struct puffstestargs *pargs; + void *args; + int fd; + + FSTEST_CONSTRUCTOR(tc, puffs, args); + FSTEST_ENTER(); + pargs = args; + + fd = rump_sys_open("file", O_CREAT | O_RDWR, 0777); + if (fd == -1) + atf_tc_fail_errno("create"); + + ATF_REQUIRE_EQ(pargs->pta_vn_toserv_ops[PUFFS_VN_INACTIVE], 0); + + if (rump_sys_unlink("file") == -1) + atf_tc_fail_errno("remove"); + + ATF_REQUIRE_EQ(pargs->pta_vn_toserv_ops[PUFFS_VN_INACTIVE], 0); + ATF_REQUIRE_EQ(pargs->pta_vn_toserv_ops[PUFFS_VN_RECLAIM], 0); + + rump_sys_close(fd); + syncbar(FSTEST_MNTNAME); + + ATF_REQUIRE(pargs->pta_vn_toserv_ops[PUFFS_VN_INACTIVE] > 0); + ATF_REQUIRE_EQ(pargs->pta_vn_toserv_ops[PUFFS_VN_RECLAIM], 1); + + FSTEST_EXIT(); + FSTEST_DESTRUCTOR(tc, puffs, args); +} + +ATF_TC(reclaim_hardlink); +ATF_TC_HEAD(reclaim_hardlink, tc) +{ + + atf_tc_set_md_var(tc, "descr", "reclaim gets called only after " + "final link is gone"); +} + +ATF_TC_BODY(reclaim_hardlink, tc) +{ + struct puffstestargs *pargs; + void *args; + int fd; + int ianow; + + FSTEST_CONSTRUCTOR(tc, puffs, args); + FSTEST_ENTER(); + pargs = args; + + fd = rump_sys_open("file", O_CREAT | O_RDWR, 0777); + if (fd == -1) + atf_tc_fail_errno("create"); + + if (rump_sys_link("file", "anotherfile") == -1) + atf_tc_fail_errno("create link"); + rump_sys_close(fd); + + ATF_REQUIRE_EQ(pargs->pta_vn_toserv_ops[PUFFS_VN_RECLAIM], 0); + + /* unlink first hardlink */ + if (rump_sys_unlink("file") == -1) + atf_tc_fail_errno("unlink 1"); + + ATF_REQUIRE_EQ(pargs->pta_vn_toserv_ops[PUFFS_VN_RECLAIM], 0); + ianow = pargs->pta_vn_toserv_ops[PUFFS_VN_INACTIVE]; + + /* unlink second hardlink */ + if (rump_sys_unlink("anotherfile") == -1) + atf_tc_fail_errno("unlink 2"); + + syncbar(FSTEST_MNTNAME); + + ATF_REQUIRE(ianow < pargs->pta_vn_toserv_ops[PUFFS_VN_INACTIVE]); + ATF_REQUIRE_EQ(pargs->pta_vn_toserv_ops[PUFFS_VN_RECLAIM], 1); + + FSTEST_EXIT(); + FSTEST_DESTRUCTOR(tc, puffs, args); +} + +ATF_TC(unlink_accessible); +ATF_TC_HEAD(unlink_accessible, tc) +{ + + atf_tc_set_md_var(tc, "descr", "open file is accessible after " + "having been unlinked"); +} + +ATF_TC_BODY(unlink_accessible, tc) +{ + MAKEOPTS("-i", "-o", "nopagecache"); + struct puffstestargs *pargs; + void *args; + char buf[512]; + int fd, ianow; + + assert(sizeof(buf) > sizeof(MAGICSTR)); + + FSTEST_CONSTRUCTOR_FSPRIV(tc, puffs, args, theopts); + FSTEST_ENTER(); + pargs = args; + + fd = rump_sys_open("file", O_CREAT | O_RDWR, 0777); + if (fd == -1) + atf_tc_fail_errno("create"); + + if (rump_sys_write(fd, MAGICSTR, sizeof(MAGICSTR)) != sizeof(MAGICSTR)) + atf_tc_fail_errno("write"); + if (rump_sys_unlink("file") == -1) + atf_tc_fail_errno("unlink"); + + ATF_REQUIRE_EQ(pargs->pta_vn_toserv_ops[PUFFS_VN_RECLAIM], 0); + ianow = pargs->pta_vn_toserv_ops[PUFFS_VN_INACTIVE]; + + if (rump_sys_pread(fd, buf, sizeof(buf), 0) == -1) + atf_tc_fail_errno("read"); + rump_sys_close(fd); + + syncbar(FSTEST_MNTNAME); + + ATF_REQUIRE_EQ(pargs->pta_vn_toserv_ops[PUFFS_VN_RECLAIM], 1); + ATF_REQUIRE(pargs->pta_vn_toserv_ops[PUFFS_VN_INACTIVE] > ianow); + + ATF_REQUIRE_STREQ(buf, MAGICSTR); + + FSTEST_EXIT(); + FSTEST_DESTRUCTOR(tc, puffs, args); +} + +ATF_TC(signals); +ATF_TC_HEAD(signals, tc) +{ + + atf_tc_set_md_var(tc, "descr", "Checks that sending a signal can " + "cause an interrupt to puffs wait"); +} + +extern struct proc *rumpns_initproc; +extern void rumpns_psignal(struct proc *, int); +extern void rumpns_sigclearall(struct proc *, void *, void *); +ATF_TC_BODY(signals, tc) +{ + struct stat sb; + void *args; + + rump_boot_setsigmodel(RUMP_SIGMODEL_RECORD); + + FSTEST_CONSTRUCTOR(tc, puffs, args); + FSTEST_ENTER(); + RL(rump_sys_stat(".", &sb)); + + /* send SIGUSR1, should not affect puffs ops */ + rump_schedule(); + rumpns_psignal(rumpns_initproc, SIGUSR1); + rump_unschedule(); + RL(rump_sys_stat(".", &sb)); + + /* send SIGTERM, should get EINTR */ + rump_schedule(); + rumpns_psignal(rumpns_initproc, SIGTERM); + rump_unschedule(); + ATF_REQUIRE_ERRNO(EINTR, rump_sys_stat(".", &sb) == -1); + + /* clear sigmask so that we can unmount */ + rump_schedule(); + rumpns_sigclearall(rumpns_initproc, NULL, NULL); + rump_unschedule(); + + FSTEST_EXIT(); + FSTEST_DESTRUCTOR(tc, puffs, args); +} + +ATF_TP_ADD_TCS(tp) +{ + + ATF_TP_ADD_TC(tp, mount); + + ATF_TP_ADD_TC(tp, root_fifo); + ATF_TP_ADD_TC(tp, root_lnk); + ATF_TP_ADD_TC(tp, root_reg); + ATF_TP_ADD_TC(tp, root_chrdev); + + ATF_TP_ADD_TC(tp, inactive_basic); + ATF_TP_ADD_TC(tp, inactive_reclaim); + ATF_TP_ADD_TC(tp, reclaim_hardlink); + ATF_TP_ADD_TC(tp, unlink_accessible); + + ATF_TP_ADD_TC(tp, signals); + + return atf_no_error(); +} diff --git a/contrib/netbsd-tests/fs/puffs/t_fuzz.c b/contrib/netbsd-tests/fs/puffs/t_fuzz.c new file mode 100644 index 000000000000..b2e000d07e5c --- /dev/null +++ b/contrib/netbsd-tests/fs/puffs/t_fuzz.c @@ -0,0 +1,283 @@ +/* $NetBSD: t_fuzz.c,v 1.6 2017/01/13 21:30:40 christos Exp $ */ + +/*- + * Copyright (c) 2010 The NetBSD Foundation, Inc. + * All rights reserved. + * + * 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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. + */ + +/* + * Fuzztest puffs mount. There are n different levels of testing: + * each one pours more and more sane garbage into the args to that + * the mount progresses further and further. Level 8 (at least when + * writing this comment) should be the one where mounting actually + * succeeds. + * + * Our metric of success is crash / no crash. + */ + +#include <sys/types.h> +#include <sys/mount.h> +#include <sys/poll.h> + +#include <assert.h> +#include <atf-c.h> +#include <err.h> +#include <errno.h> +#include <fcntl.h> +#include <pthread.h> +#include <stdio.h> +#include <unistd.h> +#include <string.h> +#include <stdlib.h> + +#include <fs/puffs/puffs_msgif.h> + +#include <rump/rump.h> +#include <rump/rump_syscalls.h> + +#include "h_macros.h" + +#define ITERATIONS 100 + +static void +fixversion(struct puffs_kargs *kargs) +{ + + kargs->pa_vers = PUFFSVERSION; +} + +static void +fixkflag(struct puffs_kargs *kargs) +{ + + kargs->pa_flags &= PUFFS_KFLAG_MASK; + + /* + * PUFFS_KFLAG_CACHE_FS_TTL require extended behavior + * from the filesystem for which we have no test right now. + */ + kargs->pa_flags &= ~PUFFS_KFLAG_CACHE_FS_TTL; +} + +static void +fixfhflag(struct puffs_kargs *kargs) +{ + + kargs->pa_fhflags &= PUFFS_FHFLAG_MASK; +} + +static void +fixspare(struct puffs_kargs *kargs) +{ + + memset(&kargs->pa_spare, 0, sizeof(kargs->pa_spare)); +} + +static void +fixhandsize(struct puffs_kargs *kargs) +{ + + kargs->pa_fhsize %= PUFFS_FHSIZE_MAX+4; +} + +static void +fixhandsize2(struct puffs_kargs *kargs) +{ + + /* XXX: values */ + if (kargs->pa_fhflags & PUFFS_FHFLAG_NFSV3) + kargs->pa_fhsize %= 60; + if (kargs->pa_fhflags & PUFFS_FHFLAG_NFSV2) + kargs->pa_fhsize %= 28; +} + +static void +fixputter(struct puffs_kargs *kargs) +{ + + kargs->pa_fd = rump_sys_open("/dev/putter", O_RDWR); + if (kargs->pa_fd == -1) + atf_tc_fail_errno("open putter"); +} + +static void +fixroot(struct puffs_kargs *kargs) +{ + + kargs->pa_root_vtype %= VBAD; +} + +static void +unfixputter(struct puffs_kargs *kargs) +{ + + rump_sys_close(kargs->pa_fd); +} + +typedef void (*fixfn)(struct puffs_kargs *); +static fixfn fixstack[] = { + fixversion, + fixkflag, + fixfhflag, + fixspare, + fixhandsize, + fixhandsize2, + fixputter, + fixroot, +}; + +static void +fixup(int nfix, struct puffs_kargs *kargs) +{ + int i; + + assert(nfix <= __arraycount(fixstack)); + for (i = 0; i < nfix; i++) + fixstack[i](kargs); +} + +static void +unfixup(int nfix, struct puffs_kargs *kargs) +{ + + if (nfix >= 7) + unfixputter(kargs); +} + +static pthread_mutex_t damtx; +static pthread_cond_t dacv; +static int dafd = -1; + +static void * +respondthread(void *arg) +{ + char buf[PUFFS_MSG_MAXSIZE]; + struct puffs_req *preq = (void *)buf; + struct pollfd pfd; + ssize_t n; + + pthread_mutex_lock(&damtx); + for (;;) { + while (dafd == -1) + pthread_cond_wait(&dacv, &damtx); + + while (dafd != -1) { + pthread_mutex_unlock(&damtx); + pfd.fd = dafd; + pfd.events = POLLIN; + pfd.revents = 0; + if (rump_sys_poll(&pfd, 1, 10) == 0) { + pthread_mutex_lock(&damtx); + continue; + } + n = rump_sys_read(dafd, buf, sizeof(buf)); + if (n <= 0) { + pthread_mutex_lock(&damtx); + break; + } + + /* just say it was succesful */ + preq->preq_rv = 0; + rump_sys_write(dafd, buf, n); + pthread_mutex_lock(&damtx); + } + } + + return NULL; +} + +static void +testbody(int nfix) +{ + pthread_t pt; + struct puffs_kargs kargs; + unsigned long seed; + int i; + + seed = time(NULL); + srandom(seed); + printf("test seeded RNG with %lu\n", seed); + + rump_init(); + + pthread_mutex_init(&damtx, NULL); + pthread_cond_init(&dacv, NULL); + pthread_create(&pt, NULL, respondthread, NULL); + + ATF_REQUIRE(rump_sys_mkdir("/mnt", 0777) == 0); + + for (i = 0; i < ITERATIONS; i++) { + tests_makegarbage(&kargs, sizeof(kargs)); + fixup(nfix, &kargs); + if (rump_sys_mount(MOUNT_PUFFS, "/mnt", 0, + &kargs, sizeof(kargs)) == 0) { + struct stat sb; + + pthread_mutex_lock(&damtx); + dafd = kargs.pa_fd; + pthread_cond_signal(&dacv); + pthread_mutex_unlock(&damtx); + + rump_sys_stat("/mnt", &sb); + rump_sys_unmount("/mnt", MNT_FORCE); + } + unfixup(nfix, &kargs); + + pthread_mutex_lock(&damtx); + dafd = -1; + pthread_mutex_unlock(&damtx); + } +} + +#define MAKETEST(_n_) \ +ATF_TC(mountfuzz##_n_); \ +ATF_TC_HEAD(mountfuzz##_n_, tc) \ +{atf_tc_set_md_var(tc, "descr", "garbage kargs, " # _n_ " fix(es)");} \ +ATF_TC_BODY(mountfuzz##_n_, tc) {testbody(_n_);} + +MAKETEST(0); +MAKETEST(1); +MAKETEST(2); +MAKETEST(3); +MAKETEST(4); +MAKETEST(5); +MAKETEST(6); +MAKETEST(7); +MAKETEST(8); + +ATF_TP_ADD_TCS(tp) +{ + + ATF_TP_ADD_TC(tp, mountfuzz0); + ATF_TP_ADD_TC(tp, mountfuzz1); + ATF_TP_ADD_TC(tp, mountfuzz2); + ATF_TP_ADD_TC(tp, mountfuzz3); + ATF_TP_ADD_TC(tp, mountfuzz4); + ATF_TP_ADD_TC(tp, mountfuzz5); + ATF_TP_ADD_TC(tp, mountfuzz6); + ATF_TP_ADD_TC(tp, mountfuzz7); + ATF_TP_ADD_TC(tp, mountfuzz8); + + return atf_no_error(); +} diff --git a/contrib/netbsd-tests/fs/puffs/t_io.c b/contrib/netbsd-tests/fs/puffs/t_io.c new file mode 100644 index 000000000000..72b5d85e23ff --- /dev/null +++ b/contrib/netbsd-tests/fs/puffs/t_io.c @@ -0,0 +1,61 @@ +/* $NetBSD: t_io.c,v 1.2 2017/01/13 21:30:40 christos Exp $ */ + +#include <sys/types.h> +#include <sys/mount.h> +#include <sys/socket.h> + +#include <assert.h> +#include <atf-c.h> +#include <err.h> +#include <errno.h> +#include <fcntl.h> +#include <pthread.h> +#include <puffs.h> +#include <puffsdump.h> +#include <stdio.h> +#include <unistd.h> +#include <string.h> +#include <stdlib.h> + +#include <rump/rump.h> +#include <rump/rump_syscalls.h> + +#include "h_macros.h" +#include "../common/h_fsmacros.h" + +#define MAKEOPTS(...) \ + char *theopts[] = {NULL, "-s", __VA_ARGS__, "dtfs", "n/a", NULL} + +ATF_TC(nocache); +ATF_TC_HEAD(nocache, tc) +{ + + atf_tc_set_md_var(tc, "descr", "tests large i/o without page cache"); +} + +ATF_TC_BODY(nocache, tc) +{ + MAKEOPTS("-o", "nopagecache"); + char data[1024*1024]; + void *args; + int fd; + + FSTEST_CONSTRUCTOR_FSPRIV(tc, puffs, args, theopts); + FSTEST_ENTER(); + + RL(fd = rump_sys_open("afile", O_CREAT | O_RDWR, 0755)); + RL(rump_sys_write(fd, data, sizeof(data))); + rump_sys_close(fd); + + FSTEST_EXIT(); + FSTEST_DESTRUCTOR(tc, puffs, args); +} + + +ATF_TP_ADD_TCS(tp) +{ + + ATF_TP_ADD_TC(tp, nocache); + + return atf_no_error(); +} diff --git a/contrib/netbsd-tests/fs/tmpfs/README b/contrib/netbsd-tests/fs/tmpfs/README new file mode 100644 index 000000000000..cdc3f2d11ca7 --- /dev/null +++ b/contrib/netbsd-tests/fs/tmpfs/README @@ -0,0 +1,17 @@ +The tests in this directory where written at the same time tmpfs was +developed. This is why, if you follow the order of tests in the Atffile, +you will notice that they start checking the most basic things and end +checking the less common ones. Furthermore, tests try not to use features +tested by further tests in the lists. + +However, the above is not the most appropriate testing procedure when you +have a working file system because some separation in test programs does +not make sense afterwards. + +Many of the tests here are applicable to any file system. They should be +refactored to be reusable on any mounted file system, which could also +remove the need to do the mount/unmount steps in each and every test case. + +Possibly take a look at the file system tests in FreeBSD. They seem to be +much more complete, even though they are written in Perl and therefore not +directly usable. diff --git a/contrib/netbsd-tests/fs/tmpfs/h_funcs.subr b/contrib/netbsd-tests/fs/tmpfs/h_funcs.subr new file mode 100644 index 000000000000..edab7899ea71 --- /dev/null +++ b/contrib/netbsd-tests/fs/tmpfs/h_funcs.subr @@ -0,0 +1,115 @@ +#!/bin/sh +# +# $NetBSD: h_funcs.subr,v 1.5 2013/03/17 01:16:45 jmmv Exp $ +# +# Copyright (c) 2005, 2006, 2007 The NetBSD Foundation, Inc. +# All rights reserved. +# +# 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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. +# + +Mount_Point= + +# +# test_mount [args] +# +# Mounts tmpfs over ${Mount_Point} and changes the current directory +# to the mount point. Optional arguments may be passed to the +# mount command. +# +test_mount() { + require_fs tmpfs + + Mount_Point=$(pwd)/mntpt + atf_check -s eq:0 -o empty -e empty mkdir "${Mount_Point}" + echo "mount -t tmpfs ${*} tmpfs ${Mount_Point}" + mount -t tmpfs "${@}" tmpfs "${Mount_Point}" 2>mounterr + if [ "${?}" -ne 0 ]; then + cat mounterr 1>&2 + if grep 'Operation not supported' mounterr > /dev/null; then + atf_skip "tmpfs not supported" + fi + atf_fail "Failed to mount a tmpfs file system" + fi + cd "${Mount_Point}" +} + +# +# test_unmount +# +# Unmounts the file system mounted by test_mount. +# +test_unmount() { + # Begin FreeBSD + _test_unmount + exit_code=$? + atf_check_equal "$exit_code" "0" + return $exit_code + # End FreeBSD + cd - >/dev/null + atf_check -s eq:0 -o empty -e empty umount ${Mount_Point} + atf_check -s eq:0 -o empty -e empty rmdir ${Mount_Point} + Mount_Point= +} + +# Begin FreeBSD +_test_unmount() { + if [ -z "${Mount_Point}" -o ! -d "${Mount_Point}" ]; then + return 0 + fi + + cd - >/dev/null + umount ${Mount_Point} + rmdir ${Mount_Point} + Mount_Point= +} +# End FreeBSD + +# +# kqueue_monitor expected_nevents file1 [.. fileN] +# +# Monitors the commands given through stdin (one per line) using +# kqueue and stores the events raised in a log that can be later +# verified with kqueue_check. +# +kqueue_monitor() { + nev=${1}; shift + echo "Running kqueue-monitored commands and expecting" \ + "${nev} events" + $(atf_get_srcdir)/h_tools kqueue ${*} >kqueue.log || \ + atf_fail "Could not launch kqueue monitor" + got=$(wc -l kqueue.log | awk '{ print $1 }') + test ${got} -eq ${nev} || \ + atf_fail "Got ${got} events but expected ${nev}" +} + +# +# kqueue_check file event +# +# Checks if kqueue raised the given event when monitoring the +# given file. +# +kqueue_check() { + echo "Checking if ${1} received ${2}" + grep "^${1} - ${2}$" kqueue.log >/dev/null || \ + atf_fail "${1} did not receive ${2}" +} diff --git a/contrib/netbsd-tests/fs/tmpfs/h_tools.c b/contrib/netbsd-tests/fs/tmpfs/h_tools.c new file mode 100644 index 000000000000..492e084d2a5c --- /dev/null +++ b/contrib/netbsd-tests/fs/tmpfs/h_tools.c @@ -0,0 +1,321 @@ +/* $NetBSD: h_tools.c,v 1.4 2011/06/11 18:03:17 christos Exp $ */ + +/* + * Copyright (c) 2005, 2006 The NetBSD Foundation, Inc. + * All rights reserved. + * + * 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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. + */ + +/* + * Helper tools for several tests. These are kept in a single file due + * to the limitations of bsd.prog.mk to build a single program in a + * given directory. + */ + +#include <sys/param.h> +#include <sys/types.h> +#include <sys/event.h> +#include <sys/mount.h> +#include <sys/statvfs.h> +#include <sys/socket.h> +#include <sys/time.h> +#include <sys/un.h> + +#include <assert.h> +#include <err.h> +#include <errno.h> +#include <fcntl.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +#ifdef __FreeBSD__ +#include <inttypes.h> +#endif + +/* --------------------------------------------------------------------- */ + +static int getfh_main(int, char **); +static int kqueue_main(int, char **); +static int rename_main(int, char **); +static int sockets_main(int, char **); +static int statvfs_main(int, char **); + +/* --------------------------------------------------------------------- */ + +int +getfh_main(int argc, char **argv) +{ + int error; + void *fh; + size_t fh_size; + + if (argc < 2) + return EXIT_FAILURE; + +#ifdef __FreeBSD__ + fh_size = sizeof(fhandle_t); +#else + fh_size = 0; +#endif + + fh = NULL; + for (;;) { + if (fh_size) { + fh = malloc(fh_size); + if (fh == NULL) { + fprintf(stderr, "out of memory"); + return EXIT_FAILURE; + } + } + /* + * The kernel provides the necessary size in fh_size - + * but it may change if someone moves things around, + * so retry untill we have enough memory. + */ +#ifdef __FreeBSD__ + error = getfh(argv[1], fh); +#else + error = getfh(argv[1], fh, &fh_size); +#endif + if (error == 0) { + break; + } else { + if (fh != NULL) + free(fh); + if (errno != E2BIG) { + warn("getfh"); + return EXIT_FAILURE; + } + } + } + + error = write(STDOUT_FILENO, fh, fh_size); + if (error == -1) { + warn("write"); + return EXIT_FAILURE; + } + free(fh); + + return 0; +} + +/* --------------------------------------------------------------------- */ + +int +kqueue_main(int argc, char **argv) +{ + char *line; + int i, kq; + size_t len; + struct kevent *changes, event; + + if (argc < 2) + return EXIT_FAILURE; + + argc--; + argv++; + + changes = malloc(sizeof(struct kevent) * argc); + if (changes == NULL) + errx(EXIT_FAILURE, "not enough memory"); + + for (i = 0; i < argc; i++) { + int fd; + + fd = open(argv[i], O_RDONLY); + if (fd == -1) + err(EXIT_FAILURE, "cannot open %s", argv[i]); + + EV_SET(&changes[i], fd, EVFILT_VNODE, + EV_ADD | EV_ENABLE | EV_ONESHOT, + NOTE_ATTRIB | NOTE_DELETE | NOTE_EXTEND | NOTE_LINK | + NOTE_RENAME | NOTE_REVOKE | NOTE_WRITE, + 0, 0); + } + + kq = kqueue(); + if (kq == -1) + err(EXIT_FAILURE, "kqueue"); + + while ((line = fgetln(stdin, &len)) != NULL) { + int ec, nev; + struct timespec to; + + to.tv_sec = 0; + to.tv_nsec = 100000; + + (void)kevent(kq, changes, argc, &event, 1, &to); + + assert(len > 0); + assert(line[len - 1] == '\n'); + line[len - 1] = '\0'; + ec = system(line); + if (ec != EXIT_SUCCESS) + errx(ec, "%s returned %d", line, ec); + + do { + nev = kevent(kq, changes, argc, &event, 1, &to); + if (nev == -1) + err(EXIT_FAILURE, "kevent"); + else if (nev > 0) { + for (i = 0; i < argc; i++) + if (event.ident == changes[i].ident) + break; + + if (event.fflags & NOTE_ATTRIB) + printf("%s - NOTE_ATTRIB\n", argv[i]); + if (event.fflags & NOTE_DELETE) + printf("%s - NOTE_DELETE\n", argv[i]); + if (event.fflags & NOTE_EXTEND) + printf("%s - NOTE_EXTEND\n", argv[i]); + if (event.fflags & NOTE_LINK) + printf("%s - NOTE_LINK\n", argv[i]); + if (event.fflags & NOTE_RENAME) + printf("%s - NOTE_RENAME\n", argv[i]); + if (event.fflags & NOTE_REVOKE) + printf("%s - NOTE_REVOKE\n", argv[i]); + if (event.fflags & NOTE_WRITE) + printf("%s - NOTE_WRITE\n", argv[i]); + } + } while (nev > 0); + } + + for (i = 0; i < argc; i++) + close(changes[i].ident); + free(changes); + + return EXIT_SUCCESS; +} + +/* --------------------------------------------------------------------- */ + +int +rename_main(int argc, char **argv) +{ + + if (argc < 3) + return EXIT_FAILURE; + + if (rename(argv[1], argv[2]) == -1) { + warn("rename"); + return EXIT_FAILURE; + } + + return EXIT_SUCCESS; +} + +/* --------------------------------------------------------------------- */ + +int +sockets_main(int argc, char **argv) +{ + int error, fd; + struct sockaddr_un addr; + + if (argc < 2) + return EXIT_FAILURE; + + fd = socket(PF_LOCAL, SOCK_STREAM, 0); + if (fd == -1) { + warn("socket"); + return EXIT_FAILURE; + } + +#ifdef __FreeBSD__ + memset(&addr, 0, sizeof(addr)); +#endif + (void)strlcpy(addr.sun_path, argv[1], sizeof(addr.sun_path)); + addr.sun_family = PF_UNIX; +#ifdef __FreeBSD__ + error = bind(fd, (struct sockaddr *)&addr, SUN_LEN(&addr)); +#else + error = bind(fd, (struct sockaddr *)&addr, sizeof(addr)); +#endif + if (error == -1) { + warn("connect"); +#ifdef __FreeBSD__ + (void)close(fd); +#endif + return EXIT_FAILURE; + } + + close(fd); + + return EXIT_SUCCESS; +} + +/* --------------------------------------------------------------------- */ + +int +statvfs_main(int argc, char **argv) +{ + int error; + struct statvfs buf; + + if (argc < 2) + return EXIT_FAILURE; + + error = statvfs(argv[1], &buf); + if (error != 0) { + warn("statvfs"); + return EXIT_FAILURE; + } + + (void)printf("f_bsize=%lu\n", buf.f_bsize); + (void)printf("f_blocks=%" PRId64 "\n", buf.f_blocks); + (void)printf("f_bfree=%" PRId64 "\n", buf.f_bfree); + (void)printf("f_files=%" PRId64 "\n", buf.f_files); + + return EXIT_SUCCESS; +} + +/* --------------------------------------------------------------------- */ + +int +main(int argc, char **argv) +{ + int error; + + if (argc < 2) + return EXIT_FAILURE; + + argc -= 1; + argv += 1; + + if (strcmp(argv[0], "getfh") == 0) + error = getfh_main(argc, argv); + else if (strcmp(argv[0], "kqueue") == 0) + error = kqueue_main(argc, argv); + else if (strcmp(argv[0], "rename") == 0) + error = rename_main(argc, argv); + else if (strcmp(argv[0], "sockets") == 0) + error = sockets_main(argc, argv); + else if (strcmp(argv[0], "statvfs") == 0) + error = statvfs_main(argc, argv); + else + error = EXIT_FAILURE; + + return error; +} diff --git a/contrib/netbsd-tests/fs/tmpfs/t_create.sh b/contrib/netbsd-tests/fs/tmpfs/t_create.sh new file mode 100755 index 000000000000..f1f894dfd65f --- /dev/null +++ b/contrib/netbsd-tests/fs/tmpfs/t_create.sh @@ -0,0 +1,122 @@ +# $NetBSD: t_create.sh,v 1.8 2011/03/05 07:41:11 pooka Exp $ +# +# Copyright (c) 2005, 2006, 2007, 2008 The NetBSD Foundation, Inc. +# All rights reserved. +# +# 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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. +# + +# +# Verifies that the create operation works. +# + +atf_test_case create +create_head() { + atf_set "descr" "Verifies that files can be created" + atf_set "require.user" "root" +} +create_body() { + test_mount + + atf_check -s eq:1 -o empty -e empty test -f a + atf_check -s eq:0 -o empty -e empty touch a + atf_check -s eq:0 -o empty -e empty test -f a + + test_unmount +} + +atf_test_case attrs +attrs_head() { + atf_set "descr" "Verifies that a new file gets the correct" \ + "attributes" + atf_set "require.config" "unprivileged-user" + atf_set "require.user" "root" +} +attrs_body() { + user=$(atf_config_get unprivileged-user) + # Allow the unprivileged user to access the work directory. + chown ${user} . + + test_mount + + umask 022 + atf_check -s eq:1 -o empty -e empty test -f a + atf_check -s eq:0 -o empty -e empty touch a + atf_check -s eq:0 -o empty -e empty test -f a + + eval $(stat -s . | sed -e 's|st_|dst_|g') + eval $(stat -s a) + test ${st_flags} -eq 0 || atf_fail "Incorrect flags" + test ${st_size} -eq 0 || atf_fail "Incorrect size" + test ${st_uid} -eq $(id -u) || atf_fail "Incorrect uid" + test ${st_gid} -eq ${dst_gid} || atf_fail "Incorrect gid" + test ${st_mode} = 0100644 || atf_fail "Incorrect mode" + + atf_check -s eq:0 -o empty -e empty mkdir b c + + atf_check -s eq:0 -o empty -e empty chown ${user}:0 b + eval $(stat -s b) + [ ${st_uid} -eq $(id -u ${user}) ] || atf_fail "Incorrect owner" + [ ${st_gid} -eq 0 ] || atf_fail "Incorrect group" + + atf_check -s eq:0 -o empty -e empty chown ${user}:100 c + eval $(stat -s c) + [ ${st_uid} -eq $(id -u ${user}) ] || atf_fail "Incorrect owner" + [ ${st_gid} -eq 100 ] || atf_fail "Incorrect group" + + atf_check -s eq:0 -o empty -e empty su -m ${user} -c 'touch b/a' + eval $(stat -s b/a) + [ ${st_uid} -eq $(id -u ${user}) ] || atf_fail "Incorrect owner" + [ ${st_gid} -eq 0 ] || atf_fail "Incorrect group" + + atf_check -s eq:0 -o empty -e empty su -m ${user} -c 'touch c/a' + eval $(stat -s c/a) + [ ${st_uid} -eq $(id -u ${user}) ] || atf_fail "Incorrect owner" + [ ${st_gid} -eq 100 ] || atf_fail "Incorrect group" + + test_unmount +} + +atf_test_case kqueue +kqueue_head() { + atf_set "descr" "Verifies that creating a file raises the correct" \ + "kqueue events" + atf_set "require.user" "root" +} +kqueue_body() { + test_mount + + atf_check -s eq:0 -o empty -e empty mkdir dir + echo 'touch dir/a' | kqueue_monitor 1 dir + kqueue_check dir NOTE_WRITE + + test_unmount +} + +atf_init_test_cases() { + . $(atf_get_srcdir)/../h_funcs.subr + . $(atf_get_srcdir)/h_funcs.subr + + atf_add_test_case create + atf_add_test_case attrs + atf_add_test_case kqueue +} diff --git a/contrib/netbsd-tests/fs/tmpfs/t_devices.sh b/contrib/netbsd-tests/fs/tmpfs/t_devices.sh new file mode 100755 index 000000000000..472d37860dd8 --- /dev/null +++ b/contrib/netbsd-tests/fs/tmpfs/t_devices.sh @@ -0,0 +1,60 @@ +# $NetBSD: t_devices.sh,v 1.5 2010/11/07 17:51:18 jmmv Exp $ +# +# Copyright (c) 2005, 2006, 2007, 2008 The NetBSD Foundation, Inc. +# All rights reserved. +# +# 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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 basic +basic_head() { + atf_set "descr" "Tests that special devices work" + atf_set "require.user" "root" +} +basic_body() { + test_mount + + umask 022 + + atf_check -s eq:0 -o ignore -e ignore /dev/MAKEDEV std + atf_check -s eq:0 -o empty -e empty test -e zero + atf_check -s eq:0 -o empty -e empty test -e null + + echo "Reading from the 'zero' character device" + atf_check -s eq:0 -o ignore -e ignore dd if=zero of=a bs=10k count=1 + [ $(md5 a | cut -d ' ' -f 4) = 1276481102f218c981e0324180bafd9f ] || \ + atf_fail "Data read is invalid" + + echo "Writing to the 'null' device" + echo foo >null + eval $(stat -s null) + [ ${st_size} -eq 0 ] || atf_fail "Invalid size for device" + + test_unmount +} + +atf_init_test_cases() { + . $(atf_get_srcdir)/../h_funcs.subr + . $(atf_get_srcdir)/h_funcs.subr + + atf_add_test_case basic +} diff --git a/contrib/netbsd-tests/fs/tmpfs/t_dots.sh b/contrib/netbsd-tests/fs/tmpfs/t_dots.sh new file mode 100755 index 000000000000..e480de7658ac --- /dev/null +++ b/contrib/netbsd-tests/fs/tmpfs/t_dots.sh @@ -0,0 +1,67 @@ +# $NetBSD: t_dots.sh,v 1.5 2010/11/07 17:51:18 jmmv Exp $ +# +# Copyright (c) 2005, 2006, 2007, 2008 The NetBSD Foundation, Inc. +# All rights reserved. +# +# 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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 topdir +topdir_head() { + atf_set "descr" "Verifies that looking up '.' and '..' in" \ + "top-level directories works" + atf_set "require.user" "root" +} +topdir_body() { + test_mount + + atf_check -s eq:0 -o empty -e empty mkdir a + atf_check -s eq:0 -o empty -e empty test -d ./a + atf_check -s eq:0 -o empty -e empty test -d a/../a + + test_unmount +} + +atf_test_case nesteddir +nesteddir_head() { + atf_set "descr" "Verifies that looking up '.' and '..' in" \ + "top-level directories works" + atf_set "require.user" "root" +} +nesteddir_body() { + test_mount + + atf_check -s eq:0 -o empty -e empty mkdir a + atf_check -s eq:0 -o empty -e empty mkdir a/b + atf_check -s eq:0 -o empty -e empty test -d a/b/../b + atf_check -s eq:0 -o empty -e empty test -d a/b/../../a + + test_unmount +} + +atf_init_test_cases() { + . $(atf_get_srcdir)/../h_funcs.subr + . $(atf_get_srcdir)/h_funcs.subr + + atf_add_test_case topdir + atf_add_test_case nesteddir +} diff --git a/contrib/netbsd-tests/fs/tmpfs/t_exec.sh b/contrib/netbsd-tests/fs/tmpfs/t_exec.sh new file mode 100755 index 000000000000..9ffc6008a139 --- /dev/null +++ b/contrib/netbsd-tests/fs/tmpfs/t_exec.sh @@ -0,0 +1,52 @@ +# $NetBSD: t_exec.sh,v 1.5 2010/11/07 17:51:18 jmmv Exp $ +# +# Copyright (c) 2005, 2006, 2007, 2008 The NetBSD Foundation, Inc. +# All rights reserved. +# +# 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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 basic +basic_head() { + atf_set "descr" "Verifies that binary files can be executed from" \ + "within the file system (i.e., whether getpages" \ + "works)" + atf_set "require.user" "root" +} +basic_body() { + test_mount + + atf_check -s eq:0 -o empty -e empty cp /bin/cp . + echo "Verifying copied file" + [ $(md5 cp | cut -d ' ' -f 4) = $(md5 /bin/cp | cut -d ' ' -f 4) ] || \ + atf_file "New binary file does not match original" + atf_check -s eq:0 -o empty -e empty ./cp cp foo + + test_unmount +} + +atf_init_test_cases() { + . $(atf_get_srcdir)/../h_funcs.subr + . $(atf_get_srcdir)/h_funcs.subr + + atf_add_test_case basic +} diff --git a/contrib/netbsd-tests/fs/tmpfs/t_link.sh b/contrib/netbsd-tests/fs/tmpfs/t_link.sh new file mode 100755 index 000000000000..612c1e204509 --- /dev/null +++ b/contrib/netbsd-tests/fs/tmpfs/t_link.sh @@ -0,0 +1,144 @@ +# $NetBSD: t_link.sh,v 1.5 2010/11/07 17:51:18 jmmv Exp $ +# +# Copyright (c) 2005, 2006, 2007, 2008 The NetBSD Foundation, Inc. +# All rights reserved. +# +# 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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. +# + +# +# Verifies that the link operation works. +# + +atf_test_case basic +basic_head() { + atf_set "descr" "Verifies that the link operation works on files" \ + "at the top directory" + atf_set "require.user" "root" +} +basic_body() { + test_mount + + atf_check -s eq:0 -o empty -e empty touch a + atf_check -s eq:0 -o empty -e empty touch z + eval $(stat -s a | sed -e 's|st_|sta_|g') + eval $(stat -s z | sed -e 's|st_|stz_|g') + test ${sta_ino} != ${stz_ino} || \ + atf_fail "Node numbers are not different" + test ${sta_nlink} -eq 1 || atf_fail "Number of links is incorrect" + atf_check -s eq:0 -o empty -e empty ln a b + + echo "Checking if link count is correct after links are created" + eval $(stat -s a | sed -e 's|st_|sta_|g') + eval $(stat -s b | sed -e 's|st_|stb_|g') + test ${sta_ino} = ${stb_ino} || atf_fail "Node number changed" + test ${sta_nlink} -eq 2 || atf_fail "Link count is incorrect" + test ${stb_nlink} -eq 2 || atf_fail "Link count is incorrect" + + echo "Checking if link count is correct after links are deleted" + atf_check -s eq:0 -o empty -e empty rm a + eval $(stat -s b | sed -e 's|st_|stb_|g') + test ${stb_nlink} -eq 1 || atf_fail "Link count is incorrect" + atf_check -s eq:0 -o empty -e empty rm b + + test_unmount +} + +atf_test_case subdirs +subdirs_head() { + atf_set "descr" "Verifies that the link operation works if used" \ + "in subdirectories" + atf_set "require.user" "root" +} +subdirs_body() { + test_mount + + atf_check -s eq:0 -o empty -e empty touch a + atf_check -s eq:0 -o empty -e empty mkdir c + atf_check -s eq:0 -o empty -e empty ln a c/b + + echo "Checking if link count is correct after links are created" + eval $(stat -s a | sed -e 's|st_|sta_|g') + eval $(stat -s c/b | sed -e 's|st_|stb_|g') + test ${sta_ino} = ${stb_ino} || atf_fail "Node number changed" + test ${sta_nlink} -eq 2 || atf_fail "Link count is incorrect" + test ${stb_nlink} -eq 2 || atf_fail "Link count is incorrect" + + echo "Checking if link count is correct after links are deleted" + atf_check -s eq:0 -o empty -e empty rm a + eval $(stat -s c/b | sed -e 's|st_|stb_|g') + test ${stb_nlink} -eq 1 || atf_fail "Link count is incorrect" + atf_check -s eq:0 -o empty -e empty rm c/b + atf_check -s eq:0 -o empty -e empty rmdir c + + test_unmount +} + +# Begin FreeBSD +if true; then +atf_test_case kqueue cleanup +kqueue_cleanup() { + Mount_Point=$(pwd)/mntpt _test_unmount || : +} +else +# End FreeBSD +atf_test_case kqueue +# Begin FreeBSD +fi +# End FreeBSD +kqueue_head() { + atf_set "descr" "Verifies that creating a link raises the correct" \ + "kqueue events" + atf_set "require.user" "root" +} +kqueue_body() { + test_mount + + # Begin FreeBSD + atf_expect_fail "fails with: dir/b did not receive NOTE_LINK - bug 213662" + # End FreeBSD + + atf_check -s eq:0 -o empty -e empty mkdir dir + atf_check -s eq:0 -o empty -e empty touch dir/a + echo 'ln dir/a dir/b' | kqueue_monitor 2 dir dir/a + kqueue_check dir/a NOTE_LINK + kqueue_check dir NOTE_WRITE + + echo 'rm dir/a' | kqueue_monitor 2 dir dir/b + # XXX According to the (short) kqueue(2) documentation, the following + # should raise a NOTE_LINK but FFS raises a NOTE_DELETE... + kqueue_check dir/b NOTE_LINK + kqueue_check dir NOTE_WRITE + atf_check -s eq:0 -o empty -e empty rm dir/b + atf_check -s eq:0 -o empty -e empty rmdir dir + + test_unmount +} + +atf_init_test_cases() { + . $(atf_get_srcdir)/../h_funcs.subr + . $(atf_get_srcdir)/h_funcs.subr + + atf_add_test_case basic + atf_add_test_case subdirs + atf_add_test_case kqueue +} diff --git a/contrib/netbsd-tests/fs/tmpfs/t_mkdir.sh b/contrib/netbsd-tests/fs/tmpfs/t_mkdir.sh new file mode 100755 index 000000000000..db0d1e3c5c8f --- /dev/null +++ b/contrib/netbsd-tests/fs/tmpfs/t_mkdir.sh @@ -0,0 +1,159 @@ +# $NetBSD: t_mkdir.sh,v 1.8 2011/03/05 07:41:11 pooka Exp $ +# +# Copyright (c) 2005, 2006, 2007, 2008 The NetBSD Foundation, Inc. +# All rights reserved. +# +# 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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. +# + +# +# Verifies that mkdir works by creating some nested directories. It also +# checks, in part, the lookup operation. +# + +atf_test_case single +single_head() { + atf_set "descr" "Creates a single directory and checks the" \ + "mount point's hard link count" + atf_set "require.user" "root" +} +single_body() { + test_mount + + atf_check -s eq:1 -o empty -e empty test -d a + atf_check -s eq:0 -o empty -e empty mkdir a + atf_check -s eq:0 -o empty -e empty test -d a + test -d a + eval $(stat -s ${Mount_Point}) + [ ${st_nlink} = 3 ] || atf_fail "Link count is not 3" + + test_unmount +} + +atf_test_case many +many_head() { + atf_set "descr" "Creates multiple directories and checks the" \ + "mount point's hard link count" + atf_set "require.user" "root" +} +many_body() { + test_mount + + for d in $(jot 100); do + atf_check -s eq:1 -o empty -e empty test -d ${d} + atf_check -s eq:0 -o empty -e empty mkdir ${d} + atf_check -s eq:0 -o empty -e empty test -d ${d} + done + eval $(stat -s ${Mount_Point}) + [ ${st_nlink} = 102 ] || atf_fail "Link count is not 102" + + test_unmount +} + +atf_test_case nested +nested_head() { + atf_set "descr" "Checks if nested directories can be created" + atf_set "require.user" "root" +} +nested_body() { + test_mount + + atf_check -s eq:1 -o empty -e empty test -d a/b/c/d/e + atf_check -s eq:0 -o empty -e empty mkdir -p a/b/c/d/e + atf_check -s eq:0 -o empty -e empty test -d a/b/c/d/e + + test_unmount +} + +atf_test_case attrs +attrs_head() { + atf_set "descr" "Checks that new directories get the proper" \ + "attributes (owner and group)" + atf_set "require.config" "unprivileged-user" + atf_set "require.user" "root" +} +attrs_body() { + user=$(atf_config_get unprivileged-user) + # Allow the unprivileged user to access the work directory. + chown ${user} . + + test_mount + + atf_check -s eq:0 -o empty -e empty mkdir b c + + atf_check -s eq:0 -o empty -e empty chown ${user}:0 b + eval $(stat -s b) + [ ${st_uid} -eq $(id -u ${user}) ] || atf_fail "Incorrect owner" + [ ${st_gid} -eq 0 ] || atf_fail "Incorrect group" + + atf_check -s eq:0 -o empty -e empty chown ${user}:100 c + eval $(stat -s c) + [ ${st_uid} -eq $(id -u ${user}) ] || atf_fail "Incorrect owner" + [ ${st_gid} -eq 100 ] || atf_fail "Incorrect group" + + atf_check -s eq:0 -o empty -e empty su -m ${user} -c 'mkdir b/a' + eval $(stat -s b/a) + [ ${st_uid} -eq $(id -u ${user}) ] || atf_fail "Incorrect owner" + [ ${st_gid} -eq 0 ] || atf_fail "Incorrect group" + + atf_check -s eq:0 -o empty -e empty su -m ${user} -c 'mkdir c/a' + eval $(stat -s c/a) + [ ${st_uid} -eq $(id -u ${user}) ] || atf_fail "Incorrect owner" + [ ${st_gid} -eq 100 ] || atf_fail "Incorrect group" + + test_unmount +} + +atf_test_case kqueue +kqueue_head() { + atf_set "descr" "Creates a directory and checks the kqueue events" \ + "raised" + atf_set "require.user" "root" +} +kqueue_body() { + test_mount + + atf_check -s eq:0 -o empty -e empty mkdir dir + echo 'mkdir dir/a' | kqueue_monitor 2 dir + + # Creating a directory raises NOTE_LINK on the parent directory + kqueue_check dir NOTE_LINK + + # Creating a directory raises NOTE_WRITE on the parent directory + kqueue_check dir NOTE_WRITE + + atf_check -s eq:0 -o empty -e empty rmdir dir/a + atf_check -s eq:0 -o empty -e empty rmdir dir + + test_unmount +} + +atf_init_test_cases() { + . $(atf_get_srcdir)/../h_funcs.subr + . $(atf_get_srcdir)/h_funcs.subr + + atf_add_test_case single + atf_add_test_case many + atf_add_test_case nested + atf_add_test_case attrs + atf_add_test_case kqueue +} diff --git a/contrib/netbsd-tests/fs/tmpfs/t_mknod.sh b/contrib/netbsd-tests/fs/tmpfs/t_mknod.sh new file mode 100755 index 000000000000..62c7cce22834 --- /dev/null +++ b/contrib/netbsd-tests/fs/tmpfs/t_mknod.sh @@ -0,0 +1,143 @@ +# $NetBSD: t_mknod.sh,v 1.5 2010/11/07 17:51:18 jmmv Exp $ +# +# Copyright (c) 2005, 2006, 2007, 2008 The NetBSD Foundation, Inc. +# All rights reserved. +# +# 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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. +# + +# +# Verifies that the mknod operation works. +# + +atf_test_case block +block_head() { + atf_set "descr" "Tests that block devices can be created" + atf_set "require.user" "root" +} +block_body() { + test_mount + umask 022 + + atf_check -s eq:0 -o empty -e empty mknod fd0a b 2 0 + eval $(stat -s fd0a) + [ ${st_mode} = 060644 ] || atf_fail "Invalid mode" + [ ${st_rdev} -eq 512 ] || atf_fail "Invalid device" + + test_unmount +} + +atf_test_case block_kqueue +block_kqueue_head() { + atf_set "descr" "Tests that creating a block device raises the" \ + "appropriate kqueue events" + atf_set "require.user" "root" +} +block_kqueue_body() { + test_mount + umask 022 + + atf_check -s eq:0 -o empty -e empty mkdir dir + echo 'mknod dir/fd0a b 2 0' | kqueue_monitor 1 dir + kqueue_check dir NOTE_WRITE + + test_unmount +} + +atf_test_case char +char_head() { + atf_set "descr" "Tests that character devices can be created" + atf_set "require.user" "root" +} +char_body() { + test_mount + umask 022 + + atf_check -s eq:0 -o empty -e empty mknod null c 2 2 + eval $(stat -s null) + [ ${st_mode} = 020644 ] || atf_fail "Invalid mode" + [ ${st_rdev} -eq 514 ] || atf_fail "Invalid device" + + test_unmount +} + +atf_test_case char_kqueue +char_kqueue_head() { + atf_set "descr" "Tests that creating a character device raises the" \ + "appropriate kqueue events" + atf_set "require.user" "root" +} +char_kqueue_body() { + test_mount + umask 022 + + atf_check -s eq:0 -o empty -e empty mkdir dir + echo 'mknod dir/null c 2 2' | kqueue_monitor 1 dir + kqueue_check dir NOTE_WRITE + + test_unmount +} + +atf_test_case pipe +pipe_head() { + atf_set "descr" "Tests that named pipes can be created" + atf_set "require.user" "root" +} +pipe_body() { + test_mount + umask 022 + + atf_check -s eq:0 -o empty -e empty mknod pipe p + eval $(stat -s pipe) + [ ${st_mode} = 010644 ] || atf_fail "Invalid mode" + + test_unmount +} + +atf_test_case pipe_kqueue +pipe_kqueue_head() { + atf_set "descr" "Tests that creating a named pipe raises the" \ + "appropriate kqueue events" + atf_set "require.user" "root" +} +pipe_kqueue_body() { + test_mount + umask 022 + + atf_check -s eq:0 -o empty -e empty mkdir dir + echo 'mknod dir/pipe p' | kqueue_monitor 1 dir + kqueue_check dir NOTE_WRITE + + test_unmount +} + +atf_init_test_cases() { + . $(atf_get_srcdir)/../h_funcs.subr + . $(atf_get_srcdir)/h_funcs.subr + + atf_add_test_case block + atf_add_test_case block_kqueue + atf_add_test_case char + atf_add_test_case char_kqueue + atf_add_test_case pipe + atf_add_test_case pipe_kqueue +} diff --git a/contrib/netbsd-tests/fs/tmpfs/t_mount.sh b/contrib/netbsd-tests/fs/tmpfs/t_mount.sh new file mode 100755 index 000000000000..9ec5e31bd1a0 --- /dev/null +++ b/contrib/netbsd-tests/fs/tmpfs/t_mount.sh @@ -0,0 +1,156 @@ +# $NetBSD: t_mount.sh,v 1.6 2010/11/07 17:51:18 jmmv Exp $ +# +# Copyright (c) 2005, 2006, 2007, 2008 The NetBSD Foundation, Inc. +# All rights reserved. +# +# 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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. +# + +# +# Verifies that an execution of mount and umount works correctly without +# causing errors and that the root node gets correct attributes. +# Also verifies command line parsing from mount_tmpfs. +# + +atf_test_case plain +plain_head() { + atf_set "descr" "Tests a mount and unmount without any options" + atf_set "require.user" "root" +} +plain_body() { + test_mount + test_unmount +} + +atf_test_case links +links_head() { + atf_set "descr" "Tests that the mount point has two hard links" + atf_set "require.user" "root" +} +links_body() { + test_mount + eval $(stat -s ${Mount_Point}) + [ ${st_nlink} = 2 ] || \ + atf_fail "Root directory does not have two hard links" + test_unmount +} + +atf_test_case options +options_head() { + atf_set "descr" "Tests the read-only mount option" + atf_set "require.user" "root" +} +options_body() { + test_mount -o ro + mount | grep ${Mount_Point} | grep -q read-only || \ + atf_fail "read-only option (ro) does not work" + test_unmount +} + +atf_test_case attrs +attrs_head() { + atf_set "descr" "Tests that root directory attributes are set" \ + "correctly" + atf_set "require.user" "root" +} +attrs_body() { + test_mount -o -u1000 -o -g100 -o -m755 + eval $(stat -s ${Mount_Point}) + [ ${st_uid} = 1000 ] || atf_fail "uid is incorrect" + [ ${st_gid} = 100 ] || atf_fail "gid is incorrect" + [ ${st_mode} = 040755 ] || atf_fail "mode is incorrect" + test_unmount +} + +atf_test_case negative +negative_head() { + atf_set "descr" "Tests that negative values passed to to -s are" \ + "handled correctly" + atf_set "require.user" "root" +} +negative_body() { + mkdir tmp + test_mount -o -s-10 + test_unmount +} + +# Begin FreeBSD +if true; then +atf_test_case large cleanup +large_cleanup() { + umount -f tmp 2>/dev/null || : + Mount_Point=$(pwd)/mnt _test_unmount || : +} +else +# End FreeBSD +atf_test_case large +# Begin FreeBSD +fi +# End FreeBSD +large_head() { + atf_set "descr" "Tests that extremely long values passed to -s" \ + "are handled correctly" + atf_set "require.user" "root" +} +large_body() { + test_mount -o -s9223372036854775807 + test_unmount + + # Begin FreeBSD + atf_expect_fail "-o -s<large-size> succeeds unexpectedly on FreeBSD - bug 212862" + # End FreeBSD + + mkdir tmp + atf_check -s eq:1 -o empty -e ignore \ + mount -t tmpfs -o -s9223372036854775808 tmpfs tmp + atf_check -s eq:1 -o empty -e ignore \ + mount -t tmpfs -o -s9223372036854775808g tmpfs tmp + rmdir tmp +} + +atf_test_case mntpt +mntpt_head() { + atf_set "descr" "Tests that the error messages printed when the" \ + "mount point is invalid do not show the source" \ + "unused parameter" +} +mntpt_body() { + mount_tmpfs unused $(pwd)/mnt >out 2>&1 + atf_check -s eq:1 -o empty -e empty grep unused out + atf_check -s eq:0 -o ignore -e empty grep "$(pwd)/mnt" out + + mount_tmpfs unused mnt >out 2>&1 + atf_check -s eq:1 -o empty -e empty grep unused out + atf_check -s eq:0 -o ignore -e empty grep mnt out +} + +atf_init_test_cases() { + . $(atf_get_srcdir)/../h_funcs.subr + . $(atf_get_srcdir)/h_funcs.subr + + atf_add_test_case plain + atf_add_test_case options + atf_add_test_case attrs + atf_add_test_case negative + atf_add_test_case large + atf_add_test_case mntpt +} diff --git a/contrib/netbsd-tests/fs/tmpfs/t_pipes.sh b/contrib/netbsd-tests/fs/tmpfs/t_pipes.sh new file mode 100755 index 000000000000..7c0065a9cb1d --- /dev/null +++ b/contrib/netbsd-tests/fs/tmpfs/t_pipes.sh @@ -0,0 +1,52 @@ +# $NetBSD: t_pipes.sh,v 1.5 2010/11/07 17:51:18 jmmv Exp $ +# +# Copyright (c) 2005, 2006, 2007, 2008 The NetBSD Foundation, Inc. +# All rights reserved. +# +# 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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 basic +basic_head() { + atf_set "descr" "Verifies that pipes work" + atf_set "require.user" "root" +} +basic_body() { + test_mount + + umask 022 + + atf_check -s eq:0 -o empty -e empty mknod pipe p + + echo "Writing to pipe and waiting for response" + echo -n foo >pipe & + [ "$(cat pipe)" = foo ] || atf_fail "Received data is incorrect" + + test_unmount +} + +atf_init_test_cases() { + . $(atf_get_srcdir)/../h_funcs.subr + . $(atf_get_srcdir)/h_funcs.subr + + atf_add_test_case basic +} diff --git a/contrib/netbsd-tests/fs/tmpfs/t_read_write.sh b/contrib/netbsd-tests/fs/tmpfs/t_read_write.sh new file mode 100755 index 000000000000..13cc2560ad44 --- /dev/null +++ b/contrib/netbsd-tests/fs/tmpfs/t_read_write.sh @@ -0,0 +1,87 @@ +# $NetBSD: t_read_write.sh,v 1.5 2010/11/07 17:51:18 jmmv Exp $ +# +# Copyright (c) 2005, 2006, 2007, 2008 The NetBSD Foundation, Inc. +# All rights reserved. +# +# 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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. +# + +# +# Verifies that the read and write operations work. +# + +atf_test_case basic +basic_head() { + atf_set "descr" "Checks that file removal works" + atf_set "require.user" "root" +} +basic_body() { + test_mount + + echo "Testing write to a small file" + echo foo >a || atf_fail "Failed to write to file" + [ $(md5 a | cut -d ' ' -f 4) = d3b07384d113edec49eaa6238ad5ff00 ] || \ + atf_fail "Invalid file contents" + + echo "Testing appending to a small file" + echo bar >>a || atf_fail "Failed to append data to file" + [ $(md5 a | cut -d ' ' -f 4) = f47c75614087a8dd938ba4acff252494 ] || \ + atf_fail "Invalid file contents" + + echo "Testing write to a big file (bigger than a page)" + jot 10000 >b || atf_fail "Failed to create a big file" + [ $(md5 b | cut -d ' ' -f 4) = 72d4ff27a28afbc066d5804999d5a504 ] || \ + atf_fail "Invalid file contents" + + test_unmount +} + +atf_test_case kqueue +kqueue_head() { + atf_set "descr" "Checks that writing to a file raises the" \ + "appropriate kqueue events" + atf_set "require.user" "root" +} +kqueue_body() { + test_mount + + atf_check -s eq:0 -o ignore -e ignore \ + dd if=/dev/zero of=c bs=1k count=10 + echo 'dd if=/dev/zero of=c seek=2 bs=1k count=1 conv=notrunc' \ + '>/dev/null 2>&1' | kqueue_monitor 1 c + kqueue_check c NOTE_WRITE + + echo foo >d + echo 'echo bar >>d' | kqueue_monitor 2 d + kqueue_check d NOTE_EXTEND + kqueue_check d NOTE_WRITE + + test_unmount +} + +atf_init_test_cases() { + . $(atf_get_srcdir)/../h_funcs.subr + . $(atf_get_srcdir)/h_funcs.subr + + atf_add_test_case basic + atf_add_test_case kqueue +} diff --git a/contrib/netbsd-tests/fs/tmpfs/t_readdir.sh b/contrib/netbsd-tests/fs/tmpfs/t_readdir.sh new file mode 100755 index 000000000000..6f5dc3ef2bde --- /dev/null +++ b/contrib/netbsd-tests/fs/tmpfs/t_readdir.sh @@ -0,0 +1,116 @@ +# $NetBSD: t_readdir.sh,v 1.5 2010/11/07 17:51:18 jmmv Exp $ +# +# Copyright (c) 2005, 2006, 2007, 2008 The NetBSD Foundation, Inc. +# All rights reserved. +# +# 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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. +# + +# +# Verifies that the readdir operation works. +# + +atf_test_case dots +dots_head() { + atf_set "descr" "Verifies that readdir returns the '.' and '..'" \ + "entries" + atf_set "require.user" "root" +} +dots_body() { + test_mount + + atf_check -s eq:0 -o save:stdout -e empty /bin/ls -a + atf_check -s eq:0 -o ignore -e empty grep '^\.$' stdout + atf_check -s eq:0 -o ignore -e empty grep '^\..$' stdout + + test_unmount +} + +atf_test_case types +types_head() { + atf_set "descr" "Verifies that readdir works for all different" \ + "file types" + atf_set "require.user" "root" +} +types_body() { + test_mount + + atf_check -s eq:0 -o empty -e empty mkdir dir + atf_check -s eq:0 -o empty -e empty touch reg + atf_check -s eq:0 -o empty -e empty ln -s reg lnk + atf_check -s eq:0 -o empty -e empty mknod blk b 0 0 + atf_check -s eq:0 -o empty -e empty mknod chr c 0 0 + atf_check -s eq:0 -o empty -e empty mknod fifo p + atf_check -s eq:0 -o empty -e empty \ + $(atf_get_srcdir)/h_tools sockets sock + + atf_check -s eq:0 -o ignore -e empty ls + atf_check -s eq:0 -o empty -e empty rm -rf * + + test_unmount +} + +atf_test_case caching +caching_head() { + atf_set "descr" "Catch a bug caused by incorrect invalidation of" \ + "readdir caching variables" + atf_set "require.user" "root" +} +caching_body() { + test_mount + + atf_check -s eq:0 -o empty -e empty touch $(jot 10) + atf_check -s eq:0 -o empty -e empty rm * + atf_check -s eq:0 -o empty -e empty touch $(jot 20) + atf_check -s eq:0 -o empty -e empty -x "ls >/dev/null" + + test_unmount +} + +atf_test_case many +many_head() { + atf_set "descr" "Verifies that readdir works with many files" + atf_set "require.user" "root" +} +many_body() { + test_mount + + atf_check -s eq:0 -o empty -e empty mkdir a + echo "Creating 500 files" + for f in $(jot 500); do + touch a/$f + done + atf_check -s eq:0 -o empty -e empty rm a/* + atf_check -s eq:0 -o empty -e empty rmdir a + + test_unmount +} + +atf_init_test_cases() { + . $(atf_get_srcdir)/../h_funcs.subr + . $(atf_get_srcdir)/h_funcs.subr + + atf_add_test_case dots + atf_add_test_case types + atf_add_test_case caching + atf_add_test_case many +} diff --git a/contrib/netbsd-tests/fs/tmpfs/t_remove.sh b/contrib/netbsd-tests/fs/tmpfs/t_remove.sh new file mode 100755 index 000000000000..f75032c0b146 --- /dev/null +++ b/contrib/netbsd-tests/fs/tmpfs/t_remove.sh @@ -0,0 +1,125 @@ +# $NetBSD: t_remove.sh,v 1.5 2010/11/07 17:51:18 jmmv Exp $ +# +# Copyright (c) 2005, 2006, 2007, 2008 The NetBSD Foundation, Inc. +# All rights reserved. +# +# 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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. +# + +# +# Verifies that the remove operation works. +# + +atf_test_case single +single_head() { + atf_set "descr" "Checks that file removal works" + atf_set "require.user" "root" +} +single_body() { + test_mount + + atf_check -s eq:1 -o empty -e empty test -f a + atf_check -s eq:0 -o empty -e empty touch a + atf_check -s eq:0 -o empty -e empty test -f a + atf_check -s eq:0 -o empty -e empty rm a + atf_check -s eq:1 -o empty -e empty test -f a + + test_unmount +} + +# Begin FreeBSD +if true; then +atf_test_case uchg cleanup +uchg_cleanup() { + Mount_Point=$(pwd)/mntpt _test_unmount +} +else +# End FreeBSD +atf_test_case uchg +# Begin FreeBSD +fi +# End FreeBSD +uchg_head() { + atf_set "descr" "Checks that files with the uchg flag set cannot" \ + "be removed" + atf_set "require.user" "root" +} +uchg_body() { + # Begin FreeBSD + atf_expect_fail "this fails on FreeBSD with root - bug 212861" + # End FreeBSD + + test_mount + + atf_check -s eq:0 -o empty -e empty touch a + atf_check -s eq:0 -o empty -e empty chflags uchg a + atf_check -s eq:1 -o empty -e ignore rm -f a + atf_check -s eq:0 -o empty -e empty chflags nouchg a + atf_check -s eq:0 -o empty -e empty rm a + atf_check -s eq:1 -o empty -e empty test -f a + + test_unmount +} + +atf_test_case dot +dot_head() { + atf_set "descr" "Checks that '.' cannot be removed" + atf_set "require.user" "root" +} +dot_body() { + test_mount + + atf_check -s eq:0 -o empty -e empty mkdir a + atf_check -s eq:1 -o empty -e ignore unlink a/. + atf_check -s eq:0 -o empty -e empty rmdir a + + test_unmount +} + +atf_test_case kqueue +kqueue_head() { + atf_set "descr" "Removes a file and checks the kqueue events" \ + "raised" + atf_set "require.user" "root" +} +kqueue_body() { + test_mount + + atf_check -s eq:0 -o empty -e empty mkdir dir + atf_check -s eq:0 -o empty -e empty touch dir/a + echo 'rm dir/a' | kqueue_monitor 2 dir dir/a + kqueue_check dir/a NOTE_DELETE + kqueue_check dir NOTE_WRITE + atf_check -s eq:0 -o empty -e empty rmdir dir + + test_unmount +} + +atf_init_test_cases() { + . $(atf_get_srcdir)/../h_funcs.subr + . $(atf_get_srcdir)/h_funcs.subr + + atf_add_test_case single + atf_add_test_case uchg + atf_add_test_case dot + atf_add_test_case kqueue +} diff --git a/contrib/netbsd-tests/fs/tmpfs/t_rename.sh b/contrib/netbsd-tests/fs/tmpfs/t_rename.sh new file mode 100755 index 000000000000..7613f1f493a8 --- /dev/null +++ b/contrib/netbsd-tests/fs/tmpfs/t_rename.sh @@ -0,0 +1,278 @@ +# $NetBSD: t_rename.sh,v 1.5 2010/11/07 17:51:18 jmmv Exp $ +# +# Copyright (c) 2005, 2006, 2007, 2008 The NetBSD Foundation, Inc. +# All rights reserved. +# +# 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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. +# + +# +# Verifies that the rename operation works (either by renaming entries or +# by moving them). +# + +atf_test_case dots +dots_head() { + atf_set "descr" "Tests that '.' and '..' cannot be renamed" + atf_set "require.user" "root" +} +dots_body() { + test_mount + + atf_check -s eq:0 -o empty -e empty mkdir a + atf_check -s eq:1 -o empty -e ignore mv a/. c + atf_check -s eq:1 -o empty -e ignore mv a/.. c + atf_check -s eq:0 -o empty -e empty rmdir a + + test_unmount +} + +atf_test_case crossdev +crossdev_head() { + atf_set "descr" "Tests that cross-device renames do not work" + atf_set "require.user" "root" +} +crossdev_body() { + test_mount + + atf_check -s eq:0 -o empty -e empty mkdir a + atf_check -s eq:1 -o empty -e save:stderr \ + $(atf_get_srcdir)/h_tools rename a /var/tmp/a + atf_check -s eq:0 -o ignore -e empty grep "Cross-device link" stderr + atf_check -s eq:0 -o empty -e empty test -d a + atf_check -s eq:0 -o empty -e empty rmdir a + + test_unmount +} + +atf_test_case basic +basic_head() { + atf_set "descr" "Tests that basic renames work" + atf_set "require.user" "root" +} +basic_body() { + test_mount + + atf_check -s eq:0 -o empty -e empty mkdir a + atf_check -s eq:0 -o empty -e empty mv a c + atf_check -s eq:1 -o empty -e empty test -d a + atf_check -s eq:0 -o empty -e empty test -d c + atf_check -s eq:0 -o empty -e empty rmdir c + + test_unmount +} + +atf_test_case dotdot +dotdot_head() { + atf_set "descr" "Tests that the '..' entry is properly updated" \ + "during moves" + atf_set "require.user" "root" +} +dotdot_body() { + test_mount + + echo "Checking if the '..' entry is updated after moves" + atf_check -s eq:0 -o empty -e empty mkdir a + atf_check -s eq:0 -o empty -e empty mkdir b + atf_check -s eq:0 -o empty -e empty mv b a + atf_check -s eq:0 -o empty -e empty test -d a/b/../b + atf_check -s eq:0 -o empty -e empty test -d a/b/../../a + eval $(stat -s a/b) + [ ${st_nlink} = 2 ] || atf_fail "Incorrect number of links" + eval $(stat -s a) + [ ${st_nlink} = 3 ] || atf_fail "Incorrect number of links" + atf_check -s eq:0 -o empty -e empty rmdir a/b + atf_check -s eq:0 -o empty -e empty rmdir a + + echo "Checking if the '..' entry is correct after renames" + atf_check -s eq:0 -o empty -e empty mkdir a + atf_check -s eq:0 -o empty -e empty mkdir b + atf_check -s eq:0 -o empty -e empty mv b a + atf_check -s eq:0 -o empty -e empty mv a c + atf_check -s eq:0 -o empty -e empty test -d c/b/../b + atf_check -s eq:0 -o empty -e empty test -d c/b/../../c + atf_check -s eq:0 -o empty -e empty rmdir c/b + atf_check -s eq:0 -o empty -e empty rmdir c + + echo "Checking if the '..' entry is correct after multiple moves" + atf_check -s eq:0 -o empty -e empty mkdir a + atf_check -s eq:0 -o empty -e empty mkdir b + atf_check -s eq:0 -o empty -e empty mv b a + atf_check -s eq:0 -o empty -e empty mv a c + atf_check -s eq:0 -o empty -e empty mv c/b d + atf_check -s eq:0 -o empty -e empty test -d d/../c + atf_check -s eq:0 -o empty -e empty rmdir d + atf_check -s eq:0 -o empty -e empty rmdir c + + test_unmount +} + +atf_test_case dir_to_emptydir +dir_to_emptydir_head() { + atf_set "descr" "Tests that renaming a directory to override an" \ + "empty directory works" + atf_set "require.user" "root" +} +dir_to_emptydir_body() { + test_mount + + atf_check -s eq:0 -o empty -e empty mkdir a + atf_check -s eq:0 -o empty -e empty touch a/c + atf_check -s eq:0 -o empty -e empty mkdir b + atf_check -s eq:0 -o empty -e empty \ + $(atf_get_srcdir)/h_tools rename a b + atf_check -s eq:1 -o empty -e empty test -e a + atf_check -s eq:0 -o empty -e empty test -d b + atf_check -s eq:0 -o empty -e empty test -f b/c + rm b/c + rmdir b + + test_unmount +} + +atf_test_case dir_to_fulldir +dir_to_fulldir_head() { + atf_set "descr" "Tests that renaming a directory to override a" \ + "non-empty directory fails" + atf_set "require.user" "root" +} +dir_to_fulldir_body() { + test_mount + + atf_check -s eq:0 -o empty -e empty mkdir a + atf_check -s eq:0 -o empty -e empty touch a/c + atf_check -s eq:0 -o empty -e empty mkdir b + atf_check -s eq:0 -o empty -e empty touch b/d + atf_check -s eq:1 -o empty -e save:stderr \ + $(atf_get_srcdir)/h_tools rename a b + atf_check -s eq:0 -o ignore -e empty grep "Directory not empty" stderr + atf_check -s eq:0 -o empty -e empty test -d a + atf_check -s eq:0 -o empty -e empty test -f a/c + atf_check -s eq:0 -o empty -e empty test -d b + atf_check -s eq:0 -o empty -e empty test -f b/d + rm a/c + rm b/d + rmdir a + rmdir b + + test_unmount +} + +atf_test_case dir_to_file +dir_to_file_head() { + atf_set "descr" "Tests that renaming a directory to override a" \ + "file fails" + atf_set "require.user" "root" +} +dir_to_file_body() { + test_mount + + atf_check -s eq:0 -o empty -e empty mkdir a + atf_check -s eq:0 -o empty -e empty touch b + atf_check -s eq:1 -o empty -e save:stderr \ + $(atf_get_srcdir)/h_tools rename a b + atf_check -s eq:0 -o ignore -e empty grep "Not a directory" stderr + atf_check -s eq:0 -o empty -e empty test -d a + atf_check -s eq:0 -o empty -e empty test -f b + rmdir a + rm b + + test_unmount +} + +atf_test_case file_to_dir +file_to_dir_head() { + atf_set "descr" "Tests that renaming a file to override a" \ + "directory fails" + atf_set "require.user" "root" +} +file_to_dir_body() { + test_mount + + atf_check -s eq:0 -o empty -e empty touch a + atf_check -s eq:0 -o empty -e empty mkdir b + atf_check -s eq:1 -o empty -e save:stderr \ + $(atf_get_srcdir)/h_tools rename a b + atf_check -s eq:0 -o ignore -e empty grep "Is a directory" stderr + atf_check -s eq:0 -o empty -e empty test -f a + atf_check -s eq:0 -o empty -e empty test -d b + rm a + rmdir b + + test_unmount +} + +atf_test_case kqueue +kqueue_head() { + atf_set "descr" "Tests that moving and renaming files raise the" \ + "correct kqueue events" + atf_set "require.user" "root" +} +kqueue_body() { + test_mount + + atf_check -s eq:0 -o empty -e empty mkdir dir + atf_check -s eq:0 -o empty -e empty touch dir/a + echo 'mv dir/a dir/b' | kqueue_monitor 2 dir dir/a + kqueue_check dir/a NOTE_RENAME + kqueue_check dir NOTE_WRITE + atf_check -s eq:0 -o empty -e empty rm dir/b + atf_check -s eq:0 -o empty -e empty rmdir dir + + atf_check -s eq:0 -o empty -e empty mkdir dir + atf_check -s eq:0 -o empty -e empty touch dir/a + atf_check -s eq:0 -o empty -e empty touch dir/b + echo 'mv dir/a dir/b' | kqueue_monitor 3 dir dir/a dir/b + kqueue_check dir/a NOTE_RENAME + kqueue_check dir NOTE_WRITE + kqueue_check dir/b NOTE_DELETE + atf_check -s eq:0 -o empty -e empty rm dir/b + atf_check -s eq:0 -o empty -e empty rmdir dir + + atf_check -s eq:0 -o empty -e empty mkdir dir1 + atf_check -s eq:0 -o empty -e empty mkdir dir2 + atf_check -s eq:0 -o empty -e empty touch dir1/a + echo 'mv dir1/a dir2/a' | kqueue_monitor 3 dir1 dir1/a dir2 + kqueue_check dir1/a NOTE_RENAME + kqueue_check dir1 NOTE_WRITE + kqueue_check dir2 NOTE_WRITE + atf_check -s eq:0 -o empty -e empty rm dir2/a + atf_check -s eq:0 -o empty -e empty rmdir dir1 + atf_check -s eq:0 -o empty -e empty rmdir dir2 + + test_unmount +} + +atf_init_test_cases() { + . $(atf_get_srcdir)/../h_funcs.subr + . $(atf_get_srcdir)/h_funcs.subr + + atf_add_test_case dots + atf_add_test_case crossdev + atf_add_test_case basic + atf_add_test_case dotdot + atf_add_test_case dir_to_emptydir + atf_add_test_case dir_to_fulldir + atf_add_test_case dir_to_file + atf_add_test_case file_to_dir + atf_add_test_case kqueue +} diff --git a/contrib/netbsd-tests/fs/tmpfs/t_renamerace.c b/contrib/netbsd-tests/fs/tmpfs/t_renamerace.c new file mode 100644 index 000000000000..d7c10e4c6679 --- /dev/null +++ b/contrib/netbsd-tests/fs/tmpfs/t_renamerace.c @@ -0,0 +1,115 @@ +/* $NetBSD: t_renamerace.c,v 1.14 2017/01/13 21:30:40 christos Exp $ */ + +/* + * Modified for rump and atf from a program supplied + * by Nicolas Joly in kern/40948 + */ + +#include <sys/types.h> +#include <sys/mount.h> +#include <sys/utsname.h> + +#include <atf-c.h> +#include <errno.h> +#include <fcntl.h> +#include <pthread.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +#include <rump/rump.h> +#include <rump/rump_syscalls.h> + +#include <fs/tmpfs/tmpfs_args.h> + +#include "h_macros.h" + +ATF_TC(renamerace2); +ATF_TC_HEAD(renamerace2, tc) +{ + atf_tc_set_md_var(tc, "descr", "rename(2) lock order inversion"); + atf_tc_set_md_var(tc, "timeout", "6"); +} + +static volatile int quittingtime = 0; +static pid_t wrkpid; + +static void * +r2w1(void *arg) +{ + int fd; + + rump_pub_lwproc_newlwp(wrkpid); + + fd = rump_sys_open("/file", O_CREAT | O_RDWR, 0777); + if (fd == -1) + atf_tc_fail_errno("creat"); + rump_sys_close(fd); + + while (!quittingtime) { + if (rump_sys_rename("/file", "/dir/file") == -1) + atf_tc_fail_errno("rename 1"); + if (rump_sys_rename("/dir/file", "/file") == -1) + atf_tc_fail_errno("rename 2"); + } + + return NULL; +} + +static void * +r2w2(void *arg) +{ + int fd; + + rump_pub_lwproc_newlwp(wrkpid); + + while (!quittingtime) { + fd = rump_sys_open("/dir/file1", O_RDWR); + if (fd != -1) + rump_sys_close(fd); + } + + return NULL; +} + +ATF_TC_BODY(renamerace2, tc) +{ + struct tmpfs_args args; + pthread_t pt[2]; + + /* + * Force SMP regardless of how many host CPUs there are. + * Deadlock is highly unlikely to trigger otherwise. + */ + setenv("RUMP_NCPU", "2", 1); + + rump_init(); + memset(&args, 0, sizeof(args)); + args.ta_version = TMPFS_ARGS_VERSION; + args.ta_root_mode = 0777; + if (rump_sys_mount(MOUNT_TMPFS, "/", 0, &args, sizeof(args)) == -1) + atf_tc_fail_errno("could not mount tmpfs"); + + if (rump_sys_mkdir("/dir", 0777) == -1) + atf_tc_fail_errno("cannot create directory"); + + RZ(rump_pub_lwproc_rfork(RUMP_RFCFDG)); + RL(wrkpid = rump_sys_getpid()); + pthread_create(&pt[0], NULL, r2w1, NULL); + pthread_create(&pt[1], NULL, r2w2, NULL); + + /* usually triggers in <<1s for me */ + sleep(4); + quittingtime = 1; + + pthread_join(pt[0], NULL); + pthread_join(pt[1], NULL); +} + +ATF_TP_ADD_TCS(tp) +{ + ATF_TP_ADD_TC(tp, renamerace2); + + return atf_no_error(); +} diff --git a/contrib/netbsd-tests/fs/tmpfs/t_rmdir.sh b/contrib/netbsd-tests/fs/tmpfs/t_rmdir.sh new file mode 100755 index 000000000000..9e5d761edf6c --- /dev/null +++ b/contrib/netbsd-tests/fs/tmpfs/t_rmdir.sh @@ -0,0 +1,204 @@ +# $NetBSD: t_rmdir.sh,v 1.5 2010/11/07 17:51:18 jmmv Exp $ +# +# Copyright (c) 2005, 2006, 2007, 2008 The NetBSD Foundation, Inc. +# All rights reserved. +# +# 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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. +# + +# +# Verifies that rmdir works by creating and removing directories. Also +# checks multiple error conditions. +# + +atf_test_case mntpt +mntpt_head() { + atf_set "descr" "Checks that the mount point cannot be removed" + atf_set "require.user" "root" +} +mntpt_body() { + test_mount + + atf_check -s eq:1 -o empty -e ignore rmdir ${Mount_Point} + + test_unmount +} + +atf_test_case non_existent +non_existent_head() { + atf_set "descr" "Checks that non-existent directories cannot" \ + "be removed" + atf_set "require.user" "root" +} +non_existent_body() { + test_mount + + atf_check -s eq:1 -o empty -e ignore rmdir non-existent + + test_unmount +} + +atf_test_case single +single_head() { + atf_set "descr" "Checks that removing a single directory works" + atf_set "require.user" "root" +} +single_body() { + test_mount + + atf_check -s eq:0 -o empty -e empty mkdir a + eval $(stat -s ${Mount_Point}) + [ ${st_nlink} = 3 ] || \ + atf_fail "Incorrect number of links after creation" + atf_check -s eq:0 -o empty -e empty rmdir a + eval $(stat -s ${Mount_Point}) + [ ${st_nlink} = 2 ] || \ + atf_fail "Incorrect number of links after removal" + + test_unmount +} + +atf_test_case nested +nested_head() { + atf_set "descr" "Checks that removing nested directories works" + atf_set "require.user" "root" +} +nested_body() { + test_mount + + atf_check -s eq:0 -o empty -e empty mkdir -p a/b/c + atf_check -s eq:0 -o empty -e empty rmdir a/b/c + atf_check -s eq:0 -o empty -e empty rmdir a/b + atf_check -s eq:0 -o empty -e empty rmdir a + + test_unmount +} + +atf_test_case dots +dots_head() { + atf_set "descr" "Checks that '.' and '..' cannot be removed" + atf_set "require.user" "root" +} +dots_body() { + test_mount + + atf_check -s eq:0 -o empty -e empty mkdir a + atf_check -s eq:1 -o empty -e ignore rmdir a/. + atf_check -s eq:1 -o empty -e ignore rmdir a/.. + atf_check -s eq:0 -o empty -e empty rmdir a + + test_unmount +} + +atf_test_case non_empty +non_empty_head() { + atf_set "descr" "Checks that non-empty directories cannot be removed" + atf_set "require.user" "root" +} +non_empty_body() { + test_mount + + atf_check -s eq:0 -o empty -e empty mkdir a + atf_check -s eq:0 -o empty -e empty mkdir a/b + atf_check -s eq:0 -o empty -e empty mkdir a/c + atf_check -s eq:1 -o empty -e ignore rmdir a + atf_check -s eq:0 -o empty -e empty rmdir a/b + atf_check -s eq:0 -o empty -e empty rmdir a/c + atf_check -s eq:0 -o empty -e empty rmdir a + + test_unmount +} + +atf_test_case links +links_head() { + atf_set "descr" "Checks the root directory's links after removals" + atf_set "require.user" "root" +} +links_body() { + test_mount + + atf_check -s eq:0 -o empty -e empty mkdir a + atf_check -s eq:0 -o empty -e empty mkdir a/b + atf_check -s eq:0 -o empty -e empty mkdir c + + atf_check -s eq:0 -o empty -e empty rmdir c + atf_check -s eq:0 -o empty -e empty rmdir a/b + atf_check -s eq:0 -o empty -e empty rmdir a + + eval $(stat -s ${Mount_Point}) + [ ${st_nlink} = 2 ] || atf_fail "Incorrect number of links" + + test_unmount +} + +atf_test_case curdir +curdir_head() { + atf_set "descr" "Checks that the current directory cannot be removed" + atf_set "require.user" "root" +} +curdir_body() { + test_mount + + atf_check -s eq:0 -o empty -e empty mkdir a + # Catch a bug that would panic the system when accessing the + # current directory after being deleted: vop_open cannot assume + # that open files are still linked to a directory. + atf_check -s eq:1 -o empty -e ignore -x '( cd a && rmdir ../a && ls )' + atf_check -s eq:1 -o empty -e empty test -e a + + test_unmount +} + +atf_test_case kqueue +kqueue_head() { + atf_set "descr" "Checks that removing a directory raises the" \ + "correct kqueue events" + atf_set "require.user" "root" +} +kqueue_body() { + test_mount + + atf_check -s eq:0 -o empty -e empty mkdir dir + atf_check -s eq:0 -o empty -e empty mkdir dir/a + echo 'rmdir dir/a' | kqueue_monitor 3 dir dir/a + kqueue_check dir/a NOTE_DELETE + kqueue_check dir NOTE_LINK + kqueue_check dir NOTE_WRITE + atf_check -s eq:0 -o empty -e empty rmdir dir + + test_unmount +} + +atf_init_test_cases() { + . $(atf_get_srcdir)/../h_funcs.subr + . $(atf_get_srcdir)/h_funcs.subr + + atf_add_test_case mntpt + atf_add_test_case non_existent + atf_add_test_case single + atf_add_test_case nested + atf_add_test_case dots + atf_add_test_case non_empty + atf_add_test_case links + atf_add_test_case curdir + atf_add_test_case kqueue +} diff --git a/contrib/netbsd-tests/fs/tmpfs/t_setattr.sh b/contrib/netbsd-tests/fs/tmpfs/t_setattr.sh new file mode 100755 index 000000000000..f64344646e48 --- /dev/null +++ b/contrib/netbsd-tests/fs/tmpfs/t_setattr.sh @@ -0,0 +1,216 @@ +# $NetBSD: t_setattr.sh,v 1.5 2010/11/07 17:51:18 jmmv Exp $ +# +# Copyright (c) 2005, 2006, 2007, 2008 The NetBSD Foundation, Inc. +# All rights reserved. +# +# 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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. +# + +# +# Verifies that the setattr vnode operation works, using several commands +# that require this function. +# + +atf_test_case chown +chown_head() { + atf_set "descr" "Tests that the file owner can be changed" + atf_set "require.user" "root" +} +chown_body() { + test_mount + + atf_check -s eq:0 -o empty -e empty mkdir own + eval $(stat -s own | sed -e 's|st_|ost_|g') + atf_check -s eq:0 -o empty -e empty chown 1234 own + eval $(stat -s own) + [ ${st_uid} -eq 1234 ] || atf_fail "uid was not set" + [ ${st_gid} -eq ${ost_gid} ] || atf_fail "gid was modified" + + test_unmount +} + +atf_test_case chown_kqueue +chown_kqueue_head() { + atf_set "descr" "Tests that changing the file owner raises" \ + "NOTE_ATTRIB on it" + atf_set "require.user" "root" +} +chown_kqueue_body() { + test_mount + + atf_check -s eq:0 -o empty -e empty mkdir ownq + echo 'chown 1234 ownq' | kqueue_monitor 1 ownq + kqueue_check ownq NOTE_ATTRIB + + test_unmount +} + +atf_test_case chgrp +chgrp_head() { + atf_set "descr" "Tests that the file group can be changed" + atf_set "require.user" "root" +} +chgrp_body() { + test_mount + + atf_check -s eq:0 -o empty -e empty mkdir grp + eval $(stat -s grp | sed -e 's|st_|ost_|g') + atf_check -s eq:0 -o empty -e empty chgrp 5678 grp + eval $(stat -s grp) + [ ${st_uid} -eq ${ost_uid} ] || atf_fail "uid was modified" + [ ${st_gid} -eq 5678 ] || atf_fail "gid was not set" + + test_unmount +} + +atf_test_case chgrp_kqueue +chgrp_kqueue_head() { + atf_set "descr" "Tests that changing the file group raises" \ + "NOTE_ATTRIB on it" + atf_set "require.user" "root" +} +chgrp_kqueue_body() { + test_mount + + atf_check -s eq:0 -o empty -e empty mkdir grpq + echo 'chgrp 1234 grpq' | kqueue_monitor 1 grpq + kqueue_check grpq NOTE_ATTRIB + + test_unmount +} + +atf_test_case chowngrp +chowngrp_head() { + atf_set "descr" "Tests that the file owner and group can be" \ + "changed at once" + atf_set "require.user" "root" +} +chowngrp_body() { + test_mount + + atf_check -s eq:0 -o empty -e empty mkdir owngrp + atf_check -s eq:0 -o empty -e empty chown 1234:5678 owngrp + eval $(stat -s owngrp) + [ ${st_uid} -eq 1234 ] || atf_fail "uid was not modified" + [ ${st_gid} -eq 5678 ] || atf_fail "gid was not modified" + + test_unmount +} + +atf_test_case chowngrp_kqueue +chowngrp_kqueue_head() { + atf_set "descr" "Tests that changing the file owner and group" \ + "raises NOTE_ATTRIB on it" + atf_set "require.user" "root" +} +chowngrp_kqueue_body() { + test_mount + + atf_check -s eq:0 -o empty -e empty mkdir owngrpp + echo 'chown 1234:5678 owngrpp' | kqueue_monitor 1 owngrpp + kqueue_check owngrpp NOTE_ATTRIB + + test_unmount +} + +atf_test_case chmod +chmod_head() { + atf_set "descr" "Tests that the file mode can be changed" + atf_set "require.user" "root" +} +chmod_body() { + test_mount + + atf_check -s eq:0 -o empty -e empty mkdir mode + atf_check -s eq:0 -o empty -e empty chmod 0000 mode + eval $(stat -s mode) + [ ${st_mode} -eq 40000 ] || af_fail "mode was not set" + + test_unmount +} + +atf_test_case chmod_kqueue +chmod_kqueue_head() { + atf_set "descr" "Tests that changing the file mode raises" \ + "NOTE_ATTRIB on it" + atf_set "require.user" "root" +} +chmod_kqueue_body() { + test_mount + + atf_check -s eq:0 -o empty -e empty mkdir modeq + echo 'chmod 0000 modeq' | kqueue_monitor 1 modeq + kqueue_check modeq NOTE_ATTRIB + + test_unmount +} + +atf_test_case chtimes +chtimes_head() { + atf_set "descr" "Tests that file times can be changed" + atf_set "require.user" "root" +} +chtimes_body() { + test_mount + + atf_check -s eq:0 -o empty -e empty mkdir times + atf_check -s eq:0 -o empty -e empty \ + -x 'TZ=GMT touch -t 200501010101 times' + eval $(stat -s times) + [ ${st_atime} = ${st_mtime} ] || \ + atf_fail "atime does not match mtime" + [ ${st_atime} = 1104541260 ] || atf_fail "atime does not match" + + test_unmount +} + +atf_test_case chtimes_kqueue +chtimes_kqueue_head() { + atf_set "descr" "Tests that changing the file times raises" \ + "NOTE_ATTRIB on it" + atf_set "require.user" "root" +} +chtimes_kqueue_body() { + test_mount + + atf_check -s eq:0 -o empty -e empty mkdir timesq + echo 'touch timesq' | kqueue_monitor 1 timesq + kqueue_check timesq NOTE_ATTRIB + + test_unmount +} + +atf_init_test_cases() { + . $(atf_get_srcdir)/../h_funcs.subr + . $(atf_get_srcdir)/h_funcs.subr + + atf_add_test_case chown + atf_add_test_case chown_kqueue + atf_add_test_case chgrp + atf_add_test_case chgrp_kqueue + atf_add_test_case chowngrp + atf_add_test_case chowngrp_kqueue + atf_add_test_case chmod + atf_add_test_case chmod_kqueue + atf_add_test_case chtimes + atf_add_test_case chtimes_kqueue +} diff --git a/contrib/netbsd-tests/fs/tmpfs/t_sizes.sh b/contrib/netbsd-tests/fs/tmpfs/t_sizes.sh new file mode 100755 index 000000000000..35abe8ac25fe --- /dev/null +++ b/contrib/netbsd-tests/fs/tmpfs/t_sizes.sh @@ -0,0 +1,139 @@ +# $NetBSD: t_sizes.sh,v 1.5 2010/11/07 17:51:18 jmmv Exp $ +# +# Copyright (c) 2005, 2006, 2007, 2008 The NetBSD Foundation, Inc. +# All rights reserved. +# +# 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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. +# + +# +# Verifies that the file system controls memory usage correctly. +# + +atf_test_case small +small_head() { + atf_set "descr" "Checks the status after creating a small file" + atf_set "require.user" "root" +} +small_body() { + test_mount -o -s10M + + echo a >a || atf_fail "Could not create file" + eval $($(atf_get_srcdir)/h_tools statvfs .) + f_bused=$((${f_blocks} - ${f_bfree})) + [ ${f_bused} -gt 1 ] || atf_fail "Incorrect bused count" + atf_check -s eq:0 -o empty -e empty rm a + + test_unmount +} + +atf_test_case big +big_head() { + atf_set "descr" "Checks the status after creating a big file" + atf_set "require.user" "root" +} +big_body() { + test_mount -o -s10M + + # Begin FreeBSD + if true; then + pagesize=$(sysctl -n hw.pagesize) + else + # End FreeBSD + pagesize=$(sysctl hw.pagesize | cut -d ' ' -f 3) + # Begin FreeBSD + fi + # End FreeBSD + eval $($(atf_get_srcdir)/h_tools statvfs . | sed -e 's|^f_|cf_|') + cf_bused=$((${cf_blocks} - ${cf_bfree})) + + atf_check -s eq:0 -o ignore -e ignore \ + dd if=/dev/zero of=a bs=1m count=5 + eval $($(atf_get_srcdir)/h_tools statvfs .) + f_bused=$((${f_blocks} - ${f_bfree})) + [ ${f_bused} -ne ${cf_bused} ] || atf_fail "bused did not change" + [ ${f_bused} -gt $((5 * 1024 * 1024 / ${pagesize})) ] || \ + atf_fail "bused too big" + of_bused=${f_bused} + atf_check -s eq:0 -o empty -e empty rm a + eval $($(atf_get_srcdir)/h_tools statvfs .) + f_bused=$((${f_blocks} - ${f_bfree})) + [ ${f_bused} -lt ${of_bused} ] || \ + atf_fail "bused was not correctly restored" + + test_unmount +} + +atf_test_case overflow +overflow_head() { + atf_set "descr" "Checks the status after creating a big file that" \ + "overflows the file system limits" + atf_set "require.user" "root" +} +overflow_body() { + test_mount -o -s10M + + atf_check -s eq:0 -o empty -e empty touch a + atf_check -s eq:0 -o empty -e empty rm a + eval $($(atf_get_srcdir)/h_tools statvfs .) + of_bused=$((${f_blocks} - ${f_bfree})) + atf_check -s eq:1 -o ignore -e ignore \ + dd if=/dev/zero of=a bs=1m count=15 + atf_check -s eq:0 -o empty -e empty rm a + eval $($(atf_get_srcdir)/h_tools statvfs .) + f_bused=$((${f_blocks} - ${f_bfree})) + [ ${f_bused} -ge ${of_bused} -a ${f_bused} -le $((${of_bused} + 1)) ] \ + || atf_fail "Incorrect bused" + + test_unmount +} + +atf_test_case overwrite +overwrite_head() { + atf_set "descr" "Checks that writing to the middle of a file" \ + "does not change its size" + atf_set "require.user" "root" +} +overwrite_body() { + test_mount -o -s10M + + atf_check -s eq:0 -o ignore -e ignore \ + dd if=/dev/zero of=a bs=1024 count=10 + sync + atf_check -s eq:0 -o ignore -e ignore \ + dd if=/dev/zero of=a bs=1024 conv=notrunc seek=1 count=1 + sync + eval $(stat -s a) + [ ${st_size} -eq 10240 ] || atf_fail "Incorrect file size" + + test_unmount +} + +atf_init_test_cases() { + . $(atf_get_srcdir)/../h_funcs.subr + . $(atf_get_srcdir)/h_funcs.subr + + atf_add_test_case small + atf_add_test_case big + atf_add_test_case overflow + atf_add_test_case overwrite +} diff --git a/contrib/netbsd-tests/fs/tmpfs/t_sockets.sh b/contrib/netbsd-tests/fs/tmpfs/t_sockets.sh new file mode 100755 index 000000000000..6b972483513c --- /dev/null +++ b/contrib/netbsd-tests/fs/tmpfs/t_sockets.sh @@ -0,0 +1,52 @@ +# $NetBSD: t_sockets.sh,v 1.5 2010/11/07 17:51:18 jmmv Exp $ +# +# Copyright (c) 2005, 2006, 2007, 2008 The NetBSD Foundation, Inc. +# All rights reserved. +# +# 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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 basic +basic_head() { + atf_set "descr" "Verifies that sockets can be created using" \ + "socket/bind" + atf_set "require.user" "root" +} +basic_body() { + test_mount + + atf_check -s eq:0 -o empty -e empty $(atf_get_srcdir)/h_tools sockets a + atf_check -s eq:0 -o empty -e empty rm a + + atf_check -s eq:0 -o empty -e empty mkdir dir + echo "$(atf_get_srcdir)/h_tools sockets dir/a" | kqueue_monitor 1 dir + kqueue_check dir NOTE_WRITE + + test_unmount +} + +atf_init_test_cases() { + . $(atf_get_srcdir)/../h_funcs.subr + . $(atf_get_srcdir)/h_funcs.subr + + atf_add_test_case basic +} diff --git a/contrib/netbsd-tests/fs/tmpfs/t_statvfs.sh b/contrib/netbsd-tests/fs/tmpfs/t_statvfs.sh new file mode 100755 index 000000000000..d0e7ac27ebb9 --- /dev/null +++ b/contrib/netbsd-tests/fs/tmpfs/t_statvfs.sh @@ -0,0 +1,67 @@ +# $NetBSD: t_statvfs.sh,v 1.4 2010/11/07 17:51:18 jmmv Exp $ +# +# Copyright (c) 2005, 2006, 2007 The NetBSD Foundation, Inc. +# All rights reserved. +# +# 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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. +# + +# +# Verifies that the statvfs system call works properly (returning the +# correct values) over a tmpfs mount point. +# + +atf_test_case values +values_head() { + atf_set "descr" "Tests that statvfs(2) returns correct values" + atf_set "require.user" "root" +} +values_body() { + test_mount -o -s10M + + # Begin FreeBSD + if true; then + pagesize=$(sysctl -n hw.pagesize) + else + # End FreeBSD + pagesize=$(sysctl hw.pagesize | cut -d ' ' -f 3) + # Begin FreeBSD + fi + # End FreeBSD + eval $($(atf_get_srcdir)/h_tools statvfs .) + [ ${pagesize} -eq ${f_bsize} ] || \ + atf_fail "Invalid bsize" + [ $((${f_bsize} * ${f_blocks})) -ge $((10 * 1024 * 1024)) ] || \ + atf_file "bsize * blocks too small" + [ $((${f_bsize} * ${f_blocks})) -le \ + $((10 * 1024 * 1024 + ${pagesize})) ] || \ + atf_fail "bsize * blocks too big" + + test_unmount +} + +atf_init_test_cases() { + . $(atf_get_srcdir)/../h_funcs.subr + . $(atf_get_srcdir)/h_funcs.subr + + atf_add_test_case values +} diff --git a/contrib/netbsd-tests/fs/tmpfs/t_symlink.sh b/contrib/netbsd-tests/fs/tmpfs/t_symlink.sh new file mode 100755 index 000000000000..2cc66c06b4a6 --- /dev/null +++ b/contrib/netbsd-tests/fs/tmpfs/t_symlink.sh @@ -0,0 +1,114 @@ +# $NetBSD: t_symlink.sh,v 1.5 2010/11/07 17:51:18 jmmv Exp $ +# +# Copyright (c) 2005, 2006, 2007, 2008 The NetBSD Foundation, Inc. +# All rights reserved. +# +# 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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. +# + +# +# Verifies that the symlink and readlink operations work. +# + +atf_test_case file +file_head() { + atf_set "descr" "Tests that symlinks to files work" + atf_set "require.user" "root" +} +file_body() { + test_mount + + atf_check -s eq:0 -o empty -e empty touch a + atf_check -s eq:0 -o empty -e empty ln -s a b + [ $(md5 b | cut -d ' ' -f 4) = d41d8cd98f00b204e9800998ecf8427e ] || \ + atf_fail "Symlink points to an incorrect file" + + atf_check -s eq:0 -o empty -e empty -x 'echo foo >a' + [ $(md5 b | cut -d ' ' -f 4) = d3b07384d113edec49eaa6238ad5ff00 ] || \ + atf_fail "Symlink points to an incorrect file" + + test_unmount +} + +atf_test_case exec +exec_head() { + atf_set "descr" "Tests symlinking to a known system binary and" \ + "executing it through the symlink" + atf_set "require.user" "root" +} +exec_body() { + test_mount + + atf_check -s eq:0 -o empty -e empty touch b + atf_check -s eq:0 -o empty -e empty ln -s /bin/cp cp + atf_check -s eq:0 -o empty -e empty ./cp b c + atf_check -s eq:0 -o empty -e empty test -f c + + test_unmount +} + +atf_test_case dir +dir_head() { + atf_set "descr" "Tests that symlinks to directories work" + atf_set "require.user" "root" +} +dir_body() { + test_mount + + atf_check -s eq:0 -o empty -e empty mkdir d + atf_check -s eq:1 -o empty -e empty test -f d/foo + atf_check -s eq:1 -o empty -e empty test -f e/foo + atf_check -s eq:0 -o empty -e empty ln -s d e + atf_check -s eq:0 -o empty -e empty touch d/foo + atf_check -s eq:0 -o empty -e empty test -f d/foo + atf_check -s eq:0 -o empty -e empty test -f e/foo + + test_unmount +} + +atf_test_case kqueue +kqueue_head() { + atf_set "descr" "Tests that creating a symlink raises the" \ + "appropriate kqueue events" + atf_set "require.user" "root" +} +kqueue_body() { + test_mount + + atf_check -s eq:0 -o empty -e empty mkdir dir + echo 'ln -s non-existent dir/a' | kqueue_monitor 1 dir + kqueue_check dir NOTE_WRITE + atf_check -s eq:0 -o empty -e empty rm dir/a + atf_check -s eq:0 -o empty -e empty rmdir dir + + test_unmount +} + +atf_init_test_cases() { + . $(atf_get_srcdir)/../h_funcs.subr + . $(atf_get_srcdir)/h_funcs.subr + + atf_add_test_case file + atf_add_test_case exec + atf_add_test_case dir + atf_add_test_case kqueue +} diff --git a/contrib/netbsd-tests/fs/tmpfs/t_times.sh b/contrib/netbsd-tests/fs/tmpfs/t_times.sh new file mode 100755 index 000000000000..7b3be8d98d03 --- /dev/null +++ b/contrib/netbsd-tests/fs/tmpfs/t_times.sh @@ -0,0 +1,169 @@ +# $NetBSD: t_times.sh,v 1.5 2010/11/07 17:51:18 jmmv Exp $ +# +# Copyright (c) 2005, 2006, 2007, 2008 The NetBSD Foundation, Inc. +# All rights reserved. +# +# 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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. +# + +# +# Verifies that node times are properly handled. +# + +atf_test_case empty +empty_head() { + atf_set "descr" "Tests that creating an empty file and later" \ + "manipulating it updates times correctly" + atf_set "require.user" "root" +} +empty_body() { + test_mount + + atf_check -s eq:0 -o empty -e empty touch a + eval $(stat -s a | sed -e 's|st_|ost_|g') || atf_fail "stat failed" + [ ${ost_birthtime} -eq ${ost_atime} ] || atf_fail "Incorrect atime" + [ ${ost_birthtime} -eq ${ost_ctime} ] || atf_fail "Incorrect ctime" + [ ${ost_birthtime} -eq ${ost_mtime} ] || atf_fail "Incorrect mtime" + + sleep 1 + atf_check -s eq:0 -o empty -e empty cat a + eval $(stat -s a) || atf_fail "stat failed" + [ ${st_atime} -gt ${ost_atime} ] || atf_fail "Incorrect atime" + [ ${st_ctime} -eq ${ost_ctime} ] || atf_fail "Incorrect ctime" + [ ${st_mtime} -eq ${ost_mtime} ] || atf_fail "Incorrect mtime" + + sleep 1 + ost_atime=${st_atime} + echo foo >a || atf_fail "Write failed" + eval $(stat -s a) || atf_fail "stat failed" + [ ${st_atime} -gt ${ost_atime} ] || atf_fail "Incorrect atime" + [ ${st_ctime} -gt ${ost_ctime} ] || atf_fail "Incorrect ctime" + [ ${st_mtime} -gt ${ost_mtime} ] || atf_fail "Incorrect mtime" + + test_unmount +} + +atf_test_case holey +holey_head() { + atf_set "descr" "Tests that creating a file consisting entirely" \ + "of a hole and later" \ + "manipulating it updates times correctly" + atf_set "require.user" "root" +} +holey_body() { + test_mount + + atf_check -s eq:0 -o empty -e empty truncate -s 8k a + eval $(stat -s a | sed -e 's|st_|ost_|g') || atf_fail "stat failed" + [ ${ost_birthtime} -eq ${ost_atime} ] || atf_fail "Incorrect atime" + [ ${ost_birthtime} -eq ${ost_ctime} ] || atf_fail "Incorrect ctime" + [ ${ost_birthtime} -eq ${ost_mtime} ] || atf_fail "Incorrect mtime" + + sleep 1 + atf_check -s eq:0 -o ignore -e empty cat a + eval $(stat -s a) || atf_fail "stat failed" + [ ${st_atime} -gt ${ost_atime} ] || atf_fail "Incorrect atime" + [ ${st_ctime} -eq ${ost_ctime} ] || atf_fail "Incorrect ctime" + [ ${st_mtime} -eq ${ost_mtime} ] || atf_fail "Incorrect mtime" + + test_unmount +} + +atf_test_case non_empty +non_empty_head() { + atf_set "descr" "Tests that creating a non-empty file and later" \ + "manipulating it updates times correctly" + atf_set "require.user" "root" +} +non_empty_body() { + test_mount + + echo foo >b || atf_fail "Non-empty creation failed" + eval $(stat -s b | sed -e 's|st_|ost_|g') || atf_fail "stat failed" + + sleep 1 + atf_check -s eq:0 -o inline:"foo\n" -e empty cat b + eval $(stat -s b) || atf_fail "stat failed" + [ ${st_atime} -gt ${ost_atime} ] || atf_fail "Incorrect atime" + [ ${st_ctime} -eq ${ost_ctime} ] || atf_fail "Incorrect ctime" + [ ${st_mtime} -eq ${ost_mtime} ] || atf_fail "Incorrect mtime" + + test_unmount +} + +atf_test_case link +link_head() { + atf_set "descr" "Tests that linking to an existing file updates" \ + "times correctly" + atf_set "require.user" "root" +} +link_body() { + test_mount + + echo foo >c || atf_fail "Non-empty creation failed" + eval $(stat -s c | sed -e 's|st_|ost_|g') || atf_fail "stat failed" + + sleep 1 + atf_check -s eq:0 -o empty -e empty ln c d + eval $(stat -s c) || atf_fail "stat failed" + [ ${st_atime} -eq ${ost_atime} ] || atf_fail "Incorrect atime" + [ ${st_ctime} -gt ${ost_ctime} ] || atf_fail "Incorrect ctime" + [ ${st_mtime} -eq ${ost_mtime} ] || atf_fail "Incorrect mtime" + + test_unmount +} + +atf_test_case rename +rename_head() { + atf_set "descr" "Tests that renaming an existing file updates" \ + "times correctly" + atf_set "require.user" "root" +} +rename_body() { + test_mount + + atf_check -s eq:0 -o empty -e empty mkdir e + echo foo >e/a || atf_fail "Creation failed" + eval $(stat -s e | sed -e 's|st_|dost_|g') || atf_fail "stat failed" + eval $(stat -s e/a | sed -e 's|st_|ost_|g') || atf_fail "stat failed" + sleep 1 + atf_check -s eq:0 -o empty -e empty mv e/a e/b + eval $(stat -s e | sed -e 's|st_|dst_|g') || atf_fail "stat failed" + eval $(stat -s e/b) || atf_fail "stat failed" + [ ${st_atime} -eq ${ost_atime} ] || atf_fail "Incorrect atime" + [ ${st_ctime} -gt ${ost_ctime} ] || atf_fail "Incorrect ctime" + [ ${st_mtime} -eq ${ost_mtime} ] || atf_fail "Incorrect mtime" + [ ${dst_mtime} -gt ${dost_mtime} ] || atf_fail "Incorrect mtime" + + test_unmount +} + +atf_init_test_cases() { + . $(atf_get_srcdir)/../h_funcs.subr + . $(atf_get_srcdir)/h_funcs.subr + + atf_add_test_case empty + atf_add_test_case holey + atf_add_test_case non_empty + atf_add_test_case link + atf_add_test_case rename +} diff --git a/contrib/netbsd-tests/fs/tmpfs/t_trail_slash.sh b/contrib/netbsd-tests/fs/tmpfs/t_trail_slash.sh new file mode 100755 index 000000000000..df5b023711bb --- /dev/null +++ b/contrib/netbsd-tests/fs/tmpfs/t_trail_slash.sh @@ -0,0 +1,52 @@ +# $NetBSD: t_trail_slash.sh,v 1.5 2010/11/07 17:51:18 jmmv Exp $ +# +# Copyright (c) 2005, 2006, 2007, 2008 The NetBSD Foundation, Inc. +# All rights reserved. +# +# 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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 main +main_head() { + atf_set "descr" "Verifies that trailing slashes are not stored" \ + "in directory names and that they do not cause" \ + "crashes" + atf_set "require.user" "root" +} +main_body() { + test_mount + + atf_check -s eq:0 -o empty -e empty mkdir a/ + atf_check -s eq:0 -o empty -e empty touch a/b + atf_check -s eq:0 -o empty -e empty test -f a/b + atf_check -s eq:0 -o empty -e empty rm a/b + atf_check -s eq:0 -o empty -e empty rmdir a/ + + test_unmount +} + +atf_init_test_cases() { + . $(atf_get_srcdir)/../h_funcs.subr + . $(atf_get_srcdir)/h_funcs.subr + + atf_add_test_case main +} diff --git a/contrib/netbsd-tests/fs/tmpfs/t_truncate.sh b/contrib/netbsd-tests/fs/tmpfs/t_truncate.sh new file mode 100755 index 000000000000..2bc1902795cb --- /dev/null +++ b/contrib/netbsd-tests/fs/tmpfs/t_truncate.sh @@ -0,0 +1,56 @@ +# $NetBSD: t_truncate.sh,v 1.4 2010/11/07 17:51:18 jmmv Exp $ +# +# Copyright (c) 2005, 2006, 2007 The NetBSD Foundation, Inc. +# All rights reserved. +# +# 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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 basic +basic_head() { + atf_set "descr" "Verifies that the truncate operation works" + atf_set "require.user" "root" +} +basic_body() { + test_mount + + echo "Creating big file" + jot 10000 >a || atf_fail "Failed to create big file" + echo "Trunctaing the file to a smaller size" + echo foo >a || atf_fail "Failed to truncate file to a smaller size" + [ $(md5 a | cut -d ' ' -f 4) = d3b07384d113edec49eaa6238ad5ff00 ] || \ + echo "Truncated file is incorrect" + + echo "Truncating to zero bytes" + >a || atf_fail "Failed to truncate to 0" + echo "Truncating to zero bytes, second try" + >a || atf_fail "Failed to re-truncate to 0" + + test_unmount +} + +atf_init_test_cases() { + . $(atf_get_srcdir)/../h_funcs.subr + . $(atf_get_srcdir)/h_funcs.subr + + atf_add_test_case basic +} diff --git a/contrib/netbsd-tests/fs/tmpfs/t_vnd.sh b/contrib/netbsd-tests/fs/tmpfs/t_vnd.sh new file mode 100755 index 000000000000..0929b55d1852 --- /dev/null +++ b/contrib/netbsd-tests/fs/tmpfs/t_vnd.sh @@ -0,0 +1,102 @@ +# $NetBSD: t_vnd.sh,v 1.9 2016/07/29 05:23:24 pgoyette Exp $ +# +# Copyright (c) 2006, 2007, 2008 The NetBSD Foundation, Inc. +# All rights reserved. +# 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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. +# + +# +# Verifies that vnd works with files stored in tmpfs. +# + +# Begin FreeBSD +MD_DEVICE_FILE=md.device +# End FreeBSD + +atf_test_case basic cleanup +basic_head() { + atf_set "descr" "Verifies that vnd works with files stored in tmpfs" + atf_set "require.user" "root" +} +basic_body() { + test_mount + + atf_check -s eq:0 -o ignore -e ignore \ + dd if=/dev/zero of=disk.img bs=1m count=10 + # Begin FreeBSD + if true; then + atf_check -s eq:0 -o empty -e empty mkdir mnt + atf_check -s eq:0 -o empty -e empty mdmfs -F disk.img md mnt + md_dev=$(df mnt | awk 'NR != 1 { print $1 }' | xargs basename) + atf_check test -c /dev/$md_dev # Sanity check + echo -n $md_dev > $TMPDIR/$MD_DEVICE_FILE + else + # End FreeBSD + atf_check -s eq:0 -o empty -e empty vndconfig /dev/vnd3 disk.img + + atf_check -s eq:0 -o ignore -e ignore newfs /dev/rvnd3a + + atf_check -s eq:0 -o empty -e empty mkdir mnt + atf_check -s eq:0 -o empty -e empty mount /dev/vnd3a mnt + # Begin FreeBSD + fi + # End FreeBSD + + echo "Creating test files" + for f in $(jot -w %u 100 | uniq); do + jot 1000 >mnt/${f} || atf_fail "Failed to create file ${f}" + done + + echo "Verifying created files" + for f in $(jot -w %u 100 | uniq); do + [ $(md5 mnt/${f} | cut -d ' ' -f 4) = \ + 53d025127ae99ab79e8502aae2d9bea6 ] || \ + atf_fail "Invalid checksum for file ${f}" + done + + atf_check -s eq:0 -o empty -e empty umount mnt + atf_check -s eq:0 -o empty -e empty vndconfig -u /dev/vnd3 + + test_unmount + touch done +} +basic_cleanup() { + # Begin FreeBSD + if md_dev=$(cat $TMPDIR/$MD_DEVICE_FILE); then + echo "Will try disconnecting $md_dev" + else + echo "$MD_DEVICE_FILE doesn't exist in $TMPDIR; returning early" + return 0 + fi + # End FreeBSD + if [ ! -f done ]; then + umount mnt 2>/dev/null 1>&2 + vndconfig -u /dev/vnd3 2>/dev/null 1>&2 + fi +} + +atf_init_test_cases() { + . $(atf_get_srcdir)/../h_funcs.subr + . $(atf_get_srcdir)/h_funcs.subr + + atf_add_test_case basic +} diff --git a/contrib/netbsd-tests/fs/tmpfs/t_vnode_leak.sh b/contrib/netbsd-tests/fs/tmpfs/t_vnode_leak.sh new file mode 100755 index 000000000000..4630a7cd97fb --- /dev/null +++ b/contrib/netbsd-tests/fs/tmpfs/t_vnode_leak.sh @@ -0,0 +1,68 @@ +# $NetBSD: t_vnode_leak.sh,v 1.6 2010/11/07 17:51:18 jmmv Exp $ +# +# Copyright (c) 2005, 2006, 2007, 2008 The NetBSD Foundation, Inc. +# All rights reserved. +# +# 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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 main cleanup +main_head() { + atf_set "descr" "Verifies that vnodes are not leaked and that" \ + "their reclaim operation works as expected: i.e.," \ + "when all free vnodes are exhausted, unused ones" \ + "have to be recycled, which is what the reclaim" \ + "operation does." + atf_set "require.user" "root" +} +main_body() { + echo "Lowering kern.maxvnodes to 2000" + # Begin FreeBSD + if true; then + sysctl -n kern.maxvnodes > oldvnodes + else + # End FreeBSD + sysctl kern.maxvnodes | awk '{ print $3; }' >oldvnodes + # Begin FreeBSD + fi + # End FreeBSD + atf_check -s eq:0 -o ignore -e empty sysctl -w kern.maxvnodes=2000 + + test_mount -o -s$(((4000 + 2) * 4096)) + echo "Creating 4000 directories" + for f in $(jot 4000); do + mkdir ${f} + done + test_unmount +} +main_cleanup() { + oldvnodes=$(cat oldvnodes) + echo "Restoring kern.maxvnodes to ${oldvnodes}" + sysctl -w kern.maxvnodes=${oldvnodes} +} + +atf_init_test_cases() { + . $(atf_get_srcdir)/../h_funcs.subr + . $(atf_get_srcdir)/h_funcs.subr + + atf_add_test_case main +} diff --git a/contrib/netbsd-tests/fs/umapfs/t_basic.c b/contrib/netbsd-tests/fs/umapfs/t_basic.c new file mode 100644 index 000000000000..c9b2d9b7a5dc --- /dev/null +++ b/contrib/netbsd-tests/fs/umapfs/t_basic.c @@ -0,0 +1,145 @@ +/* $NetBSD: t_basic.c,v 1.5 2017/01/13 21:30:40 christos Exp $ */ + +#include <sys/types.h> +#include <sys/param.h> +#include <sys/mount.h> + +#include <atf-c.h> +#include <err.h> +#include <errno.h> +#include <fcntl.h> +#include <stdio.h> +#include <unistd.h> +#include <string.h> +#include <stdlib.h> + +#include <rump/rump.h> +#include <rump/rump_syscalls.h> +#include <rump/rumpvfs_if_pub.h> + +#include <fs/tmpfs/tmpfs_args.h> +#include <miscfs/umapfs/umap.h> + +#include "h_macros.h" + +ATF_TC(basic); +ATF_TC_HEAD(basic, tc) +{ + atf_tc_set_md_var(tc, "descr", "basic umapfs mapping"); +} + +static void +xtouch(const char *path) +{ + int fd; + + fd = rump_sys_open(path, O_CREAT | O_RDWR, 0777); + if (fd == -1) + atf_tc_fail_errno("create %s", path); + rump_sys_close(fd); +} + +static void +xchown(const char *path, uid_t uid, gid_t gid) +{ + + if (rump_sys_chown(path, uid, gid) == -1) + atf_tc_fail_errno("chown %s failed", path); +} + +static void +testuidgid(const char *path, uid_t uid, gid_t gid) +{ + struct stat sb; + + if (rump_sys_stat(path, &sb) == -1) + atf_tc_fail_errno("stat %s", path); + if (uid != (uid_t)-1) { + if (sb.st_uid != uid) + atf_tc_fail("%s: expected uid %d, got %d", + path, uid, sb.st_uid); + } + if (gid != (gid_t)-1) { + if (sb.st_gid != gid) + atf_tc_fail("%s: expected gid %d, got %d", + path, gid, sb.st_gid); + } +} + +ATF_TC_BODY(basic, tc) +{ + struct umap_args umargs; + struct tmpfs_args targs; + u_long umaps[2][2]; + u_long gmaps[2][2]; + + rump_init(); + if (rump_sys_mkdir("/td1", 0777) == -1) + atf_tc_fail_errno("mp1"); + if (rump_sys_mkdir("/td2", 0777) == -1) + atf_tc_fail_errno("mp1"); + + /* use tmpfs because rumpfs doesn't support ownership */ + memset(&targs, 0, sizeof(targs)); + targs.ta_version = TMPFS_ARGS_VERSION; + targs.ta_root_mode = 0777; + if (rump_sys_mount(MOUNT_TMPFS, "/td1", 0, &targs, sizeof(targs)) == -1) + atf_tc_fail_errno("could not mount tmpfs td1"); + + memset(&umargs, 0, sizeof(umargs)); + + /* + * Map td1 uid 555 to td2 uid 777 (yes, IMHO the umapfs + * mapping format is counter-intuitive). + */ + umaps[0][0] = 777; + umaps[0][1] = 555; + umaps[1][0] = 0; + umaps[1][1] = 0; + gmaps[0][0] = 4321; + gmaps[0][1] = 1234; + gmaps[1][0] = 0; + gmaps[1][1] = 0; + + umargs.umap_target = __UNCONST("/td1"); + umargs.nentries = 2; + umargs.gnentries = 2; + umargs.mapdata = umaps; + umargs.gmapdata = gmaps; + + if (rump_sys_mount(MOUNT_UMAP, "/td2", 0, &umargs,sizeof(umargs)) == -1) + atf_tc_fail_errno("could not mount umapfs"); + + xtouch("/td1/noch"); + testuidgid("/td1/noch", 0, 0); + testuidgid("/td2/noch", 0, 0); + + xtouch("/td1/nomap"); + xchown("/td1/nomap", 1, 2); + testuidgid("/td1/nomap", 1, 2); + testuidgid("/td2/nomap", -1, -1); + + xtouch("/td1/forwmap"); + xchown("/td1/forwmap", 555, 1234); + testuidgid("/td1/forwmap", 555, 1234); + testuidgid("/td2/forwmap", 777, 4321); + + /* + * this *CANNOT* be correct??? + */ + xtouch("/td1/revmap"); + /* + * should be 777 / 4321 (?), but makes first test fail since + * it gets 777 / 4321, i.e. unmapped results. + */ + xchown("/td2/revmap", 555, 1234); + testuidgid("/td1/revmap", 555, 1234); + testuidgid("/td2/revmap", 777, 4321); + +} + +ATF_TP_ADD_TCS(tp) +{ + ATF_TP_ADD_TC(tp, basic); + return 0; /*XXX?*/ +} diff --git a/contrib/netbsd-tests/fs/union/t_pr.c b/contrib/netbsd-tests/fs/union/t_pr.c new file mode 100644 index 000000000000..fc70bcadf36b --- /dev/null +++ b/contrib/netbsd-tests/fs/union/t_pr.c @@ -0,0 +1,130 @@ +/* $NetBSD: t_pr.c,v 1.9 2017/01/13 21:30:40 christos Exp $ */ + +#include <sys/types.h> +#include <sys/mount.h> + +#include <atf-c.h> +#include <err.h> +#include <errno.h> +#include <fcntl.h> +#include <stdio.h> +#include <unistd.h> +#include <string.h> +#include <stdlib.h> + +#include <rump/rump.h> +#include <rump/rump_syscalls.h> + +#include <miscfs/union/union.h> + +#include "h_macros.h" + +ATF_TC(multilayer); +ATF_TC_HEAD(multilayer, tc) +{ + atf_tc_set_md_var(tc, "descr", "mount_union -b twice"); +} + +ATF_TC_BODY(multilayer, tc) +{ + struct union_args unionargs; + + rump_init(); + + if (rump_sys_mkdir("/Tunion", 0777) == -1) + atf_tc_fail_errno("mkdir mp1"); + if (rump_sys_mkdir("/Tunion2", 0777) == -1) + atf_tc_fail_errno("mkdir mp2"); + if (rump_sys_mkdir("/Tunion2/A", 0777) == -1) + atf_tc_fail_errno("mkdir A"); + if (rump_sys_mkdir("/Tunion2/B", 0777) == -1) + atf_tc_fail_errno("mkdir B"); + + unionargs.target = __UNCONST("/Tunion2/A"); + unionargs.mntflags = UNMNT_BELOW; + + if (rump_sys_mount(MOUNT_UNION, "/Tunion", 0, + &unionargs, sizeof(unionargs)) == -1) + atf_tc_fail_errno("union mount"); + + unionargs.target = __UNCONST("/Tunion2/B"); + unionargs.mntflags = UNMNT_BELOW; + + rump_sys_mount(MOUNT_UNION, "/Tunion", 0,&unionargs,sizeof(unionargs)); +} + +ATF_TC(devnull1); +ATF_TC_HEAD(devnull1, tc) +{ + atf_tc_set_md_var(tc, "descr", "mount_union -b and " + "'echo x > /un/null'"); +} + +ATF_TC_BODY(devnull1, tc) +{ + struct union_args unionargs; + int fd, res; + + rump_init(); + + if (rump_sys_mkdir("/mp", 0777) == -1) + atf_tc_fail_errno("mkdir mp"); + + unionargs.target = __UNCONST("/dev"); + unionargs.mntflags = UNMNT_BELOW; + + if (rump_sys_mount(MOUNT_UNION, "/mp", 0, + &unionargs, sizeof(unionargs)) == -1) + atf_tc_fail_errno("union mount"); + + fd = rump_sys_open("/mp/null", O_WRONLY | O_CREAT | O_TRUNC); + + if (fd == -1) + atf_tc_fail_errno("open"); + + res = rump_sys_write(fd, &fd, sizeof(fd)); + if (res != sizeof(fd)) + atf_tc_fail("write"); +} + +ATF_TC(devnull2); +ATF_TC_HEAD(devnull2, tc) +{ + atf_tc_set_md_var(tc, "descr", "mount_union -b and " + "'echo x >> /un/null'"); +} + +ATF_TC_BODY(devnull2, tc) +{ + struct union_args unionargs; + int fd, res; + + rump_init(); + + if (rump_sys_mkdir("/mp", 0777) == -1) + atf_tc_fail_errno("mkdir mp"); + + unionargs.target = __UNCONST("/dev"); + unionargs.mntflags = UNMNT_BELOW; + + if (rump_sys_mount(MOUNT_UNION, "/mp", 0, + &unionargs, sizeof(unionargs)) == -1) + atf_tc_fail_errno("union mount"); + + fd = rump_sys_open("/mp/null", O_WRONLY | O_CREAT | O_APPEND); + if (fd == -1) + atf_tc_fail_errno("open"); + + res = rump_sys_write(fd, &fd, sizeof(fd)); + if (res != sizeof(fd)) + atf_tc_fail("write"); +} + +ATF_TP_ADD_TCS(tp) +{ + ATF_TP_ADD_TC(tp, multilayer); + ATF_TP_ADD_TC(tp, devnull1); + ATF_TP_ADD_TC(tp, devnull2); + + return atf_no_error(); +} diff --git a/contrib/netbsd-tests/fs/vfs/t_full.c b/contrib/netbsd-tests/fs/vfs/t_full.c new file mode 100644 index 000000000000..51347deca70d --- /dev/null +++ b/contrib/netbsd-tests/fs/vfs/t_full.c @@ -0,0 +1,101 @@ +/* $NetBSD: t_full.c,v 1.9 2017/01/13 21:30:40 christos Exp $ */ + +/*- + * Copyright (c) 2010 The NetBSD Foundation, Inc. + * All rights reserved. + * + * 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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. + */ + +#include <sys/stat.h> +#include <sys/statvfs.h> + +#include <atf-c.h> +#include <fcntl.h> +#include <libgen.h> +#include <stdlib.h> +#include <unistd.h> + +#include <rump/rump_syscalls.h> +#include <rump/rump.h> + +#include "../common/h_fsmacros.h" +#include "h_macros.h" + +/* + * Write this much over the image size. This is to force an NFS commit, + * since we might just stuff data into the cache and miss the problem. + */ +#define NFSBONUS (1<<16) + +static void +fillfs(const atf_tc_t *tc, const char *mp) +{ + char buf[8192]; + size_t written; + ssize_t n = 0; /* xxxgcc */ + size_t bonus; + int fd, i = 0; + + if (FSTYPE_P2K_FFS(tc) || FSTYPE_PUFFS(tc) || FSTYPE_RUMPFS(tc)) { + atf_tc_skip("fs does not support explicit block allocation " + "(GOP_ALLOC)"); + } + + bonus = 0; + if (FSTYPE_NFS(tc)) + bonus = NFSBONUS; + + if (rump_sys_chdir(mp) == -1) + atf_tc_fail_errno("chdir mountpoint"); + fd = rump_sys_open("afile", O_CREAT | O_RDWR); + if (fd == -1) + atf_tc_fail_errno("create file"); + + for (written = 0; written < FSTEST_IMGSIZE + bonus; written +=n) { + memset(buf, i++, sizeof(buf)); /* known garbage */ + n = rump_sys_write(fd, buf, sizeof(buf)); + if (n == -1) + break; + } + if (FSTYPE_ZFS(tc)) + atf_tc_expect_fail("PR kern/47656: Test known to be broken"); + if (n == -1) { + if (errno != ENOSPC) + atf_tc_fail_errno("write"); + } else { + atf_tc_fail("filled file system over size limit"); + } + + rump_sys_close(fd); + rump_sys_chdir("/"); +} + +ATF_TC_FSAPPLY(fillfs, "fills file system, expects ENOSPC"); + +ATF_TP_ADD_TCS(tp) +{ + + ATF_TP_FSAPPLY(fillfs); + + return atf_no_error(); +} diff --git a/contrib/netbsd-tests/fs/vfs/t_io.c b/contrib/netbsd-tests/fs/vfs/t_io.c new file mode 100644 index 000000000000..b7f652936e10 --- /dev/null +++ b/contrib/netbsd-tests/fs/vfs/t_io.c @@ -0,0 +1,268 @@ +/* $NetBSD: t_io.c,v 1.17 2017/01/13 21:30:40 christos Exp $ */ + +/*- + * Copyright (c) 2010 The NetBSD Foundation, Inc. + * All rights reserved. + * + * 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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. + */ + +#include <sys/stat.h> +#include <sys/statvfs.h> + +#include <atf-c.h> +#include <fcntl.h> +#include <libgen.h> +#include <stdlib.h> +#include <unistd.h> + +#include <rump/rump_syscalls.h> +#include <rump/rump.h> + +#include "../common/h_fsmacros.h" +#include "h_macros.h" + +#define TESTSTR "this is a string. collect enough and you'll have Em" +#define TESTSZ sizeof(TESTSTR) + +static void +holywrite(const atf_tc_t *tc, const char *mp) +{ + char buf[1024]; + char *b2, *b3; + size_t therange = getpagesize()+1; + int fd; + + FSTEST_ENTER(); + + RL(fd = rump_sys_open("file", O_RDWR|O_CREAT|O_TRUNC, 0666)); + + memset(buf, 'A', sizeof(buf)); + RL(rump_sys_pwrite(fd, buf, 1, getpagesize())); + + memset(buf, 'B', sizeof(buf)); + RL(rump_sys_pwrite(fd, buf, 2, getpagesize()-1)); + + REQUIRE_LIBC(b2 = malloc(2 * getpagesize()), NULL); + REQUIRE_LIBC(b3 = malloc(2 * getpagesize()), NULL); + + RL(rump_sys_pread(fd, b2, therange, 0)); + + memset(b3, 0, therange); + memset(b3 + getpagesize() - 1, 'B', 2); + + ATF_REQUIRE_EQ(memcmp(b2, b3, therange), 0); + + rump_sys_close(fd); + FSTEST_EXIT(); +} + +static void +extendbody(const atf_tc_t *tc, off_t seekcnt) +{ + char buf[TESTSZ+1]; + struct stat sb; + int fd; + + FSTEST_ENTER(); + RL(fd = rump_sys_open("testfile", + O_CREAT | O_RDWR | (seekcnt ? O_APPEND : 0))); + RL(rump_sys_ftruncate(fd, seekcnt)); + RL(rump_sys_fstat(fd, &sb)); + ATF_REQUIRE_EQ(sb.st_size, seekcnt); + + ATF_REQUIRE_EQ(rump_sys_write(fd, TESTSTR, TESTSZ), TESTSZ); + ATF_REQUIRE_EQ(rump_sys_pread(fd, buf, TESTSZ, seekcnt), TESTSZ); + ATF_REQUIRE_STREQ(buf, TESTSTR); + + RL(rump_sys_fstat(fd, &sb)); + ATF_REQUIRE_EQ(sb.st_size, (off_t)TESTSZ + seekcnt); + RL(rump_sys_close(fd)); + FSTEST_EXIT(); +} + +static void +extendfile(const atf_tc_t *tc, const char *mp) +{ + + extendbody(tc, 0); +} + +static void +extendfile_append(const atf_tc_t *tc, const char *mp) +{ + + extendbody(tc, 37); +} + +static void +overwritebody(const atf_tc_t *tc, off_t count, bool dotrunc) +{ + char *buf; + int fd; + + REQUIRE_LIBC(buf = malloc(count), NULL); + FSTEST_ENTER(); + RL(fd = rump_sys_open("testi", O_CREAT | O_RDWR, 0666)); + ATF_REQUIRE_EQ(rump_sys_write(fd, buf, count), count); + RL(rump_sys_close(fd)); + + RL(fd = rump_sys_open("testi", O_RDWR)); + if (dotrunc) + RL(rump_sys_ftruncate(fd, 0)); + ATF_REQUIRE_EQ(rump_sys_write(fd, buf, count), count); + RL(rump_sys_close(fd)); + FSTEST_EXIT(); +} + +static void +overwrite512(const atf_tc_t *tc, const char *mp) +{ + + overwritebody(tc, 512, false); +} + +static void +overwrite64k(const atf_tc_t *tc, const char *mp) +{ + + overwritebody(tc, 1<<16, false); +} + +static void +overwrite_trunc(const atf_tc_t *tc, const char *mp) +{ + + overwritebody(tc, 1<<16, true); +} + +static void +shrinkfile(const atf_tc_t *tc, const char *mp) +{ + int fd; + + FSTEST_ENTER(); + RL(fd = rump_sys_open("file", O_RDWR|O_CREAT|O_TRUNC, 0666)); + RL(rump_sys_ftruncate(fd, 2)); + RL(rump_sys_ftruncate(fd, 1)); + rump_sys_close(fd); + FSTEST_EXIT(); +} + +#define TBSIZE 9000 +static void +read_after_unlink(const atf_tc_t *tc, const char *mp) +{ + char buf[TBSIZE], buf2[TBSIZE]; + int fd; + + FSTEST_ENTER(); + + /* create file and put some content into it */ + RL(fd = rump_sys_open("file", O_RDWR|O_CREAT, 0666)); + memset(buf, 'D', TBSIZE); + ATF_REQUIRE_EQ(rump_sys_write(fd, buf, TBSIZE), TBSIZE); + rump_sys_close(fd); + + /* flush buffers from UBC to file system */ + ATF_REQUIRE_ERRNO(EBUSY, rump_sys_unmount(mp, 0) == -1); + + RL(fd = rump_sys_open("file", O_RDWR)); + RL(rump_sys_unlink("file")); + + ATF_REQUIRE_EQ(rump_sys_read(fd, buf2, TBSIZE), TBSIZE); + ATF_REQUIRE_EQ(memcmp(buf, buf2, TBSIZE), 0); + rump_sys_close(fd); + + FSTEST_EXIT(); +} + +static void +wrrd_after_unlink(const atf_tc_t *tc, const char *mp) +{ + int value = 0x11; + int v2; + int fd; + + FSTEST_ENTER(); + + RL(fd = rump_sys_open("file", O_RDWR|O_CREAT, 0666)); + RL(rump_sys_unlink("file")); + + RL(rump_sys_pwrite(fd, &value, sizeof(value), 654321)); + + /* + * We can't easily invalidate the buffer since we hold a + * reference, but try to get them to flush anyway. + */ + RL(rump_sys_fsync(fd)); + RL(rump_sys_pread(fd, &v2, sizeof(v2), 654321)); + rump_sys_close(fd); + + ATF_REQUIRE_EQ(value, v2); + FSTEST_EXIT(); +} + +static void +read_fault(const atf_tc_t *tc, const char *mp) +{ + char ch = 123; + int fd; + + FSTEST_ENTER(); + RL(fd = rump_sys_open("file", O_CREAT | O_RDWR, 0777)); + ATF_REQUIRE_EQ(rump_sys_write(fd, &ch, 1), 1); + RL(rump_sys_close(fd)); + RL(fd = rump_sys_open("file", O_RDONLY | O_SYNC | O_RSYNC)); + ATF_REQUIRE_ERRNO(EFAULT, rump_sys_read(fd, NULL, 1) == -1); + RL(rump_sys_close(fd)); + FSTEST_EXIT(); +} + +ATF_TC_FSAPPLY(holywrite, "create a sparse file and fill hole"); +ATF_TC_FSAPPLY(extendfile, "check that extending a file works"); +ATF_TC_FSAPPLY(extendfile_append, "check that extending a file works " + "with a append-only fd (PR kern/44307)"); +ATF_TC_FSAPPLY(overwrite512, "write a 512 byte file twice"); +ATF_TC_FSAPPLY(overwrite64k, "write a 64k byte file twice"); +ATF_TC_FSAPPLY(overwrite_trunc, "write 64k + truncate + rewrite"); +ATF_TC_FSAPPLY(shrinkfile, "shrink file"); +ATF_TC_FSAPPLY(read_after_unlink, "contents can be read off disk after unlink"); +ATF_TC_FSAPPLY(wrrd_after_unlink, "file can be written and read after unlink"); +ATF_TC_FSAPPLY(read_fault, "read at bad address must return EFAULT"); + +ATF_TP_ADD_TCS(tp) +{ + + ATF_TP_FSAPPLY(holywrite); + ATF_TP_FSAPPLY(extendfile); + ATF_TP_FSAPPLY(extendfile_append); + ATF_TP_FSAPPLY(overwrite512); + ATF_TP_FSAPPLY(overwrite64k); + ATF_TP_FSAPPLY(overwrite_trunc); + ATF_TP_FSAPPLY(shrinkfile); + ATF_TP_FSAPPLY(read_after_unlink); + ATF_TP_FSAPPLY(wrrd_after_unlink); + ATF_TP_FSAPPLY(read_fault); + + return atf_no_error(); +} diff --git a/contrib/netbsd-tests/fs/vfs/t_mtime_otrunc.c b/contrib/netbsd-tests/fs/vfs/t_mtime_otrunc.c new file mode 100644 index 000000000000..bb0760992ad2 --- /dev/null +++ b/contrib/netbsd-tests/fs/vfs/t_mtime_otrunc.c @@ -0,0 +1,86 @@ +/*- + * Copyright (c) 2017 The NetBSD Foundation, Inc. + * All rights reserved. + * + * 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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. + */ + +#include <sys/cdefs.h> +__COPYRIGHT("@(#) Copyright (c) 2013\ + The NetBSD Foundation, inc. All rights reserved."); +__RCSID("$NetBSD: t_mtime_otrunc.c,v 1.1 2017/02/02 22:07:05 martin Exp $"); + +#include <errno.h> +#include <unistd.h> +#include <stdio.h> +#include <stdlib.h> +#include <sys/stat.h> +#include <atf-c.h> + +#include <rump/rump_syscalls.h> +#include <rump/rump.h> + +#include "../common/h_fsmacros.h" + +#define LOCKFILE "lock" + +static time_t +lock_it(void) +{ + struct stat st; + + if (rump_sys_stat(LOCKFILE, &st) != 0) + st.st_mtime = 0; + + int f = rump_sys_open(LOCKFILE, O_WRONLY|O_CREAT|O_TRUNC, 0666); + if (f == -1) return 0; + rump_sys_close(f); + + return st.st_mtime; +} + +static void +otrunc_mtime_update(const atf_tc_t *tc, const char *path) +{ + time_t last_ts = 0; + int res; + + /* atf_tc_expect_fail("PR kern/51762"); */ + + res = rump_sys_chdir(path); + if (res == -1) + atf_tc_fail("chdir failed"); + + for (int i = 0; i < 5; i++) { + time_t l = lock_it(); + printf("last lock: %ld\n", (long)l); + ATF_REQUIRE_MSG(i == 0 || l > last_ts, + "iteration %d: lock time did not increase, old time %lu, " + "new time %lu", i, + (unsigned long)last_ts, (unsigned long)l); + last_ts = l; + sleep(2); + } + rump_sys_chdir("/"); +} + +ATF_FSAPPLY(otrunc_mtime_update, "Checks for mtime updates by open(O_TRUNC) (PR kern/51762)"); diff --git a/contrib/netbsd-tests/fs/vfs/t_renamerace.c b/contrib/netbsd-tests/fs/vfs/t_renamerace.c new file mode 100644 index 000000000000..63cfb4479c89 --- /dev/null +++ b/contrib/netbsd-tests/fs/vfs/t_renamerace.c @@ -0,0 +1,190 @@ +/* $NetBSD: t_renamerace.c,v 1.34 2017/01/13 21:30:40 christos Exp $ */ + +/* + * Modified for rump and atf from a program supplied + * by Nicolas Joly in kern/40948 + */ + +#include <sys/types.h> +#include <sys/mount.h> +#include <sys/utsname.h> + +#include <atf-c.h> +#include <errno.h> +#include <fcntl.h> +#include <pthread.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +#include <rump/rump.h> +#include <rump/rump_syscalls.h> + +/* Bump the size of the test file system image to a larger value. + * + * These tests cause a lot of churn in the file system by creating and + * deleting files/directories in quick succession. A faster CPU will cause + * more churn because the tests are capped by a run time period in seconds, + * not number of operations. + * + * This is all fine except for LFS, because the lfs_cleanerd cannot keep up + * with the churn and thus causes the test to fail on fast machines. Hence + * the reason for this hack. */ +#define FSTEST_IMGSIZE (50000 * 512) + +#include "../common/h_fsmacros.h" +#include "h_macros.h" + +static volatile int quittingtime; +pid_t wrkpid; + +static void * +w1(void *arg) +{ + int fd; + + rump_pub_lwproc_newlwp(wrkpid); + + while (!quittingtime) { + fd = rump_sys_open("rename.test1", + O_WRONLY|O_CREAT|O_TRUNC, 0666); + if (fd == -1 && errno != EEXIST) + atf_tc_fail_errno("create"); + rump_sys_unlink("rename.test1"); + rump_sys_close(fd); + } + + return NULL; +} + +static void * +w1_dirs(void *arg) +{ + + rump_pub_lwproc_newlwp(wrkpid); + + while (!quittingtime) { + if (rump_sys_mkdir("rename.test1", 0777) == -1) + atf_tc_fail_errno("mkdir"); + rump_sys_rmdir("rename.test1"); + } + + return NULL; +} + +static void * +w2(void *arg) +{ + + rump_pub_lwproc_newlwp(wrkpid); + + while (!quittingtime) { + rump_sys_rename("rename.test1", "rename.test2"); + } + + return NULL; +} + +#define NWRK 8 +static void +renamerace(const atf_tc_t *tc, const char *mp) +{ + pthread_t pt1[NWRK], pt2[NWRK]; + int i; + + /* + * Sysvbfs supports only 8 inodes so this test would exhaust + * the inode table and creating files would fail with ENOSPC. + */ + if (FSTYPE_SYSVBFS(tc)) + atf_tc_skip("filesystem has not enough inodes"); + if (FSTYPE_RUMPFS(tc)) + atf_tc_skip("rename not supported by file system"); + if (FSTYPE_UDF(tc)) + atf_tc_expect_fail("PR kern/49046"); + + RZ(rump_pub_lwproc_rfork(RUMP_RFCFDG)); + RL(wrkpid = rump_sys_getpid()); + + RL(rump_sys_chdir(mp)); + for (i = 0; i < NWRK; i++) + pthread_create(&pt1[i], NULL, w1, NULL); + + for (i = 0; i < NWRK; i++) + pthread_create(&pt2[i], NULL, w2, NULL); + + sleep(5); + quittingtime = 1; + + for (i = 0; i < NWRK; i++) + pthread_join(pt1[i], NULL); + for (i = 0; i < NWRK; i++) + pthread_join(pt2[i], NULL); + RL(rump_sys_chdir("/")); + + if (FSTYPE_UDF(tc)) + atf_tc_fail("race did not trigger this time"); + + if (FSTYPE_MSDOS(tc)) { + atf_tc_expect_fail("PR kern/43626"); + /* + * XXX: race does not trigger every time at least + * on amd64/qemu. + */ + if (msdosfs_fstest_unmount(tc, mp, 0) != 0) { + rump_pub_vfs_mount_print(mp, 1); + atf_tc_fail_errno("unmount failed"); + } + atf_tc_fail("race did not trigger this time"); + } +} + +static void +renamerace_dirs(const atf_tc_t *tc, const char *mp) +{ + pthread_t pt1, pt2; + + if (FSTYPE_SYSVBFS(tc)) + atf_tc_skip("directories not supported by file system"); + + if (FSTYPE_RUMPFS(tc)) + atf_tc_skip("rename not supported by file system"); + + /* XXX: msdosfs also sometimes hangs */ + if (FSTYPE_MSDOS(tc)) + atf_tc_expect_signal(-1, "PR kern/43626"); + + RZ(rump_pub_lwproc_rfork(RUMP_RFCFDG)); + RL(wrkpid = rump_sys_getpid()); + + RL(rump_sys_chdir(mp)); + pthread_create(&pt1, NULL, w1_dirs, NULL); + pthread_create(&pt2, NULL, w2, NULL); + + sleep(5); + quittingtime = 1; + + pthread_join(pt1, NULL); + pthread_join(pt2, NULL); + RL(rump_sys_chdir("/")); + + /* + * Doesn't always trigger when run on a slow backend + * (i.e. not on tmpfs/mfs). So do the usual kludge. + */ + if (FSTYPE_MSDOS(tc)) + abort(); +} + +ATF_TC_FSAPPLY(renamerace, "rename(2) race with file unlinked mid-operation"); +ATF_TC_FSAPPLY(renamerace_dirs, "rename(2) race with directories"); + +ATF_TP_ADD_TCS(tp) +{ + + ATF_TP_FSAPPLY(renamerace); /* PR kern/41128 */ + ATF_TP_FSAPPLY(renamerace_dirs); + + return atf_no_error(); +} diff --git a/contrib/netbsd-tests/fs/vfs/t_rmdirrace.c b/contrib/netbsd-tests/fs/vfs/t_rmdirrace.c new file mode 100644 index 000000000000..839dbad73352 --- /dev/null +++ b/contrib/netbsd-tests/fs/vfs/t_rmdirrace.c @@ -0,0 +1,106 @@ +/* $NetBSD: t_rmdirrace.c,v 1.9 2012/02/16 02:47:56 perseant Exp $ */ + +/*- + * Copyright (c) 2010 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Nicolas Joly. + * + * 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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. + */ + +#include <sys/stat.h> + +#include <atf-c.h> +#include <fcntl.h> +#include <pthread.h> +#include <stdlib.h> +#include <unistd.h> + +#include <rump/rump_syscalls.h> +#include <rump/rump.h> + +#include "../common/h_fsmacros.h" + +#define DIRNAME "rmdir.test" + +static void *func1(void *arg) +{ + + while (*(int *)arg != 1) + rump_sys_mkdir(DIRNAME, 0755); + + return NULL; +} + +static void *func2(void *arg) +{ + + while (*(int *)arg != 1) + rump_sys_rmdir(DIRNAME); + + return NULL; +} + +static void +race(const atf_tc_t *tc, const char *path) +{ + int res, fd, quit; + pthread_t th1, th2; + + if (FSTYPE_SYSVBFS(tc)) + atf_tc_skip("directories not supported by file system"); + + fd = rump_sys_open(".", O_RDONLY, 0666); + if (fd == -1) + atf_tc_fail("open failed"); + res = rump_sys_chdir(path); + if (res == -1) + atf_tc_fail("chdir failed"); + + quit = 0; + + res = pthread_create(&th1, NULL, func1, &quit); + if (res != 0) + atf_tc_fail("pthread_create1 failed"); + res = pthread_create(&th2, NULL, func2, &quit); + if (res != 0) + atf_tc_fail("pthread_create2 failed"); + + sleep(10); + + quit = 1; + + res = pthread_join(th2, NULL); + if (res != 0) + atf_tc_fail("pthread_join2 failed"); + res = pthread_join(th1, NULL); + if (res != 0) + atf_tc_fail("pthread_join1 failed"); + + res = rump_sys_fchdir(fd); + if (res == -1) + atf_tc_fail("fchdir failed"); +} + +ATF_FSAPPLY(race, "rmdir(2) race"); diff --git a/contrib/netbsd-tests/fs/vfs/t_ro.c b/contrib/netbsd-tests/fs/vfs/t_ro.c new file mode 100644 index 000000000000..f7f45813e7b7 --- /dev/null +++ b/contrib/netbsd-tests/fs/vfs/t_ro.c @@ -0,0 +1,203 @@ +/* $NetBSD: t_ro.c,v 1.6 2017/01/13 21:30:40 christos Exp $ */ + +/*- + * Copyright (c) 2010 The NetBSD Foundation, Inc. + * All rights reserved. + * + * 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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. + */ + +#include <sys/stat.h> +#include <sys/statvfs.h> + +#include <atf-c.h> +#include <fcntl.h> +#include <libgen.h> +#include <stdlib.h> +#include <unistd.h> + +#include <rump/rump_syscalls.h> +#include <rump/rump.h> + +#include "../common/h_fsmacros.h" +#include "h_macros.h" + +#define AFILE "testfile" +#define ADIR "testdir" +#define AFIFO "testfifo" +#define ASYMLINK "testsymlink" +#define ALINK "testlink" +#define FUNTEXT "this is some non-humppa text" +#define FUNSIZE (sizeof(FUNTEXT)-1) + +static void +nullgen(const atf_tc_t *tc, const char *mp) +{ + + return; +} + +static void +filegen(const atf_tc_t *tc, const char *mp) +{ + int fd; + + FSTEST_ENTER(); + RL(fd = rump_sys_open(AFILE, O_CREAT | O_RDWR, 0777)); + ATF_REQUIRE_EQ(rump_sys_write(fd, FUNTEXT, FUNSIZE), FUNSIZE); + RL(rump_sys_close(fd)); + FSTEST_EXIT(); +} + +/* + * + * BEGIN tests + * + */ + +static void +create(const atf_tc_t *tc, const char *mp) +{ + + FSTEST_ENTER(); + ATF_REQUIRE_ERRNO(EROFS, rump_sys_open(AFILE, O_CREAT|O_RDONLY) == -1); + FSTEST_EXIT(); +} + +static void +rmfile(const atf_tc_t *tc, const char *mp) +{ + + FSTEST_ENTER(); + ATF_REQUIRE_ERRNO(EROFS, rump_sys_unlink(AFILE) == -1); + FSTEST_EXIT(); +} + +static void +fileio(const atf_tc_t *tc, const char *mp) +{ + int fd; + char buf[FUNSIZE+1]; + int expected; + + if (FSTYPE_NFSRO(tc)) + expected = EACCES; + else + expected = EROFS; + + FSTEST_ENTER(); + RL(fd = rump_sys_open(AFILE, O_RDONLY)); + ATF_REQUIRE_EQ(rump_sys_read(fd, buf, FUNSIZE), FUNSIZE); + buf[FUNSIZE] = '\0'; + ATF_REQUIRE_STREQ(buf, FUNTEXT); + RL(rump_sys_close(fd)); + + ATF_REQUIRE_ERRNO(expected, rump_sys_open(AFILE, O_WRONLY) == -1); + ATF_REQUIRE_ERRNO(expected, rump_sys_open(AFILE, O_RDWR) == -1); + FSTEST_EXIT(); +} + +static void +attrs(const atf_tc_t *tc, const char *mp) +{ + struct timeval sometvs[2]; + struct stat sb; + int fd; + + FSTEST_ENTER(); + + RL(rump_sys_stat(AFILE, &sb)); + + ATF_REQUIRE_ERRNO(EROFS, rump_sys_chmod(AFILE, 0775) == -1); + if (!FSTYPE_MSDOS(tc)) + ATF_REQUIRE_ERRNO(EROFS, rump_sys_chown(AFILE, 1, 1) == -1); + ATF_REQUIRE_ERRNO(EROFS, rump_sys_utimes(AFILE, sometvs) == -1); + + RL(fd = rump_sys_open(AFILE, O_RDONLY)); + ATF_REQUIRE_ERRNO(EROFS, rump_sys_fchmod(fd, 0775) == -1); + if (!FSTYPE_MSDOS(tc)) + ATF_REQUIRE_ERRNO(EROFS, rump_sys_fchown(fd, 1, 1) == -1); + ATF_REQUIRE_ERRNO(EROFS, rump_sys_futimes(fd, sometvs) == -1); + RL(rump_sys_close(fd)); + + FSTEST_EXIT(); +} + +static void +createdir(const atf_tc_t *tc, const char *mp) +{ + + FSTEST_ENTER(); + ATF_REQUIRE_ERRNO(EROFS, rump_sys_mkdir(ADIR, 0775) == -1); + FSTEST_EXIT(); +} + +static void +createfifo(const atf_tc_t *tc, const char *mp) +{ + + FSTEST_ENTER(); + ATF_REQUIRE_ERRNO(EROFS, rump_sys_mkfifo(AFIFO, 0775) == -1); + FSTEST_EXIT(); +} + +static void +createsymlink(const atf_tc_t *tc, const char *mp) +{ + + FSTEST_ENTER(); + ATF_REQUIRE_ERRNO(EROFS, rump_sys_symlink("hoge", ASYMLINK) == -1); + FSTEST_EXIT(); +} + +static void +createlink(const atf_tc_t *tc, const char *mp) +{ + + FSTEST_ENTER(); + ATF_REQUIRE_ERRNO(EROFS, rump_sys_link(AFILE, ALINK) == -1); + FSTEST_EXIT(); +} + +ATF_TC_FSAPPLY_RO(create, "create file on r/o mount", nullgen); +ATF_TC_FSAPPLY_RO(rmfile, "remove file from r/o mount", filegen); +ATF_TC_FSAPPLY_RO(fileio, "can read a file but not write it", filegen); +ATF_TC_FSAPPLY_RO(attrs, "can query but not change attributes", filegen); +ATF_TC_FSAPPLY_RO(createdir, "create directory on r/o mount", nullgen); +ATF_TC_FSAPPLY_RO(createfifo, "create fifo on r/o mount", nullgen); +ATF_TC_FSAPPLY_RO(createsymlink, "create symlink on r/o mount", nullgen); +ATF_TC_FSAPPLY_RO(createlink, "create hardlink on r/o mount", filegen); + +ATF_TP_ADD_TCS(tp) +{ + + ATF_TP_FSAPPLY_RO(create); + ATF_TP_FSAPPLY_RO(rmfile); + ATF_TP_FSAPPLY_RO(fileio); + ATF_TP_FSAPPLY_RO(attrs); + ATF_TP_FSAPPLY_RO(createdir); + ATF_TP_FSAPPLY_RO(createfifo); + ATF_TP_FSAPPLY_RO(createsymlink); + ATF_TP_FSAPPLY_RO(createlink); + + return atf_no_error(); +} diff --git a/contrib/netbsd-tests/fs/vfs/t_rwtoro.c b/contrib/netbsd-tests/fs/vfs/t_rwtoro.c new file mode 100644 index 000000000000..ca8af07a0a45 --- /dev/null +++ b/contrib/netbsd-tests/fs/vfs/t_rwtoro.c @@ -0,0 +1,233 @@ +/* $NetBSD: t_rwtoro.c,v 1.1 2017/01/27 10:45:11 hannken Exp $ */ + +/*- + * Copyright (c) 2017 The NetBSD Foundation, Inc. + * All rights reserved. + * + * 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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. + */ + +#include <sys/types.h> +#include <sys/mount.h> +#include <sys/stat.h> +#include <sys/statvfs.h> + +#include <atf-c.h> +#include <fcntl.h> +#include <libgen.h> +#include <stdlib.h> +#include <unistd.h> + +#include <rump/rump_syscalls.h> +#include <rump/rump.h> + +#include <miscfs/nullfs/null.h> +#include <fs/tmpfs/tmpfs_args.h> + +#include "../common/h_fsmacros.h" +#include "../../h_macros.h" + +static const char *unsupported = "fs does not support r/o remount"; +static char file_path[MAXPATHLEN]; +static int file_fd; + +/* + * Remount the filesystem read-only and test errno. + * Skip filesystems that don't implement read-write -> read-only. + */ +static void +remount_ro(const atf_tc_t *tc, const char *mp, int expected_errno) +{ + int error; + union { + struct tmpfs_args tmpfs; + char data[4095]; + } mount_args; + int mount_args_length; + struct statvfs sbuf; + + if (FSTYPE_ZFS(tc)) + atf_tc_skip("%s", unsupported); + + /* Prepare mount arguments. */ + RL(rump_sys_statvfs1(mp, &sbuf, ST_WAIT)); + mount_args_length = sizeof(mount_args); + memset(&mount_args, 0, mount_args_length); + if (FSTYPE_TMPFS(tc)) + mount_args.tmpfs.ta_version = TMPFS_ARGS_VERSION; + mount_args_length = rump_sys_mount(sbuf.f_fstypename, mp, MNT_GETARGS, + &mount_args, mount_args_length); + ATF_CHECK(mount_args_length >= 0); + + /* Remount and test result. */ + error = rump_sys_mount(sbuf.f_fstypename, mp, MNT_UPDATE | MNT_RDONLY, + &mount_args, mount_args_length); + if (errno == EOPNOTSUPP) + atf_tc_skip("%s", unsupported); + if (expected_errno == 0) + ATF_CHECK(error == 0); + else + ATF_CHECK_ERRNO(expected_errno, error == -1); +} + +static void +open_file_ro(const char *prefix) +{ + + snprintf(file_path, sizeof(file_path), "%s/file", prefix); + RL(file_fd = rump_sys_open(file_path, O_CREAT | O_RDWR, 0777)); + RL(rump_sys_close(file_fd)); + RL(file_fd = rump_sys_open(file_path, O_RDONLY)); +} + +static void +open_file_ro_unlink(const char *prefix) +{ + + snprintf(file_path, sizeof(file_path), "%s/file", prefix); + RL(file_fd = rump_sys_open(file_path, O_CREAT | O_RDWR, 0777)); + RL(rump_sys_close(file_fd)); + RL(file_fd = rump_sys_open(file_path, O_RDONLY)); + RL(rump_sys_unlink(file_path)); +} + +static void +open_file_rw(const char *prefix) +{ + + snprintf(file_path, sizeof(file_path), "%s/file", prefix); + RL(file_fd = rump_sys_open(file_path, O_CREAT | O_RDWR, 0777)); +} + +static void +close_file(const char *unused) +{ + + RL(rump_sys_close(file_fd)); +} + +static void +basic_test(const atf_tc_t *tc, const char *mp, int expected_errno, + bool use_layer, void (*pre)(const char *), void (*post)(const char *)) +{ + const char *null_mount = "/nullm"; + struct null_args nargs; + + if (use_layer) { + RL(rump_sys_mkdir(null_mount, 0777)); + memset(&nargs, 0, sizeof(nargs)); + nargs.nulla_target = __UNCONST(mp);; + RL(rump_sys_mount(MOUNT_NULL, null_mount, 0, + &nargs, sizeof(nargs))); + } + if (pre) + (*pre)(use_layer ? null_mount : mp); + remount_ro(tc, mp, expected_errno); + if (post) + (*post)(use_layer ? null_mount : mp); + if (use_layer) + RL(rump_sys_unmount(null_mount, 0)); +} + +static void +noneopen(const atf_tc_t *tc, const char *mp) +{ + + basic_test(tc, mp, 0, false, NULL, NULL); +} + +static void +readopen(const atf_tc_t *tc, const char *mp) +{ + + basic_test(tc, mp, 0, false, open_file_ro, close_file); +} + +static void +writeopen(const atf_tc_t *tc, const char *mp) +{ + + basic_test(tc, mp, EBUSY, false, open_file_rw, close_file); +} + +static void +read_unlinked(const atf_tc_t *tc, const char *mp) +{ + + basic_test(tc, mp, EBUSY, false, open_file_ro_unlink, close_file); +} + +static void +layer_noneopen(const atf_tc_t *tc, const char *mp) +{ + + basic_test(tc, mp, 0, true, NULL, NULL); +} + +static void +layer_readopen(const atf_tc_t *tc, const char *mp) +{ + + basic_test(tc, mp, 0, true, open_file_ro, close_file); +} + +static void +layer_writeopen(const atf_tc_t *tc, const char *mp) +{ + + basic_test(tc, mp, EBUSY, true, open_file_rw, close_file); +} + +static void +layer_read_unlinked(const atf_tc_t *tc, const char *mp) +{ + + basic_test(tc, mp, EBUSY, true, open_file_ro_unlink, close_file); +} + +ATF_TC_FSAPPLY(noneopen, "remount r/o with no file open"); +ATF_TC_FSAPPLY(readopen, "remount r/o with file open for reading"); +ATF_TC_FSAPPLY(writeopen, "remount r/o with file open for writing"); +ATF_TC_FSAPPLY(read_unlinked, + "remount r/o with unlinked file open for reading"); +ATF_TC_FSAPPLY(layer_noneopen, "remount r/o with no file open on layer"); +ATF_TC_FSAPPLY(layer_readopen, + "remount r/o with file open for reading on layer"); +ATF_TC_FSAPPLY(layer_writeopen, + "remount r/o with file open for writing on layer"); +ATF_TC_FSAPPLY(layer_read_unlinked, + "remount r/o with unlinked file open for reading on layer"); + +ATF_TP_ADD_TCS(tp) +{ + + ATF_TP_FSAPPLY(noneopen); + ATF_TP_FSAPPLY(readopen); + ATF_TP_FSAPPLY(writeopen); + ATF_TP_FSAPPLY(read_unlinked); + ATF_TP_FSAPPLY(layer_noneopen); + ATF_TP_FSAPPLY(layer_readopen); + ATF_TP_FSAPPLY(layer_writeopen); + ATF_TP_FSAPPLY(layer_read_unlinked); + + return atf_no_error(); +} diff --git a/contrib/netbsd-tests/fs/vfs/t_union.c b/contrib/netbsd-tests/fs/vfs/t_union.c new file mode 100644 index 000000000000..5da1ea1ff39b --- /dev/null +++ b/contrib/netbsd-tests/fs/vfs/t_union.c @@ -0,0 +1,204 @@ +/* $NetBSD: t_union.c,v 1.9 2017/01/13 21:30:40 christos Exp $ */ + +#include <sys/types.h> +#include <sys/mount.h> + +#include <atf-c.h> +#include <err.h> +#include <errno.h> +#include <fcntl.h> +#include <stdio.h> +#include <unistd.h> +#include <string.h> +#include <stdlib.h> + +#include <rump/rump.h> +#include <rump/rump_syscalls.h> + +#include <miscfs/union/union.h> + +#include "h_macros.h" +#include "../common/h_fsmacros.h" + +#define MSTR "magic bus" + +static void +xput_tfile(const char *mp, const char *path) +{ + char pathb[MAXPATHLEN]; + int fd; + + strcpy(pathb, mp); + strcat(pathb, "/"); + strcat(pathb, path); + + RL(fd = rump_sys_open(pathb, O_CREAT | O_RDWR, 0777)); + if (rump_sys_write(fd, MSTR, sizeof(MSTR)) != sizeof(MSTR)) + atf_tc_fail_errno("write to testfile"); + RL(rump_sys_close(fd)); +} + +static int +xread_tfile(const char *mp, const char *path) +{ + char pathb[MAXPATHLEN]; + char buf[128]; + int fd; + + strcpy(pathb, mp); + strcat(pathb, "/"); + strcat(pathb, path); + + fd = rump_sys_open(pathb, O_RDONLY); + if (fd == -1) + return errno; + if (rump_sys_read(fd, buf, sizeof(buf)) == -1) + atf_tc_fail_errno("read tfile"); + RL(rump_sys_close(fd)); + if (strcmp(buf, MSTR) == 0) + return 0; + return EPROGMISMATCH; +} + +/* + * Mount a unionfs for testing. Before calling, "mp" contains + * the upper layer. Lowerpath is constructed so that the directory + * contains rumpfs. + */ +static void +mountunion(const char *mp, char *lowerpath) +{ + struct union_args unionargs; + + sprintf(lowerpath, "/lower"); + rump_sys_mkdir(lowerpath, 0777); + + /* mount the union with our testfs as the upper layer */ + memset(&unionargs, 0, sizeof(unionargs)); + unionargs.target = lowerpath; + unionargs.mntflags = UNMNT_BELOW; + + if (rump_sys_mount(MOUNT_UNION, mp, 0, + &unionargs, sizeof(unionargs)) == -1) { + if (errno == EOPNOTSUPP) { + atf_tc_skip("fs does not support VOP_WHITEOUT"); + } else { + atf_tc_fail_errno("union mount"); + } + } +} + +#if 0 +static void +toggleroot(void) +{ + static int status; + + status ^= MNT_RDONLY; + + printf("0x%x\n", status); + RL(rump_sys_mount(MOUNT_RUMPFS, "/", status | MNT_UPDATE, NULL, 0)); +} +#endif + +#define TFILE "tensti" +#define TDIR "testdir" +#define TDFILE TDIR "/indir" + +static void +basic(const atf_tc_t *tc, const char *mp) +{ + char lowerpath[MAXPATHLEN]; + char dbuf[8192]; + struct stat sb; + struct dirent *dp; + int error, fd, dsize; + + mountunion(mp, lowerpath); + + /* create a file in the lower layer */ + xput_tfile(lowerpath, TFILE); + + /* first, test we can read the old file from the new namespace */ + error = xread_tfile(mp, TFILE); + if (error != 0) + atf_tc_fail("union compare failed: %d (%s)", + error, strerror(error)); + + /* then, test upper layer writes don't affect the lower layer */ + xput_tfile(mp, "kiekko"); + if ((error = xread_tfile(lowerpath, "kiekko")) != ENOENT) + atf_tc_fail("invisibility failed: %d (%s)", + error, strerror(error)); + + /* check that we can whiteout stuff in the upper layer */ + FSTEST_ENTER(); + RL(rump_sys_unlink(TFILE)); + ATF_REQUIRE_ERRNO(ENOENT, rump_sys_stat(TFILE, &sb) == -1); + FSTEST_EXIT(); + + /* check that the removed node is not in the directory listing */ + RL(fd = rump_sys_open(mp, O_RDONLY)); + RL(dsize = rump_sys_getdents(fd, dbuf, sizeof(dbuf))); + for (dp = (struct dirent *)dbuf; + (char *)dp < dbuf + dsize; + dp = _DIRENT_NEXT(dp)) { + if (strcmp(dp->d_name, TFILE) == 0 && dp->d_type != DT_WHT) + atf_tc_fail("removed file non-white-outed"); + } + RL(rump_sys_close(fd)); + + RL(rump_sys_unmount(mp, 0)); +} + +static void +whiteout(const atf_tc_t *tc, const char *mp) +{ + char lower[MAXPATHLEN]; + struct stat sb; + void *fsarg; + + /* + * XXX: use ffs here to make sure any screwups in rumpfs don't + * affect the test + */ + RL(ffs_fstest_newfs(tc, &fsarg, "daimage", 1024*1024*5, NULL)); + RL(ffs_fstest_mount(tc, fsarg, "/lower", 0)); + + /* create a file in the lower layer */ + RL(rump_sys_chdir("/lower")); + RL(rump_sys_mkdir(TDIR, 0777)); + RL(rump_sys_mkdir(TDFILE, 0777)); + RL(rump_sys_chdir("/")); + + RL(ffs_fstest_unmount(tc, "/lower", 0)); + RL(ffs_fstest_mount(tc, fsarg, "/lower", MNT_RDONLY)); + + mountunion(mp, lower); + + FSTEST_ENTER(); + ATF_REQUIRE_ERRNO(ENOTEMPTY, rump_sys_rmdir(TDIR) == -1); + RL(rump_sys_rmdir(TDFILE)); + RL(rump_sys_rmdir(TDIR)); + ATF_REQUIRE_ERRNO(ENOENT, rump_sys_stat(TDFILE, &sb) == -1); + ATF_REQUIRE_ERRNO(ENOENT, rump_sys_stat(TDIR, &sb) == -1); + + RL(rump_sys_mkdir(TDIR, 0777)); + RL(rump_sys_stat(TDIR, &sb)); + ATF_REQUIRE_ERRNO(ENOENT, rump_sys_stat(TDFILE, &sb) == -1); + FSTEST_EXIT(); + + RL(rump_sys_unmount(mp, 0)); +} + +ATF_TC_FSAPPLY(basic, "check basic union functionality"); +ATF_TC_FSAPPLY(whiteout, "create whiteout in upper layer"); + +ATF_TP_ADD_TCS(tp) +{ + + ATF_TP_FSAPPLY(basic); + ATF_TP_FSAPPLY(whiteout); + + return atf_no_error(); +} diff --git a/contrib/netbsd-tests/fs/vfs/t_unpriv.c b/contrib/netbsd-tests/fs/vfs/t_unpriv.c new file mode 100644 index 000000000000..6536c21d9572 --- /dev/null +++ b/contrib/netbsd-tests/fs/vfs/t_unpriv.c @@ -0,0 +1,239 @@ +/* $NetBSD: t_unpriv.c,v 1.13 2017/01/13 21:30:40 christos Exp $ */ + +/*- + * Copyright (c) 2011 The NetBSD Foundation, Inc. + * All rights reserved. + * + * 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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. + */ + +#include <sys/stat.h> +#include <sys/time.h> + +#include <atf-c.h> +#include <libgen.h> +#include <limits.h> +#include <unistd.h> + +#include <rump/rump_syscalls.h> +#include <rump/rump.h> + +#include "../common/h_fsmacros.h" +#include "h_macros.h" + +#define USES_OWNER \ + if (FSTYPE_MSDOS(tc)) \ + atf_tc_skip("owner not supported by file system") + +static void +owner(const atf_tc_t *tc, const char *mp) +{ + + USES_OWNER; + + FSTEST_ENTER(); + + rump_pub_lwproc_rfork(RUMP_RFCFDG); + if (rump_sys_setuid(1) == -1) + atf_tc_fail_errno("setuid"); + if (rump_sys_chown(".", 1, -1) != -1 || errno != EPERM) + atf_tc_fail_errno("chown"); + if (rump_sys_chmod(".", 0000) != -1 || errno != EPERM) + atf_tc_fail_errno("chmod"); + rump_pub_lwproc_releaselwp(); + + if (rump_sys_chown(".", 1, -1) == -1) + atf_tc_fail_errno("chown"); + + rump_pub_lwproc_rfork(RUMP_RFCFDG); + if (rump_sys_setuid(1) == -1) + atf_tc_fail_errno("setuid"); + if (rump_sys_chown(".", 1, -1) == -1) + atf_tc_fail_errno("chown"); + if (rump_sys_chmod(".", 0000) == -1) + atf_tc_fail_errno("chmod"); + rump_pub_lwproc_releaselwp(); + + FSTEST_EXIT(); +} + +static void +dirperms(const atf_tc_t *tc, const char *mp) +{ + char name[] = "dir.test/file.test"; + char *dir = dirname(name); + int fd; + + if (FSTYPE_SYSVBFS(tc)) + atf_tc_skip("directories not supported by file system"); + + FSTEST_ENTER(); + + if (rump_sys_mkdir(dir, 0777) == -1) + atf_tc_fail_errno("mkdir"); + + rump_pub_lwproc_rfork(RUMP_RFCFDG); + if (rump_sys_setuid(1) == -1) + atf_tc_fail_errno("setuid"); + if (FSTYPE_ZFS(tc)) + atf_tc_expect_fail("PR kern/47656: Test known to be broken"); + if (rump_sys_open(name, O_RDWR|O_CREAT, 0666) != -1 || errno != EACCES) + atf_tc_fail_errno("open"); + rump_pub_lwproc_releaselwp(); + + if ((fd = rump_sys_open(name, O_RDWR|O_CREAT, 0666)) == -1) + atf_tc_fail_errno("open"); + if (rump_sys_close(fd) == -1) + atf_tc_fail_errno("close"); + + rump_pub_lwproc_rfork(RUMP_RFCFDG); + if (rump_sys_setuid(1) == -1) + atf_tc_fail_errno("setuid"); + if (rump_sys_unlink(name) != -1 || errno != EACCES) + atf_tc_fail_errno("unlink"); + rump_pub_lwproc_releaselwp(); + + if (rump_sys_unlink(name) == -1) + atf_tc_fail_errno("unlink"); + + if (rump_sys_rmdir(dir) == -1) + atf_tc_fail_errno("rmdir"); + + FSTEST_EXIT(); +} + +static void +times(const atf_tc_t *tc, const char *mp) +{ + const char *name = "file.test"; + int fd; + unsigned int i, j; + struct timeval tmv[2]; + static struct timeval tmvs[] = { + { QUAD_MIN, 0 }, + { 0, 0 }, + { QUAD_MAX, 999999 } + }; + + FSTEST_ENTER(); + + if ((fd = rump_sys_open(name, O_RDWR|O_CREAT, 0666)) == -1) + atf_tc_fail_errno("open"); + if (rump_sys_close(fd) == -1) + atf_tc_fail_errno("close"); + + rump_pub_lwproc_rfork(RUMP_RFCFDG); + if (rump_sys_setuid(1) == -1) + atf_tc_fail_errno("setuid"); + if (FSTYPE_ZFS(tc)) + atf_tc_expect_fail("PR kern/47656: Test known to be broken"); + if (rump_sys_utimes(name, NULL) != -1 || errno != EACCES) + atf_tc_fail_errno("utimes"); + rump_pub_lwproc_releaselwp(); + + if (rump_sys_utimes(name, NULL) == -1) + atf_tc_fail_errno("utimes"); + + for (i = 0; i < sizeof(tmvs) / sizeof(tmvs[0]); i++) { + for (j = 0; j < sizeof(tmvs) / sizeof(tmvs[0]); j++) { + tmv[0] = tmvs[i]; + tmv[1] = tmvs[j]; + rump_pub_lwproc_rfork(RUMP_RFCFDG); + if (rump_sys_setuid(1) == -1) + atf_tc_fail_errno("setuid"); + if (rump_sys_utimes(name, tmv) != -1 || errno != EPERM) + atf_tc_fail_errno("utimes"); + rump_pub_lwproc_releaselwp(); + + if (rump_sys_utimes(name, tmv) == -1) + atf_tc_fail_errno("utimes"); + } + } + + if (rump_sys_unlink(name) == -1) + atf_tc_fail_errno("unlink"); + + FSTEST_EXIT(); +} + +static void +flags(const atf_tc_t *tc, const char *mp) +{ + const char *name = "file.test"; + int fd, fflags; + struct stat st; + + FSTEST_ENTER(); + + if ((fd = rump_sys_open(name, O_RDWR|O_CREAT, 0666)) == -1) + atf_tc_fail_errno("open"); + if (rump_sys_close(fd) == -1) + atf_tc_fail_errno("close"); + + if (rump_sys_stat(name, &st) == -1) + atf_tc_fail_errno("stat"); + if (FSTYPE_ZFS(tc)) + atf_tc_expect_fail("PR kern/47656: Test known to be broken"); + if (rump_sys_chflags(name, st.st_flags) == -1) { + if (errno == EOPNOTSUPP) + atf_tc_skip("file flags not supported by file system"); + atf_tc_fail_errno("chflags"); + } + + fflags = st.st_flags | UF_IMMUTABLE; + + rump_pub_lwproc_rfork(RUMP_RFCFDG); + if (rump_sys_setuid(1) == -1) + atf_tc_fail_errno("setuid"); + fflags |= UF_IMMUTABLE; + if (rump_sys_chflags(name, fflags) != -1 || errno != EPERM) + atf_tc_fail_errno("chflags"); + rump_pub_lwproc_releaselwp(); + + if (rump_sys_chflags(name, fflags) == -1) + atf_tc_fail_errno("chflags"); + + fflags &= ~UF_IMMUTABLE; + if (rump_sys_chflags(name, fflags) == -1) + atf_tc_fail_errno("chflags"); + + if (rump_sys_unlink(name) == -1) + atf_tc_fail_errno("unlink"); + + FSTEST_EXIT(); +} + +ATF_TC_FSAPPLY(owner, "owner unprivileged checks"); +ATF_TC_FSAPPLY(dirperms, "directory permission checks"); +ATF_TC_FSAPPLY(times, "time set checks"); +ATF_TC_FSAPPLY(flags, "file flags checks"); + +ATF_TP_ADD_TCS(tp) +{ + + ATF_TP_FSAPPLY(owner); + ATF_TP_FSAPPLY(dirperms); + ATF_TP_FSAPPLY(times); + ATF_TP_FSAPPLY(flags); + + return atf_no_error(); +} diff --git a/contrib/netbsd-tests/fs/vfs/t_vfsops.c b/contrib/netbsd-tests/fs/vfs/t_vfsops.c new file mode 100644 index 000000000000..bbed9f9d3089 --- /dev/null +++ b/contrib/netbsd-tests/fs/vfs/t_vfsops.c @@ -0,0 +1,211 @@ +/* $NetBSD: t_vfsops.c,v 1.12 2017/01/13 21:30:40 christos Exp $ */ + +/*- + * Copyright (c) 2010 The NetBSD Foundation, Inc. + * All rights reserved. + * + * 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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. + */ + +#include <sys/stat.h> +#include <sys/statvfs.h> + +#include <atf-c.h> +#include <dirent.h> +#include <fcntl.h> +#include <stdlib.h> +#include <unistd.h> + +#include <rump/rump_syscalls.h> +#include <rump/rump.h> + +#include "../common/h_fsmacros.h" +#include "h_macros.h" + +static void +tmount(const atf_tc_t *tc, const char *path) +{ + + return; +} + +static void +tstatvfs(const atf_tc_t *tc, const char *path) +{ + const char *fstype = atf_tc_get_md_var(tc, "X-fs.mntname"); + struct statvfs svb; + + if (rump_sys_statvfs1(path, &svb, ST_WAIT) == -1) + atf_tc_fail_errno("statvfs"); + + ATF_REQUIRE(svb.f_namemax > 0 && svb.f_namemax <= MAXNAMLEN); + if (!(FSTYPE_PUFFS(tc) || FSTYPE_P2K_FFS(tc))) + ATF_REQUIRE_STREQ(svb.f_fstypename, fstype); + ATF_REQUIRE_STREQ(svb.f_mntonname, path); +} + +static void +tsync(const atf_tc_t *tc, const char *path) +{ + + rump_sys_sync(); +} + +#define MAGICSTR "just a string, I like A" +static void +tfilehandle(const atf_tc_t *tc, const char *path) +{ + char fpath[MAXPATHLEN]; + char buf[sizeof(MAGICSTR)]; + size_t fhsize; + void *fhp; + int fd; + + sprintf(fpath, "%s/file", path); + fd = rump_sys_open(fpath, O_RDWR | O_CREAT, 0777); + if (fd == -1) + atf_tc_fail_errno("open"); + + if (rump_sys_write(fd, MAGICSTR, sizeof(MAGICSTR)) != sizeof(MAGICSTR)) + atf_tc_fail("write to file"); + rump_sys_close(fd); + + /* + * Get file handle size. + * This also weeds out unsupported file systems. + */ + fhsize = 0; + if (rump_sys_getfh(fpath, NULL, &fhsize) == -1) { + if (errno == EOPNOTSUPP) { + atf_tc_skip("file handles not supported"); + } else if (errno != E2BIG) { + atf_tc_fail_errno("getfh size"); + } + } + + fhp = malloc(fhsize); + if (rump_sys_getfh(fpath, fhp, &fhsize) == -1) + atf_tc_fail_errno("getfh"); + + /* open file based on file handle */ + fd = rump_sys_fhopen(fhp, fhsize, O_RDONLY); + if (fd == -1) { + atf_tc_fail_errno("fhopen"); + } + + /* check that we got the same file */ + if (rump_sys_read(fd, buf, sizeof(buf)) != sizeof(MAGICSTR)) + atf_tc_fail("read fhopened file"); + + ATF_REQUIRE_STREQ(buf, MAGICSTR); + + rump_sys_close(fd); +} + +#define FNAME "a_file" +static void +tfhremove(const atf_tc_t *tc, const char *path) +{ + size_t fhsize; + void *fhp; + int fd; + + RL(rump_sys_chdir(path)); + RL(fd = rump_sys_open(FNAME, O_RDWR | O_CREAT, 0777)); + RL(rump_sys_close(fd)); + + fhsize = 0; + if (rump_sys_getfh(FNAME, NULL, &fhsize) == -1) { + if (errno == EOPNOTSUPP) { + atf_tc_skip("file handles not supported"); + } else if (errno != E2BIG) { + atf_tc_fail_errno("getfh size"); + } + } + + fhp = malloc(fhsize); + RL(rump_sys_getfh(FNAME, fhp, &fhsize)); + RL(rump_sys_unlink(FNAME)); + + if (FSTYPE_LFS(tc)) + atf_tc_expect_fail("fhopen() for removed file succeeds " + "(PR kern/43745)"); + ATF_REQUIRE_ERRNO(ESTALE, rump_sys_fhopen(fhp, fhsize, O_RDONLY) == -1); + atf_tc_expect_pass(); + + RL(rump_sys_chdir("/")); +} +#undef FNAME + +/* + * This test only checks the file system doesn't crash. We *might* + * try a valid file handle. + */ +static void +tfhinval(const atf_tc_t *tc, const char *path) +{ + size_t fhsize; + void *fhp; + unsigned long seed; + int fd; + + srandom(seed = time(NULL)); + printf("RNG seed %lu\n", seed); + + RL(rump_sys_chdir(path)); + fhsize = 0; + if (rump_sys_getfh(".", NULL, &fhsize) == -1) { + if (errno == EOPNOTSUPP) { + atf_tc_skip("file handles not supported"); + } else if (errno != E2BIG) { + atf_tc_fail_errno("getfh size"); + } + } + + fhp = malloc(fhsize); + tests_makegarbage(fhp, fhsize); + fd = rump_sys_fhopen(fhp, fhsize, O_RDWR); + if (fd != -1) + rump_sys_close(fd); + + RL(rump_sys_chdir("/")); +} + +ATF_TC_FSAPPLY(tmount, "mount/unmount"); +ATF_TC_FSAPPLY(tstatvfs, "statvfs"); +ATF_TC_FSAPPLY(tsync, "sync"); +ATF_TC_FSAPPLY(tfilehandle, "file handles"); +ATF_TC_FSAPPLY(tfhremove, "fhtovp for removed file"); +ATF_TC_FSAPPLY(tfhinval, "fhopen invalid filehandle"); + +ATF_TP_ADD_TCS(tp) +{ + + ATF_TP_FSAPPLY(tmount); + ATF_TP_FSAPPLY(tstatvfs); + ATF_TP_FSAPPLY(tsync); + ATF_TP_FSAPPLY(tfilehandle); + ATF_TP_FSAPPLY(tfhremove); + ATF_TP_FSAPPLY(tfhinval); + + return atf_no_error(); +} diff --git a/contrib/netbsd-tests/fs/vfs/t_vnops.c b/contrib/netbsd-tests/fs/vfs/t_vnops.c new file mode 100644 index 000000000000..7da53c8d4386 --- /dev/null +++ b/contrib/netbsd-tests/fs/vfs/t_vnops.c @@ -0,0 +1,1080 @@ +/* $NetBSD: t_vnops.c,v 1.59 2017/01/13 21:30:40 christos Exp $ */ + +/*- + * Copyright (c) 2010 The NetBSD Foundation, Inc. + * All rights reserved. + * + * 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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. + */ + +#include <sys/stat.h> +#include <sys/statvfs.h> +#include <sys/time.h> + +#include <assert.h> +#include <atf-c.h> +#include <ctype.h> +#include <fcntl.h> +#include <libgen.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +#include <rump/rump_syscalls.h> +#include <rump/rump.h> + +#include "../common/h_fsmacros.h" +#include "h_macros.h" + +#define TESTFILE "afile" + +#define USES_DIRS \ + if (FSTYPE_SYSVBFS(tc)) \ + atf_tc_skip("directories not supported by file system") + +#define USES_SYMLINKS \ + if (FSTYPE_SYSVBFS(tc) || FSTYPE_MSDOS(tc)) \ + atf_tc_skip("symlinks not supported by file system") + +static char * +md(char *buf, size_t buflen, const char *base, const char *tail) +{ + + snprintf(buf, buflen, "%s/%s", base, tail); + return buf; +} + +static void +lookup_simple(const atf_tc_t *tc, const char *mountpath) +{ + char pb[MAXPATHLEN], final[MAXPATHLEN]; + struct stat sb1, sb2; + + strcpy(final, mountpath); + snprintf(pb, sizeof(pb), "%s/../%s", mountpath, basename(final)); + if (rump_sys_stat(pb, &sb1) == -1) + atf_tc_fail_errno("stat 1"); + + snprintf(pb, sizeof(pb), "%s/./../%s", mountpath, basename(final)); + if (rump_sys_stat(pb, &sb2) == -1) + atf_tc_fail_errno("stat 2"); + + ATF_REQUIRE(memcmp(&sb1, &sb2, sizeof(sb1)) == 0); +} + +static void +lookup_complex(const atf_tc_t *tc, const char *mountpath) +{ + char pb[MAXPATHLEN]; + struct stat sb1, sb2; + struct timespec atplus1, onesec; + + USES_DIRS; + + snprintf(pb, sizeof(pb), "%s/dir", mountpath); + if (rump_sys_mkdir(pb, 0777) == -1) + atf_tc_fail_errno("mkdir"); + if (rump_sys_stat(pb, &sb1) == -1) + atf_tc_fail_errno("stat 1"); + + snprintf(pb, sizeof(pb), "%s/./dir/../././dir/.", mountpath); + if (rump_sys_stat(pb, &sb2) == -1) + atf_tc_fail_errno("stat 2"); + + /* + * The lookup is permitted to modify the access time of + * any directories searched - such a directory is the + * subject of this test. Any difference should cause + * the 2nd lookup atime tp be >= the first, if it is ==, all is + * OK (atime is not required to be modified by the search, or + * both references may happen within the came clock tick), if the + * 2nd lookup atime is > the first, but not "too much" greater, + * just set it back, so the memcmp just below succeeds + * (assuming all else is OK). + */ + onesec.tv_sec = 1; + onesec.tv_nsec = 0; + timespecadd(&sb1.st_atimespec, &onesec, &atplus1); + if (timespeccmp(&sb2.st_atimespec, &sb1.st_atimespec, >) && + timespeccmp(&sb2.st_atimespec, &atplus1, <)) + sb2.st_atimespec = sb1.st_atimespec; + + if (memcmp(&sb1, &sb2, sizeof(sb1)) != 0) { + printf("what\tsb1\t\tsb2\n"); + +#define FIELD(FN) \ + printf(#FN "\t%lld\t%lld\n", \ + (long long)sb1.FN, (long long)sb2.FN) +#define TIME(FN) \ + printf(#FN "\t%lld.%ld\t%lld.%ld\n", \ + (long long)sb1.FN.tv_sec, sb1.FN.tv_nsec, \ + (long long)sb2.FN.tv_sec, sb2.FN.tv_nsec) + + FIELD(st_dev); + FIELD(st_mode); + FIELD(st_ino); + FIELD(st_nlink); + FIELD(st_uid); + FIELD(st_gid); + FIELD(st_rdev); + TIME(st_atimespec); + TIME(st_mtimespec); + TIME(st_ctimespec); + TIME(st_birthtimespec); + FIELD(st_size); + FIELD(st_blocks); + FIELD(st_flags); + FIELD(st_gen); + +#undef FIELD +#undef TIME + + atf_tc_fail("stat results differ, see ouput for more details"); + } +} + +static void +dir_simple(const atf_tc_t *tc, const char *mountpath) +{ + char pb[MAXPATHLEN]; + struct stat sb; + + USES_DIRS; + + /* check we can create directories */ + snprintf(pb, sizeof(pb), "%s/dir", mountpath); + if (rump_sys_mkdir(pb, 0777) == -1) + atf_tc_fail_errno("mkdir"); + if (rump_sys_stat(pb, &sb) == -1) + atf_tc_fail_errno("stat new directory"); + + /* check we can remove then and that it makes them unreachable */ + if (rump_sys_rmdir(pb) == -1) + atf_tc_fail_errno("rmdir"); + if (rump_sys_stat(pb, &sb) != -1 || errno != ENOENT) + atf_tc_fail("ENOENT expected from stat"); +} + +static void +dir_notempty(const atf_tc_t *tc, const char *mountpath) +{ + char pb[MAXPATHLEN], pb2[MAXPATHLEN]; + int fd, rv; + + USES_DIRS; + + /* check we can create directories */ + snprintf(pb, sizeof(pb), "%s/dir", mountpath); + if (rump_sys_mkdir(pb, 0777) == -1) + atf_tc_fail_errno("mkdir"); + + snprintf(pb2, sizeof(pb2), "%s/dir/file", mountpath); + fd = rump_sys_open(pb2, O_RDWR | O_CREAT, 0777); + if (fd == -1) + atf_tc_fail_errno("create file"); + rump_sys_close(fd); + + rv = rump_sys_rmdir(pb); + if (rv != -1 || errno != ENOTEMPTY) + atf_tc_fail("non-empty directory removed succesfully"); + + if (rump_sys_unlink(pb2) == -1) + atf_tc_fail_errno("cannot remove dir/file"); + + if (rump_sys_rmdir(pb) == -1) + atf_tc_fail_errno("remove directory"); +} + +static void +dir_rmdirdotdot(const atf_tc_t *tc, const char *mp) +{ + char pb[MAXPATHLEN]; + int xerrno; + + USES_DIRS; + + FSTEST_ENTER(); + RL(rump_sys_mkdir("test", 0777)); + RL(rump_sys_chdir("test")); + + RL(rump_sys_mkdir("subtest", 0777)); + RL(rump_sys_chdir("subtest")); + + md(pb, sizeof(pb), mp, "test/subtest"); + RL(rump_sys_rmdir(pb)); + md(pb, sizeof(pb), mp, "test"); + RL(rump_sys_rmdir(pb)); + + if (FSTYPE_NFS(tc)) + xerrno = ESTALE; + else + xerrno = ENOENT; + ATF_REQUIRE_ERRNO(xerrno, rump_sys_chdir("..") == -1); + FSTEST_EXIT(); +} + +static void +checkfile(const char *path, struct stat *refp) +{ + char buf[MAXPATHLEN]; + struct stat sb; + static int n = 1; + + md(buf, sizeof(buf), path, "file"); + if (rump_sys_stat(buf, &sb) == -1) + atf_tc_fail_errno("cannot stat file %d (%s)", n, buf); + if (memcmp(&sb, refp, sizeof(sb)) != 0) + atf_tc_fail("stat mismatch %d", n); + n++; +} + +static void +rename_dir(const atf_tc_t *tc, const char *mp) +{ + char pb1[MAXPATHLEN], pb2[MAXPATHLEN], pb3[MAXPATHLEN]; + struct stat ref, sb; + + if (FSTYPE_RUMPFS(tc)) + atf_tc_skip("rename not supported by file system"); + + USES_DIRS; + + md(pb1, sizeof(pb1), mp, "dir1"); + if (rump_sys_mkdir(pb1, 0777) == -1) + atf_tc_fail_errno("mkdir 1"); + + md(pb2, sizeof(pb2), mp, "dir2"); + if (rump_sys_mkdir(pb2, 0777) == -1) + atf_tc_fail_errno("mkdir 2"); + md(pb2, sizeof(pb2), mp, "dir2/subdir"); + if (rump_sys_mkdir(pb2, 0777) == -1) + atf_tc_fail_errno("mkdir 3"); + + md(pb3, sizeof(pb3), mp, "dir1/file"); + if (rump_sys_mknod(pb3, S_IFREG | 0777, -1) == -1) + atf_tc_fail_errno("create file"); + if (rump_sys_stat(pb3, &ref) == -1) + atf_tc_fail_errno("stat of file"); + + /* + * First try ops which should succeed. + */ + + /* rename within directory */ + md(pb3, sizeof(pb3), mp, "dir3"); + if (rump_sys_rename(pb1, pb3) == -1) + atf_tc_fail_errno("rename 1"); + checkfile(pb3, &ref); + + /* rename directory onto itself (two ways, should fail) */ + md(pb1, sizeof(pb1), mp, "dir3/."); + if (rump_sys_rename(pb1, pb3) != -1 || errno != EINVAL) + atf_tc_fail_errno("rename 2"); + if (rump_sys_rename(pb3, pb1) != -1 || errno != EISDIR) + atf_tc_fail_errno("rename 3"); + + checkfile(pb3, &ref); + + /* rename father of directory into directory */ + md(pb1, sizeof(pb1), mp, "dir2/dir"); + md(pb2, sizeof(pb2), mp, "dir2"); + if (rump_sys_rename(pb2, pb1) != -1 || errno != EINVAL) + atf_tc_fail_errno("rename 4"); + + /* same for grandfather */ + md(pb1, sizeof(pb1), mp, "dir2/subdir/dir2"); + if (rump_sys_rename(pb2, pb1) != -1 || errno != EINVAL) + atf_tc_fail("rename 5"); + + checkfile(pb3, &ref); + + /* rename directory over a non-empty directory */ + if (rump_sys_rename(pb2, pb3) != -1 || errno != ENOTEMPTY) + atf_tc_fail("rename 6"); + + /* cross-directory rename */ + md(pb1, sizeof(pb1), mp, "dir3"); + md(pb2, sizeof(pb2), mp, "dir2/somedir"); + if (rump_sys_rename(pb1, pb2) == -1) + atf_tc_fail_errno("rename 7"); + checkfile(pb2, &ref); + + /* move to parent directory */ + md(pb1, sizeof(pb1), mp, "dir2/somedir/../../dir3"); + if (rump_sys_rename(pb2, pb1) == -1) + atf_tc_fail_errno("rename 8"); + md(pb1, sizeof(pb1), mp, "dir2/../dir3"); + checkfile(pb1, &ref); + + /* atomic cross-directory rename */ + md(pb3, sizeof(pb3), mp, "dir2/subdir"); + if (rump_sys_rename(pb1, pb3) == -1) + atf_tc_fail_errno("rename 9"); + checkfile(pb3, &ref); + + /* rename directory over an empty directory */ + md(pb1, sizeof(pb1), mp, "parent"); + md(pb2, sizeof(pb2), mp, "parent/dir1"); + md(pb3, sizeof(pb3), mp, "parent/dir2"); + RL(rump_sys_mkdir(pb1, 0777)); + RL(rump_sys_mkdir(pb2, 0777)); + RL(rump_sys_mkdir(pb3, 0777)); + RL(rump_sys_rename(pb2, pb3)); + + RL(rump_sys_stat(pb1, &sb)); + if (! FSTYPE_MSDOS(tc)) + ATF_CHECK_EQ(sb.st_nlink, 3); + RL(rump_sys_rmdir(pb3)); + RL(rump_sys_rmdir(pb1)); +} + +static void +rename_dotdot(const atf_tc_t *tc, const char *mp) +{ + + if (FSTYPE_RUMPFS(tc)) + atf_tc_skip("rename not supported by file system"); + + USES_DIRS; + + if (rump_sys_chdir(mp) == -1) + atf_tc_fail_errno("chdir mountpoint"); + + if (rump_sys_mkdir("dir1", 0777) == -1) + atf_tc_fail_errno("mkdir 1"); + if (rump_sys_mkdir("dir2", 0777) == -1) + atf_tc_fail_errno("mkdir 2"); + + if (rump_sys_rename("dir1", "dir1/..") != -1 || errno != EINVAL) + atf_tc_fail_errno("self-dotdot to"); + + if (rump_sys_rename("dir1/..", "sometarget") != -1 || errno != EINVAL) + atf_tc_fail_errno("self-dotdot from"); + + if (rump_sys_rename("dir1", "dir2/..") != -1 || errno != EINVAL) + atf_tc_fail("other-dotdot"); + + rump_sys_chdir("/"); +} + +static void +rename_reg_nodir(const atf_tc_t *tc, const char *mp) +{ + bool haslinks; + struct stat sb; + ino_t f1ino; + + if (FSTYPE_RUMPFS(tc)) + atf_tc_skip("rename not supported by file system"); + + if (rump_sys_chdir(mp) == -1) + atf_tc_fail_errno("chdir mountpoint"); + + if (FSTYPE_MSDOS(tc) || FSTYPE_SYSVBFS(tc)) + haslinks = false; + else + haslinks = true; + + if (rump_sys_mknod("file1", S_IFREG | 0777, -1) == -1) + atf_tc_fail_errno("create file"); + if (rump_sys_mknod("file2", S_IFREG | 0777, -1) == -1) + atf_tc_fail_errno("create file"); + + if (rump_sys_stat("file1", &sb) == -1) + atf_tc_fail_errno("stat"); + f1ino = sb.st_ino; + + if (haslinks) { + if (rump_sys_link("file1", "file_link") == -1) + atf_tc_fail_errno("link"); + if (rump_sys_stat("file_link", &sb) == -1) + atf_tc_fail_errno("stat"); + ATF_REQUIRE_EQ(sb.st_ino, f1ino); + ATF_REQUIRE_EQ(sb.st_nlink, 2); + } + + if (rump_sys_stat("file2", &sb) == -1) + atf_tc_fail_errno("stat"); + + if (rump_sys_rename("file1", "file3") == -1) + atf_tc_fail_errno("rename 1"); + if (rump_sys_stat("file3", &sb) == -1) + atf_tc_fail_errno("stat 1"); + if (haslinks) { + ATF_REQUIRE_EQ(sb.st_ino, f1ino); + } + if (rump_sys_stat("file1", &sb) != -1 || errno != ENOENT) + atf_tc_fail_errno("source 1"); + + if (rump_sys_rename("file3", "file2") == -1) + atf_tc_fail_errno("rename 2"); + if (rump_sys_stat("file2", &sb) == -1) + atf_tc_fail_errno("stat 2"); + if (haslinks) { + ATF_REQUIRE_EQ(sb.st_ino, f1ino); + } + + if (rump_sys_stat("file3", &sb) != -1 || errno != ENOENT) + atf_tc_fail_errno("source 2"); + + if (haslinks) { + if (rump_sys_rename("file2", "file_link") == -1) + atf_tc_fail_errno("rename hardlink"); + if (rump_sys_stat("file2", &sb) != -1 || errno != ENOENT) + atf_tc_fail_errno("source 3"); + if (rump_sys_stat("file_link", &sb) == -1) + atf_tc_fail_errno("stat 2"); + ATF_REQUIRE_EQ(sb.st_ino, f1ino); + ATF_REQUIRE_EQ(sb.st_nlink, 1); + } + + ATF_CHECK_ERRNO(EFAULT, rump_sys_rename("file2", NULL) == -1); + ATF_CHECK_ERRNO(EFAULT, rump_sys_rename(NULL, "file2") == -1); + + rump_sys_chdir("/"); +} + +/* PR kern/50607 */ +static void +create_many(const atf_tc_t *tc, const char *mp) +{ + char buf[64]; + int nfiles = 2324; /* #Nancy */ + int i; + + /* takes forever with many files */ + if (FSTYPE_MSDOS(tc)) + nfiles /= 4; + + RL(rump_sys_chdir(mp)); + + if (FSTYPE_SYSVBFS(tc)) { + /* fs doesn't support many files or subdirectories */ + nfiles = 5; + } else { + /* msdosfs doesn't like many entries in the root directory */ + RL(rump_sys_mkdir("subdir", 0777)); + RL(rump_sys_chdir("subdir")); + } + + /* create them */ +#define TESTFN "testfile" + for (i = 0; i < nfiles; i++) { + int fd; + + snprintf(buf, sizeof(buf), TESTFN "%d", i); + RL(fd = rump_sys_open(buf, O_RDWR|O_CREAT|O_EXCL, 0666)); + RL(rump_sys_close(fd)); + } + + /* wipe them out */ + for (i = 0; i < nfiles; i++) { + snprintf(buf, sizeof(buf), TESTFN "%d", i); + RLF(rump_sys_unlink(buf), "%s", buf); + } +#undef TESTFN + + rump_sys_chdir("/"); +} + +/* + * Test creating files with one-character names using all possible + * character values. Failures to create the file are ignored as the + * characters allowed in file names vary by file system, but at least + * we can check that the fs does not crash, and if the file is + * successfully created, unlinking it should also succeed. + */ +static void +create_nonalphanum(const atf_tc_t *tc, const char *mp) +{ + char buf[64]; + int i; + + RL(rump_sys_chdir(mp)); + + for (i = 0; i < 256; i++) { + int fd; + snprintf(buf, sizeof(buf), "%c", i); + fd = rump_sys_open(buf, O_RDWR|O_CREAT|O_EXCL, 0666); + if (fd == -1) + continue; + RLF(rump_sys_close(fd), "%d", fd); + RLF(rump_sys_unlink(buf), "%s", buf); + } + printf("\n"); + + rump_sys_chdir("/"); +} + +static void +create_nametoolong(const atf_tc_t *tc, const char *mp) +{ + char *name; + int fd; + long val; + size_t len; + + if (rump_sys_chdir(mp) == -1) + atf_tc_fail_errno("chdir mountpoint"); + + val = rump_sys_pathconf(".", _PC_NAME_MAX); + if (val == -1) + atf_tc_fail_errno("pathconf"); + + len = val + 1; + name = malloc(len+1); + if (name == NULL) + atf_tc_fail_errno("malloc"); + + memset(name, 'a', len); + *(name+len) = '\0'; + + val = rump_sys_pathconf(".", _PC_NO_TRUNC); + if (val == -1) + atf_tc_fail_errno("pathconf"); + + fd = rump_sys_open(name, O_RDWR|O_CREAT, 0666); + if (val != 0 && (fd != -1 || errno != ENAMETOOLONG)) + atf_tc_fail_errno("open"); + + if (val == 0 && rump_sys_close(fd) == -1) + atf_tc_fail_errno("close"); + if (val == 0 && rump_sys_unlink(name) == -1) + atf_tc_fail_errno("unlink"); + + free(name); + + rump_sys_chdir("/"); +} + +static void +create_exist(const atf_tc_t *tc, const char *mp) +{ + const char *name = "hoge"; + int fd; + + RL(rump_sys_chdir(mp)); + RL(fd = rump_sys_open(name, O_RDWR|O_CREAT|O_EXCL, 0666)); + RL(rump_sys_close(fd)); + RL(rump_sys_unlink(name)); + RL(fd = rump_sys_open(name, O_RDWR|O_CREAT, 0666)); + RL(rump_sys_close(fd)); + RL(fd = rump_sys_open(name, O_RDWR|O_CREAT, 0666)); + RL(rump_sys_close(fd)); + ATF_REQUIRE_ERRNO(EEXIST, + (fd = rump_sys_open(name, O_RDWR|O_CREAT|O_EXCL, 0666))); + RL(rump_sys_unlink(name)); + RL(rump_sys_chdir("/")); +} + +static void +rename_nametoolong(const atf_tc_t *tc, const char *mp) +{ + char *name; + int res, fd; + long val; + size_t len; + + if (FSTYPE_RUMPFS(tc)) + atf_tc_skip("rename not supported by file system"); + + if (rump_sys_chdir(mp) == -1) + atf_tc_fail_errno("chdir mountpoint"); + + val = rump_sys_pathconf(".", _PC_NAME_MAX); + if (val == -1) + atf_tc_fail_errno("pathconf"); + + len = val + 1; + name = malloc(len+1); + if (name == NULL) + atf_tc_fail_errno("malloc"); + + memset(name, 'a', len); + *(name+len) = '\0'; + + fd = rump_sys_open("dummy", O_RDWR|O_CREAT, 0666); + if (fd == -1) + atf_tc_fail_errno("open"); + if (rump_sys_close(fd) == -1) + atf_tc_fail_errno("close"); + + val = rump_sys_pathconf(".", _PC_NO_TRUNC); + if (val == -1) + atf_tc_fail_errno("pathconf"); + + res = rump_sys_rename("dummy", name); + if (val != 0 && (res != -1 || errno != ENAMETOOLONG)) + atf_tc_fail_errno("rename"); + + if (val == 0 && rump_sys_unlink(name) == -1) + atf_tc_fail_errno("unlink"); + + free(name); + + rump_sys_chdir("/"); +} + +/* + * Test creating a symlink whose length is "len" bytes, not including + * the terminating NUL. + */ +static void +symlink_len(const atf_tc_t *tc, const char *mp, size_t len) +{ + char *buf; + int r; + + USES_SYMLINKS; + + RLF(rump_sys_chdir(mp), "%s", mp); + + buf = malloc(len + 1); + ATF_REQUIRE(buf); + memset(buf, 'a', len); + buf[len] = '\0'; + r = rump_sys_symlink(buf, "afile"); + if (r == -1) { + ATF_REQUIRE_ERRNO(ENAMETOOLONG, r); + } else { + RL(rump_sys_unlink("afile")); + } + free(buf); + + RL(rump_sys_chdir("/")); +} + +static void +symlink_zerolen(const atf_tc_t *tc, const char *mp) +{ + symlink_len(tc, mp, 0); +} + +static void +symlink_long(const atf_tc_t *tc, const char *mp) +{ + /* + * Test lengths close to powers of two, as those are likely + * to be edge cases. + */ + size_t len; + int fuzz; + for (len = 2; len <= 65536; len *= 2) { + for (fuzz = -1; fuzz <= 1; fuzz++) { + symlink_len(tc, mp, len + fuzz); + } + } +} + +static void +symlink_root(const atf_tc_t *tc, const char *mp) +{ + + USES_SYMLINKS; + + RL(rump_sys_chdir(mp)); + RL(rump_sys_symlink("/", "foo")); + RL(rump_sys_chdir("foo")); +} + +static void +attrs(const atf_tc_t *tc, const char *mp) +{ + struct stat sb, sb2; + struct timeval tv[2]; + int fd; + + FSTEST_ENTER(); + RL(fd = rump_sys_open(TESTFILE, O_RDWR | O_CREAT, 0755)); + RL(rump_sys_close(fd)); + RL(rump_sys_stat(TESTFILE, &sb)); + if (!(FSTYPE_MSDOS(tc) || FSTYPE_SYSVBFS(tc))) { + RL(rump_sys_chown(TESTFILE, 1, 2)); + sb.st_uid = 1; + sb.st_gid = 2; + RL(rump_sys_chmod(TESTFILE, 0123)); + sb.st_mode = (sb.st_mode & ~ACCESSPERMS) | 0123; + } + + tv[0].tv_sec = 1000000000; /* need something >1980 for msdosfs */ + tv[0].tv_usec = 1; + tv[1].tv_sec = 1000000002; /* need even seconds for msdosfs */ + tv[1].tv_usec = 3; + RL(rump_sys_utimes(TESTFILE, tv)); + RL(rump_sys_utimes(TESTFILE, tv)); /* XXX: utimes & birthtime */ + sb.st_atimespec.tv_sec = 1000000000; + sb.st_atimespec.tv_nsec = 1000; + sb.st_mtimespec.tv_sec = 1000000002; + sb.st_mtimespec.tv_nsec = 3000; + + RL(rump_sys_stat(TESTFILE, &sb2)); +#define CHECK(a) ATF_REQUIRE_EQ(sb.a, sb2.a) + if (!(FSTYPE_MSDOS(tc) || FSTYPE_SYSVBFS(tc))) { + CHECK(st_uid); + CHECK(st_gid); + CHECK(st_mode); + } + if (!FSTYPE_MSDOS(tc)) { + /* msdosfs has only access date, not time */ + CHECK(st_atimespec.tv_sec); + } + CHECK(st_mtimespec.tv_sec); + if (!(FSTYPE_EXT2FS(tc) || FSTYPE_MSDOS(tc) || + FSTYPE_SYSVBFS(tc) || FSTYPE_V7FS(tc))) { + CHECK(st_atimespec.tv_nsec); + CHECK(st_mtimespec.tv_nsec); + } +#undef CHECK + + FSTEST_EXIT(); +} + +static void +fcntl_lock(const atf_tc_t *tc, const char *mp) +{ + int fd, fd2; + struct flock l; + struct lwp *lwp1, *lwp2; + + FSTEST_ENTER(); + l.l_pid = 0; + l.l_start = l.l_len = 1024; + l.l_type = F_RDLCK | F_WRLCK; + l.l_whence = SEEK_END; + + lwp1 = rump_pub_lwproc_curlwp(); + RL(fd = rump_sys_open(TESTFILE, O_RDWR | O_CREAT, 0755)); + RL(rump_sys_ftruncate(fd, 8192)); + + RL(rump_sys_fcntl(fd, F_SETLK, &l)); + + /* Next, we fork and try to lock the same area */ + RZ(rump_pub_lwproc_rfork(RUMP_RFCFDG)); + lwp2 = rump_pub_lwproc_curlwp(); + RL(fd2 = rump_sys_open(TESTFILE, O_RDWR, 0)); + ATF_REQUIRE_ERRNO(EAGAIN, rump_sys_fcntl(fd2, F_SETLK, &l)); + + /* Switch back and unlock... */ + rump_pub_lwproc_switch(lwp1); + l.l_type = F_UNLCK; + RL(rump_sys_fcntl(fd, F_SETLK, &l)); + + /* ... and try to lock again */ + rump_pub_lwproc_switch(lwp2); + l.l_type = F_RDLCK | F_WRLCK; + RL(rump_sys_fcntl(fd2, F_SETLK, &l)); + + RL(rump_sys_close(fd2)); + rump_pub_lwproc_releaselwp(); + + RL(rump_sys_close(fd)); + + FSTEST_EXIT(); +} + +static int +flock_compare(const void *p, const void *q) +{ + int a = ((const struct flock *)p)->l_start; + int b = ((const struct flock *)q)->l_start; + return a < b ? -1 : (a > b ? 1 : 0); +} + +/* + * Find all locks set by fcntl_getlock_pids test + * using GETLK for a range [start, start+end], and, + * if there is a blocking lock, recursively find + * all locks to the left (toward the beginning of + * a file) and to the right of the lock. + * The function also understands "until end of file" + * convention when len==0. + */ +static unsigned int +fcntl_getlocks(int fildes, off_t start, off_t len, + struct flock *lock, struct flock *end) +{ + unsigned int rv = 0; + const struct flock l = { start, len, 0, F_RDLCK, SEEK_SET }; + + if (lock == end) + return rv; + + RL(rump_sys_fcntl(fildes, F_GETLK, &l)); + + if (l.l_type == F_UNLCK) + return rv; + + *lock++ = l; + rv += 1; + + ATF_REQUIRE(l.l_whence == SEEK_SET); + + if (l.l_start > start) { + unsigned int n = + fcntl_getlocks(fildes, start, l.l_start - start, lock, end); + rv += n; + lock += n; + if (lock == end) + return rv; + } + + if (l.l_len == 0) /* does l spans until the end? */ + return rv; + + if (len == 0) /* are we looking for locks until the end? */ { + rv += fcntl_getlocks(fildes, l.l_start + l.l_len, len, lock, end); + } else if (l.l_start + l.l_len < start + len) { + len -= l.l_start + l.l_len - start; + rv += fcntl_getlocks(fildes, l.l_start + l.l_len, len, lock, end); + } + + return rv; +} + +static void +fcntl_getlock_pids(const atf_tc_t *tc, const char *mp) +{ + /* test non-overlaping ranges */ + struct flock expect[4]; + const struct flock lock[4] = { + { 0, 2, 0, F_WRLCK, SEEK_SET }, + { 2, 1, 0, F_WRLCK, SEEK_SET }, + { 7, 5, 0, F_WRLCK, SEEK_SET }, + { 4, 3, 0, F_WRLCK, SEEK_SET }, + }; + + /* Add extra element to make sure recursion does't stop at array end */ + struct flock result[5]; + + /* Add 5th process */ + int fd[5]; + pid_t pid[5]; + struct lwp *lwp[5]; + + unsigned int i, j; + const off_t sz = 8192; + int omode = 0755; + int oflags = O_RDWR | O_CREAT; + + memcpy(expect, lock, sizeof(lock)); + + FSTEST_ENTER(); + + /* + * First, we create 4 processes and let each lock a range of the + * file. Note that the third and fourth processes lock in + * "reverse" order, i.e. the greater pid locks a range before + * the lesser pid. + * Then, we create 5th process which doesn't lock anything. + */ + for (i = 0; i < __arraycount(lwp); i++) { + RZ(rump_pub_lwproc_rfork(RUMP_RFCFDG)); + + lwp[i] = rump_pub_lwproc_curlwp(); + pid[i] = rump_sys_getpid(); + + RL(fd[i] = rump_sys_open(TESTFILE, oflags, omode)); + oflags = O_RDWR; + omode = 0; + + RL(rump_sys_ftruncate(fd[i], sz)); + + if (i < __arraycount(lock)) { + RL(rump_sys_fcntl(fd[i], F_SETLK, &lock[i])); + expect[i].l_pid = pid[i]; + } + } + + qsort(expect, __arraycount(expect), sizeof(expect[0]), &flock_compare); + + /* + * In the context of each process, recursively find all locks + * that would block the current process. Processes 1-4 don't + * see their own lock, we insert it to simplify checks. + * Process 5 sees all 4 locks. + */ + for (i = 0; i < __arraycount(lwp); i++) { + unsigned int nlocks; + + rump_pub_lwproc_switch(lwp[i]); + + memset(result, 0, sizeof(result)); + nlocks = fcntl_getlocks(fd[i], 0, sz, + result, result + __arraycount(result)); + + if (i < __arraycount(lock)) { + ATF_REQUIRE(nlocks < __arraycount(result)); + result[nlocks] = lock[i]; + result[nlocks].l_pid = pid[i]; + nlocks++; + } + + ATF_CHECK_EQ(nlocks, __arraycount(expect)); + + qsort(result, nlocks, sizeof(result[0]), &flock_compare); + + for (j = 0; j < nlocks; j++) { + ATF_CHECK_EQ(result[j].l_start, expect[j].l_start ); + ATF_CHECK_EQ(result[j].l_len, expect[j].l_len ); + ATF_CHECK_EQ(result[j].l_pid, expect[j].l_pid ); + ATF_CHECK_EQ(result[j].l_type, expect[j].l_type ); + ATF_CHECK_EQ(result[j].l_whence, expect[j].l_whence); + } + } + + /* + * Release processes. This also releases the fds and locks + * making fs unmount possible + */ + for (i = 0; i < __arraycount(lwp); i++) { + rump_pub_lwproc_switch(lwp[i]); + rump_pub_lwproc_releaselwp(); + } + + FSTEST_EXIT(); +} + +static void +access_simple(const atf_tc_t *tc, const char *mp) +{ + int fd; + int tmode; + + FSTEST_ENTER(); + RL(fd = rump_sys_open("tfile", O_CREAT | O_RDWR, 0777)); + RL(rump_sys_close(fd)); + +#define ALLACC (F_OK | X_OK | W_OK | R_OK) + if (FSTYPE_SYSVBFS(tc) || FSTYPE_MSDOS(tc)) + tmode = F_OK; + else + tmode = ALLACC; + + RL(rump_sys_access("tfile", tmode)); + + /* PR kern/44648 */ + ATF_REQUIRE_ERRNO(EINVAL, rump_sys_access("tfile", ALLACC+1) == -1); +#undef ALLACC + FSTEST_EXIT(); +} + +static void +read_directory(const atf_tc_t *tc, const char *mp) +{ + char buf[1024]; + int fd, res; + ssize_t size; + + FSTEST_ENTER(); + fd = rump_sys_open(".", O_DIRECTORY | O_RDONLY, 0777); + ATF_REQUIRE(fd != -1); + + size = rump_sys_pread(fd, buf, sizeof(buf), 0); + ATF_CHECK(size != -1 || errno == EISDIR); + size = rump_sys_read(fd, buf, sizeof(buf)); + ATF_CHECK(size != -1 || errno == EISDIR); + + res = rump_sys_close(fd); + ATF_REQUIRE(res != -1); + FSTEST_EXIT(); +} + +static void +lstat_symlink(const atf_tc_t *tc, const char *mp) +{ + const char *src, *dst; + int res; + struct stat st; + + USES_SYMLINKS; + + FSTEST_ENTER(); + + src = "source"; + dst = "destination"; + + res = rump_sys_symlink(src, dst); + ATF_REQUIRE(res != -1); + res = rump_sys_lstat(dst, &st); + ATF_REQUIRE(res != -1); + + ATF_CHECK(S_ISLNK(st.st_mode) != 0); + ATF_CHECK(st.st_size == (off_t)strlen(src)); + + FSTEST_EXIT(); +} + +ATF_TC_FSAPPLY(lookup_simple, "simple lookup (./.. on root)"); +ATF_TC_FSAPPLY(lookup_complex, "lookup of non-dot entries"); +ATF_TC_FSAPPLY(dir_simple, "mkdir/rmdir"); +ATF_TC_FSAPPLY(dir_notempty, "non-empty directories cannot be removed"); +ATF_TC_FSAPPLY(dir_rmdirdotdot, "remove .. and try to cd out (PR kern/44657)"); +ATF_TC_FSAPPLY(rename_dir, "exercise various directory renaming ops " +"(PR kern/44288)"); +ATF_TC_FSAPPLY(rename_dotdot, "rename dir .. (PR kern/43617)"); +ATF_TC_FSAPPLY(rename_reg_nodir, "rename regular files, no subdirectories"); +ATF_TC_FSAPPLY(create_nametoolong, "create file with name too long"); +ATF_TC_FSAPPLY(create_exist, "create with O_EXCL"); +ATF_TC_FSAPPLY(rename_nametoolong, "rename to file with name too long"); +ATF_TC_FSAPPLY(symlink_zerolen, "symlink with target of length 0"); +ATF_TC_FSAPPLY(symlink_long, "symlink with target of length > 0"); +ATF_TC_FSAPPLY(symlink_root, "symlink to root directory"); +ATF_TC_FSAPPLY(attrs, "check setting attributes works"); +ATF_TC_FSAPPLY(fcntl_lock, "check fcntl F_SETLK"); +ATF_TC_FSAPPLY(fcntl_getlock_pids,"fcntl F_GETLK w/ many procs, PR kern/44494"); +ATF_TC_FSAPPLY(access_simple, "access(2)"); +ATF_TC_FSAPPLY(read_directory, "read(2) on directories"); +ATF_TC_FSAPPLY(lstat_symlink, "lstat(2) values for symbolic links"); + +#undef FSTEST_IMGSIZE +#define FSTEST_IMGSIZE (1024*1024*64) +ATF_TC_FSAPPLY(create_many, "create many directory entries"); +ATF_TC_FSAPPLY(create_nonalphanum, "non-alphanumeric filenames"); + +ATF_TP_ADD_TCS(tp) +{ + + ATF_TP_FSAPPLY(lookup_simple); + ATF_TP_FSAPPLY(lookup_complex); + ATF_TP_FSAPPLY(dir_simple); + ATF_TP_FSAPPLY(dir_notempty); + ATF_TP_FSAPPLY(dir_rmdirdotdot); + ATF_TP_FSAPPLY(rename_dir); + ATF_TP_FSAPPLY(rename_dotdot); + ATF_TP_FSAPPLY(rename_reg_nodir); + ATF_TP_FSAPPLY(create_many); + ATF_TP_FSAPPLY(create_nonalphanum); + ATF_TP_FSAPPLY(create_nametoolong); + ATF_TP_FSAPPLY(create_exist); + ATF_TP_FSAPPLY(rename_nametoolong); + ATF_TP_FSAPPLY(symlink_zerolen); + ATF_TP_FSAPPLY(symlink_long); + ATF_TP_FSAPPLY(symlink_root); + ATF_TP_FSAPPLY(attrs); + ATF_TP_FSAPPLY(fcntl_lock); + ATF_TP_FSAPPLY(fcntl_getlock_pids); + ATF_TP_FSAPPLY(access_simple); + ATF_TP_FSAPPLY(read_directory); + ATF_TP_FSAPPLY(lstat_symlink); + + return atf_no_error(); +} diff --git a/contrib/netbsd-tests/fs/zfs/t_zpool.sh b/contrib/netbsd-tests/fs/zfs/t_zpool.sh new file mode 100755 index 000000000000..e3c2380da343 --- /dev/null +++ b/contrib/netbsd-tests/fs/zfs/t_zpool.sh @@ -0,0 +1,66 @@ +# $NetBSD: t_zpool.sh,v 1.3 2011/12/06 18:18:59 njoly Exp $ +# +# Copyright (c) 2011 The NetBSD Foundation, Inc. +# All rights reserved. +# +# 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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. +# + +server='rump_server -lrumpvfs -lrumpkern_solaris -lrumpfs_zfs -lrumpdev -lrumpdev_rnd -d key=/dk,hostpath=zfs.img,size=100m' + +export RUMP_SERVER=unix://zsuck + +atf_test_case create cleanup +create_head() +{ + atf_set "descr" "basic zpool create" +} + +IFS=' ' +exmount='rumpfs on / type rumpfs (local) +jippo on /jippo type zfs (local) +' + +create_body() +{ + + atf_check -s exit:0 -o ignore -e ignore ${server} ${RUMP_SERVER} + + export LD_PRELOAD=/usr/lib/librumphijack.so + export RUMPHIJACK=blanket=/dev/zfs:/dk:/jippo + atf_check -s exit:0 zpool create jippo /dk + + export RUMPHIJACK=vfs=all + atf_check -s exit:0 -o inline:"${exmount}" mount +} + +create_cleanup() +{ + + rump.halt +} + +atf_init_test_cases() +{ + + atf_add_test_case create +} |