1271294Sngie/*-
2271294Sngie * Copyright (c) 2006-2010 Pawel Jakub Dawidek <pjd@FreeBSD.org>
3271294Sngie * All rights reserved.
4271294Sngie *
5271294Sngie * Redistribution and use in source and binary forms, with or without
6271294Sngie * modification, are permitted provided that the following conditions
7271294Sngie * are met:
8271294Sngie * 1. Redistributions of source code must retain the above copyright
9271294Sngie *    notice, this list of conditions and the following disclaimer.
10271294Sngie * 2. Redistributions in binary form must reproduce the above copyright
11271294Sngie *    notice, this list of conditions and the following disclaimer in the
12271294Sngie *    documentation and/or other materials provided with the distribution.
13271294Sngie *
14271294Sngie * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
15271294Sngie * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16271294Sngie * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17271294Sngie * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
18271294Sngie * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19271294Sngie * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20271294Sngie * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21271294Sngie * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22271294Sngie * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23271294Sngie * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24271294Sngie * SUCH DAMAGE.
25271294Sngie *
26271294Sngie * $FreeBSD$
27271294Sngie */
28271294Sngie
29271294Sngie#include <sys/param.h>
30271294Sngie#include <sys/types.h>
31271294Sngie#include <sys/stat.h>
32271294Sngie#include <sys/socket.h>
33271294Sngie#include <sys/un.h>
34271294Sngie#ifndef makedev
35271294Sngie#include <sys/mkdev.h>
36271294Sngie#endif
37271294Sngie
38271294Sngie#include <assert.h>
39271294Sngie#include <ctype.h>
40271294Sngie#include <errno.h>
41271294Sngie#include <fcntl.h>
42271294Sngie#include <grp.h>
43271294Sngie#include <stdio.h>
44271294Sngie#include <stdlib.h>
45271294Sngie#include <string.h>
46271294Sngie#include <unistd.h>
47271294Sngie
48271294Sngie#ifndef HAS_TRUNCATE64
49271294Sngie#define	truncate64	truncate
50271294Sngie#define	ftruncate64	ftruncate
51271294Sngie#endif
52271294Sngie#ifndef HAS_STAT64
53271294Sngie#define	stat64	stat
54271294Sngie#define	fstat64	fstat
55271294Sngie#define	lstat64	lstat
56271294Sngie#endif
57271294Sngie#ifdef HAS_FREEBSD_ACL
58271294Sngie#include <sys/acl.h>
59271294Sngie#endif
60271294Sngie
61271294Sngie#ifndef ALLPERMS
62271294Sngie#define	ALLPERMS	(S_ISUID|S_ISGID|S_ISVTX|S_IRWXU|S_IRWXG|S_IRWXO)
63271294Sngie#endif
64271294Sngie
65271294Sngieenum action {
66271294Sngie	ACTION_OPEN,
67271294Sngie	ACTION_OPENAT,
68271294Sngie	ACTION_CREATE,
69271294Sngie	ACTION_UNLINK,
70271294Sngie	ACTION_UNLINKAT,
71271294Sngie	ACTION_MKDIR,
72271294Sngie	ACTION_MKDIRAT,
73271294Sngie	ACTION_RMDIR,
74271294Sngie	ACTION_LINK,
75271294Sngie	ACTION_LINKAT,
76271294Sngie	ACTION_SYMLINK,
77271294Sngie	ACTION_SYMLINKAT,
78271294Sngie	ACTION_RENAME,
79271294Sngie	ACTION_RENAMEAT,
80271294Sngie	ACTION_MKFIFO,
81271294Sngie	ACTION_MKFIFOAT,
82271294Sngie	ACTION_MKNOD,
83271294Sngie	ACTION_MKNODAT,
84271294Sngie	ACTION_BIND,
85271294Sngie#ifdef HAS_BINDAT
86271294Sngie	ACTION_BINDAT,
87271294Sngie#endif
88271294Sngie	ACTION_CONNECT,
89271294Sngie#ifdef HAS_CONNECTAT
90271294Sngie	ACTION_CONNECTAT,
91271294Sngie#endif
92271294Sngie	ACTION_CHMOD,
93271294Sngie	ACTION_FCHMOD,
94271294Sngie#ifdef HAS_LCHMOD
95271294Sngie	ACTION_LCHMOD,
96271294Sngie#endif
97271294Sngie	ACTION_FCHMODAT,
98271294Sngie	ACTION_CHOWN,
99271294Sngie	ACTION_FCHOWN,
100271294Sngie	ACTION_LCHOWN,
101271294Sngie	ACTION_FCHOWNAT,
102271294Sngie#ifdef HAS_CHFLAGS
103271294Sngie	ACTION_CHFLAGS,
104271294Sngie#endif
105271294Sngie#ifdef HAS_FCHFLAGS
106271294Sngie	ACTION_FCHFLAGS,
107271294Sngie#endif
108271294Sngie#ifdef HAS_CHFLAGSAT
109271294Sngie	ACTION_CHFLAGSAT,
110271294Sngie#endif
111271294Sngie#ifdef HAS_LCHFLAGS
112271294Sngie	ACTION_LCHFLAGS,
113271294Sngie#endif
114271294Sngie	ACTION_TRUNCATE,
115271294Sngie	ACTION_FTRUNCATE,
116271294Sngie	ACTION_STAT,
117271294Sngie	ACTION_FSTAT,
118271294Sngie	ACTION_LSTAT,
119271294Sngie	ACTION_FSTATAT,
120271294Sngie	ACTION_PATHCONF,
121271294Sngie	ACTION_FPATHCONF,
122271294Sngie#ifdef HAS_LPATHCONF
123271294Sngie	ACTION_LPATHCONF,
124271294Sngie#endif
125271294Sngie#ifdef HAS_FREEBSD_ACL
126271294Sngie	ACTION_PREPENDACL,
127271294Sngie	ACTION_READACL,
128271294Sngie#endif
129271294Sngie	ACTION_WRITE,
130271294Sngie};
131271294Sngie
132271294Sngie#define	TYPE_NONE	0x0000
133271294Sngie#define	TYPE_STRING	0x0001
134271294Sngie#define	TYPE_NUMBER	0x0002
135271294Sngie#define	TYPE_DESCRIPTOR	0x0003
136271294Sngie#define	TYPE_MASK	0x000f
137271294Sngie
138271294Sngie#define	TYPE_OPTIONAL	0x0100
139271294Sngie
140271294Sngie#define	MAX_ARGS	8
141271294Sngie
142271294Sngiestruct syscall_desc {
143271294Sngie	const char	*sd_name;
144271294Sngie	enum action	 sd_action;
145271294Sngie	int		 sd_args[MAX_ARGS];
146271294Sngie};
147271294Sngie
148271294Sngiestatic struct syscall_desc syscalls[] = {
149271294Sngie	{ "open", ACTION_OPEN, { TYPE_STRING, TYPE_STRING, TYPE_NUMBER | TYPE_OPTIONAL, TYPE_NONE } },
150271294Sngie	{ "openat", ACTION_OPENAT, { TYPE_DESCRIPTOR, TYPE_STRING, TYPE_STRING, TYPE_NUMBER | TYPE_OPTIONAL, TYPE_NONE } },
151271294Sngie	{ "create", ACTION_CREATE, { TYPE_STRING, TYPE_NUMBER, TYPE_NONE } },
152271294Sngie	{ "unlink", ACTION_UNLINK, { TYPE_STRING, TYPE_NONE } },
153271294Sngie	{ "unlinkat", ACTION_UNLINKAT, { TYPE_DESCRIPTOR, TYPE_STRING, TYPE_STRING, TYPE_NONE } },
154271294Sngie	{ "mkdir", ACTION_MKDIR, { TYPE_STRING, TYPE_NUMBER, TYPE_NONE } },
155271294Sngie	{ "mkdirat", ACTION_MKDIRAT, { TYPE_DESCRIPTOR, TYPE_STRING, TYPE_NUMBER, TYPE_NONE } },
156271294Sngie	{ "rmdir", ACTION_RMDIR, { TYPE_STRING, TYPE_NONE } },
157271294Sngie	{ "link", ACTION_LINK, { TYPE_STRING, TYPE_STRING, TYPE_NONE } },
158271294Sngie	{ "linkat", ACTION_LINKAT, { TYPE_DESCRIPTOR, TYPE_STRING, TYPE_DESCRIPTOR, TYPE_STRING, TYPE_STRING, TYPE_NONE } },
159271294Sngie	{ "symlink", ACTION_SYMLINK, { TYPE_STRING, TYPE_STRING, TYPE_NONE } },
160271294Sngie	{ "symlinkat", ACTION_SYMLINKAT, { TYPE_STRING, TYPE_DESCRIPTOR, TYPE_STRING, TYPE_NONE } },
161271294Sngie	{ "rename", ACTION_RENAME, { TYPE_STRING, TYPE_STRING, TYPE_NONE } },
162271294Sngie	{ "renameat", ACTION_RENAMEAT, { TYPE_DESCRIPTOR, TYPE_STRING, TYPE_DESCRIPTOR, TYPE_STRING, TYPE_NONE } },
163271294Sngie	{ "mkfifo", ACTION_MKFIFO, { TYPE_STRING, TYPE_NUMBER, TYPE_NONE } },
164271294Sngie	{ "mkfifoat", ACTION_MKFIFOAT, { TYPE_DESCRIPTOR, TYPE_STRING, TYPE_NUMBER, TYPE_NONE } },
165271294Sngie	{ "mknod", ACTION_MKNOD, { TYPE_STRING, TYPE_STRING, TYPE_NUMBER, TYPE_NUMBER, TYPE_NUMBER, TYPE_NONE} },
166271294Sngie	{ "mknodat", ACTION_MKNODAT, { TYPE_DESCRIPTOR, TYPE_STRING, TYPE_STRING, TYPE_NUMBER, TYPE_NUMBER, TYPE_NUMBER, TYPE_NONE} },
167271294Sngie	{ "bind", ACTION_BIND, { TYPE_STRING, TYPE_NONE } },
168271294Sngie#ifdef HAS_BINDAT
169271294Sngie	{ "bindat", ACTION_BINDAT, { TYPE_DESCRIPTOR, TYPE_STRING, TYPE_NONE } },
170271294Sngie#endif
171271294Sngie	{ "connect", ACTION_CONNECT, { TYPE_STRING, TYPE_NONE } },
172271294Sngie#ifdef HAS_CONNECTAT
173271294Sngie	{ "connectat", ACTION_CONNECTAT, { TYPE_DESCRIPTOR, TYPE_STRING, TYPE_NONE } },
174271294Sngie#endif
175271294Sngie	{ "chmod", ACTION_CHMOD, { TYPE_STRING, TYPE_NUMBER, TYPE_NONE } },
176271294Sngie	{ "fchmod", ACTION_FCHMOD, { TYPE_DESCRIPTOR, TYPE_NUMBER, TYPE_NONE } },
177271294Sngie#ifdef HAS_LCHMOD
178271294Sngie	{ "lchmod", ACTION_LCHMOD, { TYPE_STRING, TYPE_NUMBER, TYPE_NONE } },
179271294Sngie#endif
180271294Sngie	{ "fchmodat", ACTION_FCHMODAT, { TYPE_DESCRIPTOR, TYPE_STRING, TYPE_NUMBER, TYPE_STRING, TYPE_NONE } },
181271294Sngie	{ "chown", ACTION_CHOWN, { TYPE_STRING, TYPE_NUMBER, TYPE_NUMBER, TYPE_NONE } },
182271294Sngie	{ "fchown", ACTION_FCHOWN, { TYPE_DESCRIPTOR, TYPE_NUMBER, TYPE_NUMBER, TYPE_NONE } },
183271294Sngie	{ "lchown", ACTION_LCHOWN, { TYPE_STRING, TYPE_NUMBER, TYPE_NUMBER, TYPE_NONE } },
184271294Sngie	{ "fchownat", ACTION_FCHOWNAT, { TYPE_DESCRIPTOR, TYPE_STRING, TYPE_NUMBER, TYPE_NUMBER, TYPE_STRING, TYPE_NONE } },
185271294Sngie#ifdef HAS_CHFLAGS
186271294Sngie	{ "chflags", ACTION_CHFLAGS, { TYPE_STRING, TYPE_STRING, TYPE_NONE } },
187271294Sngie#endif
188271294Sngie#ifdef HAS_FCHFLAGS
189271294Sngie	{ "fchflags", ACTION_FCHFLAGS, { TYPE_DESCRIPTOR, TYPE_STRING, TYPE_NONE } },
190271294Sngie#endif
191271294Sngie#ifdef HAS_CHFLAGSAT
192271294Sngie	{ "chflagsat", ACTION_CHFLAGSAT, { TYPE_DESCRIPTOR, TYPE_STRING, TYPE_STRING, TYPE_STRING, TYPE_NONE } },
193271294Sngie#endif
194271294Sngie#ifdef HAS_LCHFLAGS
195271294Sngie	{ "lchflags", ACTION_LCHFLAGS, { TYPE_STRING, TYPE_STRING, TYPE_NONE } },
196271294Sngie#endif
197271294Sngie	{ "truncate", ACTION_TRUNCATE, { TYPE_STRING, TYPE_NUMBER, TYPE_NONE } },
198271294Sngie	{ "ftruncate", ACTION_FTRUNCATE, { TYPE_DESCRIPTOR, TYPE_NUMBER, TYPE_NONE } },
199271294Sngie	{ "stat", ACTION_STAT, { TYPE_STRING, TYPE_STRING, TYPE_NONE } },
200271294Sngie	{ "fstat", ACTION_FSTAT, { TYPE_DESCRIPTOR, TYPE_STRING, TYPE_NONE } },
201271294Sngie	{ "lstat", ACTION_LSTAT, { TYPE_STRING, TYPE_STRING, TYPE_NONE } },
202271294Sngie	{ "fstatat", ACTION_FSTATAT, { TYPE_DESCRIPTOR, TYPE_STRING, TYPE_STRING, TYPE_STRING, TYPE_NONE } },
203271294Sngie	{ "pathconf", ACTION_PATHCONF, { TYPE_STRING, TYPE_STRING, TYPE_NONE } },
204271294Sngie	{ "fpathconf", ACTION_FPATHCONF, { TYPE_DESCRIPTOR, TYPE_STRING, TYPE_NONE } },
205271294Sngie#ifdef HAS_LPATHCONF
206271294Sngie	{ "lpathconf", ACTION_LPATHCONF, { TYPE_STRING, TYPE_STRING, TYPE_NONE } },
207271294Sngie#endif
208271294Sngie#ifdef HAS_FREEBSD_ACL
209271294Sngie	{ "prependacl", ACTION_PREPENDACL, { TYPE_STRING, TYPE_STRING, TYPE_NONE } },
210271294Sngie	{ "readacl", ACTION_READACL, { TYPE_STRING, TYPE_NONE } },
211271294Sngie#endif
212271294Sngie	{ "write", ACTION_WRITE, { TYPE_DESCRIPTOR, TYPE_STRING, TYPE_NONE } },
213271294Sngie	{ NULL, -1, { TYPE_NONE } }
214271294Sngie};
215271294Sngie
216271294Sngiestruct flag {
217271294Sngie	long long	 f_flag;
218271294Sngie	const char	*f_str;
219271294Sngie};
220271294Sngie
221271294Sngiestatic struct flag open_flags[] = {
222271294Sngie#ifdef O_RDONLY
223271294Sngie	{ O_RDONLY, "O_RDONLY" },
224271294Sngie#endif
225271294Sngie#ifdef O_WRONLY
226271294Sngie	{ O_WRONLY, "O_WRONLY" },
227271294Sngie#endif
228271294Sngie#ifdef O_RDWR
229271294Sngie	{ O_RDWR, "O_RDWR" },
230271294Sngie#endif
231271294Sngie#ifdef O_NONBLOCK
232271294Sngie	{ O_NONBLOCK, "O_NONBLOCK" },
233271294Sngie#endif
234271294Sngie#ifdef O_APPEND
235271294Sngie	{ O_APPEND, "O_APPEND" },
236271294Sngie#endif
237271294Sngie#ifdef O_CREAT
238271294Sngie	{ O_CREAT, "O_CREAT" },
239271294Sngie#endif
240271294Sngie#ifdef O_TRUNC
241271294Sngie	{ O_TRUNC, "O_TRUNC" },
242271294Sngie#endif
243271294Sngie#ifdef O_EXCL
244271294Sngie	{ O_EXCL, "O_EXCL" },
245271294Sngie#endif
246271294Sngie#ifdef O_SHLOCK
247271294Sngie	{ O_SHLOCK, "O_SHLOCK" },
248271294Sngie#endif
249271294Sngie#ifdef O_EXLOCK
250271294Sngie	{ O_EXLOCK, "O_EXLOCK" },
251271294Sngie#endif
252271294Sngie#ifdef O_DIRECT
253271294Sngie	{ O_DIRECT, "O_DIRECT" },
254271294Sngie#endif
255271294Sngie#ifdef O_FSYNC
256271294Sngie	{ O_FSYNC, "O_FSYNC" },
257271294Sngie#endif
258271294Sngie#ifdef O_SYNC
259271294Sngie	{ O_SYNC, "O_SYNC" },
260271294Sngie#endif
261271294Sngie#ifdef O_NOFOLLOW
262271294Sngie	{ O_NOFOLLOW, "O_NOFOLLOW" },
263271294Sngie#endif
264271294Sngie#ifdef O_NOCTTY
265271294Sngie	{ O_NOCTTY, "O_NOCTTY" },
266271294Sngie#endif
267271294Sngie#ifdef O_DIRECTORY
268271294Sngie	{ O_DIRECTORY, "O_DIRECTORY" },
269271294Sngie#endif
270271294Sngie	{ 0, NULL }
271271294Sngie};
272271294Sngie
273271294Sngie#ifdef HAS_CHFLAGS
274271294Sngiestatic struct flag chflags_flags[] = {
275271294Sngie#ifdef UF_NODUMP
276271294Sngie	{ UF_NODUMP, "UF_NODUMP" },
277271294Sngie#endif
278271294Sngie#ifdef UF_IMMUTABLE
279271294Sngie	{ UF_IMMUTABLE, "UF_IMMUTABLE" },
280271294Sngie#endif
281271294Sngie#ifdef UF_APPEND
282271294Sngie	{ UF_APPEND, "UF_APPEND" },
283271294Sngie#endif
284271294Sngie#ifdef UF_NOUNLINK
285271294Sngie	{ UF_NOUNLINK, "UF_NOUNLINK" },
286271294Sngie#endif
287271294Sngie#ifdef UF_OPAQUE
288271294Sngie	{ UF_OPAQUE, "UF_OPAQUE" },
289271294Sngie#endif
290271294Sngie#ifdef SF_ARCHIVED
291271294Sngie	{ SF_ARCHIVED, "SF_ARCHIVED" },
292271294Sngie#endif
293271294Sngie#ifdef SF_IMMUTABLE
294271294Sngie	{ SF_IMMUTABLE, "SF_IMMUTABLE" },
295271294Sngie#endif
296271294Sngie#ifdef SF_APPEND
297271294Sngie	{ SF_APPEND, "SF_APPEND" },
298271294Sngie#endif
299271294Sngie#ifdef SF_NOUNLINK
300271294Sngie	{ SF_NOUNLINK, "SF_NOUNLINK" },
301271294Sngie#endif
302271294Sngie#ifdef SF_SNAPSHOT
303271294Sngie	{ SF_SNAPSHOT, "SF_SNAPSHOT" },
304271294Sngie#endif
305271294Sngie	{ 0, NULL }
306271294Sngie};
307271294Sngie#endif
308271294Sngie
309271294Sngiestatic struct flag unlinkat_flags[] = {
310271294Sngie	{ AT_REMOVEDIR, "AT_REMOVEDIR" },
311271294Sngie	{ 0, NULL }
312271294Sngie};
313271294Sngie
314271294Sngiestatic struct flag linkat_flags[] = {
315271294Sngie	{ AT_SYMLINK_FOLLOW, "AT_SYMLINK_FOLLOW" },
316271294Sngie	{ 0, NULL }
317271294Sngie};
318271294Sngie
319271294Sngiestatic struct flag chflagsat_flags[] = {
320271294Sngie	{ AT_SYMLINK_NOFOLLOW, "AT_SYMLINK_NOFOLLOW" },
321271294Sngie	{ 0, NULL }
322271294Sngie};
323271294Sngie
324271294Sngiestatic struct flag fchmodat_flags[] = {
325271294Sngie	{ AT_SYMLINK_NOFOLLOW, "AT_SYMLINK_NOFOLLOW" },
326271294Sngie	{ 0, NULL }
327271294Sngie};
328271294Sngie
329271294Sngiestatic struct flag fchownat_flags[] = {
330271294Sngie	{ AT_SYMLINK_NOFOLLOW, "AT_SYMLINK_NOFOLLOW" },
331271294Sngie	{ 0, NULL }
332271294Sngie};
333271294Sngie
334271294Sngiestatic struct flag fstatat_flags[] = {
335271294Sngie	{ AT_SYMLINK_NOFOLLOW, "AT_SYMLINK_NOFOLLOW" },
336271294Sngie	{ 0, NULL }
337271294Sngie};
338271294Sngie
339271294Sngiestruct name {
340271294Sngie	int		 n_name;
341271294Sngie	const char	*n_str;
342271294Sngie};
343271294Sngie
344271294Sngiestatic struct name pathconf_names[] = {
345271294Sngie#ifdef _PC_LINK_MAX
346271294Sngie	{ _PC_LINK_MAX, "_PC_LINK_MAX" },
347271294Sngie#endif
348271294Sngie#ifdef _PC_NAME_MAX
349271294Sngie	{ _PC_NAME_MAX, "_PC_NAME_MAX" },
350271294Sngie#endif
351271294Sngie#ifdef _PC_PATH_MAX
352271294Sngie	{ _PC_PATH_MAX, "_PC_PATH_MAX" },
353271294Sngie#endif
354271294Sngie#ifdef _PC_SYMLINK_MAX
355271294Sngie	{ _PC_SYMLINK_MAX, "_PC_SYMLINK_MAX" },
356271294Sngie#endif
357271294Sngie	{ 0, NULL }
358271294Sngie};
359271294Sngie
360271294Sngiestatic const char *err2str(int error);
361271294Sngie
362271294Sngiestatic int *descriptors;
363271294Sngiestatic int ndescriptors;
364271294Sngie
365271294Sngiestatic void
366271294Sngieusage(void)
367271294Sngie{
368271294Sngie
369271294Sngie	fprintf(stderr, "usage: pjdfstest [-U umask] [-u uid] [-g gid1[,gid2[...]]] syscall args ...\n");
370271294Sngie	exit(1);
371271294Sngie}
372271294Sngie
373271294Sngiestatic long long
374271294Sngiestr2flags(struct flag *tflags, char *sflags)
375271294Sngie{
376271294Sngie	long long flags = 0;
377271294Sngie	unsigned int i;
378271294Sngie	char *f;
379271294Sngie
380271294Sngie	/* 'none' or '0' means no flags */
381271294Sngie	if (strcmp(sflags, "none") == 0 || strcmp(sflags, "0") == 0)
382271294Sngie		return (0);
383271294Sngie	for (f = strtok(sflags, ",|"); f != NULL; f = strtok(NULL, ",|")) {
384271294Sngie		for (i = 0; tflags[i].f_str != NULL; i++) {
385271294Sngie			if (strcmp(tflags[i].f_str, f) == 0)
386271294Sngie				break;
387271294Sngie		}
388271294Sngie		if (tflags[i].f_str == NULL) {
389271294Sngie			fprintf(stderr, "unknown flag '%s'\n", f);
390271294Sngie			exit(1);
391271294Sngie		}
392271294Sngie		flags |= tflags[i].f_flag;
393271294Sngie	}
394271294Sngie	return (flags);
395271294Sngie}
396271294Sngie
397271294Sngie#ifdef HAS_CHFLAGS
398271294Sngiestatic char *
399271294Sngieflags2str(struct flag *tflags, long long flags)
400271294Sngie{
401271294Sngie	static char sflags[1024];
402271294Sngie	unsigned int i;
403271294Sngie
404271294Sngie	sflags[0] = '\0';
405271294Sngie	for (i = 0; tflags[i].f_str != NULL; i++) {
406271294Sngie		if (flags & tflags[i].f_flag) {
407271294Sngie			if (sflags[0] != '\0')
408271294Sngie				strlcat(sflags, ",", sizeof(sflags));
409271294Sngie			strlcat(sflags, tflags[i].f_str, sizeof(sflags));
410271294Sngie		}
411271294Sngie	}
412271294Sngie	if (sflags[0] == '\0')
413271294Sngie		strlcpy(sflags, "none", sizeof(sflags));
414271294Sngie	return (sflags);
415271294Sngie}
416271294Sngie#endif
417271294Sngie
418271294Sngiestatic int
419271294Sngiestr2name(struct name *names, char *name)
420271294Sngie{
421271294Sngie	unsigned int i;
422271294Sngie
423271294Sngie	for (i = 0; names[i].n_str != NULL; i++) {
424271294Sngie		if (strcmp(names[i].n_str, name) == 0)
425271294Sngie			return (names[i].n_name);
426271294Sngie	}
427271294Sngie	return (-1);
428271294Sngie}
429271294Sngie
430271294Sngiestatic struct syscall_desc *
431271294Sngiefind_syscall(const char *name)
432271294Sngie{
433271294Sngie	int i;
434271294Sngie
435271294Sngie	for (i = 0; syscalls[i].sd_name != NULL; i++) {
436271294Sngie		if (strcmp(syscalls[i].sd_name, name) == 0)
437271294Sngie			return (&syscalls[i]);
438271294Sngie	}
439271294Sngie	return (NULL);
440271294Sngie}
441271294Sngie
442271294Sngiestatic void
443271294Sngieshow_stat(struct stat64 *sp, const char *what)
444271294Sngie{
445271294Sngie
446271294Sngie	if (strcmp(what, "mode") == 0)
447271294Sngie		printf("0%o", (unsigned int)(sp->st_mode & ALLPERMS));
448271294Sngie	else if (strcmp(what, "inode") == 0)
449271294Sngie		printf("%lld", (long long)sp->st_ino);
450271294Sngie	else if (strcmp(what, "nlink") == 0)
451271294Sngie		printf("%lld", (long long)sp->st_nlink);
452271294Sngie	else if (strcmp(what, "uid") == 0)
453271294Sngie		printf("%d", (int)sp->st_uid);
454271294Sngie	else if (strcmp(what, "gid") == 0)
455271294Sngie		printf("%d", (int)sp->st_gid);
456271294Sngie	else if (strcmp(what, "size") == 0)
457271294Sngie		printf("%lld", (long long)sp->st_size);
458271294Sngie	else if (strcmp(what, "blocks") == 0)
459271294Sngie		printf("%lld", (long long)sp->st_blocks);
460271294Sngie	else if (strcmp(what, "atime") == 0)
461271294Sngie		printf("%lld", (long long)sp->st_atime);
462271294Sngie	else if (strcmp(what, "mtime") == 0)
463271294Sngie		printf("%lld", (long long)sp->st_mtime);
464271294Sngie	else if (strcmp(what, "ctime") == 0)
465271294Sngie		printf("%lld", (long long)sp->st_ctime);
466271294Sngie#ifdef HAS_CHFLAGS
467271294Sngie	else if (strcmp(what, "flags") == 0)
468271294Sngie		printf("%s", flags2str(chflags_flags, (long long)sp->st_flags));
469271294Sngie#endif
470271294Sngie	else if (strcmp(what, "major") == 0)
471271294Sngie		printf("%u", (unsigned int)major(sp->st_rdev));
472271294Sngie	else if (strcmp(what, "minor") == 0)
473271294Sngie		printf("%u", (unsigned int)minor(sp->st_rdev));
474271294Sngie	else if (strcmp(what, "type") == 0) {
475271294Sngie		switch (sp->st_mode & S_IFMT) {
476271294Sngie		case S_IFIFO:
477271294Sngie			printf("fifo");
478271294Sngie			break;
479271294Sngie		case S_IFCHR:
480271294Sngie			printf("char");
481271294Sngie			break;
482271294Sngie		case S_IFDIR:
483271294Sngie			printf("dir");
484271294Sngie			break;
485271294Sngie		case S_IFBLK:
486271294Sngie			printf("block");
487271294Sngie			break;
488271294Sngie		case S_IFREG:
489271294Sngie			printf("regular");
490271294Sngie			break;
491271294Sngie		case S_IFLNK:
492271294Sngie			printf("symlink");
493271294Sngie			break;
494271294Sngie		case S_IFSOCK:
495271294Sngie			printf("socket");
496271294Sngie			break;
497271294Sngie		default:
498271294Sngie			printf("unknown");
499271294Sngie			break;
500271294Sngie		}
501271294Sngie	} else {
502271294Sngie		printf("unknown");
503271294Sngie	}
504271294Sngie}
505271294Sngie
506271294Sngiestatic void
507271294Sngieshow_stats(struct stat64 *sp, char *what)
508271294Sngie{
509271294Sngie	const char *s = "";
510271294Sngie	char *w;
511271294Sngie
512271294Sngie	for (w = strtok(what, ","); w != NULL; w = strtok(NULL, ",")) {
513271294Sngie		printf("%s", s);
514271294Sngie		show_stat(sp, w);
515271294Sngie		s = ",";
516271294Sngie	}
517271294Sngie	printf("\n");
518271294Sngie}
519271294Sngie
520271294Sngiestatic void
521271294Sngiedescriptor_add(int fd)
522271294Sngie{
523271294Sngie
524271294Sngie	ndescriptors++;
525271294Sngie	if (descriptors == NULL) {
526271294Sngie		descriptors = malloc(sizeof(descriptors[0]) * ndescriptors);
527271294Sngie	} else {
528271294Sngie		descriptors = realloc(descriptors,
529271294Sngie		    sizeof(descriptors[0]) * ndescriptors);
530271294Sngie	}
531271294Sngie	assert(descriptors != NULL);
532271294Sngie	descriptors[ndescriptors - 1] = fd;
533271294Sngie}
534271294Sngie
535271294Sngiestatic int
536271294Sngiedescriptor_get(int pos)
537271294Sngie{
538271294Sngie
539271294Sngie	if (pos < 0 || pos >= ndescriptors) {
540271294Sngie		fprintf(stderr, "invalid descriptor %d\n", pos);
541271294Sngie		exit(1);
542271294Sngie	}
543271294Sngie
544271294Sngie	return (descriptors[pos]);
545271294Sngie}
546271294Sngie
547271294Sngiestatic unsigned int
548271294Sngiecall_syscall(struct syscall_desc *scall, char *argv[])
549271294Sngie{
550271294Sngie	struct stat64 sb;
551271294Sngie	long long flags;
552271294Sngie	unsigned int i;
553271294Sngie	char *endp;
554271294Sngie	int name, rval;
555271294Sngie	union {
556271294Sngie		char *str;
557271294Sngie		long long num;
558271294Sngie	} args[MAX_ARGS];
559271294Sngie#ifdef HAS_FREEBSD_ACL
560271294Sngie	int entry_id = ACL_FIRST_ENTRY;
561271294Sngie	acl_t acl, newacl;
562271294Sngie	acl_entry_t entry, newentry;
563271294Sngie#endif
564271294Sngie
565271294Sngie	/*
566271294Sngie	 * Verify correctness of the arguments.
567271294Sngie	 */
568271294Sngie	for (i = 0; i < sizeof(args)/sizeof(args[0]); i++) {
569271294Sngie		if (scall->sd_args[i] == TYPE_NONE) {
570271294Sngie			if (argv[i] == NULL || strcmp(argv[i], ":") == 0)
571271294Sngie				break;
572271294Sngie			fprintf(stderr, "too many arguments [%s]\n", argv[i]);
573271294Sngie			exit(1);
574271294Sngie		} else {
575271294Sngie			if (argv[i] == NULL || strcmp(argv[i], ":") == 0) {
576271294Sngie				if (scall->sd_args[i] & TYPE_OPTIONAL)
577271294Sngie					break;
578271294Sngie				fprintf(stderr, "too few arguments\n");
579271294Sngie				exit(1);
580271294Sngie			}
581271294Sngie			if ((scall->sd_args[i] & TYPE_MASK) == TYPE_STRING) {
582271294Sngie				if (strcmp(argv[i], "NULL") == 0)
583271294Sngie					args[i].str = NULL;
584271294Sngie				else if (strcmp(argv[i], "DEADCODE") == 0)
585271294Sngie					args[i].str = (void *)0xdeadc0de;
586271294Sngie				else
587271294Sngie					args[i].str = argv[i];
588271294Sngie			} else if ((scall->sd_args[i] & TYPE_MASK) ==
589271294Sngie			    TYPE_NUMBER) {
590271294Sngie				args[i].num = strtoll(argv[i], &endp, 0);
591271294Sngie				if (*endp != '\0' &&
592271294Sngie				    !isspace((unsigned char)*endp)) {
593271294Sngie					fprintf(stderr,
594271294Sngie					    "invalid argument %u, number expected [%s]\n",
595271294Sngie					    i, endp);
596271294Sngie					exit(1);
597271294Sngie				}
598271294Sngie			} else if ((scall->sd_args[i] & TYPE_MASK) ==
599271294Sngie			    TYPE_DESCRIPTOR) {
600271294Sngie				if (strcmp(argv[i], "AT_FDCWD") == 0) {
601271294Sngie					args[i].num = AT_FDCWD;
602271294Sngie				} else if (strcmp(argv[i], "BADFD") == 0) {
603271294Sngie					/* In case AT_FDCWD is -1 on some systems... */
604271294Sngie					if (AT_FDCWD == -1)
605271294Sngie						args[i].num = -2;
606271294Sngie					else
607271294Sngie						args[i].num = -1;
608271294Sngie				} else {
609271294Sngie					int pos;
610271294Sngie
611271294Sngie					pos = strtoll(argv[i], &endp, 0);
612271294Sngie					if (*endp != '\0' &&
613271294Sngie					    !isspace((unsigned char)*endp)) {
614271294Sngie						fprintf(stderr,
615271294Sngie						    "invalid argument %u, number expected [%s]\n",
616271294Sngie						    i, endp);
617271294Sngie						exit(1);
618271294Sngie					}
619271294Sngie					args[i].num = descriptor_get(pos);
620271294Sngie				}
621271294Sngie			}
622271294Sngie		}
623271294Sngie	}
624271294Sngie	/*
625271294Sngie	 * Call the given syscall.
626271294Sngie	 */
627271294Sngie#define	NUM(n)	(args[(n)].num)
628271294Sngie#define	STR(n)	(args[(n)].str)
629271294Sngie	switch (scall->sd_action) {
630271294Sngie	case ACTION_OPEN:
631271294Sngie		flags = str2flags(open_flags, STR(1));
632271294Sngie		if (flags & O_CREAT) {
633271294Sngie			if (i == 2) {
634271294Sngie				fprintf(stderr, "too few arguments\n");
635271294Sngie				exit(1);
636271294Sngie			}
637271294Sngie			rval = open(STR(0), (int)flags, (mode_t)NUM(2));
638271294Sngie		} else {
639271294Sngie			if (i == 3) {
640271294Sngie				fprintf(stderr, "too many arguments\n");
641271294Sngie				exit(1);
642271294Sngie			}
643271294Sngie			rval = open(STR(0), (int)flags);
644271294Sngie		}
645271294Sngie		if (rval >= 0)
646271294Sngie			descriptor_add(rval);
647271294Sngie		break;
648271294Sngie	case ACTION_OPENAT:
649271294Sngie		flags = str2flags(open_flags, STR(2));
650271294Sngie		if (flags & O_CREAT) {
651271294Sngie			if (i == 3) {
652271294Sngie				fprintf(stderr, "too few arguments\n");
653271294Sngie				exit(1);
654271294Sngie			}
655271294Sngie			rval = openat(NUM(0), STR(1), (int)flags,
656271294Sngie			    (mode_t)NUM(3));
657271294Sngie		} else {
658271294Sngie			if (i == 4) {
659271294Sngie				fprintf(stderr, "too many arguments\n");
660271294Sngie				exit(1);
661271294Sngie			}
662271294Sngie			rval = openat(NUM(0), STR(1), (int)flags);
663271294Sngie		}
664271294Sngie		if (rval >= 0)
665271294Sngie			descriptor_add(rval);
666271294Sngie		break;
667271294Sngie	case ACTION_CREATE:
668271294Sngie		rval = open(STR(0), O_CREAT | O_EXCL, (mode_t)NUM(1));
669271294Sngie		if (rval >= 0)
670271294Sngie			close(rval);
671271294Sngie		break;
672271294Sngie	case ACTION_UNLINK:
673271294Sngie		rval = unlink(STR(0));
674271294Sngie		break;
675271294Sngie	case ACTION_UNLINKAT:
676271294Sngie		rval = unlinkat(NUM(0), STR(1),
677271294Sngie		    (int)str2flags(unlinkat_flags, STR(2)));
678271294Sngie		break;
679271294Sngie	case ACTION_MKDIR:
680271294Sngie		rval = mkdir(STR(0), (mode_t)NUM(1));
681271294Sngie		break;
682271294Sngie	case ACTION_MKDIRAT:
683271294Sngie		rval = mkdirat(NUM(0), STR(1), (mode_t)NUM(2));
684271294Sngie		break;
685271294Sngie	case ACTION_RMDIR:
686271294Sngie		rval = rmdir(STR(0));
687271294Sngie		break;
688271294Sngie	case ACTION_LINK:
689271294Sngie		rval = link(STR(0), STR(1));
690271294Sngie		break;
691271294Sngie	case ACTION_LINKAT:
692271294Sngie		rval = linkat(NUM(0), STR(1), NUM(2), STR(3),
693271294Sngie		    (int)str2flags(linkat_flags, STR(4)));
694271294Sngie		break;
695271294Sngie	case ACTION_SYMLINK:
696271294Sngie		rval = symlink(STR(0), STR(1));
697271294Sngie		break;
698271294Sngie	case ACTION_SYMLINKAT:
699271294Sngie		rval = symlinkat(STR(0), NUM(1), STR(2));
700271294Sngie		break;
701271294Sngie	case ACTION_RENAME:
702271294Sngie		rval = rename(STR(0), STR(1));
703271294Sngie		break;
704271294Sngie	case ACTION_RENAMEAT:
705271294Sngie		rval = renameat(NUM(0), STR(1), NUM(2), STR(3));
706271294Sngie		break;
707271294Sngie	case ACTION_MKFIFO:
708271294Sngie		rval = mkfifo(STR(0), (mode_t)NUM(1));
709271294Sngie		break;
710271294Sngie	case ACTION_MKFIFOAT:
711271294Sngie		rval = mkfifoat(NUM(0), STR(1), (mode_t)NUM(2));
712271294Sngie		break;
713271294Sngie	case ACTION_MKNOD:
714271294Sngie	case ACTION_MKNODAT:
715271294Sngie	    {
716271294Sngie		mode_t ntype;
717271294Sngie		dev_t dev;
718271294Sngie		int fa;
719271294Sngie
720271294Sngie		switch (scall->sd_action) {
721271294Sngie		case ACTION_MKNOD:
722271294Sngie			fa = 0;
723271294Sngie			break;
724271294Sngie		case ACTION_MKNODAT:
725271294Sngie			fa = 1;
726271294Sngie			break;
727271294Sngie		default:
728271294Sngie			abort();
729271294Sngie		}
730271294Sngie
731271294Sngie		dev = makedev(NUM(fa + 3), NUM(fa + 4));
732271294Sngie		if (strcmp(STR(fa + 1), "c") == 0)	/* character device */
733271294Sngie			ntype = S_IFCHR;
734271294Sngie		else if (strcmp(STR(fa + 1), "b") == 0)	/* block device */
735271294Sngie			ntype = S_IFBLK;
736271294Sngie		else if (strcmp(STR(fa + 1), "f") == 0)	/* fifo special */
737271294Sngie			ntype = S_IFIFO;
738271294Sngie		else if (strcmp(STR(fa + 1), "d") == 0)	/* directory */
739271294Sngie			ntype = S_IFDIR;
740271294Sngie		else if (strcmp(STR(fa + 1), "o") == 0)	/* regular file */
741271294Sngie			ntype = S_IFREG;
742271294Sngie		else {
743271294Sngie			fprintf(stderr, "wrong argument 1\n");
744271294Sngie			exit(1);
745271294Sngie		}
746271294Sngie		switch (scall->sd_action) {
747271294Sngie		case ACTION_MKNOD:
748271294Sngie			rval = mknod(STR(0), ntype | NUM(2), dev);
749271294Sngie			break;
750271294Sngie		case ACTION_MKNODAT:
751271294Sngie			rval = mknodat(NUM(0), STR(1), ntype | NUM(3), dev);
752271294Sngie			break;
753271294Sngie		default:
754271294Sngie			abort();
755271294Sngie		}
756271294Sngie		break;
757271294Sngie	    }
758271294Sngie	case ACTION_BIND:
759271294Sngie	    {
760271294Sngie		struct sockaddr_un sunx;
761271294Sngie
762271294Sngie		sunx.sun_family = AF_UNIX;
763271294Sngie		strncpy(sunx.sun_path, STR(0), sizeof(sunx.sun_path) - 1);
764271294Sngie		sunx.sun_path[sizeof(sunx.sun_path) - 1] = '\0';
765271294Sngie		rval = socket(AF_UNIX, SOCK_STREAM, 0);
766271294Sngie		if (rval < 0)
767271294Sngie			break;
768271294Sngie		rval = bind(rval, (struct sockaddr *)&sunx, sizeof(sunx));
769271294Sngie		break;
770271294Sngie	    }
771271294Sngie#ifdef HAS_BINDAT
772271294Sngie	case ACTION_BINDAT:
773271294Sngie	    {
774271294Sngie		struct sockaddr_un sunx;
775271294Sngie
776271294Sngie		sunx.sun_family = AF_UNIX;
777271294Sngie		strncpy(sunx.sun_path, STR(1), sizeof(sunx.sun_path) - 1);
778271294Sngie		sunx.sun_path[sizeof(sunx.sun_path) - 1] = '\0';
779271294Sngie		rval = socket(AF_UNIX, SOCK_STREAM, 0);
780271294Sngie		if (rval < 0)
781271294Sngie			break;
782271294Sngie		rval = bindat(NUM(0), rval, (struct sockaddr *)&sunx,
783271294Sngie		    sizeof(sunx));
784271294Sngie		break;
785271294Sngie	    }
786271294Sngie#endif
787271294Sngie	case ACTION_CONNECT:
788271294Sngie	    {
789271294Sngie		struct sockaddr_un sunx;
790271294Sngie
791271294Sngie		sunx.sun_family = AF_UNIX;
792271294Sngie		strncpy(sunx.sun_path, STR(0), sizeof(sunx.sun_path) - 1);
793271294Sngie		sunx.sun_path[sizeof(sunx.sun_path) - 1] = '\0';
794271294Sngie		rval = socket(AF_UNIX, SOCK_STREAM, 0);
795271294Sngie		if (rval < 0)
796271294Sngie			break;
797271294Sngie		rval = connect(rval, (struct sockaddr *)&sunx, sizeof(sunx));
798271294Sngie		break;
799271294Sngie	    }
800271294Sngie#ifdef HAS_CONNECTAT
801271294Sngie	case ACTION_CONNECTAT:
802271294Sngie	    {
803271294Sngie		struct sockaddr_un sunx;
804271294Sngie
805271294Sngie		sunx.sun_family = AF_UNIX;
806271294Sngie		strncpy(sunx.sun_path, STR(1), sizeof(sunx.sun_path) - 1);
807271294Sngie		sunx.sun_path[sizeof(sunx.sun_path) - 1] = '\0';
808271294Sngie		rval = socket(AF_UNIX, SOCK_STREAM, 0);
809271294Sngie		if (rval < 0)
810271294Sngie			break;
811271294Sngie		rval = connectat(NUM(0), rval, (struct sockaddr *)&sunx,
812271294Sngie		    sizeof(sunx));
813271294Sngie		break;
814271294Sngie	    }
815271294Sngie#endif
816271294Sngie	case ACTION_CHMOD:
817271294Sngie		rval = chmod(STR(0), (mode_t)NUM(1));
818271294Sngie		break;
819271294Sngie	case ACTION_FCHMOD:
820271294Sngie		rval = fchmod(NUM(0), (mode_t)NUM(1));
821271294Sngie		break;
822271294Sngie#ifdef HAS_LCHMOD
823271294Sngie	case ACTION_LCHMOD:
824271294Sngie		rval = lchmod(STR(0), (mode_t)NUM(1));
825271294Sngie		break;
826271294Sngie#endif
827271294Sngie	case ACTION_FCHMODAT:
828271294Sngie		rval = fchmodat(NUM(0), STR(1), (mode_t)NUM(2),
829271294Sngie		    str2flags(fchmodat_flags, STR(3)));
830271294Sngie		break;
831271294Sngie	case ACTION_CHOWN:
832271294Sngie		rval = chown(STR(0), (uid_t)NUM(1), (gid_t)NUM(2));
833271294Sngie		break;
834271294Sngie	case ACTION_FCHOWN:
835271294Sngie		rval = fchown(NUM(0), (uid_t)NUM(1), (gid_t)NUM(2));
836271294Sngie		break;
837271294Sngie	case ACTION_LCHOWN:
838271294Sngie		rval = lchown(STR(0), (uid_t)NUM(1), (gid_t)NUM(2));
839271294Sngie		break;
840271294Sngie	case ACTION_FCHOWNAT:
841271294Sngie		rval = fchownat(NUM(0), STR(1), (uid_t)NUM(2), (gid_t)NUM(3),
842271294Sngie		    (int)str2flags(fchownat_flags, STR(4)));
843271294Sngie		break;
844271294Sngie#ifdef HAS_CHFLAGS
845271294Sngie	case ACTION_CHFLAGS:
846271294Sngie		rval = chflags(STR(0),
847271294Sngie		    (unsigned long)str2flags(chflags_flags, STR(1)));
848271294Sngie		break;
849271294Sngie#endif
850271294Sngie#ifdef HAS_FCHFLAGS
851271294Sngie	case ACTION_FCHFLAGS:
852271294Sngie		rval = fchflags(NUM(0),
853271294Sngie		    (unsigned long)str2flags(chflags_flags, STR(1)));
854271294Sngie		break;
855271294Sngie#endif
856271294Sngie#ifdef HAS_CHFLAGSAT
857271294Sngie	case ACTION_CHFLAGSAT:
858271294Sngie		rval = chflagsat(NUM(0), STR(1),
859271294Sngie		    (unsigned long)str2flags(chflags_flags, STR(2)),
860271294Sngie		    (int)str2flags(chflagsat_flags, STR(3)));
861271294Sngie		break;
862271294Sngie#endif
863271294Sngie#ifdef HAS_LCHFLAGS
864271294Sngie	case ACTION_LCHFLAGS:
865271294Sngie		rval = lchflags(STR(0),
866271294Sngie		    (unsigned long)str2flags(chflags_flags, STR(1)));
867271294Sngie		break;
868271294Sngie#endif
869271294Sngie	case ACTION_TRUNCATE:
870271294Sngie		rval = truncate64(STR(0), NUM(1));
871271294Sngie		break;
872271294Sngie	case ACTION_FTRUNCATE:
873271294Sngie		rval = ftruncate64(NUM(0), NUM(1));
874271294Sngie		break;
875271294Sngie	case ACTION_STAT:
876271294Sngie		rval = stat64(STR(0), &sb);
877271294Sngie		if (rval == 0) {
878271294Sngie			show_stats(&sb, STR(1));
879271294Sngie			return (i);
880271294Sngie		}
881271294Sngie		break;
882271294Sngie	case ACTION_FSTAT:
883271294Sngie		rval = fstat64(NUM(0), &sb);
884271294Sngie		if (rval == 0) {
885271294Sngie			show_stats(&sb, STR(1));
886271294Sngie			return (i);
887271294Sngie		}
888271294Sngie		break;
889271294Sngie	case ACTION_LSTAT:
890271294Sngie		rval = lstat64(STR(0), &sb);
891271294Sngie		if (rval == 0) {
892271294Sngie			show_stats(&sb, STR(1));
893271294Sngie			return (i);
894271294Sngie		}
895271294Sngie		break;
896271294Sngie	case ACTION_FSTATAT:
897271294Sngie		rval = fstatat(NUM(0), STR(1), &sb,
898271294Sngie		    (int)str2flags(fstatat_flags, STR(2)));
899271294Sngie		if (rval == 0) {
900271294Sngie			show_stats(&sb, STR(3));
901271294Sngie			return (i);
902271294Sngie		}
903271294Sngie		break;
904271294Sngie	case ACTION_PATHCONF:
905271294Sngie	case ACTION_FPATHCONF:
906271294Sngie#ifdef HAS_LPATHCONF
907271294Sngie	case ACTION_LPATHCONF:
908271294Sngie#endif
909271294Sngie	    {
910271294Sngie		long lrval;
911271294Sngie
912271294Sngie		name = str2name(pathconf_names, STR(1));
913271294Sngie		if (name == -1) {
914271294Sngie			fprintf(stderr, "unknown name %s", STR(1));
915271294Sngie			exit(1);
916271294Sngie		}
917271294Sngie		errno = 0;
918271294Sngie		switch (scall->sd_action) {
919271294Sngie		case ACTION_PATHCONF:
920271294Sngie			lrval = pathconf(STR(0), name);
921271294Sngie			break;
922271294Sngie		case ACTION_FPATHCONF:
923271294Sngie			lrval = fpathconf(NUM(0), name);
924271294Sngie			break;
925271294Sngie#ifdef HAS_LPATHCONF
926271294Sngie		case ACTION_LPATHCONF:
927271294Sngie			lrval = lpathconf(STR(0), name);
928271294Sngie			break;
929271294Sngie#endif
930271294Sngie		default:
931271294Sngie			abort();
932271294Sngie		}
933271294Sngie		if (lrval == -1 && errno == 0) {
934271294Sngie			printf("unlimited\n");
935271294Sngie			return (i);
936271294Sngie		} else if (lrval >= 0) {
937271294Sngie			printf("%ld\n", lrval);
938271294Sngie			return (i);
939271294Sngie		}
940271294Sngie		rval = -1;
941271294Sngie		break;
942271294Sngie	    }
943271294Sngie#ifdef HAS_FREEBSD_ACL
944271294Sngie	case ACTION_PREPENDACL:
945271294Sngie		rval = -1;
946271294Sngie
947271294Sngie		acl = acl_get_file(STR(0), ACL_TYPE_NFS4);
948271294Sngie		if (acl == NULL)
949271294Sngie			break;
950271294Sngie
951271294Sngie		newacl = acl_from_text(STR(1));
952271294Sngie		if (acl == NULL)
953271294Sngie			break;
954271294Sngie
955271294Sngie		while (acl_get_entry(newacl, entry_id, &newentry) == 1) {
956271294Sngie			entry_id = ACL_NEXT_ENTRY;
957271294Sngie
958271294Sngie			if (acl_create_entry_np(&acl, &entry, 0))
959271294Sngie				break;
960271294Sngie
961271294Sngie			if (acl_copy_entry(entry, newentry))
962271294Sngie				break;
963271294Sngie		}
964271294Sngie
965271294Sngie		rval = acl_set_file(STR(0), ACL_TYPE_NFS4, acl);
966271294Sngie		break;
967271294Sngie	case ACTION_READACL:
968271294Sngie		acl = acl_get_file(STR(0), ACL_TYPE_NFS4);
969271294Sngie		if (acl == NULL)
970271294Sngie			rval = -1;
971271294Sngie		else
972271294Sngie			rval = 0;
973271294Sngie		break;
974271294Sngie#endif
975271294Sngie	case ACTION_WRITE:
976271294Sngie		rval = write(NUM(0), STR(1), strlen(STR(1)));
977271294Sngie		break;
978271294Sngie	default:
979271294Sngie		fprintf(stderr, "unsupported syscall\n");
980271294Sngie		exit(1);
981271294Sngie	}
982271294Sngie#undef STR
983271294Sngie#undef NUM
984271294Sngie	if (rval < 0) {
985271294Sngie		const char *serrno;
986271294Sngie
987271294Sngie		serrno = err2str(errno);
988271294Sngie		fprintf(stderr, "%s returned %d\n", scall->sd_name, rval);
989271294Sngie		printf("%s\n", serrno);
990271294Sngie		exit(1);
991271294Sngie	}
992271294Sngie	printf("0\n");
993271294Sngie	return (i);
994271294Sngie}
995271294Sngie
996271294Sngiestatic void
997271294Sngieset_gids(char *gids)
998271294Sngie{
999271294Sngie	gid_t *gidset;
1000271294Sngie	long ngroups;
1001271294Sngie	char *g, *endp;
1002271294Sngie	unsigned i;
1003271294Sngie
1004271294Sngie	ngroups = sysconf(_SC_NGROUPS_MAX);
1005271294Sngie	assert(ngroups > 0);
1006271294Sngie	gidset = malloc(sizeof(*gidset) * ngroups);
1007271294Sngie	assert(gidset != NULL);
1008271294Sngie	for (i = 0, g = strtok(gids, ","); g != NULL;
1009271294Sngie	    g = strtok(NULL, ","), i++) {
1010271294Sngie		if (i >= ngroups) {
1011271294Sngie			fprintf(stderr, "too many gids\n");
1012271294Sngie			exit(1);
1013271294Sngie		}
1014271294Sngie		gidset[i] = strtol(g, &endp, 0);
1015271294Sngie		if (*endp != '\0' && !isspace((unsigned char)*endp)) {
1016271294Sngie			fprintf(stderr, "invalid gid '%s' - number expected\n",
1017271294Sngie			    g);
1018271294Sngie			exit(1);
1019271294Sngie		}
1020271294Sngie	}
1021271294Sngie	if (setgroups(i, gidset) < 0) {
1022271294Sngie		fprintf(stderr, "cannot change groups: %s\n", strerror(errno));
1023271294Sngie		exit(1);
1024271294Sngie	}
1025271294Sngie	if (setegid(gidset[0]) < 0) {
1026271294Sngie		fprintf(stderr, "cannot change effective gid: %s\n",
1027271294Sngie		    strerror(errno));
1028271294Sngie		exit(1);
1029271294Sngie	}
1030271294Sngie	free(gidset);
1031271294Sngie}
1032271294Sngie
1033271294Sngieint
1034271294Sngiemain(int argc, char *argv[])
1035271294Sngie{
1036271294Sngie	struct syscall_desc *scall;
1037271294Sngie	unsigned int n;
1038271294Sngie	char *gids, *endp;
1039271294Sngie	int uid, umsk, ch;
1040271294Sngie
1041271294Sngie	uid = -1;
1042271294Sngie	gids = NULL;
1043271294Sngie	umsk = 0;
1044271294Sngie
1045271294Sngie	while ((ch = getopt(argc, argv, "g:u:U:")) != -1) {
1046271294Sngie		switch(ch) {
1047271294Sngie		case 'g':
1048271294Sngie			gids = optarg;
1049271294Sngie			break;
1050271294Sngie		case 'u':
1051271294Sngie			uid = (int)strtol(optarg, &endp, 0);
1052271294Sngie			if (*endp != '\0' && !isspace((unsigned char)*endp)) {
1053271294Sngie				fprintf(stderr, "invalid uid '%s' - number "
1054271294Sngie				    "expected\n", optarg);
1055271294Sngie				exit(1);
1056271294Sngie			}
1057271294Sngie			break;
1058271294Sngie		case 'U':
1059271294Sngie			umsk = (int)strtol(optarg, &endp, 0);
1060271294Sngie			if (*endp != '\0' && !isspace((unsigned char)*endp)) {
1061271294Sngie				fprintf(stderr, "invalid umask '%s' - number "
1062271294Sngie				    "expected\n", optarg);
1063271294Sngie				exit(1);
1064271294Sngie			}
1065271294Sngie			break;
1066271294Sngie		default:
1067271294Sngie			usage();
1068271294Sngie		}
1069271294Sngie	}
1070271294Sngie	argc -= optind;
1071271294Sngie	argv += optind;
1072271294Sngie
1073271294Sngie	if (argc < 1) {
1074271294Sngie		fprintf(stderr, "too few arguments\n");
1075271294Sngie		usage();
1076271294Sngie	}
1077271294Sngie
1078271294Sngie	if (gids != NULL) {
1079271294Sngie		fprintf(stderr, "changing groups to %s\n", gids);
1080271294Sngie		set_gids(gids);
1081271294Sngie	}
1082271294Sngie	if (uid != -1) {
1083271294Sngie		fprintf(stderr, "changing uid to %d\n", uid);
1084271294Sngie		if (setuid(uid) < 0) {
1085271294Sngie			fprintf(stderr, "cannot change uid: %s\n",
1086271294Sngie			    strerror(errno));
1087271294Sngie			exit(1);
1088271294Sngie		}
1089271294Sngie	}
1090271294Sngie
1091271294Sngie	/* Change umask to requested value or to 0, if not requested. */
1092271294Sngie	umask(umsk);
1093271294Sngie
1094271294Sngie	for (;;) {
1095271294Sngie		scall = find_syscall(argv[0]);
1096271294Sngie		if (scall == NULL) {
1097271294Sngie			fprintf(stderr, "syscall '%s' not supported\n",
1098271294Sngie			    argv[0]);
1099271294Sngie			exit(1);
1100271294Sngie		}
1101271294Sngie		argc++;
1102271294Sngie		argv++;
1103271294Sngie		n = call_syscall(scall, argv);
1104271294Sngie		argc += n;
1105271294Sngie		argv += n;
1106271294Sngie		if (argv[0] == NULL)
1107271294Sngie			break;
1108271294Sngie		argc++;
1109271294Sngie		argv++;
1110271294Sngie	}
1111271294Sngie
1112271294Sngie	exit(0);
1113271294Sngie}
1114271294Sngie
1115271294Sngiestatic const char *
1116271294Sngieerr2str(int error)
1117271294Sngie{
1118271294Sngie	static char errnum[8];
1119271294Sngie
1120271294Sngie	switch (error) {
1121271294Sngie#ifdef EPERM
1122271294Sngie	case EPERM:
1123271294Sngie		return ("EPERM");
1124271294Sngie#endif
1125271294Sngie#ifdef ENOENT
1126271294Sngie	case ENOENT:
1127271294Sngie		return ("ENOENT");
1128271294Sngie#endif
1129271294Sngie#ifdef ESRCH
1130271294Sngie	case ESRCH:
1131271294Sngie		return ("ESRCH");
1132271294Sngie#endif
1133271294Sngie#ifdef EINTR
1134271294Sngie	case EINTR:
1135271294Sngie		return ("EINTR");
1136271294Sngie#endif
1137271294Sngie#ifdef EIO
1138271294Sngie	case EIO:
1139271294Sngie		return ("EIO");
1140271294Sngie#endif
1141271294Sngie#ifdef ENXIO
1142271294Sngie	case ENXIO:
1143271294Sngie		return ("ENXIO");
1144271294Sngie#endif
1145271294Sngie#ifdef E2BIG
1146271294Sngie	case E2BIG:
1147271294Sngie		return ("E2BIG");
1148271294Sngie#endif
1149271294Sngie#ifdef ENOEXEC
1150271294Sngie	case ENOEXEC:
1151271294Sngie		return ("ENOEXEC");
1152271294Sngie#endif
1153271294Sngie#ifdef EBADF
1154271294Sngie	case EBADF:
1155271294Sngie		return ("EBADF");
1156271294Sngie#endif
1157271294Sngie#ifdef ECHILD
1158271294Sngie	case ECHILD:
1159271294Sngie		return ("ECHILD");
1160271294Sngie#endif
1161271294Sngie#ifdef EDEADLK
1162271294Sngie	case EDEADLK:
1163271294Sngie		return ("EDEADLK");
1164271294Sngie#endif
1165271294Sngie#ifdef ENOMEM
1166271294Sngie	case ENOMEM:
1167271294Sngie		return ("ENOMEM");
1168271294Sngie#endif
1169271294Sngie#ifdef EACCES
1170271294Sngie	case EACCES:
1171271294Sngie		return ("EACCES");
1172271294Sngie#endif
1173271294Sngie#ifdef EFAULT
1174271294Sngie	case EFAULT:
1175271294Sngie		return ("EFAULT");
1176271294Sngie#endif
1177271294Sngie#ifdef ENOTBLK
1178271294Sngie	case ENOTBLK:
1179271294Sngie		return ("ENOTBLK");
1180271294Sngie#endif
1181271294Sngie#ifdef EBUSY
1182271294Sngie	case EBUSY:
1183271294Sngie		return ("EBUSY");
1184271294Sngie#endif
1185271294Sngie#ifdef EEXIST
1186271294Sngie	case EEXIST:
1187271294Sngie		return ("EEXIST");
1188271294Sngie#endif
1189271294Sngie#ifdef EXDEV
1190271294Sngie	case EXDEV:
1191271294Sngie		return ("EXDEV");
1192271294Sngie#endif
1193271294Sngie#ifdef ENODEV
1194271294Sngie	case ENODEV:
1195271294Sngie		return ("ENODEV");
1196271294Sngie#endif
1197271294Sngie#ifdef ENOTDIR
1198271294Sngie	case ENOTDIR:
1199271294Sngie		return ("ENOTDIR");
1200271294Sngie#endif
1201271294Sngie#ifdef EISDIR
1202271294Sngie	case EISDIR:
1203271294Sngie		return ("EISDIR");
1204271294Sngie#endif
1205271294Sngie#ifdef EINVAL
1206271294Sngie	case EINVAL:
1207271294Sngie		return ("EINVAL");
1208271294Sngie#endif
1209271294Sngie#ifdef ENFILE
1210271294Sngie	case ENFILE:
1211271294Sngie		return ("ENFILE");
1212271294Sngie#endif
1213271294Sngie#ifdef EMFILE
1214271294Sngie	case EMFILE:
1215271294Sngie		return ("EMFILE");
1216271294Sngie#endif
1217271294Sngie#ifdef ENOTTY
1218271294Sngie	case ENOTTY:
1219271294Sngie		return ("ENOTTY");
1220271294Sngie#endif
1221271294Sngie#ifdef ETXTBSY
1222271294Sngie	case ETXTBSY:
1223271294Sngie		return ("ETXTBSY");
1224271294Sngie#endif
1225271294Sngie#ifdef EFBIG
1226271294Sngie	case EFBIG:
1227271294Sngie		return ("EFBIG");
1228271294Sngie#endif
1229271294Sngie#ifdef ENOSPC
1230271294Sngie	case ENOSPC:
1231271294Sngie		return ("ENOSPC");
1232271294Sngie#endif
1233271294Sngie#ifdef ESPIPE
1234271294Sngie	case ESPIPE:
1235271294Sngie		return ("ESPIPE");
1236271294Sngie#endif
1237271294Sngie#ifdef EROFS
1238271294Sngie	case EROFS:
1239271294Sngie		return ("EROFS");
1240271294Sngie#endif
1241271294Sngie#ifdef EMLINK
1242271294Sngie	case EMLINK:
1243271294Sngie		return ("EMLINK");
1244271294Sngie#endif
1245271294Sngie#ifdef EPIPE
1246271294Sngie	case EPIPE:
1247271294Sngie		return ("EPIPE");
1248271294Sngie#endif
1249271294Sngie#ifdef EDOM
1250271294Sngie	case EDOM:
1251271294Sngie		return ("EDOM");
1252271294Sngie#endif
1253271294Sngie#ifdef ERANGE
1254271294Sngie	case ERANGE:
1255271294Sngie		return ("ERANGE");
1256271294Sngie#endif
1257271294Sngie#ifdef EAGAIN
1258271294Sngie	case EAGAIN:
1259271294Sngie		return ("EAGAIN");
1260271294Sngie#endif
1261271294Sngie#ifdef EINPROGRESS
1262271294Sngie	case EINPROGRESS:
1263271294Sngie		return ("EINPROGRESS");
1264271294Sngie#endif
1265271294Sngie#ifdef EALREADY
1266271294Sngie	case EALREADY:
1267271294Sngie		return ("EALREADY");
1268271294Sngie#endif
1269271294Sngie#ifdef ENOTSOCK
1270271294Sngie	case ENOTSOCK:
1271271294Sngie		return ("ENOTSOCK");
1272271294Sngie#endif
1273271294Sngie#ifdef EDESTADDRREQ
1274271294Sngie	case EDESTADDRREQ:
1275271294Sngie		return ("EDESTADDRREQ");
1276271294Sngie#endif
1277271294Sngie#ifdef EMSGSIZE
1278271294Sngie	case EMSGSIZE:
1279271294Sngie		return ("EMSGSIZE");
1280271294Sngie#endif
1281271294Sngie#ifdef EPROTOTYPE
1282271294Sngie	case EPROTOTYPE:
1283271294Sngie		return ("EPROTOTYPE");
1284271294Sngie#endif
1285271294Sngie#ifdef ENOPROTOOPT
1286271294Sngie	case ENOPROTOOPT:
1287271294Sngie		return ("ENOPROTOOPT");
1288271294Sngie#endif
1289271294Sngie#ifdef EPROTONOSUPPORT
1290271294Sngie	case EPROTONOSUPPORT:
1291271294Sngie		return ("EPROTONOSUPPORT");
1292271294Sngie#endif
1293271294Sngie#ifdef ESOCKTNOSUPPORT
1294271294Sngie	case ESOCKTNOSUPPORT:
1295271294Sngie		return ("ESOCKTNOSUPPORT");
1296271294Sngie#endif
1297271294Sngie#ifdef EOPNOTSUPP
1298271294Sngie	case EOPNOTSUPP:
1299271294Sngie		return ("EOPNOTSUPP");
1300271294Sngie#endif
1301271294Sngie#ifdef EPFNOSUPPORT
1302271294Sngie	case EPFNOSUPPORT:
1303271294Sngie		return ("EPFNOSUPPORT");
1304271294Sngie#endif
1305271294Sngie#ifdef EAFNOSUPPORT
1306271294Sngie	case EAFNOSUPPORT:
1307271294Sngie		return ("EAFNOSUPPORT");
1308271294Sngie#endif
1309271294Sngie#ifdef EADDRINUSE
1310271294Sngie	case EADDRINUSE:
1311271294Sngie		return ("EADDRINUSE");
1312271294Sngie#endif
1313271294Sngie#ifdef EADDRNOTAVAIL
1314271294Sngie	case EADDRNOTAVAIL:
1315271294Sngie		return ("EADDRNOTAVAIL");
1316271294Sngie#endif
1317271294Sngie#ifdef ENETDOWN
1318271294Sngie	case ENETDOWN:
1319271294Sngie		return ("ENETDOWN");
1320271294Sngie#endif
1321271294Sngie#ifdef ENETUNREACH
1322271294Sngie	case ENETUNREACH:
1323271294Sngie		return ("ENETUNREACH");
1324271294Sngie#endif
1325271294Sngie#ifdef ENETRESET
1326271294Sngie	case ENETRESET:
1327271294Sngie		return ("ENETRESET");
1328271294Sngie#endif
1329271294Sngie#ifdef ECONNABORTED
1330271294Sngie	case ECONNABORTED:
1331271294Sngie		return ("ECONNABORTED");
1332271294Sngie#endif
1333271294Sngie#ifdef ECONNRESET
1334271294Sngie	case ECONNRESET:
1335271294Sngie		return ("ECONNRESET");
1336271294Sngie#endif
1337271294Sngie#ifdef ENOBUFS
1338271294Sngie	case ENOBUFS:
1339271294Sngie		return ("ENOBUFS");
1340271294Sngie#endif
1341271294Sngie#ifdef EISCONN
1342271294Sngie	case EISCONN:
1343271294Sngie		return ("EISCONN");
1344271294Sngie#endif
1345271294Sngie#ifdef ENOTCONN
1346271294Sngie	case ENOTCONN:
1347271294Sngie		return ("ENOTCONN");
1348271294Sngie#endif
1349271294Sngie#ifdef ESHUTDOWN
1350271294Sngie	case ESHUTDOWN:
1351271294Sngie		return ("ESHUTDOWN");
1352271294Sngie#endif
1353271294Sngie#ifdef ETOOMANYREFS
1354271294Sngie	case ETOOMANYREFS:
1355271294Sngie		return ("ETOOMANYREFS");
1356271294Sngie#endif
1357271294Sngie#ifdef ETIMEDOUT
1358271294Sngie	case ETIMEDOUT:
1359271294Sngie		return ("ETIMEDOUT");
1360271294Sngie#endif
1361271294Sngie#ifdef ECONNREFUSED
1362271294Sngie	case ECONNREFUSED:
1363271294Sngie		return ("ECONNREFUSED");
1364271294Sngie#endif
1365271294Sngie#ifdef ELOOP
1366271294Sngie	case ELOOP:
1367271294Sngie		return ("ELOOP");
1368271294Sngie#endif
1369271294Sngie#ifdef ENAMETOOLONG
1370271294Sngie	case ENAMETOOLONG:
1371271294Sngie		return ("ENAMETOOLONG");
1372271294Sngie#endif
1373271294Sngie#ifdef EHOSTDOWN
1374271294Sngie	case EHOSTDOWN:
1375271294Sngie		return ("EHOSTDOWN");
1376271294Sngie#endif
1377271294Sngie#ifdef EHOSTUNREACH
1378271294Sngie	case EHOSTUNREACH:
1379271294Sngie		return ("EHOSTUNREACH");
1380271294Sngie#endif
1381271294Sngie#ifdef ENOTEMPTY
1382271294Sngie	case ENOTEMPTY:
1383271294Sngie		return ("ENOTEMPTY");
1384271294Sngie#endif
1385271294Sngie#ifdef EPROCLIM
1386271294Sngie	case EPROCLIM:
1387271294Sngie		return ("EPROCLIM");
1388271294Sngie#endif
1389271294Sngie#ifdef EUSERS
1390271294Sngie	case EUSERS:
1391271294Sngie		return ("EUSERS");
1392271294Sngie#endif
1393271294Sngie#ifdef EDQUOT
1394271294Sngie	case EDQUOT:
1395271294Sngie		return ("EDQUOT");
1396271294Sngie#endif
1397271294Sngie#ifdef ESTALE
1398271294Sngie	case ESTALE:
1399271294Sngie		return ("ESTALE");
1400271294Sngie#endif
1401271294Sngie#ifdef EREMOTE
1402271294Sngie	case EREMOTE:
1403271294Sngie		return ("EREMOTE");
1404271294Sngie#endif
1405271294Sngie#ifdef EBADRPC
1406271294Sngie	case EBADRPC:
1407271294Sngie		return ("EBADRPC");
1408271294Sngie#endif
1409271294Sngie#ifdef ERPCMISMATCH
1410271294Sngie	case ERPCMISMATCH:
1411271294Sngie		return ("ERPCMISMATCH");
1412271294Sngie#endif
1413271294Sngie#ifdef EPROGUNAVAIL
1414271294Sngie	case EPROGUNAVAIL:
1415271294Sngie		return ("EPROGUNAVAIL");
1416271294Sngie#endif
1417271294Sngie#ifdef EPROGMISMATCH
1418271294Sngie	case EPROGMISMATCH:
1419271294Sngie		return ("EPROGMISMATCH");
1420271294Sngie#endif
1421271294Sngie#ifdef EPROCUNAVAIL
1422271294Sngie	case EPROCUNAVAIL:
1423271294Sngie		return ("EPROCUNAVAIL");
1424271294Sngie#endif
1425271294Sngie#ifdef ENOLCK
1426271294Sngie	case ENOLCK:
1427271294Sngie		return ("ENOLCK");
1428271294Sngie#endif
1429271294Sngie#ifdef ENOSYS
1430271294Sngie	case ENOSYS:
1431271294Sngie		return ("ENOSYS");
1432271294Sngie#endif
1433271294Sngie#ifdef EFTYPE
1434271294Sngie	case EFTYPE:
1435271294Sngie		return ("EFTYPE");
1436271294Sngie#endif
1437271294Sngie#ifdef EAUTH
1438271294Sngie	case EAUTH:
1439271294Sngie		return ("EAUTH");
1440271294Sngie#endif
1441271294Sngie#ifdef ENEEDAUTH
1442271294Sngie	case ENEEDAUTH:
1443271294Sngie		return ("ENEEDAUTH");
1444271294Sngie#endif
1445271294Sngie#ifdef EIDRM
1446271294Sngie	case EIDRM:
1447271294Sngie		return ("EIDRM");
1448271294Sngie#endif
1449271294Sngie#ifdef ENOMSG
1450271294Sngie	case ENOMSG:
1451271294Sngie		return ("ENOMSG");
1452271294Sngie#endif
1453271294Sngie#ifdef EOVERFLOW
1454271294Sngie	case EOVERFLOW:
1455271294Sngie		return ("EOVERFLOW");
1456271294Sngie#endif
1457271294Sngie#ifdef ECANCELED
1458271294Sngie	case ECANCELED:
1459271294Sngie		return ("ECANCELED");
1460271294Sngie#endif
1461271294Sngie#ifdef EILSEQ
1462271294Sngie	case EILSEQ:
1463271294Sngie		return ("EILSEQ");
1464271294Sngie#endif
1465271294Sngie#ifdef ENOATTR
1466271294Sngie	case ENOATTR:
1467271294Sngie		return ("ENOATTR");
1468271294Sngie#endif
1469271294Sngie#ifdef EDOOFUS
1470271294Sngie	case EDOOFUS:
1471271294Sngie		return ("EDOOFUS");
1472271294Sngie#endif
1473271294Sngie#ifdef EBADMSG
1474271294Sngie	case EBADMSG:
1475271294Sngie		return ("EBADMSG");
1476271294Sngie#endif
1477271294Sngie#ifdef EMULTIHOP
1478271294Sngie	case EMULTIHOP:
1479271294Sngie		return ("EMULTIHOP");
1480271294Sngie#endif
1481271294Sngie#ifdef ENOLINK
1482271294Sngie	case ENOLINK:
1483271294Sngie		return ("ENOLINK");
1484271294Sngie#endif
1485271294Sngie#ifdef EPROTO
1486271294Sngie	case EPROTO:
1487271294Sngie		return ("EPROTO");
1488271294Sngie#endif
1489271294Sngie	default:
1490271294Sngie		snprintf(errnum, sizeof(errnum), "%d", error);
1491271294Sngie		return (errnum);
1492271294Sngie	}
1493271294Sngie}
1494