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