t_vnops.c revision 314817
1/*	$NetBSD: t_vnops.c,v 1.59 2017/01/13 21:30:40 christos Exp $	*/
2
3/*-
4 * Copyright (c) 2010 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 *    notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 *    notice, this list of conditions and the following disclaimer in the
14 *    documentation and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
17 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
18 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
20 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26 * POSSIBILITY OF SUCH DAMAGE.
27 */
28
29#include <sys/stat.h>
30#include <sys/statvfs.h>
31#include <sys/time.h>
32
33#include <assert.h>
34#include <atf-c.h>
35#include <ctype.h>
36#include <fcntl.h>
37#include <libgen.h>
38#include <stdlib.h>
39#include <string.h>
40#include <unistd.h>
41
42#include <rump/rump_syscalls.h>
43#include <rump/rump.h>
44
45#include "../common/h_fsmacros.h"
46#include "h_macros.h"
47
48#define TESTFILE "afile"
49
50#define USES_DIRS					\
51    if (FSTYPE_SYSVBFS(tc))				\
52	atf_tc_skip("directories not supported by file system")
53
54#define USES_SYMLINKS					\
55    if (FSTYPE_SYSVBFS(tc) || FSTYPE_MSDOS(tc))		\
56	atf_tc_skip("symlinks not supported by file system")
57
58static char *
59md(char *buf, size_t buflen, const char *base, const char *tail)
60{
61
62	snprintf(buf, buflen, "%s/%s", base, tail);
63	return buf;
64}
65
66static void
67lookup_simple(const atf_tc_t *tc, const char *mountpath)
68{
69	char pb[MAXPATHLEN], final[MAXPATHLEN];
70	struct stat sb1, sb2;
71
72	strcpy(final, mountpath);
73	snprintf(pb, sizeof(pb), "%s/../%s", mountpath, basename(final));
74	if (rump_sys_stat(pb, &sb1) == -1)
75		atf_tc_fail_errno("stat 1");
76
77	snprintf(pb, sizeof(pb), "%s/./../%s", mountpath, basename(final));
78	if (rump_sys_stat(pb, &sb2) == -1)
79		atf_tc_fail_errno("stat 2");
80
81	ATF_REQUIRE(memcmp(&sb1, &sb2, sizeof(sb1)) == 0);
82}
83
84static void
85lookup_complex(const atf_tc_t *tc, const char *mountpath)
86{
87	char pb[MAXPATHLEN];
88	struct stat sb1, sb2;
89	struct timespec atplus1, onesec;
90
91	USES_DIRS;
92
93	snprintf(pb, sizeof(pb), "%s/dir", mountpath);
94	if (rump_sys_mkdir(pb, 0777) == -1)
95		atf_tc_fail_errno("mkdir");
96	if (rump_sys_stat(pb, &sb1) == -1)
97		atf_tc_fail_errno("stat 1");
98
99	snprintf(pb, sizeof(pb), "%s/./dir/../././dir/.", mountpath);
100	if (rump_sys_stat(pb, &sb2) == -1)
101		atf_tc_fail_errno("stat 2");
102
103	/*
104	 * The lookup is permitted to modify the access time of
105	 * any directories searched - such a directory is the
106	 * subject of this test.   Any difference should cause
107	 * the 2nd lookup atime tp be >= the first, if it is ==, all is
108	 * OK (atime is not required to be modified by the search, or
109	 * both references may happen within the came clock tick), if the
110	 * 2nd lookup atime is > the first, but not "too much" greater,
111	 * just set it back, so the memcmp just below succeeds
112	 * (assuming all else is OK).
113	 */
114	onesec.tv_sec = 1;
115	onesec.tv_nsec = 0;
116	timespecadd(&sb1.st_atimespec, &onesec, &atplus1);
117	if (timespeccmp(&sb2.st_atimespec, &sb1.st_atimespec, >) &&
118	    timespeccmp(&sb2.st_atimespec, &atplus1, <))
119		sb2.st_atimespec = sb1.st_atimespec;
120
121	if (memcmp(&sb1, &sb2, sizeof(sb1)) != 0) {
122		printf("what\tsb1\t\tsb2\n");
123
124#define FIELD(FN)	\
125		printf(#FN "\t%lld\t%lld\n", \
126		(long long)sb1.FN, (long long)sb2.FN)
127#define TIME(FN)	\
128		printf(#FN "\t%lld.%ld\t%lld.%ld\n", \
129		(long long)sb1.FN.tv_sec, sb1.FN.tv_nsec, \
130		(long long)sb2.FN.tv_sec, sb2.FN.tv_nsec)
131
132		FIELD(st_dev);
133		FIELD(st_mode);
134		FIELD(st_ino);
135		FIELD(st_nlink);
136		FIELD(st_uid);
137		FIELD(st_gid);
138		FIELD(st_rdev);
139		TIME(st_atimespec);
140		TIME(st_mtimespec);
141		TIME(st_ctimespec);
142		TIME(st_birthtimespec);
143		FIELD(st_size);
144		FIELD(st_blocks);
145		FIELD(st_flags);
146		FIELD(st_gen);
147
148#undef FIELD
149#undef TIME
150
151		atf_tc_fail("stat results differ, see ouput for more details");
152	}
153}
154
155static void
156dir_simple(const atf_tc_t *tc, const char *mountpath)
157{
158	char pb[MAXPATHLEN];
159	struct stat sb;
160
161	USES_DIRS;
162
163	/* check we can create directories */
164	snprintf(pb, sizeof(pb), "%s/dir", mountpath);
165	if (rump_sys_mkdir(pb, 0777) == -1)
166		atf_tc_fail_errno("mkdir");
167	if (rump_sys_stat(pb, &sb) == -1)
168		atf_tc_fail_errno("stat new directory");
169
170	/* check we can remove then and that it makes them unreachable */
171	if (rump_sys_rmdir(pb) == -1)
172		atf_tc_fail_errno("rmdir");
173	if (rump_sys_stat(pb, &sb) != -1 || errno != ENOENT)
174		atf_tc_fail("ENOENT expected from stat");
175}
176
177static void
178dir_notempty(const atf_tc_t *tc, const char *mountpath)
179{
180	char pb[MAXPATHLEN], pb2[MAXPATHLEN];
181	int fd, rv;
182
183	USES_DIRS;
184
185	/* check we can create directories */
186	snprintf(pb, sizeof(pb), "%s/dir", mountpath);
187	if (rump_sys_mkdir(pb, 0777) == -1)
188		atf_tc_fail_errno("mkdir");
189
190	snprintf(pb2, sizeof(pb2), "%s/dir/file", mountpath);
191	fd = rump_sys_open(pb2, O_RDWR | O_CREAT, 0777);
192	if (fd == -1)
193		atf_tc_fail_errno("create file");
194	rump_sys_close(fd);
195
196	rv = rump_sys_rmdir(pb);
197	if (rv != -1 || errno != ENOTEMPTY)
198		atf_tc_fail("non-empty directory removed succesfully");
199
200	if (rump_sys_unlink(pb2) == -1)
201		atf_tc_fail_errno("cannot remove dir/file");
202
203	if (rump_sys_rmdir(pb) == -1)
204		atf_tc_fail_errno("remove directory");
205}
206
207static void
208dir_rmdirdotdot(const atf_tc_t *tc, const char *mp)
209{
210	char pb[MAXPATHLEN];
211	int xerrno;
212
213	USES_DIRS;
214
215	FSTEST_ENTER();
216	RL(rump_sys_mkdir("test", 0777));
217	RL(rump_sys_chdir("test"));
218
219	RL(rump_sys_mkdir("subtest", 0777));
220	RL(rump_sys_chdir("subtest"));
221
222	md(pb, sizeof(pb), mp, "test/subtest");
223	RL(rump_sys_rmdir(pb));
224	md(pb, sizeof(pb), mp, "test");
225	RL(rump_sys_rmdir(pb));
226
227	if (FSTYPE_NFS(tc))
228		xerrno = ESTALE;
229	else
230		xerrno = ENOENT;
231	ATF_REQUIRE_ERRNO(xerrno, rump_sys_chdir("..") == -1);
232	FSTEST_EXIT();
233}
234
235static void
236checkfile(const char *path, struct stat *refp)
237{
238	char buf[MAXPATHLEN];
239	struct stat sb;
240	static int n = 1;
241
242	md(buf, sizeof(buf), path, "file");
243	if (rump_sys_stat(buf, &sb) == -1)
244		atf_tc_fail_errno("cannot stat file %d (%s)", n, buf);
245	if (memcmp(&sb, refp, sizeof(sb)) != 0)
246		atf_tc_fail("stat mismatch %d", n);
247	n++;
248}
249
250static void
251rename_dir(const atf_tc_t *tc, const char *mp)
252{
253	char pb1[MAXPATHLEN], pb2[MAXPATHLEN], pb3[MAXPATHLEN];
254	struct stat ref, sb;
255
256	if (FSTYPE_RUMPFS(tc))
257		atf_tc_skip("rename not supported by file system");
258
259	USES_DIRS;
260
261	md(pb1, sizeof(pb1), mp, "dir1");
262	if (rump_sys_mkdir(pb1, 0777) == -1)
263		atf_tc_fail_errno("mkdir 1");
264
265	md(pb2, sizeof(pb2), mp, "dir2");
266	if (rump_sys_mkdir(pb2, 0777) == -1)
267		atf_tc_fail_errno("mkdir 2");
268	md(pb2, sizeof(pb2), mp, "dir2/subdir");
269	if (rump_sys_mkdir(pb2, 0777) == -1)
270		atf_tc_fail_errno("mkdir 3");
271
272	md(pb3, sizeof(pb3), mp, "dir1/file");
273	if (rump_sys_mknod(pb3, S_IFREG | 0777, -1) == -1)
274		atf_tc_fail_errno("create file");
275	if (rump_sys_stat(pb3, &ref) == -1)
276		atf_tc_fail_errno("stat of file");
277
278	/*
279	 * First try ops which should succeed.
280	 */
281
282	/* rename within directory */
283	md(pb3, sizeof(pb3), mp, "dir3");
284	if (rump_sys_rename(pb1, pb3) == -1)
285		atf_tc_fail_errno("rename 1");
286	checkfile(pb3, &ref);
287
288	/* rename directory onto itself (two ways, should fail) */
289	md(pb1, sizeof(pb1), mp, "dir3/.");
290	if (rump_sys_rename(pb1, pb3) != -1 || errno != EINVAL)
291		atf_tc_fail_errno("rename 2");
292	if (rump_sys_rename(pb3, pb1) != -1 || errno != EISDIR)
293		atf_tc_fail_errno("rename 3");
294
295	checkfile(pb3, &ref);
296
297	/* rename father of directory into directory */
298	md(pb1, sizeof(pb1), mp, "dir2/dir");
299	md(pb2, sizeof(pb2), mp, "dir2");
300	if (rump_sys_rename(pb2, pb1) != -1 || errno != EINVAL)
301		atf_tc_fail_errno("rename 4");
302
303	/* same for grandfather */
304	md(pb1, sizeof(pb1), mp, "dir2/subdir/dir2");
305	if (rump_sys_rename(pb2, pb1) != -1 || errno != EINVAL)
306		atf_tc_fail("rename 5");
307
308	checkfile(pb3, &ref);
309
310	/* rename directory over a non-empty directory */
311	if (rump_sys_rename(pb2, pb3) != -1 || errno != ENOTEMPTY)
312		atf_tc_fail("rename 6");
313
314	/* cross-directory rename */
315	md(pb1, sizeof(pb1), mp, "dir3");
316	md(pb2, sizeof(pb2), mp, "dir2/somedir");
317	if (rump_sys_rename(pb1, pb2) == -1)
318		atf_tc_fail_errno("rename 7");
319	checkfile(pb2, &ref);
320
321	/* move to parent directory */
322	md(pb1, sizeof(pb1), mp, "dir2/somedir/../../dir3");
323	if (rump_sys_rename(pb2, pb1) == -1)
324		atf_tc_fail_errno("rename 8");
325	md(pb1, sizeof(pb1), mp, "dir2/../dir3");
326	checkfile(pb1, &ref);
327
328	/* atomic cross-directory rename */
329	md(pb3, sizeof(pb3), mp, "dir2/subdir");
330	if (rump_sys_rename(pb1, pb3) == -1)
331		atf_tc_fail_errno("rename 9");
332	checkfile(pb3, &ref);
333
334	/* rename directory over an empty directory */
335	md(pb1, sizeof(pb1), mp, "parent");
336	md(pb2, sizeof(pb2), mp, "parent/dir1");
337	md(pb3, sizeof(pb3), mp, "parent/dir2");
338	RL(rump_sys_mkdir(pb1, 0777));
339	RL(rump_sys_mkdir(pb2, 0777));
340	RL(rump_sys_mkdir(pb3, 0777));
341	RL(rump_sys_rename(pb2, pb3));
342
343	RL(rump_sys_stat(pb1, &sb));
344	if (! FSTYPE_MSDOS(tc))
345		ATF_CHECK_EQ(sb.st_nlink, 3);
346	RL(rump_sys_rmdir(pb3));
347	RL(rump_sys_rmdir(pb1));
348}
349
350static void
351rename_dotdot(const atf_tc_t *tc, const char *mp)
352{
353
354	if (FSTYPE_RUMPFS(tc))
355		atf_tc_skip("rename not supported by file system");
356
357	USES_DIRS;
358
359	if (rump_sys_chdir(mp) == -1)
360		atf_tc_fail_errno("chdir mountpoint");
361
362	if (rump_sys_mkdir("dir1", 0777) == -1)
363		atf_tc_fail_errno("mkdir 1");
364	if (rump_sys_mkdir("dir2", 0777) == -1)
365		atf_tc_fail_errno("mkdir 2");
366
367	if (rump_sys_rename("dir1", "dir1/..") != -1 || errno != EINVAL)
368		atf_tc_fail_errno("self-dotdot to");
369
370	if (rump_sys_rename("dir1/..", "sometarget") != -1 || errno != EINVAL)
371		atf_tc_fail_errno("self-dotdot from");
372
373	if (rump_sys_rename("dir1", "dir2/..") != -1 || errno != EINVAL)
374		atf_tc_fail("other-dotdot");
375
376	rump_sys_chdir("/");
377}
378
379static void
380rename_reg_nodir(const atf_tc_t *tc, const char *mp)
381{
382	bool haslinks;
383	struct stat sb;
384	ino_t f1ino;
385
386	if (FSTYPE_RUMPFS(tc))
387		atf_tc_skip("rename not supported by file system");
388
389	if (rump_sys_chdir(mp) == -1)
390		atf_tc_fail_errno("chdir mountpoint");
391
392	if (FSTYPE_MSDOS(tc) || FSTYPE_SYSVBFS(tc))
393		haslinks = false;
394	else
395		haslinks = true;
396
397	if (rump_sys_mknod("file1", S_IFREG | 0777, -1) == -1)
398		atf_tc_fail_errno("create file");
399	if (rump_sys_mknod("file2", S_IFREG | 0777, -1) == -1)
400		atf_tc_fail_errno("create file");
401
402	if (rump_sys_stat("file1", &sb) == -1)
403		atf_tc_fail_errno("stat");
404	f1ino = sb.st_ino;
405
406	if (haslinks) {
407		if (rump_sys_link("file1", "file_link") == -1)
408			atf_tc_fail_errno("link");
409		if (rump_sys_stat("file_link", &sb) == -1)
410			atf_tc_fail_errno("stat");
411		ATF_REQUIRE_EQ(sb.st_ino, f1ino);
412		ATF_REQUIRE_EQ(sb.st_nlink, 2);
413	}
414
415	if (rump_sys_stat("file2", &sb) == -1)
416		atf_tc_fail_errno("stat");
417
418	if (rump_sys_rename("file1", "file3") == -1)
419		atf_tc_fail_errno("rename 1");
420	if (rump_sys_stat("file3", &sb) == -1)
421		atf_tc_fail_errno("stat 1");
422	if (haslinks) {
423		ATF_REQUIRE_EQ(sb.st_ino, f1ino);
424	}
425	if (rump_sys_stat("file1", &sb) != -1 || errno != ENOENT)
426		atf_tc_fail_errno("source 1");
427
428	if (rump_sys_rename("file3", "file2") == -1)
429		atf_tc_fail_errno("rename 2");
430	if (rump_sys_stat("file2", &sb) == -1)
431		atf_tc_fail_errno("stat 2");
432	if (haslinks) {
433		ATF_REQUIRE_EQ(sb.st_ino, f1ino);
434	}
435
436	if (rump_sys_stat("file3", &sb) != -1 || errno != ENOENT)
437		atf_tc_fail_errno("source 2");
438
439	if (haslinks) {
440		if (rump_sys_rename("file2", "file_link") == -1)
441			atf_tc_fail_errno("rename hardlink");
442		if (rump_sys_stat("file2", &sb) != -1 || errno != ENOENT)
443			atf_tc_fail_errno("source 3");
444		if (rump_sys_stat("file_link", &sb) == -1)
445			atf_tc_fail_errno("stat 2");
446		ATF_REQUIRE_EQ(sb.st_ino, f1ino);
447		ATF_REQUIRE_EQ(sb.st_nlink, 1);
448	}
449
450	ATF_CHECK_ERRNO(EFAULT, rump_sys_rename("file2", NULL) == -1);
451	ATF_CHECK_ERRNO(EFAULT, rump_sys_rename(NULL, "file2") == -1);
452
453	rump_sys_chdir("/");
454}
455
456/* PR kern/50607 */
457static void
458create_many(const atf_tc_t *tc, const char *mp)
459{
460	char buf[64];
461	int nfiles = 2324; /* #Nancy */
462	int i;
463
464	/* takes forever with many files */
465	if (FSTYPE_MSDOS(tc))
466		nfiles /= 4;
467
468	RL(rump_sys_chdir(mp));
469
470	if (FSTYPE_SYSVBFS(tc)) {
471		/* fs doesn't support many files or subdirectories */
472		nfiles = 5;
473	} else {
474		/* msdosfs doesn't like many entries in the root directory */
475		RL(rump_sys_mkdir("subdir", 0777));
476		RL(rump_sys_chdir("subdir"));
477	}
478
479	/* create them */
480#define TESTFN "testfile"
481	for (i = 0; i < nfiles; i++) {
482		int fd;
483
484		snprintf(buf, sizeof(buf), TESTFN "%d", i);
485		RL(fd = rump_sys_open(buf, O_RDWR|O_CREAT|O_EXCL, 0666));
486		RL(rump_sys_close(fd));
487	}
488
489	/* wipe them out */
490	for (i = 0; i < nfiles; i++) {
491		snprintf(buf, sizeof(buf), TESTFN "%d", i);
492		RLF(rump_sys_unlink(buf), "%s", buf);
493	}
494#undef TESTFN
495
496	rump_sys_chdir("/");
497}
498
499/*
500 * Test creating files with one-character names using all possible
501 * character values.  Failures to create the file are ignored as the
502 * characters allowed in file names vary by file system, but at least
503 * we can check that the fs does not crash, and if the file is
504 * successfully created, unlinking it should also succeed.
505 */
506static void
507create_nonalphanum(const atf_tc_t *tc, const char *mp)
508{
509	char buf[64];
510	int i;
511
512	RL(rump_sys_chdir(mp));
513
514	for (i = 0; i < 256; i++) {
515		int fd;
516		snprintf(buf, sizeof(buf), "%c", i);
517		fd = rump_sys_open(buf, O_RDWR|O_CREAT|O_EXCL, 0666);
518		if (fd == -1)
519			continue;
520		RLF(rump_sys_close(fd), "%d", fd);
521		RLF(rump_sys_unlink(buf), "%s", buf);
522	}
523	printf("\n");
524
525	rump_sys_chdir("/");
526}
527
528static void
529create_nametoolong(const atf_tc_t *tc, const char *mp)
530{
531	char *name;
532	int fd;
533	long val;
534	size_t len;
535
536	if (rump_sys_chdir(mp) == -1)
537		atf_tc_fail_errno("chdir mountpoint");
538
539	val = rump_sys_pathconf(".", _PC_NAME_MAX);
540	if (val == -1)
541		atf_tc_fail_errno("pathconf");
542
543	len = val + 1;
544	name = malloc(len+1);
545	if (name == NULL)
546		atf_tc_fail_errno("malloc");
547
548	memset(name, 'a', len);
549	*(name+len) = '\0';
550
551	val = rump_sys_pathconf(".", _PC_NO_TRUNC);
552	if (val == -1)
553		atf_tc_fail_errno("pathconf");
554
555	fd = rump_sys_open(name, O_RDWR|O_CREAT, 0666);
556	if (val != 0 && (fd != -1 || errno != ENAMETOOLONG))
557		atf_tc_fail_errno("open");
558
559	if (val == 0 && rump_sys_close(fd) == -1)
560		atf_tc_fail_errno("close");
561	if (val == 0 && rump_sys_unlink(name) == -1)
562		atf_tc_fail_errno("unlink");
563
564	free(name);
565
566	rump_sys_chdir("/");
567}
568
569static void
570create_exist(const atf_tc_t *tc, const char *mp)
571{
572	const char *name = "hoge";
573	int fd;
574
575	RL(rump_sys_chdir(mp));
576	RL(fd = rump_sys_open(name, O_RDWR|O_CREAT|O_EXCL, 0666));
577	RL(rump_sys_close(fd));
578	RL(rump_sys_unlink(name));
579	RL(fd = rump_sys_open(name, O_RDWR|O_CREAT, 0666));
580	RL(rump_sys_close(fd));
581	RL(fd = rump_sys_open(name, O_RDWR|O_CREAT, 0666));
582	RL(rump_sys_close(fd));
583	ATF_REQUIRE_ERRNO(EEXIST,
584	    (fd = rump_sys_open(name, O_RDWR|O_CREAT|O_EXCL, 0666)));
585	RL(rump_sys_unlink(name));
586	RL(rump_sys_chdir("/"));
587}
588
589static void
590rename_nametoolong(const atf_tc_t *tc, const char *mp)
591{
592	char *name;
593	int res, fd;
594	long val;
595	size_t len;
596
597	if (FSTYPE_RUMPFS(tc))
598		atf_tc_skip("rename not supported by file system");
599
600	if (rump_sys_chdir(mp) == -1)
601		atf_tc_fail_errno("chdir mountpoint");
602
603	val = rump_sys_pathconf(".", _PC_NAME_MAX);
604	if (val == -1)
605		atf_tc_fail_errno("pathconf");
606
607	len = val + 1;
608	name = malloc(len+1);
609	if (name == NULL)
610		atf_tc_fail_errno("malloc");
611
612	memset(name, 'a', len);
613	*(name+len) = '\0';
614
615	fd = rump_sys_open("dummy", O_RDWR|O_CREAT, 0666);
616	if (fd == -1)
617		atf_tc_fail_errno("open");
618	if (rump_sys_close(fd) == -1)
619		atf_tc_fail_errno("close");
620
621	val = rump_sys_pathconf(".", _PC_NO_TRUNC);
622	if (val == -1)
623		atf_tc_fail_errno("pathconf");
624
625	res = rump_sys_rename("dummy", name);
626	if (val != 0 && (res != -1 || errno != ENAMETOOLONG))
627		atf_tc_fail_errno("rename");
628
629	if (val == 0 && rump_sys_unlink(name) == -1)
630		atf_tc_fail_errno("unlink");
631
632	free(name);
633
634	rump_sys_chdir("/");
635}
636
637/*
638 * Test creating a symlink whose length is "len" bytes, not including
639 * the terminating NUL.
640 */
641static void
642symlink_len(const atf_tc_t *tc, const char *mp, size_t len)
643{
644	char *buf;
645	int r;
646
647	USES_SYMLINKS;
648
649	RLF(rump_sys_chdir(mp), "%s", mp);
650
651	buf = malloc(len + 1);
652	ATF_REQUIRE(buf);
653	memset(buf, 'a', len);
654	buf[len] = '\0';
655	r = rump_sys_symlink(buf, "afile");
656	if (r == -1) {
657		ATF_REQUIRE_ERRNO(ENAMETOOLONG, r);
658	} else {
659		RL(rump_sys_unlink("afile"));
660	}
661	free(buf);
662
663	RL(rump_sys_chdir("/"));
664}
665
666static void
667symlink_zerolen(const atf_tc_t *tc, const char *mp)
668{
669	symlink_len(tc, mp, 0);
670}
671
672static void
673symlink_long(const atf_tc_t *tc, const char *mp)
674{
675	/*
676	 * Test lengths close to powers of two, as those are likely
677	 * to be edge cases.
678	 */
679	size_t len;
680	int fuzz;
681	for (len = 2; len <= 65536; len *= 2) {
682		for (fuzz = -1; fuzz <= 1; fuzz++) {
683			symlink_len(tc, mp, len + fuzz);
684		}
685	}
686}
687
688static void
689symlink_root(const atf_tc_t *tc, const char *mp)
690{
691
692	USES_SYMLINKS;
693
694	RL(rump_sys_chdir(mp));
695	RL(rump_sys_symlink("/", "foo"));
696	RL(rump_sys_chdir("foo"));
697}
698
699static void
700attrs(const atf_tc_t *tc, const char *mp)
701{
702	struct stat sb, sb2;
703	struct timeval tv[2];
704	int fd;
705
706	FSTEST_ENTER();
707	RL(fd = rump_sys_open(TESTFILE, O_RDWR | O_CREAT, 0755));
708	RL(rump_sys_close(fd));
709	RL(rump_sys_stat(TESTFILE, &sb));
710	if (!(FSTYPE_MSDOS(tc) || FSTYPE_SYSVBFS(tc))) {
711		RL(rump_sys_chown(TESTFILE, 1, 2));
712		sb.st_uid = 1;
713		sb.st_gid = 2;
714		RL(rump_sys_chmod(TESTFILE, 0123));
715		sb.st_mode = (sb.st_mode & ~ACCESSPERMS) | 0123;
716	}
717
718	tv[0].tv_sec = 1000000000; /* need something >1980 for msdosfs */
719	tv[0].tv_usec = 1;
720	tv[1].tv_sec = 1000000002; /* need even seconds for msdosfs */
721	tv[1].tv_usec = 3;
722	RL(rump_sys_utimes(TESTFILE, tv));
723	RL(rump_sys_utimes(TESTFILE, tv)); /* XXX: utimes & birthtime */
724	sb.st_atimespec.tv_sec = 1000000000;
725	sb.st_atimespec.tv_nsec = 1000;
726	sb.st_mtimespec.tv_sec = 1000000002;
727	sb.st_mtimespec.tv_nsec = 3000;
728
729	RL(rump_sys_stat(TESTFILE, &sb2));
730#define CHECK(a) ATF_REQUIRE_EQ(sb.a, sb2.a)
731	if (!(FSTYPE_MSDOS(tc) || FSTYPE_SYSVBFS(tc))) {
732		CHECK(st_uid);
733		CHECK(st_gid);
734		CHECK(st_mode);
735	}
736	if (!FSTYPE_MSDOS(tc)) {
737		/* msdosfs has only access date, not time */
738		CHECK(st_atimespec.tv_sec);
739	}
740	CHECK(st_mtimespec.tv_sec);
741	if (!(FSTYPE_EXT2FS(tc) || FSTYPE_MSDOS(tc) ||
742	      FSTYPE_SYSVBFS(tc) || FSTYPE_V7FS(tc))) {
743		CHECK(st_atimespec.tv_nsec);
744		CHECK(st_mtimespec.tv_nsec);
745	}
746#undef  CHECK
747
748	FSTEST_EXIT();
749}
750
751static void
752fcntl_lock(const atf_tc_t *tc, const char *mp)
753{
754	int fd, fd2;
755	struct flock l;
756	struct lwp *lwp1, *lwp2;
757
758	FSTEST_ENTER();
759	l.l_pid = 0;
760	l.l_start = l.l_len = 1024;
761	l.l_type = F_RDLCK | F_WRLCK;
762	l.l_whence = SEEK_END;
763
764	lwp1 = rump_pub_lwproc_curlwp();
765	RL(fd = rump_sys_open(TESTFILE, O_RDWR | O_CREAT, 0755));
766	RL(rump_sys_ftruncate(fd, 8192));
767
768	RL(rump_sys_fcntl(fd, F_SETLK, &l));
769
770	/* Next, we fork and try to lock the same area */
771	RZ(rump_pub_lwproc_rfork(RUMP_RFCFDG));
772	lwp2 = rump_pub_lwproc_curlwp();
773	RL(fd2 = rump_sys_open(TESTFILE, O_RDWR, 0));
774	ATF_REQUIRE_ERRNO(EAGAIN, rump_sys_fcntl(fd2, F_SETLK, &l));
775
776	/* Switch back and unlock... */
777	rump_pub_lwproc_switch(lwp1);
778	l.l_type = F_UNLCK;
779	RL(rump_sys_fcntl(fd, F_SETLK, &l));
780
781	/* ... and try to lock again */
782	rump_pub_lwproc_switch(lwp2);
783	l.l_type = F_RDLCK | F_WRLCK;
784	RL(rump_sys_fcntl(fd2, F_SETLK, &l));
785
786	RL(rump_sys_close(fd2));
787	rump_pub_lwproc_releaselwp();
788
789	RL(rump_sys_close(fd));
790
791	FSTEST_EXIT();
792}
793
794static int
795flock_compare(const void *p, const void *q)
796{
797	int a = ((const struct flock *)p)->l_start;
798	int b = ((const struct flock *)q)->l_start;
799	return a < b ? -1 : (a > b ? 1 : 0);
800}
801
802/*
803 * Find all locks set by fcntl_getlock_pids test
804 * using GETLK for a range [start, start+end], and,
805 * if there is a blocking lock, recursively find
806 * all locks to the left (toward the beginning of
807 * a file) and to the right of the lock.
808 * The function also understands "until end of file"
809 * convention when len==0.
810 */
811static unsigned int
812fcntl_getlocks(int fildes, off_t start, off_t len,
813    struct flock *lock, struct flock *end)
814{
815	unsigned int rv = 0;
816	const struct flock l = { start, len, 0, F_RDLCK, SEEK_SET };
817
818	if (lock == end)
819		return rv;
820
821	RL(rump_sys_fcntl(fildes, F_GETLK, &l));
822
823	if (l.l_type == F_UNLCK)
824		return rv;
825
826	*lock++ = l;
827	rv += 1;
828
829	ATF_REQUIRE(l.l_whence == SEEK_SET);
830
831	if (l.l_start > start) {
832		unsigned int n =
833		    fcntl_getlocks(fildes, start, l.l_start - start, lock, end);
834		rv += n;
835		lock += n;
836		if (lock == end)
837			return rv;
838	}
839
840	if (l.l_len == 0) /* does l spans until the end? */
841		return rv;
842
843	if (len == 0) /* are we looking for locks until the end? */ {
844		rv += fcntl_getlocks(fildes, l.l_start + l.l_len, len, lock, end);
845	} else if (l.l_start + l.l_len < start + len) {
846		len -= l.l_start + l.l_len - start;
847		rv += fcntl_getlocks(fildes, l.l_start + l.l_len, len, lock, end);
848	}
849
850	return rv;
851}
852
853static void
854fcntl_getlock_pids(const atf_tc_t *tc, const char *mp)
855{
856	/* test non-overlaping ranges */
857	struct flock expect[4];
858	const struct flock lock[4] = {
859		{ 0, 2, 0, F_WRLCK, SEEK_SET },
860		{ 2, 1, 0, F_WRLCK, SEEK_SET },
861		{ 7, 5, 0, F_WRLCK, SEEK_SET },
862		{ 4, 3, 0, F_WRLCK, SEEK_SET },
863	};
864
865    /* Add extra element to make sure recursion does't stop at array end */
866	struct flock result[5];
867
868	/* Add 5th process */
869	int fd[5];
870	pid_t pid[5];
871	struct lwp *lwp[5];
872
873	unsigned int i, j;
874	const off_t sz = 8192;
875	int omode  = 0755;
876	int oflags = O_RDWR | O_CREAT;
877
878	memcpy(expect, lock, sizeof(lock));
879
880	FSTEST_ENTER();
881
882	/*
883	 * First, we create 4 processes and let each lock a range of the
884	 * file.  Note that the third and fourth processes lock in
885	 * "reverse" order, i.e. the greater pid locks a range before
886	 * the lesser pid.
887	 * Then, we create 5th process which doesn't lock anything.
888	 */
889	for (i = 0; i < __arraycount(lwp); i++) {
890		RZ(rump_pub_lwproc_rfork(RUMP_RFCFDG));
891
892		lwp[i] = rump_pub_lwproc_curlwp();
893		pid[i] = rump_sys_getpid();
894
895		RL(fd[i] = rump_sys_open(TESTFILE, oflags, omode));
896		oflags = O_RDWR;
897		omode  = 0;
898
899		RL(rump_sys_ftruncate(fd[i], sz));
900
901		if (i < __arraycount(lock)) {
902			RL(rump_sys_fcntl(fd[i], F_SETLK, &lock[i]));
903			expect[i].l_pid = pid[i];
904		}
905	}
906
907	qsort(expect, __arraycount(expect), sizeof(expect[0]), &flock_compare);
908
909	/*
910	 * In the context of each process, recursively find all locks
911	 * that would block the current process. Processes 1-4 don't
912	 * see their own lock, we insert it to simplify checks.
913	 * Process 5 sees all 4 locks.
914	 */
915	for (i = 0; i < __arraycount(lwp); i++) {
916		unsigned int nlocks;
917
918		rump_pub_lwproc_switch(lwp[i]);
919
920		memset(result, 0, sizeof(result));
921		nlocks = fcntl_getlocks(fd[i], 0, sz,
922		    result, result + __arraycount(result));
923
924		if (i < __arraycount(lock)) {
925			ATF_REQUIRE(nlocks < __arraycount(result));
926			result[nlocks] = lock[i];
927			result[nlocks].l_pid = pid[i];
928			nlocks++;
929		}
930
931		ATF_CHECK_EQ(nlocks, __arraycount(expect));
932
933		qsort(result, nlocks, sizeof(result[0]), &flock_compare);
934
935		for (j = 0; j < nlocks; j++) {
936			ATF_CHECK_EQ(result[j].l_start,  expect[j].l_start );
937			ATF_CHECK_EQ(result[j].l_len,    expect[j].l_len   );
938			ATF_CHECK_EQ(result[j].l_pid,    expect[j].l_pid   );
939			ATF_CHECK_EQ(result[j].l_type,   expect[j].l_type  );
940			ATF_CHECK_EQ(result[j].l_whence, expect[j].l_whence);
941		}
942	}
943
944	/*
945	 * Release processes.  This also releases the fds and locks
946	 * making fs unmount possible
947	 */
948	for (i = 0; i < __arraycount(lwp); i++) {
949		rump_pub_lwproc_switch(lwp[i]);
950		rump_pub_lwproc_releaselwp();
951	}
952
953	FSTEST_EXIT();
954}
955
956static void
957access_simple(const atf_tc_t *tc, const char *mp)
958{
959	int fd;
960	int tmode;
961
962	FSTEST_ENTER();
963	RL(fd = rump_sys_open("tfile", O_CREAT | O_RDWR, 0777));
964	RL(rump_sys_close(fd));
965
966#define ALLACC (F_OK | X_OK | W_OK | R_OK)
967	if (FSTYPE_SYSVBFS(tc) || FSTYPE_MSDOS(tc))
968		tmode = F_OK;
969	else
970		tmode = ALLACC;
971
972	RL(rump_sys_access("tfile", tmode));
973
974	/* PR kern/44648 */
975	ATF_REQUIRE_ERRNO(EINVAL, rump_sys_access("tfile", ALLACC+1) == -1);
976#undef ALLACC
977	FSTEST_EXIT();
978}
979
980static void
981read_directory(const atf_tc_t *tc, const char *mp)
982{
983	char buf[1024];
984	int fd, res;
985	ssize_t size;
986
987	FSTEST_ENTER();
988	fd = rump_sys_open(".", O_DIRECTORY | O_RDONLY, 0777);
989	ATF_REQUIRE(fd != -1);
990
991	size = rump_sys_pread(fd, buf, sizeof(buf), 0);
992	ATF_CHECK(size != -1 || errno == EISDIR);
993	size = rump_sys_read(fd, buf, sizeof(buf));
994	ATF_CHECK(size != -1 || errno == EISDIR);
995
996	res = rump_sys_close(fd);
997	ATF_REQUIRE(res != -1);
998	FSTEST_EXIT();
999}
1000
1001static void
1002lstat_symlink(const atf_tc_t *tc, const char *mp)
1003{
1004	const char *src, *dst;
1005	int res;
1006	struct stat st;
1007
1008	USES_SYMLINKS;
1009
1010	FSTEST_ENTER();
1011
1012	src = "source";
1013	dst = "destination";
1014
1015	res = rump_sys_symlink(src, dst);
1016	ATF_REQUIRE(res != -1);
1017	res = rump_sys_lstat(dst, &st);
1018	ATF_REQUIRE(res != -1);
1019
1020	ATF_CHECK(S_ISLNK(st.st_mode) != 0);
1021	ATF_CHECK(st.st_size == (off_t)strlen(src));
1022
1023	FSTEST_EXIT();
1024}
1025
1026ATF_TC_FSAPPLY(lookup_simple, "simple lookup (./.. on root)");
1027ATF_TC_FSAPPLY(lookup_complex, "lookup of non-dot entries");
1028ATF_TC_FSAPPLY(dir_simple, "mkdir/rmdir");
1029ATF_TC_FSAPPLY(dir_notempty, "non-empty directories cannot be removed");
1030ATF_TC_FSAPPLY(dir_rmdirdotdot, "remove .. and try to cd out (PR kern/44657)");
1031ATF_TC_FSAPPLY(rename_dir, "exercise various directory renaming ops "
1032"(PR kern/44288)");
1033ATF_TC_FSAPPLY(rename_dotdot, "rename dir .. (PR kern/43617)");
1034ATF_TC_FSAPPLY(rename_reg_nodir, "rename regular files, no subdirectories");
1035ATF_TC_FSAPPLY(create_nametoolong, "create file with name too long");
1036ATF_TC_FSAPPLY(create_exist, "create with O_EXCL");
1037ATF_TC_FSAPPLY(rename_nametoolong, "rename to file with name too long");
1038ATF_TC_FSAPPLY(symlink_zerolen, "symlink with target of length 0");
1039ATF_TC_FSAPPLY(symlink_long, "symlink with target of length > 0");
1040ATF_TC_FSAPPLY(symlink_root, "symlink to root directory");
1041ATF_TC_FSAPPLY(attrs, "check setting attributes works");
1042ATF_TC_FSAPPLY(fcntl_lock, "check fcntl F_SETLK");
1043ATF_TC_FSAPPLY(fcntl_getlock_pids,"fcntl F_GETLK w/ many procs, PR kern/44494");
1044ATF_TC_FSAPPLY(access_simple, "access(2)");
1045ATF_TC_FSAPPLY(read_directory, "read(2) on directories");
1046ATF_TC_FSAPPLY(lstat_symlink, "lstat(2) values for symbolic links");
1047
1048#undef FSTEST_IMGSIZE
1049#define FSTEST_IMGSIZE (1024*1024*64)
1050ATF_TC_FSAPPLY(create_many, "create many directory entries");
1051ATF_TC_FSAPPLY(create_nonalphanum, "non-alphanumeric filenames");
1052
1053ATF_TP_ADD_TCS(tp)
1054{
1055
1056	ATF_TP_FSAPPLY(lookup_simple);
1057	ATF_TP_FSAPPLY(lookup_complex);
1058	ATF_TP_FSAPPLY(dir_simple);
1059	ATF_TP_FSAPPLY(dir_notempty);
1060	ATF_TP_FSAPPLY(dir_rmdirdotdot);
1061	ATF_TP_FSAPPLY(rename_dir);
1062	ATF_TP_FSAPPLY(rename_dotdot);
1063	ATF_TP_FSAPPLY(rename_reg_nodir);
1064	ATF_TP_FSAPPLY(create_many);
1065	ATF_TP_FSAPPLY(create_nonalphanum);
1066	ATF_TP_FSAPPLY(create_nametoolong);
1067	ATF_TP_FSAPPLY(create_exist);
1068	ATF_TP_FSAPPLY(rename_nametoolong);
1069	ATF_TP_FSAPPLY(symlink_zerolen);
1070	ATF_TP_FSAPPLY(symlink_long);
1071	ATF_TP_FSAPPLY(symlink_root);
1072	ATF_TP_FSAPPLY(attrs);
1073	ATF_TP_FSAPPLY(fcntl_lock);
1074	ATF_TP_FSAPPLY(fcntl_getlock_pids);
1075	ATF_TP_FSAPPLY(access_simple);
1076	ATF_TP_FSAPPLY(read_directory);
1077	ATF_TP_FSAPPLY(lstat_symlink);
1078
1079	return atf_no_error();
1080}
1081