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
58typedef	struct stat64	stat_t;
59#else
60typedef	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
67enum 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
166struct syscall_desc {
167	const char	*sd_name;
168	enum action	 sd_action;
169	int		 sd_args[MAX_ARGS];
170};
171
172static 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
275struct flag {
276	long long	 f_flag;
277	const char	*f_str;
278};
279
280static 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
333static 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
369static struct flag unlinkat_flags[] = {
370	{ AT_REMOVEDIR, "AT_REMOVEDIR" },
371	{ 0, NULL }
372};
373#endif
374
375#ifdef	HAVE_LINKAT
376static 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
385static struct flag chflagsat_flags[] = {
386	{ AT_SYMLINK_NOFOLLOW, "AT_SYMLINK_NOFOLLOW" },
387	{ 0, NULL }
388};
389#endif
390
391#ifdef	HAVE_FCHMODAT
392static struct flag fchmodat_flags[] = {
393	{ AT_SYMLINK_NOFOLLOW, "AT_SYMLINK_NOFOLLOW" },
394	{ 0, NULL }
395};
396#endif
397
398#ifdef	HAVE_FCHOWNAT
399static struct flag fchownat_flags[] = {
400	{ AT_SYMLINK_NOFOLLOW, "AT_SYMLINK_NOFOLLOW" },
401	{ 0, NULL }
402};
403#endif
404
405#ifdef	HAVE_FSTATAT
406static struct flag fstatat_flags[] = {
407	{ AT_SYMLINK_NOFOLLOW, "AT_SYMLINK_NOFOLLOW" },
408	{ 0, NULL }
409};
410#endif
411
412struct name {
413	int		 n_name;
414	const char	*n_str;
415};
416
417static 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
433static const char *err2str(int error);
434
435static int *descriptors;
436static int ndescriptors;
437
438static void
439usage(void)
440{
441
442	fprintf(stderr, "usage: pjdfstest [-U umask] [-u uid] [-g gid1[,gid2[...]]] syscall args ...\n");
443	exit(1);
444}
445
446static long long
447str2flags(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
471static char *
472flags2str(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
491static int
492str2name(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
503static struct syscall_desc *
504find_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
515static void
516show_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
619static void
620show_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
633static void
634descriptor_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
648static int
649descriptor_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
660static unsigned int
661call_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
1191static void
1192set_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
1228int
1229main(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
1310static const char *
1311err2str(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