xref: /freebsd/contrib/pjdfstest/pjdfstest.c (revision a0409676120c1e558d0ade943019934e0f15118d)
1 /*-
2  * Copyright (c) 2006-2010 Pawel Jakub Dawidek <pjd@FreeBSD.org>
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24  * SUCH DAMAGE.
25  *
26  * $FreeBSD$
27  */
28 
29 /* Needs to be first to twiddle appropriate system configuration/HAVE_* flags */
30 #include "config.h"
31 
32 #include <sys/param.h>
33 #ifdef	HAVE_SYS_ACL_H
34 #include <sys/acl.h>
35 #endif
36 #ifdef	HAVE_SYS_MKDEV_H
37 #include <sys/mkdev.h>
38 #endif
39 #include <sys/stat.h>
40 #include <sys/socket.h>
41 #include <sys/un.h>
42 
43 #include <assert.h>
44 #include <ctype.h>
45 #include <errno.h>
46 #include <fcntl.h>
47 #include <grp.h>
48 #include <stdio.h>
49 #include <stdlib.h>
50 #include <string.h>
51 #include <unistd.h>
52 
53 #ifdef	__sun__
54 #define	_USE_STAT64
55 #endif
56 
57 #ifdef	_USE_STAT64
58 typedef	struct stat64	stat_t;
59 #else
60 typedef	struct stat	stat_t;
61 #endif
62 
63 #ifndef ALLPERMS
64 #define	ALLPERMS	(S_ISUID|S_ISGID|S_ISVTX|S_IRWXU|S_IRWXG|S_IRWXO)
65 #endif
66 
67 enum action {
68 	ACTION_OPEN,
69 #ifdef	HAVE_OPENAT
70 	ACTION_OPENAT,
71 #endif
72 	ACTION_CREATE,
73 	ACTION_UNLINK,
74 #ifdef	HAVE_UNLINKAT
75 	ACTION_UNLINKAT,
76 #endif
77 	ACTION_MKDIR,
78 #ifdef	HAVE_MKDIRAT
79 	ACTION_MKDIRAT,
80 #endif
81 	ACTION_RMDIR,
82 	ACTION_LINK,
83 #ifdef	HAVE_LINKAT
84 	ACTION_LINKAT,
85 #endif
86 	ACTION_SYMLINK,
87 #ifdef	HAVE_SYMLINKAT
88 	ACTION_SYMLINKAT,
89 #endif
90 	ACTION_RENAME,
91 #ifdef	HAVE_RENAMEAT
92 	ACTION_RENAMEAT,
93 #endif
94 	ACTION_MKFIFO,
95 #ifdef	HAVE_MKFIFOAT
96 	ACTION_MKFIFOAT,
97 #endif
98 	ACTION_MKNOD,
99 	ACTION_MKNODAT,
100 	ACTION_BIND,
101 #ifdef	HAVE_BINDAT
102 	ACTION_BINDAT,
103 #endif
104 	ACTION_CONNECT,
105 #ifdef	HAVE_CONNECTAT
106 	ACTION_CONNECTAT,
107 #endif
108 	ACTION_CHMOD,
109 	ACTION_FCHMOD,
110 #ifdef	HAVE_LCHMOD
111 	ACTION_LCHMOD,
112 #endif
113 	ACTION_FCHMODAT,
114 	ACTION_CHOWN,
115 	ACTION_FCHOWN,
116 	ACTION_LCHOWN,
117 #ifdef	HAVE_FCHOWNAT
118 	ACTION_FCHOWNAT,
119 #endif
120 #ifdef	HAVE_CHFLAGS
121 	ACTION_CHFLAGS,
122 #endif
123 #ifdef	HAVE_FCHFLAGS
124 	ACTION_FCHFLAGS,
125 #endif
126 #ifdef	HAVE_CHFLAGSAT
127 	ACTION_CHFLAGSAT,
128 #endif
129 #ifdef	HAVE_LCHFLAGS
130 	ACTION_LCHFLAGS,
131 #endif
132 	ACTION_TRUNCATE,
133 	ACTION_FTRUNCATE,
134 #ifdef	HAVE_POSIX_FALLOCATE
135 	ACTION_POSIX_FALLOCATE,
136 #endif
137 	ACTION_STAT,
138 	ACTION_FSTAT,
139 	ACTION_LSTAT,
140 	ACTION_FSTATAT,
141 	ACTION_PATHCONF,
142 	ACTION_FPATHCONF,
143 #ifdef	HAVE_LPATHCONF
144 	ACTION_LPATHCONF,
145 #endif
146 #ifdef	HAS_NFSV4_ACL_SUPPORT
147 	ACTION_PREPENDACL,
148 	ACTION_READACL,
149 #endif
150 	ACTION_WRITE,
151 #ifdef	HAVE_UTIMENSAT
152 	ACTION_UTIMENSAT,
153 #endif
154 };
155 
156 #define	TYPE_NONE	0x0000
157 #define	TYPE_STRING	0x0001
158 #define	TYPE_NUMBER	0x0002
159 #define	TYPE_DESCRIPTOR	0x0003
160 #define	TYPE_MASK	0x000f
161 
162 #define	TYPE_OPTIONAL	0x0100
163 
164 #define	MAX_ARGS	8
165 
166 struct syscall_desc {
167 	const char	*sd_name;
168 	enum action	 sd_action;
169 	int		 sd_args[MAX_ARGS];
170 };
171 
172 static struct syscall_desc syscalls[] = {
173 	{ "open", ACTION_OPEN, { TYPE_STRING, TYPE_STRING, TYPE_NUMBER | TYPE_OPTIONAL, TYPE_NONE } },
174 #ifdef	HAVE_OPENAT
175 	{ "openat", ACTION_OPENAT, { TYPE_DESCRIPTOR, TYPE_STRING, TYPE_STRING, TYPE_NUMBER | TYPE_OPTIONAL, TYPE_NONE } },
176 #endif
177 	{ "create", ACTION_CREATE, { TYPE_STRING, TYPE_NUMBER, TYPE_NONE } },
178 	{ "unlink", ACTION_UNLINK, { TYPE_STRING, TYPE_NONE } },
179 #ifdef	HAVE_UNLINKAT
180 	{ "unlinkat", ACTION_UNLINKAT, { TYPE_DESCRIPTOR, TYPE_STRING, TYPE_STRING, TYPE_NONE } },
181 #endif
182 	{ "mkdir", ACTION_MKDIR, { TYPE_STRING, TYPE_NUMBER, TYPE_NONE } },
183 #ifdef	HAVE_MKDIRAT
184 	{ "mkdirat", ACTION_MKDIRAT, { TYPE_DESCRIPTOR, TYPE_STRING, TYPE_NUMBER, TYPE_NONE } },
185 #endif
186 	{ "rmdir", ACTION_RMDIR, { TYPE_STRING, TYPE_NONE } },
187 	{ "link", ACTION_LINK, { TYPE_STRING, TYPE_STRING, TYPE_NONE } },
188 #ifdef	HAVE_LINKAT
189 	{ "linkat", ACTION_LINKAT, { TYPE_DESCRIPTOR, TYPE_STRING, TYPE_DESCRIPTOR, TYPE_STRING, TYPE_STRING, TYPE_NONE } },
190 #endif
191 	{ "symlink", ACTION_SYMLINK, { TYPE_STRING, TYPE_STRING, TYPE_NONE } },
192 #ifdef	HAVE_SYMLINKAT
193 	{ "symlinkat", ACTION_SYMLINKAT, { TYPE_STRING, TYPE_DESCRIPTOR, TYPE_STRING, TYPE_NONE } },
194 #endif
195 	{ "rename", ACTION_RENAME, { TYPE_STRING, TYPE_STRING, TYPE_NONE } },
196 #ifdef	HAVE_RENAMEAT
197 	{ "renameat", ACTION_RENAMEAT, { TYPE_DESCRIPTOR, TYPE_STRING, TYPE_DESCRIPTOR, TYPE_STRING, TYPE_NONE } },
198 #endif
199 	{ "mkfifo", ACTION_MKFIFO, { TYPE_STRING, TYPE_NUMBER, TYPE_NONE } },
200 #ifdef	HAVE_MKFIFOAT
201 	{ "mkfifoat", ACTION_MKFIFOAT, { TYPE_DESCRIPTOR, TYPE_STRING, TYPE_NUMBER, TYPE_NONE } },
202 #endif
203 	{ "mknod", ACTION_MKNOD, { TYPE_STRING, TYPE_STRING, TYPE_NUMBER, TYPE_NUMBER, TYPE_NUMBER, TYPE_NONE} },
204 #ifdef	HAVE_MKNODAT
205 	{ "mknodat", ACTION_MKNODAT, { TYPE_DESCRIPTOR, TYPE_STRING, TYPE_STRING, TYPE_NUMBER, TYPE_NUMBER, TYPE_NUMBER, TYPE_NONE} },
206 #endif
207 	{ "bind", ACTION_BIND, { TYPE_STRING, TYPE_NONE } },
208 #ifdef	HAVE_BINDAT
209 	{ "bindat", ACTION_BINDAT, { TYPE_DESCRIPTOR, TYPE_STRING, TYPE_NONE } },
210 #endif
211 	{ "connect", ACTION_CONNECT, { TYPE_STRING, TYPE_NONE } },
212 #ifdef	HAVE_CONNECTAT
213 	{ "connectat", ACTION_CONNECTAT, { TYPE_DESCRIPTOR, TYPE_STRING, TYPE_NONE } },
214 #endif
215 	{ "chmod", ACTION_CHMOD, { TYPE_STRING, TYPE_NUMBER, TYPE_NONE } },
216 	{ "fchmod", ACTION_FCHMOD, { TYPE_DESCRIPTOR, TYPE_NUMBER, TYPE_NONE } },
217 #ifdef	HAVE_LCHMOD
218 	{ "lchmod", ACTION_LCHMOD, { TYPE_STRING, TYPE_NUMBER, TYPE_NONE } },
219 #endif
220 #ifdef	HAVE_FCHMODAT
221 	{ "fchmodat", ACTION_FCHMODAT, { TYPE_DESCRIPTOR, TYPE_STRING, TYPE_NUMBER, TYPE_STRING, TYPE_NONE } },
222 #endif
223 	{ "chown", ACTION_CHOWN, { TYPE_STRING, TYPE_NUMBER, TYPE_NUMBER, TYPE_NONE } },
224 	{ "fchown", ACTION_FCHOWN, { TYPE_DESCRIPTOR, TYPE_NUMBER, TYPE_NUMBER, TYPE_NONE } },
225 	{ "lchown", ACTION_LCHOWN, { TYPE_STRING, TYPE_NUMBER, TYPE_NUMBER, TYPE_NONE } },
226 #ifdef	HAVE_FCHOWNAT
227 	{ "fchownat", ACTION_FCHOWNAT, { TYPE_DESCRIPTOR, TYPE_STRING, TYPE_NUMBER, TYPE_NUMBER, TYPE_STRING, TYPE_NONE } },
228 #endif
229 #ifdef	HAVE_CHFLAGS
230 	{ "chflags", ACTION_CHFLAGS, { TYPE_STRING, TYPE_STRING, TYPE_NONE } },
231 #endif
232 #ifdef	HAVE_FCHFLAGS
233 	{ "fchflags", ACTION_FCHFLAGS, { TYPE_DESCRIPTOR, TYPE_STRING, TYPE_NONE } },
234 #endif
235 #ifdef	HAVE_CHFLAGSAT
236 	{ "chflagsat", ACTION_CHFLAGSAT, { TYPE_DESCRIPTOR, TYPE_STRING, TYPE_STRING, TYPE_STRING, TYPE_NONE } },
237 #endif
238 #ifdef	HAVE_LCHFLAGS
239 	{ "lchflags", ACTION_LCHFLAGS, { TYPE_STRING, TYPE_STRING, TYPE_NONE } },
240 #endif
241 	{ "truncate", ACTION_TRUNCATE, { TYPE_STRING, TYPE_NUMBER, TYPE_NONE } },
242 	{ "ftruncate", ACTION_FTRUNCATE, { TYPE_DESCRIPTOR, TYPE_NUMBER, TYPE_NONE } },
243 #ifdef	HAVE_POSIX_FALLOCATE
244 	{ "posix_fallocate", ACTION_POSIX_FALLOCATE, { TYPE_DESCRIPTOR, TYPE_NUMBER, TYPE_NUMBER, TYPE_NONE } },
245 #endif
246 	{ "stat", ACTION_STAT, { TYPE_STRING, TYPE_STRING, TYPE_NONE } },
247 	{ "fstat", ACTION_FSTAT, { TYPE_DESCRIPTOR, TYPE_STRING, TYPE_NONE } },
248 	{ "lstat", ACTION_LSTAT, { TYPE_STRING, TYPE_STRING, TYPE_NONE } },
249 #ifdef	HAVE_FSTATAT
250 	{ "fstatat", ACTION_FSTATAT, { TYPE_DESCRIPTOR, TYPE_STRING, TYPE_STRING, TYPE_STRING, TYPE_NONE } },
251 #endif
252 	{ "pathconf", ACTION_PATHCONF, { TYPE_STRING, TYPE_STRING, TYPE_NONE } },
253 	{ "fpathconf", ACTION_FPATHCONF, { TYPE_DESCRIPTOR, TYPE_STRING, TYPE_NONE } },
254 #ifdef	HAVE_LPATHCONF
255 	{ "lpathconf", ACTION_LPATHCONF, { TYPE_STRING, TYPE_STRING, TYPE_NONE } },
256 #endif
257 #ifdef	HAS_NFSV4_ACL_SUPPORT
258 	{ "prependacl", ACTION_PREPENDACL, { TYPE_STRING, TYPE_STRING, TYPE_NONE } },
259 	{ "readacl", ACTION_READACL, { TYPE_STRING, TYPE_NONE } },
260 #endif
261 	{ "write", ACTION_WRITE, { TYPE_DESCRIPTOR, TYPE_STRING, TYPE_NONE } },
262 #ifdef	HAVE_UTIMENSAT
263 	{ "utimensat", ACTION_UTIMENSAT, {
264 						 TYPE_DESCRIPTOR, /* Directory */
265 						 TYPE_STRING, /* Relative path */
266 						 TYPE_NUMBER, /* atime seconds */
267 						 TYPE_STRING, /* atime nanoseconds */
268 						 TYPE_NUMBER, /* mtime seconds */
269 						 TYPE_STRING, /* mtime nanoseconds */
270 						 TYPE_STRING, /* flags */}},
271 #endif
272 	{ NULL, -1, { TYPE_NONE } }
273 };
274 
275 struct flag {
276 	long long	 f_flag;
277 	const char	*f_str;
278 };
279 
280 static struct flag open_flags[] = {
281 #ifdef	O_RDONLY
282 	{ O_RDONLY, "O_RDONLY" },
283 #endif
284 #ifdef	O_WRONLY
285 	{ O_WRONLY, "O_WRONLY" },
286 #endif
287 #ifdef	O_RDWR
288 	{ O_RDWR, "O_RDWR" },
289 #endif
290 #ifdef	O_NONBLOCK
291 	{ O_NONBLOCK, "O_NONBLOCK" },
292 #endif
293 #ifdef	O_APPEND
294 	{ O_APPEND, "O_APPEND" },
295 #endif
296 #ifdef	O_CREAT
297 	{ O_CREAT, "O_CREAT" },
298 #endif
299 #ifdef	O_TRUNC
300 	{ O_TRUNC, "O_TRUNC" },
301 #endif
302 #ifdef	O_EXCL
303 	{ O_EXCL, "O_EXCL" },
304 #endif
305 #ifdef	O_SHLOCK
306 	{ O_SHLOCK, "O_SHLOCK" },
307 #endif
308 #ifdef	O_EXLOCK
309 	{ O_EXLOCK, "O_EXLOCK" },
310 #endif
311 #ifdef	O_DIRECT
312 	{ O_DIRECT, "O_DIRECT" },
313 #endif
314 #ifdef	O_FSYNC
315 	{ O_FSYNC, "O_FSYNC" },
316 #endif
317 #ifdef	O_SYNC
318 	{ O_SYNC, "O_SYNC" },
319 #endif
320 #ifdef	O_NOFOLLOW
321 	{ O_NOFOLLOW, "O_NOFOLLOW" },
322 #endif
323 #ifdef	O_NOCTTY
324 	{ O_NOCTTY, "O_NOCTTY" },
325 #endif
326 #ifdef	O_DIRECTORY
327 	{ O_DIRECTORY, "O_DIRECTORY" },
328 #endif
329 	{ 0, NULL }
330 };
331 
332 #ifdef	HAVE_CHFLAGS
333 static struct flag chflags_flags[] = {
334 #ifdef	UF_NODUMP
335 	{ UF_NODUMP, "UF_NODUMP" },
336 #endif
337 #ifdef	UF_IMMUTABLE
338 	{ UF_IMMUTABLE, "UF_IMMUTABLE" },
339 #endif
340 #ifdef	UF_APPEND
341 	{ UF_APPEND, "UF_APPEND" },
342 #endif
343 #ifdef	UF_NOUNLINK
344 	{ UF_NOUNLINK, "UF_NOUNLINK" },
345 #endif
346 #ifdef	UF_OPAQUE
347 	{ UF_OPAQUE, "UF_OPAQUE" },
348 #endif
349 #ifdef	SF_ARCHIVED
350 	{ SF_ARCHIVED, "SF_ARCHIVED" },
351 #endif
352 #ifdef	SF_IMMUTABLE
353 	{ SF_IMMUTABLE, "SF_IMMUTABLE" },
354 #endif
355 #ifdef	SF_APPEND
356 	{ SF_APPEND, "SF_APPEND" },
357 #endif
358 #ifdef	SF_NOUNLINK
359 	{ SF_NOUNLINK, "SF_NOUNLINK" },
360 #endif
361 #ifdef	SF_SNAPSHOT
362 	{ SF_SNAPSHOT, "SF_SNAPSHOT" },
363 #endif
364 	{ 0, NULL }
365 };
366 #endif
367 
368 #ifdef	HAVE_UNLINKAT
369 static struct flag unlinkat_flags[] = {
370 	{ AT_REMOVEDIR, "AT_REMOVEDIR" },
371 	{ 0, NULL }
372 };
373 #endif
374 
375 #ifdef	HAVE_LINKAT
376 static struct flag linkat_flags[] = {
377 #ifdef	AT_SYMLINK_FOLLOW
378 	{ AT_SYMLINK_FOLLOW, "AT_SYMLINK_FOLLOW" },
379 #endif
380 	{ 0, NULL }
381 };
382 #endif
383 
384 #ifdef	HAVE_CHFLAGSAT
385 static struct flag chflagsat_flags[] = {
386 	{ AT_SYMLINK_NOFOLLOW, "AT_SYMLINK_NOFOLLOW" },
387 	{ 0, NULL }
388 };
389 #endif
390 
391 #ifdef	HAVE_FCHMODAT
392 static struct flag fchmodat_flags[] = {
393 	{ AT_SYMLINK_NOFOLLOW, "AT_SYMLINK_NOFOLLOW" },
394 	{ 0, NULL }
395 };
396 #endif
397 
398 #ifdef	HAVE_FCHOWNAT
399 static struct flag fchownat_flags[] = {
400 	{ AT_SYMLINK_NOFOLLOW, "AT_SYMLINK_NOFOLLOW" },
401 	{ 0, NULL }
402 };
403 #endif
404 
405 #ifdef	HAVE_FSTATAT
406 static struct flag fstatat_flags[] = {
407 	{ AT_SYMLINK_NOFOLLOW, "AT_SYMLINK_NOFOLLOW" },
408 	{ 0, NULL }
409 };
410 #endif
411 
412 struct name {
413 	int		 n_name;
414 	const char	*n_str;
415 };
416 
417 static struct name pathconf_names[] = {
418 #ifdef	_PC_LINK_MAX
419 	{ _PC_LINK_MAX, "_PC_LINK_MAX" },
420 #endif
421 #ifdef	_PC_NAME_MAX
422 	{ _PC_NAME_MAX, "_PC_NAME_MAX" },
423 #endif
424 #ifdef	_PC_PATH_MAX
425 	{ _PC_PATH_MAX, "_PC_PATH_MAX" },
426 #endif
427 #ifdef	_PC_SYMLINK_MAX
428 	{ _PC_SYMLINK_MAX, "_PC_SYMLINK_MAX" },
429 #endif
430 	{ 0, NULL }
431 };
432 
433 static const char *err2str(int error);
434 
435 static int *descriptors;
436 static int ndescriptors;
437 
438 static void
439 usage(void)
440 {
441 
442 	fprintf(stderr, "usage: pjdfstest [-U umask] [-u uid] [-g gid1[,gid2[...]]] syscall args ...\n");
443 	exit(1);
444 }
445 
446 static long long
447 str2flags(struct flag *tflags, char *sflags)
448 {
449 	long long flags = 0;
450 	unsigned int i;
451 	char *f;
452 
453 	/* 'none' or '0' means no flags */
454 	if (strcmp(sflags, "none") == 0 || strcmp(sflags, "0") == 0)
455 		return (0);
456 	for (f = strtok(sflags, ",|"); f != NULL; f = strtok(NULL, ",|")) {
457 		for (i = 0; tflags[i].f_str != NULL; i++) {
458 			if (strcmp(tflags[i].f_str, f) == 0)
459 				break;
460 		}
461 		if (tflags[i].f_str == NULL) {
462 			fprintf(stderr, "unknown flag '%s'\n", f);
463 			exit(1);
464 		}
465 		flags |= tflags[i].f_flag;
466 	}
467 	return (flags);
468 }
469 
470 #ifdef	HAVE_CHFLAGS
471 static char *
472 flags2str(struct flag *tflags, long long flags)
473 {
474 	static char sflags[1024];
475 	unsigned int i;
476 
477 	sflags[0] = '\0';
478 	for (i = 0; tflags[i].f_str != NULL; i++) {
479 		if (flags & tflags[i].f_flag) {
480 			if (sflags[0] != '\0')
481 				strlcat(sflags, ",", sizeof(sflags));
482 			strlcat(sflags, tflags[i].f_str, sizeof(sflags));
483 		}
484 	}
485 	if (sflags[0] == '\0')
486 		strlcpy(sflags, "none", sizeof(sflags));
487 	return (sflags);
488 }
489 #endif
490 
491 static int
492 str2name(struct name *names, char *name)
493 {
494 	unsigned int i;
495 
496 	for (i = 0; names[i].n_str != NULL; i++) {
497 		if (strcmp(names[i].n_str, name) == 0)
498 			return (names[i].n_name);
499 	}
500 	return (-1);
501 }
502 
503 static struct syscall_desc *
504 find_syscall(const char *name)
505 {
506 	int i;
507 
508 	for (i = 0; syscalls[i].sd_name != NULL; i++) {
509 		if (strcmp(syscalls[i].sd_name, name) == 0)
510 			return (&syscalls[i]);
511 	}
512 	return (NULL);
513 }
514 
515 static void
516 show_stat(stat_t *sp, const char *what)
517 {
518 
519 	if (strcmp(what, "mode") == 0)
520 		printf("0%o", (unsigned int)(sp->st_mode & ALLPERMS));
521 	else if (strcmp(what, "inode") == 0)
522 		printf("%lld", (long long)sp->st_ino);
523 	else if (strcmp(what, "nlink") == 0)
524 		printf("%lld", (long long)sp->st_nlink);
525 	else if (strcmp(what, "uid") == 0)
526 		printf("%d", (int)sp->st_uid);
527 	else if (strcmp(what, "gid") == 0)
528 		printf("%d", (int)sp->st_gid);
529 	else if (strcmp(what, "size") == 0)
530 		printf("%lld", (long long)sp->st_size);
531 	else if (strcmp(what, "blocks") == 0)
532 		printf("%lld", (long long)sp->st_blocks);
533 	else if (strcmp(what, "atime") == 0)
534 		printf("%lld", (long long)sp->st_atime);
535 #if	defined(HAVE_STRUCT_STAT_ST_ATIM) || \
536 	defined(HAVE_STRUCT_STAT_ST_ATIMESPEC)
537 	else if (strcmp(what, "atime_ns") == 0)
538 #ifdef	HAVE_STRUCT_STAT_ST_ATIMESPEC
539 		printf("%lld", (long long)sp->st_atimespec.tv_nsec);
540 #else
541 		printf("%lld", (long long)sp->st_atim.tv_nsec);
542 #endif
543 #endif	/* st_atim* */
544 	else if (strcmp(what, "ctime") == 0)
545 		printf("%lld", (long long)sp->st_ctime);
546 #if	defined(HAVE_STRUCT_STAT_ST_CTIM) || \
547 	defined(HAVE_STRUCT_STAT_ST_CTIMESPEC)
548 	else if (strcmp(what, "ctime_ns") == 0)
549 #ifdef	HAVE_STRUCT_STAT_ST_CTIMESPEC
550 		printf("%lld", (long long)sp->st_ctimespec.tv_nsec);
551 #else
552 		printf("%lld", (long long)sp->st_ctim.tv_nsec);
553 #endif
554 #endif	/* st_ctim* */
555 	else if (strcmp(what, "mtime") == 0)
556 		printf("%lld", (long long)sp->st_mtime);
557 	else if (strcmp(what, "mtime_ns") == 0)
558 #if	defined(HAVE_STRUCT_STAT_ST_MTIM) || \
559 	defined(HAVE_STRUCT_STAT_ST_MTIMESPEC)
560 #ifdef	HAVE_STRUCT_STAT_ST_MTIMESPEC
561 		printf("%lld", (long long)sp->st_mtimespec.tv_nsec);
562 #else
563 		printf("%lld", (long long)sp->st_mtim.tv_nsec);
564 #endif
565 #endif	/* st_mtim* */
566 #ifdef	HAVE_STRUCT_STAT_ST_BIRTHTIME
567 	else if (strcmp(what, "birthtime") == 0)
568 		printf("%lld", (long long)sp->st_birthtime);
569 #endif	/* st_birthtime */
570 #if	defined(HAVE_STRUCT_STAT_ST_BIRTHTIM) || \
571 	defined(HAVE_STRUCT_STAT_ST_BIRTHTIMESPEC)
572 	else if (strcmp(what, "birthtime_ns") == 0)
573 #ifdef	HAVE_STRUCT_STAT_ST_BIRTHTIMESPEC
574 		printf("%lld", (long long)sp->st_birthtimespec.tv_nsec);
575 #else
576 		printf("%lld", (long long)sp->st_birthtim.tv_nsec);
577 #endif
578 #endif	/* st_birthtim{,espec} */
579 #ifdef	HAVE_CHFLAGS
580 	else if (strcmp(what, "flags") == 0)
581 		printf("%s", flags2str(chflags_flags, (long long)sp->st_flags));
582 #endif
583 	else if (strcmp(what, "major") == 0)
584 		printf("%u", (unsigned int)major(sp->st_rdev));
585 	else if (strcmp(what, "minor") == 0)
586 		printf("%u", (unsigned int)minor(sp->st_rdev));
587 	else if (strcmp(what, "type") == 0) {
588 		switch (sp->st_mode & S_IFMT) {
589 		case S_IFIFO:
590 			printf("fifo");
591 			break;
592 		case S_IFCHR:
593 			printf("char");
594 			break;
595 		case S_IFDIR:
596 			printf("dir");
597 			break;
598 		case S_IFBLK:
599 			printf("block");
600 			break;
601 		case S_IFREG:
602 			printf("regular");
603 			break;
604 		case S_IFLNK:
605 			printf("symlink");
606 			break;
607 		case S_IFSOCK:
608 			printf("socket");
609 			break;
610 		default:
611 			printf("unknown");
612 			break;
613 		}
614 	} else {
615 		printf("unknown");
616 	}
617 }
618 
619 static void
620 show_stats(stat_t *sp, char *what)
621 {
622 	const char *s = "";
623 	char *w;
624 
625 	for (w = strtok(what, ","); w != NULL; w = strtok(NULL, ",")) {
626 		printf("%s", s);
627 		show_stat(sp, w);
628 		s = ",";
629 	}
630 	printf("\n");
631 }
632 
633 static void
634 descriptor_add(int fd)
635 {
636 
637 	ndescriptors++;
638 	if (descriptors == NULL) {
639 		descriptors = malloc(sizeof(descriptors[0]) * ndescriptors);
640 	} else {
641 		descriptors = realloc(descriptors,
642 		    sizeof(descriptors[0]) * ndescriptors);
643 	}
644 	assert(descriptors != NULL);
645 	descriptors[ndescriptors - 1] = fd;
646 }
647 
648 static int
649 descriptor_get(int pos)
650 {
651 
652 	if (pos < 0 || pos >= ndescriptors) {
653 		fprintf(stderr, "invalid descriptor %d\n", pos);
654 		exit(1);
655 	}
656 
657 	return (descriptors[pos]);
658 }
659 
660 static unsigned int
661 call_syscall(struct syscall_desc *scall, char *argv[])
662 {
663 	stat_t sb;
664 #ifdef	HAVE_UTIMENSAT
665 	struct timespec times[2];
666 	int flag;
667 #endif
668 	long long flags;
669 	unsigned int i;
670 	char *endp;
671 	int name, rval;
672 	union {
673 		char *str;
674 		long long num;
675 	} args[MAX_ARGS];
676 #ifdef	HAS_NFSV4_ACL_SUPPORT
677 	int entry_id = ACL_FIRST_ENTRY;
678 	acl_t acl, newacl;
679 	acl_entry_t entry, newentry;
680 #endif
681 
682 	/*
683 	 * Verify correctness of the arguments.
684 	 */
685 	for (i = 0; i < sizeof(args)/sizeof(args[0]); i++) {
686 		if (scall->sd_args[i] == TYPE_NONE) {
687 			if (argv[i] == NULL || strcmp(argv[i], ":") == 0)
688 				break;
689 			fprintf(stderr, "too many arguments [%s]\n", argv[i]);
690 			exit(1);
691 		} else {
692 			if (argv[i] == NULL || strcmp(argv[i], ":") == 0) {
693 				if (scall->sd_args[i] & TYPE_OPTIONAL)
694 					break;
695 				fprintf(stderr, "too few arguments\n");
696 				exit(1);
697 			}
698 			if ((scall->sd_args[i] & TYPE_MASK) == TYPE_STRING) {
699 				if (strcmp(argv[i], "NULL") == 0)
700 					args[i].str = NULL;
701 				else if (strcmp(argv[i], "DEADCODE") == 0)
702 					args[i].str = (void *)0xdeadc0de;
703 				else
704 					args[i].str = argv[i];
705 			} else if ((scall->sd_args[i] & TYPE_MASK) ==
706 			    TYPE_NUMBER) {
707 				args[i].num = strtoll(argv[i], &endp, 0);
708 				if (*endp != '\0' &&
709 				    !isspace((unsigned char)*endp)) {
710 					fprintf(stderr,
711 					    "invalid argument %u, number expected [%s]\n",
712 					    i, endp);
713 					exit(1);
714 				}
715 			} else if ((scall->sd_args[i] & TYPE_MASK) ==
716 			    TYPE_DESCRIPTOR) {
717 				if (strcmp(argv[i], "AT_FDCWD") == 0) {
718 					args[i].num = AT_FDCWD;
719 				} else if (strcmp(argv[i], "BADFD") == 0) {
720 					/* In case AT_FDCWD is -1 on some systems... */
721 					if (AT_FDCWD == -1)
722 						args[i].num = -2;
723 					else
724 						args[i].num = -1;
725 				} else {
726 					int pos;
727 
728 					pos = strtoll(argv[i], &endp, 0);
729 					if (*endp != '\0' &&
730 					    !isspace((unsigned char)*endp)) {
731 						fprintf(stderr,
732 						    "invalid argument %u, number expected [%s]\n",
733 						    i, endp);
734 						exit(1);
735 					}
736 					args[i].num = descriptor_get(pos);
737 				}
738 			}
739 		}
740 	}
741 	/*
742 	 * Call the given syscall.
743 	 */
744 #define	NUM(n)	(args[(n)].num)
745 #define	STR(n)	(args[(n)].str)
746 	switch (scall->sd_action) {
747 	case ACTION_OPEN:
748 		flags = str2flags(open_flags, STR(1));
749 		if (flags & O_CREAT) {
750 			if (i == 2) {
751 				fprintf(stderr, "too few arguments\n");
752 				exit(1);
753 			}
754 			rval = open(STR(0), (int)flags, (mode_t)NUM(2));
755 		} else {
756 			if (i == 3) {
757 				fprintf(stderr, "too many arguments\n");
758 				exit(1);
759 			}
760 			rval = open(STR(0), (int)flags);
761 		}
762 		if (rval >= 0)
763 			descriptor_add(rval);
764 		break;
765 #ifdef	HAVE_OPENAT
766 	case ACTION_OPENAT:
767 		flags = str2flags(open_flags, STR(2));
768 		if (flags & O_CREAT) {
769 			if (i == 3) {
770 				fprintf(stderr, "too few arguments\n");
771 				exit(1);
772 			}
773 			rval = openat(NUM(0), STR(1), (int)flags,
774 			    (mode_t)NUM(3));
775 		} else {
776 			if (i == 4) {
777 				fprintf(stderr, "too many arguments\n");
778 				exit(1);
779 			}
780 			rval = openat(NUM(0), STR(1), (int)flags);
781 		}
782 		if (rval >= 0)
783 			descriptor_add(rval);
784 		break;
785 #endif
786 	case ACTION_CREATE:
787 		rval = open(STR(0), O_CREAT | O_EXCL, (mode_t)NUM(1));
788 		if (rval >= 0)
789 			close(rval);
790 		break;
791 	case ACTION_UNLINK:
792 		rval = unlink(STR(0));
793 		break;
794 #ifdef	HAVE_UNLINKAT
795 	case ACTION_UNLINKAT:
796 		rval = unlinkat(NUM(0), STR(1),
797 		    (int)str2flags(unlinkat_flags, STR(2)));
798 		break;
799 #endif
800 	case ACTION_MKDIR:
801 		rval = mkdir(STR(0), (mode_t)NUM(1));
802 		break;
803 #ifdef	HAVE_MKDIRAT
804 	case ACTION_MKDIRAT:
805 		rval = mkdirat(NUM(0), STR(1), (mode_t)NUM(2));
806 		break;
807 #endif
808 	case ACTION_RMDIR:
809 		rval = rmdir(STR(0));
810 		break;
811 	case ACTION_LINK:
812 		rval = link(STR(0), STR(1));
813 		break;
814 #ifdef	HAVE_LINKAT
815 	case ACTION_LINKAT:
816 		rval = linkat(NUM(0), STR(1), NUM(2), STR(3),
817 		    (int)str2flags(linkat_flags, STR(4)));
818 		break;
819 #endif
820 	case ACTION_SYMLINK:
821 		rval = symlink(STR(0), STR(1));
822 		break;
823 #ifdef	HAVE_SYMLINKAT
824 	case ACTION_SYMLINKAT:
825 		rval = symlinkat(STR(0), NUM(1), STR(2));
826 		break;
827 #endif
828 	case ACTION_RENAME:
829 		rval = rename(STR(0), STR(1));
830 		break;
831 #ifdef	HAVE_RENAMEAT
832 	case ACTION_RENAMEAT:
833 		rval = renameat(NUM(0), STR(1), NUM(2), STR(3));
834 		break;
835 #endif
836 	case ACTION_MKFIFO:
837 		rval = mkfifo(STR(0), (mode_t)NUM(1));
838 		break;
839 #ifdef	HAVE_MKFIFOAT
840 	case ACTION_MKFIFOAT:
841 		rval = mkfifoat(NUM(0), STR(1), (mode_t)NUM(2));
842 		break;
843 #endif
844 	case ACTION_MKNOD:
845 #ifdef	HAVE_MKNODAT
846 	case ACTION_MKNODAT:
847 #endif
848 	    {
849 		mode_t ntype;
850 		dev_t dev;
851 		int fa;
852 
853 		switch (scall->sd_action) {
854 		case ACTION_MKNOD:
855 			fa = 0;
856 			break;
857 #ifdef	HAVE_MKNODAT
858 		case ACTION_MKNODAT:
859 			fa = 1;
860 			break;
861 #endif
862 		default:
863 			abort();
864 		}
865 
866 		dev = makedev(NUM(fa + 3), NUM(fa + 4));
867 		if (strcmp(STR(fa + 1), "c") == 0)	/* character device */
868 			ntype = S_IFCHR;
869 		else if (strcmp(STR(fa + 1), "b") == 0)	/* block device */
870 			ntype = S_IFBLK;
871 		else if (strcmp(STR(fa + 1), "f") == 0)	/* fifo special */
872 			ntype = S_IFIFO;
873 		else if (strcmp(STR(fa + 1), "d") == 0)	/* directory */
874 			ntype = S_IFDIR;
875 		else if (strcmp(STR(fa + 1), "o") == 0)	/* regular file */
876 			ntype = S_IFREG;
877 		else {
878 			fprintf(stderr, "wrong argument 1\n");
879 			exit(1);
880 		}
881 		switch (scall->sd_action) {
882 		case ACTION_MKNOD:
883 			rval = mknod(STR(0), ntype | NUM(2), dev);
884 			break;
885 #ifdef	HAVE_MKNODAT
886 		case ACTION_MKNODAT:
887 			rval = mknodat(NUM(0), STR(1), ntype | NUM(3), dev);
888 			break;
889 #endif
890 		default:
891 			abort();
892 		}
893 		break;
894 	    }
895 	case ACTION_BIND:
896 	    {
897 		struct sockaddr_un sunx;
898 
899 		sunx.sun_family = AF_UNIX;
900 		strncpy(sunx.sun_path, STR(0), sizeof(sunx.sun_path) - 1);
901 		sunx.sun_path[sizeof(sunx.sun_path) - 1] = '\0';
902 		rval = socket(AF_UNIX, SOCK_STREAM, 0);
903 		if (rval < 0)
904 			break;
905 		rval = bind(rval, (struct sockaddr *)&sunx, sizeof(sunx));
906 		break;
907 	    }
908 #ifdef	HAVE_BINDAT
909 	case ACTION_BINDAT:
910 	    {
911 		struct sockaddr_un sunx;
912 
913 		sunx.sun_family = AF_UNIX;
914 		strncpy(sunx.sun_path, STR(1), sizeof(sunx.sun_path) - 1);
915 		sunx.sun_path[sizeof(sunx.sun_path) - 1] = '\0';
916 		rval = socket(AF_UNIX, SOCK_STREAM, 0);
917 		if (rval < 0)
918 			break;
919 		rval = bindat(NUM(0), rval, (struct sockaddr *)&sunx,
920 		    sizeof(sunx));
921 		break;
922 	    }
923 #endif
924 	case ACTION_CONNECT:
925 	    {
926 		struct sockaddr_un sunx;
927 
928 		sunx.sun_family = AF_UNIX;
929 		strncpy(sunx.sun_path, STR(0), sizeof(sunx.sun_path) - 1);
930 		sunx.sun_path[sizeof(sunx.sun_path) - 1] = '\0';
931 		rval = socket(AF_UNIX, SOCK_STREAM, 0);
932 		if (rval < 0)
933 			break;
934 		rval = connect(rval, (struct sockaddr *)&sunx, sizeof(sunx));
935 		break;
936 	    }
937 #ifdef	HAVE_CONNECTAT
938 	case ACTION_CONNECTAT:
939 	    {
940 		struct sockaddr_un sunx;
941 
942 		sunx.sun_family = AF_UNIX;
943 		strncpy(sunx.sun_path, STR(1), sizeof(sunx.sun_path) - 1);
944 		sunx.sun_path[sizeof(sunx.sun_path) - 1] = '\0';
945 		rval = socket(AF_UNIX, SOCK_STREAM, 0);
946 		if (rval < 0)
947 			break;
948 		rval = connectat(NUM(0), rval, (struct sockaddr *)&sunx,
949 		    sizeof(sunx));
950 		break;
951 	    }
952 #endif
953 	case ACTION_CHMOD:
954 		rval = chmod(STR(0), (mode_t)NUM(1));
955 		break;
956 	case ACTION_FCHMOD:
957 		rval = fchmod(NUM(0), (mode_t)NUM(1));
958 		break;
959 #ifdef	HAVE_LCHMOD
960 	case ACTION_LCHMOD:
961 		rval = lchmod(STR(0), (mode_t)NUM(1));
962 		break;
963 #endif
964 #ifdef	HAVE_FCHMODAT
965 	case ACTION_FCHMODAT:
966 		rval = fchmodat(NUM(0), STR(1), (mode_t)NUM(2),
967 		    str2flags(fchmodat_flags, STR(3)));
968 		break;
969 #endif
970 	case ACTION_CHOWN:
971 		rval = chown(STR(0), (uid_t)NUM(1), (gid_t)NUM(2));
972 		break;
973 	case ACTION_FCHOWN:
974 		rval = fchown(NUM(0), (uid_t)NUM(1), (gid_t)NUM(2));
975 		break;
976 	case ACTION_LCHOWN:
977 		rval = lchown(STR(0), (uid_t)NUM(1), (gid_t)NUM(2));
978 		break;
979 #ifdef	HAVE_FCHOWNAT
980 	case ACTION_FCHOWNAT:
981 		rval = fchownat(NUM(0), STR(1), (uid_t)NUM(2), (gid_t)NUM(3),
982 		    (int)str2flags(fchownat_flags, STR(4)));
983 		break;
984 #endif
985 #ifdef	HAVE_CHFLAGS
986 	case ACTION_CHFLAGS:
987 		rval = chflags(STR(0),
988 		    (unsigned long)str2flags(chflags_flags, STR(1)));
989 		break;
990 #endif
991 #ifdef	HAVE_FCHFLAGS
992 	case ACTION_FCHFLAGS:
993 		rval = fchflags(NUM(0),
994 		    (unsigned long)str2flags(chflags_flags, STR(1)));
995 		break;
996 #endif
997 #ifdef	HAVE_CHFLAGSAT
998 	case ACTION_CHFLAGSAT:
999 		rval = chflagsat(NUM(0), STR(1),
1000 		    (unsigned long)str2flags(chflags_flags, STR(2)),
1001 		    (int)str2flags(chflagsat_flags, STR(3)));
1002 		break;
1003 #endif
1004 #ifdef	HAVE_LCHFLAGS
1005 	case ACTION_LCHFLAGS:
1006 		rval = lchflags(STR(0),
1007 		    (unsigned long)str2flags(chflags_flags, STR(1)));
1008 		break;
1009 #endif
1010 	case ACTION_TRUNCATE:
1011 #ifdef	_USE_STAT64
1012 		rval = truncate64(STR(0), NUM(1));
1013 #else
1014 		rval = truncate(STR(0), NUM(1));
1015 #endif
1016 		break;
1017 	case ACTION_FTRUNCATE:
1018 #ifdef	_USE_STAT64
1019 		rval = ftruncate64(NUM(0), NUM(1));
1020 #else
1021 		rval = ftruncate(NUM(0), NUM(1));
1022 #endif
1023 		break;
1024 #ifdef	HAVE_POSIX_FALLOCATE
1025 	case ACTION_POSIX_FALLOCATE:
1026 		rval = posix_fallocate(NUM(0), NUM(1), NUM(2));
1027 		if (rval != 0) {
1028 			errno = rval;
1029 			rval = -1;
1030 		}
1031 		break;
1032 #endif
1033 	case ACTION_STAT:
1034 #ifdef	_USE_STAT64
1035 		rval = stat64(STR(0), &sb);
1036 #else
1037 		rval = stat(STR(0), &sb);
1038 #endif
1039 		if (rval == 0) {
1040 			show_stats(&sb, STR(1));
1041 			return (i);
1042 		}
1043 		break;
1044 	case ACTION_FSTAT:
1045 #ifdef	_USE_STAT64
1046 		rval = fstat64(NUM(0), &sb);
1047 #else
1048 		rval = fstat(NUM(0), &sb);
1049 #endif
1050 		if (rval == 0) {
1051 			show_stats(&sb, STR(1));
1052 			return (i);
1053 		}
1054 		break;
1055 	case ACTION_LSTAT:
1056 #ifdef	_USE_STAT64
1057 		rval = lstat64(STR(0), &sb);
1058 #else
1059 		rval = lstat(STR(0), &sb);
1060 #endif
1061 		if (rval == 0) {
1062 			show_stats(&sb, STR(1));
1063 			return (i);
1064 		}
1065 		break;
1066 #ifdef	HAVE_FSTATAT
1067 	case ACTION_FSTATAT:
1068 		rval = fstatat(NUM(0), STR(1), &sb,
1069 		    (int)str2flags(fstatat_flags, STR(2)));
1070 		if (rval == 0) {
1071 			show_stats(&sb, STR(3));
1072 			return (i);
1073 		}
1074 		break;
1075 #endif
1076 	case ACTION_PATHCONF:
1077 	case ACTION_FPATHCONF:
1078 #ifdef	HAVE_LPATHCONF
1079 	case ACTION_LPATHCONF:
1080 #endif
1081 	    {
1082 		long lrval;
1083 
1084 		name = str2name(pathconf_names, STR(1));
1085 		if (name == -1) {
1086 			fprintf(stderr, "unknown name %s", STR(1));
1087 			exit(1);
1088 		}
1089 		errno = 0;
1090 		switch (scall->sd_action) {
1091 		case ACTION_PATHCONF:
1092 			lrval = pathconf(STR(0), name);
1093 			break;
1094 		case ACTION_FPATHCONF:
1095 			lrval = fpathconf(NUM(0), name);
1096 			break;
1097 #ifdef	HAVE_LPATHCONF
1098 		case ACTION_LPATHCONF:
1099 			lrval = lpathconf(STR(0), name);
1100 			break;
1101 #endif
1102 		default:
1103 			abort();
1104 		}
1105 		if (lrval == -1 && errno == 0) {
1106 			printf("unlimited\n");
1107 			return (i);
1108 		} else if (lrval >= 0) {
1109 			printf("%ld\n", lrval);
1110 			return (i);
1111 		}
1112 		rval = -1;
1113 		break;
1114 	    }
1115 #ifdef	HAS_NFSV4_ACL_SUPPORT
1116 	case ACTION_PREPENDACL:
1117 		rval = -1;
1118 
1119 		acl = acl_get_file(STR(0), ACL_TYPE_NFS4);
1120 		if (acl == NULL)
1121 			break;
1122 
1123 		newacl = acl_from_text(STR(1));
1124 		if (acl == NULL)
1125 			break;
1126 
1127 		while (acl_get_entry(newacl, entry_id, &newentry) == 1) {
1128 			entry_id = ACL_NEXT_ENTRY;
1129 
1130 			if (acl_create_entry_np(&acl, &entry, 0))
1131 				break;
1132 
1133 			if (acl_copy_entry(entry, newentry))
1134 				break;
1135 		}
1136 
1137 		rval = acl_set_file(STR(0), ACL_TYPE_NFS4, acl);
1138 		break;
1139 	case ACTION_READACL:
1140 		acl = acl_get_file(STR(0), ACL_TYPE_NFS4);
1141 		if (acl == NULL)
1142 			rval = -1;
1143 		else
1144 			rval = 0;
1145 		break;
1146 #endif
1147 	case ACTION_WRITE:
1148 		rval = write(NUM(0), STR(1), strlen(STR(1)));
1149 		break;
1150 #ifdef	HAVE_UTIMENSAT
1151 	case ACTION_UTIMENSAT:
1152 		times[0].tv_sec = NUM(2);
1153 		if (strcmp(STR(3), "UTIME_NOW") == 0)
1154 			times[0].tv_nsec = UTIME_NOW;
1155 		else if (strcmp(STR(3), "UTIME_OMIT") == 0)
1156 			times[0].tv_nsec = UTIME_OMIT;
1157 		else
1158 			times[0].tv_nsec = strtol(STR(3), NULL, 10);
1159 		times[1].tv_sec = NUM(4);
1160 		if (strcmp(STR(5), "UTIME_NOW") == 0)
1161 			times[1].tv_nsec = UTIME_NOW;
1162 		else if (strcmp(STR(5), "UTIME_OMIT") == 0)
1163 			times[1].tv_nsec = UTIME_OMIT;
1164 		else
1165 			times[1].tv_nsec = strtol(STR(5), NULL, 10);
1166 		if (strcmp(STR(6), "AT_SYMLINK_NOFOLLOW") == 0)
1167 			flag = AT_SYMLINK_NOFOLLOW;
1168 		else
1169 			flag = strtol(STR(6), NULL, 10);
1170 		rval = utimensat(NUM(0), STR(1), times, flag);
1171 		break;
1172 #endif
1173 	default:
1174 		fprintf(stderr, "unsupported syscall\n");
1175 		exit(1);
1176 	}
1177 #undef STR
1178 #undef NUM
1179 	if (rval < 0) {
1180 		const char *serrno;
1181 
1182 		serrno = err2str(errno);
1183 		fprintf(stderr, "%s returned %d\n", scall->sd_name, rval);
1184 		printf("%s\n", serrno);
1185 		exit(1);
1186 	}
1187 	printf("0\n");
1188 	return (i);
1189 }
1190 
1191 static void
1192 set_gids(char *gids)
1193 {
1194 	gid_t *gidset;
1195 	long ngroups;
1196 	char *g, *endp;
1197 	unsigned i;
1198 
1199 	ngroups = sysconf(_SC_NGROUPS_MAX);
1200 	assert(ngroups > 0);
1201 	gidset = malloc(sizeof(*gidset) * ngroups);
1202 	assert(gidset != NULL);
1203 	for (i = 0, g = strtok(gids, ","); g != NULL;
1204 	    g = strtok(NULL, ","), i++) {
1205 		if ((long)i >= ngroups) {
1206 			fprintf(stderr, "too many gids\n");
1207 			exit(1);
1208 		}
1209 		gidset[i] = strtol(g, &endp, 0);
1210 		if (*endp != '\0' && !isspace((unsigned char)*endp)) {
1211 			fprintf(stderr, "invalid gid '%s' - number expected\n",
1212 			    g);
1213 			exit(1);
1214 		}
1215 	}
1216 	if (setgroups(i, gidset) < 0) {
1217 		fprintf(stderr, "cannot change groups: %s\n", strerror(errno));
1218 		exit(1);
1219 	}
1220 	if (setegid(gidset[0]) < 0) {
1221 		fprintf(stderr, "cannot change effective gid: %s\n",
1222 		    strerror(errno));
1223 		exit(1);
1224 	}
1225 	free(gidset);
1226 }
1227 
1228 int
1229 main(int argc, char *argv[])
1230 {
1231 	struct syscall_desc *scall;
1232 	unsigned int n;
1233 	char *gids, *endp;
1234 	int uid, umsk, ch;
1235 
1236 	uid = -1;
1237 	gids = NULL;
1238 	umsk = 0;
1239 
1240 	while ((ch = getopt(argc, argv, "g:u:U:")) != -1) {
1241 		switch(ch) {
1242 		case 'g':
1243 			gids = optarg;
1244 			break;
1245 		case 'u':
1246 			uid = (int)strtol(optarg, &endp, 0);
1247 			if (*endp != '\0' && !isspace((unsigned char)*endp)) {
1248 				fprintf(stderr, "invalid uid '%s' - number "
1249 				    "expected\n", optarg);
1250 				exit(1);
1251 			}
1252 			break;
1253 		case 'U':
1254 			umsk = (int)strtol(optarg, &endp, 0);
1255 			if (*endp != '\0' && !isspace((unsigned char)*endp)) {
1256 				fprintf(stderr, "invalid umask '%s' - number "
1257 				    "expected\n", optarg);
1258 				exit(1);
1259 			}
1260 			break;
1261 		default:
1262 			usage();
1263 		}
1264 	}
1265 	argc -= optind;
1266 	argv += optind;
1267 
1268 	if (argc < 1) {
1269 		fprintf(stderr, "too few arguments\n");
1270 		usage();
1271 	}
1272 
1273 	if (gids != NULL) {
1274 		fprintf(stderr, "changing groups to %s\n", gids);
1275 		set_gids(gids);
1276 	}
1277 	if (uid != -1) {
1278 		fprintf(stderr, "changing uid to %d\n", uid);
1279 		if (setuid(uid) < 0) {
1280 			fprintf(stderr, "cannot change uid: %s\n",
1281 			    strerror(errno));
1282 			exit(1);
1283 		}
1284 	}
1285 
1286 	/* Change umask to requested value or to 0, if not requested. */
1287 	umask(umsk);
1288 
1289 	for (;;) {
1290 		scall = find_syscall(argv[0]);
1291 		if (scall == NULL) {
1292 			fprintf(stderr, "syscall '%s' not supported\n",
1293 			    argv[0]);
1294 			exit(1);
1295 		}
1296 		argc++;
1297 		argv++;
1298 		n = call_syscall(scall, argv);
1299 		argc += n;
1300 		argv += n;
1301 		if (argv[0] == NULL)
1302 			break;
1303 		argc++;
1304 		argv++;
1305 	}
1306 
1307 	exit(0);
1308 }
1309 
1310 static const char *
1311 err2str(int error)
1312 {
1313 	static char errnum[8];
1314 
1315 	switch (error) {
1316 #ifdef	EPERM
1317 	case EPERM:
1318 		return ("EPERM");
1319 #endif
1320 #ifdef	ENOENT
1321 	case ENOENT:
1322 		return ("ENOENT");
1323 #endif
1324 #ifdef	ESRCH
1325 	case ESRCH:
1326 		return ("ESRCH");
1327 #endif
1328 #ifdef	EINTR
1329 	case EINTR:
1330 		return ("EINTR");
1331 #endif
1332 #ifdef	EIO
1333 	case EIO:
1334 		return ("EIO");
1335 #endif
1336 #ifdef	ENXIO
1337 	case ENXIO:
1338 		return ("ENXIO");
1339 #endif
1340 #ifdef	E2BIG
1341 	case E2BIG:
1342 		return ("E2BIG");
1343 #endif
1344 #ifdef	ENOEXEC
1345 	case ENOEXEC:
1346 		return ("ENOEXEC");
1347 #endif
1348 #ifdef	EBADF
1349 	case EBADF:
1350 		return ("EBADF");
1351 #endif
1352 #ifdef	ECHILD
1353 	case ECHILD:
1354 		return ("ECHILD");
1355 #endif
1356 #ifdef	EDEADLK
1357 	case EDEADLK:
1358 		return ("EDEADLK");
1359 #endif
1360 #ifdef	ENOMEM
1361 	case ENOMEM:
1362 		return ("ENOMEM");
1363 #endif
1364 #ifdef	EACCES
1365 	case EACCES:
1366 		return ("EACCES");
1367 #endif
1368 #ifdef	EFAULT
1369 	case EFAULT:
1370 		return ("EFAULT");
1371 #endif
1372 #ifdef	ENOTBLK
1373 	case ENOTBLK:
1374 		return ("ENOTBLK");
1375 #endif
1376 #ifdef	EBUSY
1377 	case EBUSY:
1378 		return ("EBUSY");
1379 #endif
1380 #ifdef	EEXIST
1381 	case EEXIST:
1382 		return ("EEXIST");
1383 #endif
1384 #ifdef	EXDEV
1385 	case EXDEV:
1386 		return ("EXDEV");
1387 #endif
1388 #ifdef	ENODEV
1389 	case ENODEV:
1390 		return ("ENODEV");
1391 #endif
1392 #ifdef	ENOTDIR
1393 	case ENOTDIR:
1394 		return ("ENOTDIR");
1395 #endif
1396 #ifdef	EISDIR
1397 	case EISDIR:
1398 		return ("EISDIR");
1399 #endif
1400 #ifdef	EINVAL
1401 	case EINVAL:
1402 		return ("EINVAL");
1403 #endif
1404 #ifdef	ENFILE
1405 	case ENFILE:
1406 		return ("ENFILE");
1407 #endif
1408 #ifdef	EMFILE
1409 	case EMFILE:
1410 		return ("EMFILE");
1411 #endif
1412 #ifdef	ENOTTY
1413 	case ENOTTY:
1414 		return ("ENOTTY");
1415 #endif
1416 #ifdef	ETXTBSY
1417 	case ETXTBSY:
1418 		return ("ETXTBSY");
1419 #endif
1420 #ifdef	EFBIG
1421 	case EFBIG:
1422 		return ("EFBIG");
1423 #endif
1424 #ifdef	ENOSPC
1425 	case ENOSPC:
1426 		return ("ENOSPC");
1427 #endif
1428 #ifdef	ESPIPE
1429 	case ESPIPE:
1430 		return ("ESPIPE");
1431 #endif
1432 #ifdef	EROFS
1433 	case EROFS:
1434 		return ("EROFS");
1435 #endif
1436 #ifdef	EMLINK
1437 	case EMLINK:
1438 		return ("EMLINK");
1439 #endif
1440 #ifdef	EPIPE
1441 	case EPIPE:
1442 		return ("EPIPE");
1443 #endif
1444 #ifdef	EDOM
1445 	case EDOM:
1446 		return ("EDOM");
1447 #endif
1448 #ifdef	ERANGE
1449 	case ERANGE:
1450 		return ("ERANGE");
1451 #endif
1452 #ifdef	EAGAIN
1453 	case EAGAIN:
1454 		return ("EAGAIN");
1455 #endif
1456 #ifdef	EINPROGRESS
1457 	case EINPROGRESS:
1458 		return ("EINPROGRESS");
1459 #endif
1460 #ifdef	EALREADY
1461 	case EALREADY:
1462 		return ("EALREADY");
1463 #endif
1464 #ifdef	ENOTSOCK
1465 	case ENOTSOCK:
1466 		return ("ENOTSOCK");
1467 #endif
1468 #ifdef	EDESTADDRREQ
1469 	case EDESTADDRREQ:
1470 		return ("EDESTADDRREQ");
1471 #endif
1472 #ifdef	EMSGSIZE
1473 	case EMSGSIZE:
1474 		return ("EMSGSIZE");
1475 #endif
1476 #ifdef	EPROTOTYPE
1477 	case EPROTOTYPE:
1478 		return ("EPROTOTYPE");
1479 #endif
1480 #ifdef	ENOPROTOOPT
1481 	case ENOPROTOOPT:
1482 		return ("ENOPROTOOPT");
1483 #endif
1484 #ifdef	EPROTONOSUPPORT
1485 	case EPROTONOSUPPORT:
1486 		return ("EPROTONOSUPPORT");
1487 #endif
1488 #ifdef	ESOCKTNOSUPPORT
1489 	case ESOCKTNOSUPPORT:
1490 		return ("ESOCKTNOSUPPORT");
1491 #endif
1492 #ifdef	EOPNOTSUPP
1493 	case EOPNOTSUPP:
1494 		return ("EOPNOTSUPP");
1495 #endif
1496 #ifdef	EPFNOSUPPORT
1497 	case EPFNOSUPPORT:
1498 		return ("EPFNOSUPPORT");
1499 #endif
1500 #ifdef	EAFNOSUPPORT
1501 	case EAFNOSUPPORT:
1502 		return ("EAFNOSUPPORT");
1503 #endif
1504 #ifdef	EADDRINUSE
1505 	case EADDRINUSE:
1506 		return ("EADDRINUSE");
1507 #endif
1508 #ifdef	EADDRNOTAVAIL
1509 	case EADDRNOTAVAIL:
1510 		return ("EADDRNOTAVAIL");
1511 #endif
1512 #ifdef	ENETDOWN
1513 	case ENETDOWN:
1514 		return ("ENETDOWN");
1515 #endif
1516 #ifdef	ENETUNREACH
1517 	case ENETUNREACH:
1518 		return ("ENETUNREACH");
1519 #endif
1520 #ifdef	ENETRESET
1521 	case ENETRESET:
1522 		return ("ENETRESET");
1523 #endif
1524 #ifdef	ECONNABORTED
1525 	case ECONNABORTED:
1526 		return ("ECONNABORTED");
1527 #endif
1528 #ifdef	ECONNRESET
1529 	case ECONNRESET:
1530 		return ("ECONNRESET");
1531 #endif
1532 #ifdef	ENOBUFS
1533 	case ENOBUFS:
1534 		return ("ENOBUFS");
1535 #endif
1536 #ifdef	EISCONN
1537 	case EISCONN:
1538 		return ("EISCONN");
1539 #endif
1540 #ifdef	ENOTCONN
1541 	case ENOTCONN:
1542 		return ("ENOTCONN");
1543 #endif
1544 #ifdef	ESHUTDOWN
1545 	case ESHUTDOWN:
1546 		return ("ESHUTDOWN");
1547 #endif
1548 #ifdef	ETOOMANYREFS
1549 	case ETOOMANYREFS:
1550 		return ("ETOOMANYREFS");
1551 #endif
1552 #ifdef	ETIMEDOUT
1553 	case ETIMEDOUT:
1554 		return ("ETIMEDOUT");
1555 #endif
1556 #ifdef	ECONNREFUSED
1557 	case ECONNREFUSED:
1558 		return ("ECONNREFUSED");
1559 #endif
1560 #ifdef	ELOOP
1561 	case ELOOP:
1562 		return ("ELOOP");
1563 #endif
1564 #ifdef	ENAMETOOLONG
1565 	case ENAMETOOLONG:
1566 		return ("ENAMETOOLONG");
1567 #endif
1568 #ifdef	EHOSTDOWN
1569 	case EHOSTDOWN:
1570 		return ("EHOSTDOWN");
1571 #endif
1572 #ifdef	EHOSTUNREACH
1573 	case EHOSTUNREACH:
1574 		return ("EHOSTUNREACH");
1575 #endif
1576 #ifdef	ENOTEMPTY
1577 	case ENOTEMPTY:
1578 		return ("ENOTEMPTY");
1579 #endif
1580 #ifdef	EPROCLIM
1581 	case EPROCLIM:
1582 		return ("EPROCLIM");
1583 #endif
1584 #ifdef	EUSERS
1585 	case EUSERS:
1586 		return ("EUSERS");
1587 #endif
1588 #ifdef	EDQUOT
1589 	case EDQUOT:
1590 		return ("EDQUOT");
1591 #endif
1592 #ifdef	ESTALE
1593 	case ESTALE:
1594 		return ("ESTALE");
1595 #endif
1596 #ifdef	EREMOTE
1597 	case EREMOTE:
1598 		return ("EREMOTE");
1599 #endif
1600 #ifdef	EBADRPC
1601 	case EBADRPC:
1602 		return ("EBADRPC");
1603 #endif
1604 #ifdef	ERPCMISMATCH
1605 	case ERPCMISMATCH:
1606 		return ("ERPCMISMATCH");
1607 #endif
1608 #ifdef	EPROGUNAVAIL
1609 	case EPROGUNAVAIL:
1610 		return ("EPROGUNAVAIL");
1611 #endif
1612 #ifdef	EPROGMISMATCH
1613 	case EPROGMISMATCH:
1614 		return ("EPROGMISMATCH");
1615 #endif
1616 #ifdef	EPROCUNAVAIL
1617 	case EPROCUNAVAIL:
1618 		return ("EPROCUNAVAIL");
1619 #endif
1620 #ifdef	ENOLCK
1621 	case ENOLCK:
1622 		return ("ENOLCK");
1623 #endif
1624 #ifdef	ENOSYS
1625 	case ENOSYS:
1626 		return ("ENOSYS");
1627 #endif
1628 #ifdef	EFTYPE
1629 	case EFTYPE:
1630 		return ("EFTYPE");
1631 #endif
1632 #ifdef	EAUTH
1633 	case EAUTH:
1634 		return ("EAUTH");
1635 #endif
1636 #ifdef	ENEEDAUTH
1637 	case ENEEDAUTH:
1638 		return ("ENEEDAUTH");
1639 #endif
1640 #ifdef	EIDRM
1641 	case EIDRM:
1642 		return ("EIDRM");
1643 #endif
1644 #ifdef	ENOMSG
1645 	case ENOMSG:
1646 		return ("ENOMSG");
1647 #endif
1648 #ifdef	EOVERFLOW
1649 	case EOVERFLOW:
1650 		return ("EOVERFLOW");
1651 #endif
1652 #ifdef	ECANCELED
1653 	case ECANCELED:
1654 		return ("ECANCELED");
1655 #endif
1656 #ifdef	EILSEQ
1657 	case EILSEQ:
1658 		return ("EILSEQ");
1659 #endif
1660 #ifdef	ENOATTR
1661 	case ENOATTR:
1662 		return ("ENOATTR");
1663 #endif
1664 #ifdef	EDOOFUS
1665 	case EDOOFUS:
1666 		return ("EDOOFUS");
1667 #endif
1668 #ifdef	EBADMSG
1669 	case EBADMSG:
1670 		return ("EBADMSG");
1671 #endif
1672 #ifdef	EMULTIHOP
1673 	case EMULTIHOP:
1674 		return ("EMULTIHOP");
1675 #endif
1676 #ifdef	ENOLINK
1677 	case ENOLINK:
1678 		return ("ENOLINK");
1679 #endif
1680 #ifdef	EPROTO
1681 	case EPROTO:
1682 		return ("EPROTO");
1683 #endif
1684 	default:
1685 		snprintf(errnum, sizeof(errnum), "%d", error);
1686 		return (errnum);
1687 	}
1688 }
1689