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