1166065Spjd/*-
2211351Spjd * Copyright (c) 2006-2010 Pawel Jakub Dawidek <pjd@FreeBSD.org>
3166065Spjd * All rights reserved.
4166065Spjd *
5166065Spjd * Redistribution and use in source and binary forms, with or without
6166065Spjd * modification, are permitted provided that the following conditions
7166065Spjd * are met:
8166065Spjd * 1. Redistributions of source code must retain the above copyright
9166065Spjd *    notice, this list of conditions and the following disclaimer.
10166065Spjd * 2. Redistributions in binary form must reproduce the above copyright
11166065Spjd *    notice, this list of conditions and the following disclaimer in the
12166065Spjd *    documentation and/or other materials provided with the distribution.
13166065Spjd *
14166065Spjd * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
15166065Spjd * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16166065Spjd * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17166065Spjd * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
18166065Spjd * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19166065Spjd * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20166065Spjd * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21166065Spjd * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22166065Spjd * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23166065Spjd * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24166065Spjd * SUCH DAMAGE.
25166065Spjd *
26166065Spjd * $FreeBSD$
27166065Spjd */
28166065Spjd
29166065Spjd#include <sys/param.h>
30210965Spjd#include <sys/types.h>
31166065Spjd#include <sys/stat.h>
32210951Spjd#include <sys/socket.h>
33210951Spjd#include <sys/un.h>
34210965Spjd#ifndef makedev
35210965Spjd#include <sys/mkdev.h>
36210965Spjd#endif
37210964Spjd
38210964Spjd#include <assert.h>
39210964Spjd#include <ctype.h>
40210964Spjd#include <errno.h>
41210964Spjd#include <fcntl.h>
42210964Spjd#include <grp.h>
43166065Spjd#include <stdio.h>
44166065Spjd#include <stdlib.h>
45210964Spjd#include <string.h>
46166065Spjd#include <unistd.h>
47166065Spjd
48166065Spjd#ifndef HAS_TRUNCATE64
49166065Spjd#define	truncate64	truncate
50219437Spjd#define	ftruncate64	ftruncate
51166065Spjd#endif
52166065Spjd#ifndef HAS_STAT64
53166065Spjd#define	stat64	stat
54219437Spjd#define	fstat64	fstat
55166065Spjd#define	lstat64	lstat
56166065Spjd#endif
57196948Strasz#ifdef HAS_FREEBSD_ACL
58196948Strasz#include <sys/acl.h>
59196948Strasz#endif
60166065Spjd
61166065Spjd#ifndef ALLPERMS
62166065Spjd#define	ALLPERMS	(S_ISUID|S_ISGID|S_ISVTX|S_IRWXU|S_IRWXG|S_IRWXO)
63166065Spjd#endif
64166065Spjd
65166065Spjdenum action {
66166065Spjd	ACTION_OPEN,
67219464Spjd	ACTION_OPENAT,
68166065Spjd	ACTION_CREATE,
69166065Spjd	ACTION_UNLINK,
70219464Spjd	ACTION_UNLINKAT,
71166065Spjd	ACTION_MKDIR,
72219464Spjd	ACTION_MKDIRAT,
73166065Spjd	ACTION_RMDIR,
74166065Spjd	ACTION_LINK,
75219464Spjd	ACTION_LINKAT,
76166065Spjd	ACTION_SYMLINK,
77219464Spjd	ACTION_SYMLINKAT,
78166065Spjd	ACTION_RENAME,
79219464Spjd	ACTION_RENAMEAT,
80166065Spjd	ACTION_MKFIFO,
81219464Spjd	ACTION_MKFIFOAT,
82210965Spjd	ACTION_MKNOD,
83219464Spjd	ACTION_MKNODAT,
84210951Spjd	ACTION_BIND,
85247669Spjd#ifdef HAS_BINDAT
86247669Spjd	ACTION_BINDAT,
87247669Spjd#endif
88210951Spjd	ACTION_CONNECT,
89247669Spjd#ifdef HAS_CONNECTAT
90247669Spjd	ACTION_CONNECTAT,
91247669Spjd#endif
92166065Spjd	ACTION_CHMOD,
93219437Spjd	ACTION_FCHMOD,
94166065Spjd#ifdef HAS_LCHMOD
95166065Spjd	ACTION_LCHMOD,
96166065Spjd#endif
97219464Spjd	ACTION_FCHMODAT,
98166065Spjd	ACTION_CHOWN,
99219437Spjd	ACTION_FCHOWN,
100166065Spjd	ACTION_LCHOWN,
101219464Spjd	ACTION_FCHOWNAT,
102166065Spjd#ifdef HAS_CHFLAGS
103166065Spjd	ACTION_CHFLAGS,
104166065Spjd#endif
105219437Spjd#ifdef HAS_FCHFLAGS
106219437Spjd	ACTION_FCHFLAGS,
107219437Spjd#endif
108248603Spjd#ifdef HAS_CHFLAGSAT
109248603Spjd	ACTION_CHFLAGSAT,
110248603Spjd#endif
111166065Spjd#ifdef HAS_LCHFLAGS
112166065Spjd	ACTION_LCHFLAGS,
113166065Spjd#endif
114166065Spjd	ACTION_TRUNCATE,
115219437Spjd	ACTION_FTRUNCATE,
116166065Spjd	ACTION_STAT,
117219437Spjd	ACTION_FSTAT,
118166065Spjd	ACTION_LSTAT,
119219464Spjd	ACTION_FSTATAT,
120196948Strasz	ACTION_PATHCONF,
121219437Spjd	ACTION_FPATHCONF,
122219437Spjd	ACTION_LPATHCONF,
123196948Strasz#ifdef HAS_FREEBSD_ACL
124196948Strasz	ACTION_PREPENDACL,
125196948Strasz	ACTION_READACL,
126196948Strasz#endif
127196948Strasz	ACTION_WRITE,
128166065Spjd};
129166065Spjd
130166065Spjd#define	TYPE_NONE	0x0000
131166065Spjd#define	TYPE_STRING	0x0001
132166065Spjd#define	TYPE_NUMBER	0x0002
133219464Spjd#define	TYPE_DESCRIPTOR	0x0003
134219464Spjd#define	TYPE_MASK	0x000f
135166065Spjd
136166065Spjd#define	TYPE_OPTIONAL	0x0100
137166065Spjd
138166065Spjd#define	MAX_ARGS	8
139166065Spjd
140166065Spjdstruct syscall_desc {
141219566Spjd	const char	*sd_name;
142166065Spjd	enum action	 sd_action;
143166065Spjd	int		 sd_args[MAX_ARGS];
144166065Spjd};
145166065Spjd
146166065Spjdstatic struct syscall_desc syscalls[] = {
147166065Spjd	{ "open", ACTION_OPEN, { TYPE_STRING, TYPE_STRING, TYPE_NUMBER | TYPE_OPTIONAL, TYPE_NONE } },
148219464Spjd	{ "openat", ACTION_OPENAT, { TYPE_DESCRIPTOR, TYPE_STRING, TYPE_STRING, TYPE_NUMBER | TYPE_OPTIONAL, TYPE_NONE } },
149166065Spjd	{ "create", ACTION_CREATE, { TYPE_STRING, TYPE_NUMBER, TYPE_NONE } },
150166065Spjd	{ "unlink", ACTION_UNLINK, { TYPE_STRING, TYPE_NONE } },
151219464Spjd	{ "unlinkat", ACTION_UNLINKAT, { TYPE_DESCRIPTOR, TYPE_STRING, TYPE_STRING, TYPE_NONE } },
152166065Spjd	{ "mkdir", ACTION_MKDIR, { TYPE_STRING, TYPE_NUMBER, TYPE_NONE } },
153219464Spjd	{ "mkdirat", ACTION_MKDIRAT, { TYPE_DESCRIPTOR, TYPE_STRING, TYPE_NUMBER, TYPE_NONE } },
154166065Spjd	{ "rmdir", ACTION_RMDIR, { TYPE_STRING, TYPE_NONE } },
155166065Spjd	{ "link", ACTION_LINK, { TYPE_STRING, TYPE_STRING, TYPE_NONE } },
156219464Spjd	{ "linkat", ACTION_LINKAT, { TYPE_DESCRIPTOR, TYPE_STRING, TYPE_DESCRIPTOR, TYPE_STRING, TYPE_STRING, TYPE_NONE } },
157166065Spjd	{ "symlink", ACTION_SYMLINK, { TYPE_STRING, TYPE_STRING, TYPE_NONE } },
158219464Spjd	{ "symlinkat", ACTION_SYMLINKAT, { TYPE_STRING, TYPE_DESCRIPTOR, TYPE_STRING, TYPE_NONE } },
159166065Spjd	{ "rename", ACTION_RENAME, { TYPE_STRING, TYPE_STRING, TYPE_NONE } },
160219464Spjd	{ "renameat", ACTION_RENAMEAT, { TYPE_DESCRIPTOR, TYPE_STRING, TYPE_DESCRIPTOR, TYPE_STRING, TYPE_NONE } },
161166065Spjd	{ "mkfifo", ACTION_MKFIFO, { TYPE_STRING, TYPE_NUMBER, TYPE_NONE } },
162219464Spjd	{ "mkfifoat", ACTION_MKFIFOAT, { TYPE_DESCRIPTOR, TYPE_STRING, TYPE_NUMBER, TYPE_NONE } },
163210965Spjd	{ "mknod", ACTION_MKNOD, { TYPE_STRING, TYPE_STRING, TYPE_NUMBER, TYPE_NUMBER, TYPE_NUMBER, TYPE_NONE} },
164219464Spjd	{ "mknodat", ACTION_MKNODAT, { TYPE_DESCRIPTOR, TYPE_STRING, TYPE_STRING, TYPE_NUMBER, TYPE_NUMBER, TYPE_NUMBER, TYPE_NONE} },
165210951Spjd	{ "bind", ACTION_BIND, { TYPE_STRING, TYPE_NONE } },
166247669Spjd#ifdef HAS_BINDAT
167247669Spjd	{ "bindat", ACTION_BINDAT, { TYPE_DESCRIPTOR, TYPE_STRING, TYPE_NONE } },
168247669Spjd#endif
169210951Spjd	{ "connect", ACTION_CONNECT, { TYPE_STRING, TYPE_NONE } },
170247669Spjd#ifdef HAS_CONNECTAT
171247669Spjd	{ "connectat", ACTION_CONNECTAT, { TYPE_DESCRIPTOR, TYPE_STRING, TYPE_NONE } },
172247669Spjd#endif
173166065Spjd	{ "chmod", ACTION_CHMOD, { TYPE_STRING, TYPE_NUMBER, TYPE_NONE } },
174219464Spjd	{ "fchmod", ACTION_FCHMOD, { TYPE_DESCRIPTOR, TYPE_NUMBER, TYPE_NONE } },
175166065Spjd#ifdef HAS_LCHMOD
176166065Spjd	{ "lchmod", ACTION_LCHMOD, { TYPE_STRING, TYPE_NUMBER, TYPE_NONE } },
177166065Spjd#endif
178219464Spjd	{ "fchmodat", ACTION_FCHMODAT, { TYPE_DESCRIPTOR, TYPE_STRING, TYPE_NUMBER, TYPE_STRING, TYPE_NONE } },
179166065Spjd	{ "chown", ACTION_CHOWN, { TYPE_STRING, TYPE_NUMBER, TYPE_NUMBER, TYPE_NONE } },
180219464Spjd	{ "fchown", ACTION_FCHOWN, { TYPE_DESCRIPTOR, TYPE_NUMBER, TYPE_NUMBER, TYPE_NONE } },
181166065Spjd	{ "lchown", ACTION_LCHOWN, { TYPE_STRING, TYPE_NUMBER, TYPE_NUMBER, TYPE_NONE } },
182219464Spjd	{ "fchownat", ACTION_FCHOWNAT, { TYPE_DESCRIPTOR, TYPE_STRING, TYPE_NUMBER, TYPE_NUMBER, TYPE_STRING, TYPE_NONE } },
183166065Spjd#ifdef HAS_CHFLAGS
184166065Spjd	{ "chflags", ACTION_CHFLAGS, { TYPE_STRING, TYPE_STRING, TYPE_NONE } },
185166065Spjd#endif
186219437Spjd#ifdef HAS_FCHFLAGS
187219464Spjd	{ "fchflags", ACTION_FCHFLAGS, { TYPE_DESCRIPTOR, TYPE_STRING, TYPE_NONE } },
188219437Spjd#endif
189248603Spjd#ifdef HAS_CHFLAGSAT
190248603Spjd	{ "chflagsat", ACTION_CHFLAGSAT, { TYPE_DESCRIPTOR, TYPE_STRING, TYPE_STRING, TYPE_STRING, TYPE_NONE } },
191248603Spjd#endif
192166065Spjd#ifdef HAS_LCHFLAGS
193166065Spjd	{ "lchflags", ACTION_LCHFLAGS, { TYPE_STRING, TYPE_STRING, TYPE_NONE } },
194166065Spjd#endif
195166065Spjd	{ "truncate", ACTION_TRUNCATE, { TYPE_STRING, TYPE_NUMBER, TYPE_NONE } },
196219464Spjd	{ "ftruncate", ACTION_FTRUNCATE, { TYPE_DESCRIPTOR, TYPE_NUMBER, TYPE_NONE } },
197166065Spjd	{ "stat", ACTION_STAT, { TYPE_STRING, TYPE_STRING, TYPE_NONE } },
198219464Spjd	{ "fstat", ACTION_FSTAT, { TYPE_DESCRIPTOR, TYPE_STRING, TYPE_NONE } },
199166065Spjd	{ "lstat", ACTION_LSTAT, { TYPE_STRING, TYPE_STRING, TYPE_NONE } },
200219464Spjd	{ "fstatat", ACTION_FSTATAT, { TYPE_DESCRIPTOR, TYPE_STRING, TYPE_STRING, TYPE_STRING, TYPE_NONE } },
201185219Spjd	{ "pathconf", ACTION_PATHCONF, { TYPE_STRING, TYPE_STRING, TYPE_NONE } },
202219464Spjd	{ "fpathconf", ACTION_FPATHCONF, { TYPE_DESCRIPTOR, TYPE_STRING, TYPE_NONE } },
203219437Spjd	{ "lpathconf", ACTION_LPATHCONF, { TYPE_STRING, TYPE_STRING, TYPE_NONE } },
204196948Strasz#ifdef HAS_FREEBSD_ACL
205196948Strasz	{ "prependacl", ACTION_PREPENDACL, { TYPE_STRING, TYPE_STRING, TYPE_NONE } },
206196948Strasz	{ "readacl", ACTION_READACL, { TYPE_STRING, TYPE_NONE } },
207196948Strasz#endif
208219464Spjd	{ "write", ACTION_WRITE, { TYPE_DESCRIPTOR, TYPE_STRING, TYPE_NONE } },
209166065Spjd	{ NULL, -1, { TYPE_NONE } }
210166065Spjd};
211166065Spjd
212166065Spjdstruct flag {
213166065Spjd	long long	 f_flag;
214219566Spjd	const char	*f_str;
215166065Spjd};
216166065Spjd
217166065Spjdstatic struct flag open_flags[] = {
218166065Spjd#ifdef O_RDONLY
219166065Spjd	{ O_RDONLY, "O_RDONLY" },
220166065Spjd#endif
221166065Spjd#ifdef O_WRONLY
222166065Spjd	{ O_WRONLY, "O_WRONLY" },
223166065Spjd#endif
224166065Spjd#ifdef O_RDWR
225166065Spjd	{ O_RDWR, "O_RDWR" },
226166065Spjd#endif
227166065Spjd#ifdef O_NONBLOCK
228166065Spjd	{ O_NONBLOCK, "O_NONBLOCK" },
229166065Spjd#endif
230166065Spjd#ifdef O_APPEND
231166065Spjd	{ O_APPEND, "O_APPEND" },
232166065Spjd#endif
233166065Spjd#ifdef O_CREAT
234166065Spjd	{ O_CREAT, "O_CREAT" },
235166065Spjd#endif
236166065Spjd#ifdef O_TRUNC
237166065Spjd	{ O_TRUNC, "O_TRUNC" },
238166065Spjd#endif
239166065Spjd#ifdef O_EXCL
240166065Spjd	{ O_EXCL, "O_EXCL" },
241166065Spjd#endif
242166065Spjd#ifdef O_SHLOCK
243166065Spjd	{ O_SHLOCK, "O_SHLOCK" },
244166065Spjd#endif
245166065Spjd#ifdef O_EXLOCK
246166065Spjd	{ O_EXLOCK, "O_EXLOCK" },
247166065Spjd#endif
248166065Spjd#ifdef O_DIRECT
249166065Spjd	{ O_DIRECT, "O_DIRECT" },
250166065Spjd#endif
251166065Spjd#ifdef O_FSYNC
252166065Spjd	{ O_FSYNC, "O_FSYNC" },
253166065Spjd#endif
254166065Spjd#ifdef O_SYNC
255166065Spjd	{ O_SYNC, "O_SYNC" },
256166065Spjd#endif
257166065Spjd#ifdef O_NOFOLLOW
258166065Spjd	{ O_NOFOLLOW, "O_NOFOLLOW" },
259166065Spjd#endif
260166065Spjd#ifdef O_NOCTTY
261166065Spjd	{ O_NOCTTY, "O_NOCTTY" },
262166065Spjd#endif
263219464Spjd#ifdef O_DIRECTORY
264219464Spjd	{ O_DIRECTORY, "O_DIRECTORY" },
265219464Spjd#endif
266166065Spjd	{ 0, NULL }
267166065Spjd};
268166065Spjd
269166065Spjd#ifdef HAS_CHFLAGS
270166065Spjdstatic struct flag chflags_flags[] = {
271166065Spjd#ifdef UF_NODUMP
272166065Spjd	{ UF_NODUMP, "UF_NODUMP" },
273166065Spjd#endif
274166065Spjd#ifdef UF_IMMUTABLE
275166065Spjd	{ UF_IMMUTABLE, "UF_IMMUTABLE" },
276166065Spjd#endif
277166065Spjd#ifdef UF_APPEND
278166065Spjd	{ UF_APPEND, "UF_APPEND" },
279166065Spjd#endif
280166065Spjd#ifdef UF_NOUNLINK
281166065Spjd	{ UF_NOUNLINK, "UF_NOUNLINK" },
282166065Spjd#endif
283166065Spjd#ifdef UF_OPAQUE
284166065Spjd	{ UF_OPAQUE, "UF_OPAQUE" },
285166065Spjd#endif
286166065Spjd#ifdef SF_ARCHIVED
287166065Spjd	{ SF_ARCHIVED, "SF_ARCHIVED" },
288166065Spjd#endif
289166065Spjd#ifdef SF_IMMUTABLE
290166065Spjd	{ SF_IMMUTABLE, "SF_IMMUTABLE" },
291166065Spjd#endif
292166065Spjd#ifdef SF_APPEND
293166065Spjd	{ SF_APPEND, "SF_APPEND" },
294166065Spjd#endif
295166065Spjd#ifdef SF_NOUNLINK
296166065Spjd	{ SF_NOUNLINK, "SF_NOUNLINK" },
297166065Spjd#endif
298166065Spjd#ifdef SF_SNAPSHOT
299166065Spjd	{ SF_SNAPSHOT, "SF_SNAPSHOT" },
300166065Spjd#endif
301166065Spjd	{ 0, NULL }
302166065Spjd};
303166065Spjd#endif
304166065Spjd
305219464Spjdstatic struct flag unlinkat_flags[] = {
306219464Spjd	{ AT_REMOVEDIR, "AT_REMOVEDIR" },
307219464Spjd	{ 0, NULL }
308219464Spjd};
309219464Spjd
310219464Spjdstatic struct flag linkat_flags[] = {
311219464Spjd	{ AT_SYMLINK_FOLLOW, "AT_SYMLINK_FOLLOW" },
312219464Spjd	{ 0, NULL }
313219464Spjd};
314219464Spjd
315248603Spjdstatic struct flag chflagsat_flags[] = {
316248603Spjd	{ AT_SYMLINK_NOFOLLOW, "AT_SYMLINK_NOFOLLOW" },
317248603Spjd	{ 0, NULL }
318248603Spjd};
319248603Spjd
320219464Spjdstatic struct flag fchmodat_flags[] = {
321219464Spjd	{ AT_SYMLINK_NOFOLLOW, "AT_SYMLINK_NOFOLLOW" },
322219464Spjd	{ 0, NULL }
323219464Spjd};
324219464Spjd
325219464Spjdstatic struct flag fchownat_flags[] = {
326219464Spjd	{ AT_SYMLINK_NOFOLLOW, "AT_SYMLINK_NOFOLLOW" },
327219464Spjd	{ 0, NULL }
328219464Spjd};
329219464Spjd
330219464Spjdstatic struct flag fstatat_flags[] = {
331219464Spjd	{ AT_SYMLINK_NOFOLLOW, "AT_SYMLINK_NOFOLLOW" },
332219464Spjd	{ 0, NULL }
333219464Spjd};
334219464Spjd
335185219Spjdstruct name {
336219566Spjd	int		 n_name;
337219566Spjd	const char	*n_str;
338185219Spjd};
339185219Spjd
340185219Spjdstatic struct name pathconf_names[] = {
341185219Spjd#ifdef _PC_LINK_MAX
342185219Spjd	{ _PC_LINK_MAX, "_PC_LINK_MAX" },
343185219Spjd#endif
344185219Spjd#ifdef _PC_NAME_MAX
345185219Spjd	{ _PC_NAME_MAX, "_PC_NAME_MAX" },
346185219Spjd#endif
347185219Spjd#ifdef _PC_PATH_MAX
348185219Spjd	{ _PC_PATH_MAX, "_PC_PATH_MAX" },
349185219Spjd#endif
350185219Spjd#ifdef _PC_SYMLINK_MAX
351185219Spjd	{ _PC_SYMLINK_MAX, "_PC_SYMLINK_MAX" },
352185219Spjd#endif
353185219Spjd	{ 0, NULL }
354185219Spjd};
355185219Spjd
356166065Spjdstatic const char *err2str(int error);
357166065Spjd
358219437Spjdstatic int *descriptors;
359219437Spjdstatic int ndescriptors;
360219437Spjd
361166065Spjdstatic void
362166065Spjdusage(void)
363166065Spjd{
364166065Spjd
365211354Spjd	fprintf(stderr, "usage: pjdfstest [-U umask] [-u uid] [-g gid1[,gid2[...]]] syscall args ...\n");
366166065Spjd	exit(1);
367166065Spjd}
368166065Spjd
369166065Spjdstatic long long
370166065Spjdstr2flags(struct flag *tflags, char *sflags)
371166065Spjd{
372166065Spjd	long long flags = 0;
373166065Spjd	unsigned int i;
374166065Spjd	char *f;
375166065Spjd
376238110Spjd	/* 'none' or '0' means no flags */
377238110Spjd	if (strcmp(sflags, "none") == 0 || strcmp(sflags, "0") == 0)
378238110Spjd		return (0);
379238110Spjd	for (f = strtok(sflags, ",|"); f != NULL; f = strtok(NULL, ",|")) {
380166065Spjd		for (i = 0; tflags[i].f_str != NULL; i++) {
381166065Spjd			if (strcmp(tflags[i].f_str, f) == 0)
382166065Spjd				break;
383166065Spjd		}
384166065Spjd		if (tflags[i].f_str == NULL) {
385166065Spjd			fprintf(stderr, "unknown flag '%s'\n", f);
386166065Spjd			exit(1);
387166065Spjd		}
388166065Spjd		flags |= tflags[i].f_flag;
389166065Spjd	}
390166065Spjd	return (flags);
391166065Spjd}
392166065Spjd
393166065Spjd#ifdef HAS_CHFLAGS
394166065Spjdstatic char *
395166065Spjdflags2str(struct flag *tflags, long long flags)
396166065Spjd{
397166065Spjd	static char sflags[1024];
398166065Spjd	unsigned int i;
399166065Spjd
400166065Spjd	sflags[0] = '\0';
401166065Spjd	for (i = 0; tflags[i].f_str != NULL; i++) {
402166065Spjd		if (flags & tflags[i].f_flag) {
403166065Spjd			if (sflags[0] != '\0')
404166065Spjd				strlcat(sflags, ",", sizeof(sflags));
405166065Spjd			strlcat(sflags, tflags[i].f_str, sizeof(sflags));
406166065Spjd		}
407166065Spjd	}
408166065Spjd	if (sflags[0] == '\0')
409166065Spjd		strlcpy(sflags, "none", sizeof(sflags));
410166065Spjd	return (sflags);
411166065Spjd}
412166065Spjd#endif
413166065Spjd
414185219Spjdstatic int
415185219Spjdstr2name(struct name *names, char *name)
416185219Spjd{
417185219Spjd	unsigned int i;
418185219Spjd
419185219Spjd	for (i = 0; names[i].n_str != NULL; i++) {
420185219Spjd		if (strcmp(names[i].n_str, name) == 0)
421185219Spjd			return (names[i].n_name);
422185219Spjd	}
423185219Spjd	return (-1);
424185219Spjd}
425185219Spjd
426166065Spjdstatic struct syscall_desc *
427166065Spjdfind_syscall(const char *name)
428166065Spjd{
429166065Spjd	int i;
430166065Spjd
431166065Spjd	for (i = 0; syscalls[i].sd_name != NULL; i++) {
432166065Spjd		if (strcmp(syscalls[i].sd_name, name) == 0)
433166065Spjd			return (&syscalls[i]);
434166065Spjd	}
435166065Spjd	return (NULL);
436166065Spjd}
437166065Spjd
438166065Spjdstatic void
439166065Spjdshow_stat(struct stat64 *sp, const char *what)
440166065Spjd{
441166065Spjd
442166065Spjd	if (strcmp(what, "mode") == 0)
443166065Spjd		printf("0%o", (unsigned int)(sp->st_mode & ALLPERMS));
444166065Spjd	else if (strcmp(what, "inode") == 0)
445166065Spjd		printf("%lld", (long long)sp->st_ino);
446166065Spjd	else if (strcmp(what, "nlink") == 0)
447166065Spjd		printf("%lld", (long long)sp->st_nlink);
448166065Spjd	else if (strcmp(what, "uid") == 0)
449166065Spjd		printf("%d", (int)sp->st_uid);
450166065Spjd	else if (strcmp(what, "gid") == 0)
451166065Spjd		printf("%d", (int)sp->st_gid);
452166065Spjd	else if (strcmp(what, "size") == 0)
453166065Spjd		printf("%lld", (long long)sp->st_size);
454166065Spjd	else if (strcmp(what, "blocks") == 0)
455166065Spjd		printf("%lld", (long long)sp->st_blocks);
456166065Spjd	else if (strcmp(what, "atime") == 0)
457166065Spjd		printf("%lld", (long long)sp->st_atime);
458166065Spjd	else if (strcmp(what, "mtime") == 0)
459166065Spjd		printf("%lld", (long long)sp->st_mtime);
460166065Spjd	else if (strcmp(what, "ctime") == 0)
461166065Spjd		printf("%lld", (long long)sp->st_ctime);
462166065Spjd#ifdef HAS_CHFLAGS
463166065Spjd	else if (strcmp(what, "flags") == 0)
464188934Spjd		printf("%s", flags2str(chflags_flags, (long long)sp->st_flags));
465166065Spjd#endif
466210965Spjd	else if (strcmp(what, "major") == 0)
467210965Spjd		printf("%u", (unsigned int)major(sp->st_rdev));
468210965Spjd	else if (strcmp(what, "minor") == 0)
469210965Spjd		printf("%u", (unsigned int)minor(sp->st_rdev));
470166065Spjd	else if (strcmp(what, "type") == 0) {
471166065Spjd		switch (sp->st_mode & S_IFMT) {
472166065Spjd		case S_IFIFO:
473166065Spjd			printf("fifo");
474166065Spjd			break;
475166065Spjd		case S_IFCHR:
476166065Spjd			printf("char");
477166065Spjd			break;
478166065Spjd		case S_IFDIR:
479166065Spjd			printf("dir");
480166065Spjd			break;
481166065Spjd		case S_IFBLK:
482166065Spjd			printf("block");
483166065Spjd			break;
484166065Spjd		case S_IFREG:
485166065Spjd			printf("regular");
486166065Spjd			break;
487166065Spjd		case S_IFLNK:
488166065Spjd			printf("symlink");
489166065Spjd			break;
490166065Spjd		case S_IFSOCK:
491166065Spjd			printf("socket");
492166065Spjd			break;
493166065Spjd		default:
494166065Spjd			printf("unknown");
495166065Spjd			break;
496166065Spjd		}
497166065Spjd	} else {
498166065Spjd		printf("unknown");
499166065Spjd	}
500166065Spjd}
501166065Spjd
502166065Spjdstatic void
503166065Spjdshow_stats(struct stat64 *sp, char *what)
504166065Spjd{
505166065Spjd	const char *s = "";
506166065Spjd	char *w;
507166065Spjd
508166065Spjd	for (w = strtok(what, ","); w != NULL; w = strtok(NULL, ",")) {
509166065Spjd		printf("%s", s);
510166065Spjd		show_stat(sp, w);
511166065Spjd		s = ",";
512166065Spjd	}
513166065Spjd	printf("\n");
514166065Spjd}
515166065Spjd
516219437Spjdstatic void
517219437Spjddescriptor_add(int fd)
518219437Spjd{
519219437Spjd
520219437Spjd	ndescriptors++;
521219437Spjd	if (descriptors == NULL) {
522219437Spjd		descriptors = malloc(sizeof(descriptors[0]) * ndescriptors);
523219437Spjd	} else {
524219437Spjd		descriptors = realloc(descriptors,
525219437Spjd		    sizeof(descriptors[0]) * ndescriptors);
526219437Spjd	}
527219437Spjd	assert(descriptors != NULL);
528219437Spjd	descriptors[ndescriptors - 1] = fd;
529219437Spjd}
530219437Spjd
531219437Spjdstatic int
532219437Spjddescriptor_get(int pos)
533219437Spjd{
534219437Spjd
535219437Spjd	if (pos < 0 || pos >= ndescriptors) {
536219437Spjd		fprintf(stderr, "invalid descriptor %d\n", pos);
537219437Spjd		exit(1);
538219437Spjd	}
539219437Spjd
540219437Spjd	return (descriptors[pos]);
541219437Spjd}
542219437Spjd
543166065Spjdstatic unsigned int
544166065Spjdcall_syscall(struct syscall_desc *scall, char *argv[])
545166065Spjd{
546166065Spjd	struct stat64 sb;
547166065Spjd	long long flags;
548166065Spjd	unsigned int i;
549166065Spjd	char *endp;
550185219Spjd	int name, rval;
551166065Spjd	union {
552166065Spjd		char *str;
553166065Spjd		long long num;
554166065Spjd	} args[MAX_ARGS];
555196948Strasz#ifdef HAS_FREEBSD_ACL
556196948Strasz	int entry_id = ACL_FIRST_ENTRY;
557196948Strasz	acl_t acl, newacl;
558196948Strasz	acl_entry_t entry, newentry;
559196948Strasz#endif
560166065Spjd
561166065Spjd	/*
562166065Spjd	 * Verify correctness of the arguments.
563166065Spjd	 */
564166065Spjd	for (i = 0; i < sizeof(args)/sizeof(args[0]); i++) {
565166065Spjd		if (scall->sd_args[i] == TYPE_NONE) {
566166065Spjd			if (argv[i] == NULL || strcmp(argv[i], ":") == 0)
567166065Spjd				break;
568166065Spjd			fprintf(stderr, "too many arguments [%s]\n", argv[i]);
569166065Spjd			exit(1);
570166065Spjd		} else {
571166065Spjd			if (argv[i] == NULL || strcmp(argv[i], ":") == 0) {
572166065Spjd				if (scall->sd_args[i] & TYPE_OPTIONAL)
573166065Spjd					break;
574166065Spjd				fprintf(stderr, "too few arguments\n");
575166065Spjd				exit(1);
576166065Spjd			}
577219464Spjd			if ((scall->sd_args[i] & TYPE_MASK) == TYPE_STRING) {
578166065Spjd				if (strcmp(argv[i], "NULL") == 0)
579166065Spjd					args[i].str = NULL;
580166065Spjd				else if (strcmp(argv[i], "DEADCODE") == 0)
581166065Spjd					args[i].str = (void *)0xdeadc0de;
582166065Spjd				else
583166065Spjd					args[i].str = argv[i];
584249594Spjd			} else if ((scall->sd_args[i] & TYPE_MASK) ==
585249594Spjd			    TYPE_NUMBER) {
586166065Spjd				args[i].num = strtoll(argv[i], &endp, 0);
587249594Spjd				if (*endp != '\0' &&
588249594Spjd				    !isspace((unsigned char)*endp)) {
589249594Spjd					fprintf(stderr,
590249594Spjd					    "invalid argument %u, number expected [%s]\n",
591249594Spjd					    i, endp);
592166065Spjd					exit(1);
593166065Spjd				}
594249594Spjd			} else if ((scall->sd_args[i] & TYPE_MASK) ==
595249594Spjd			    TYPE_DESCRIPTOR) {
596219464Spjd				if (strcmp(argv[i], "AT_FDCWD") == 0) {
597219464Spjd					args[i].num = AT_FDCWD;
598219464Spjd				} else if (strcmp(argv[i], "BADFD") == 0) {
599219464Spjd					/* In case AT_FDCWD is -1 on some systems... */
600219464Spjd					if (AT_FDCWD == -1)
601219464Spjd						args[i].num = -2;
602219464Spjd					else
603219464Spjd						args[i].num = -1;
604219464Spjd				} else {
605219464Spjd					int pos;
606219464Spjd
607219464Spjd					pos = strtoll(argv[i], &endp, 0);
608249594Spjd					if (*endp != '\0' &&
609249594Spjd					    !isspace((unsigned char)*endp)) {
610249594Spjd						fprintf(stderr,
611249594Spjd						    "invalid argument %u, number expected [%s]\n",
612249594Spjd						    i, endp);
613219464Spjd						exit(1);
614219464Spjd					}
615219464Spjd					args[i].num = descriptor_get(pos);
616219464Spjd				}
617166065Spjd			}
618166065Spjd		}
619166065Spjd	}
620166065Spjd	/*
621166065Spjd	 * Call the given syscall.
622166065Spjd	 */
623166065Spjd#define	NUM(n)	(args[(n)].num)
624166065Spjd#define	STR(n)	(args[(n)].str)
625166065Spjd	switch (scall->sd_action) {
626166065Spjd	case ACTION_OPEN:
627166065Spjd		flags = str2flags(open_flags, STR(1));
628166065Spjd		if (flags & O_CREAT) {
629166065Spjd			if (i == 2) {
630166065Spjd				fprintf(stderr, "too few arguments\n");
631166065Spjd				exit(1);
632166065Spjd			}
633188934Spjd			rval = open(STR(0), (int)flags, (mode_t)NUM(2));
634166065Spjd		} else {
635166065Spjd			if (i == 3) {
636166065Spjd				fprintf(stderr, "too many arguments\n");
637166065Spjd				exit(1);
638166065Spjd			}
639188934Spjd			rval = open(STR(0), (int)flags);
640166065Spjd		}
641219437Spjd		if (rval >= 0)
642219437Spjd			descriptor_add(rval);
643166065Spjd		break;
644219464Spjd	case ACTION_OPENAT:
645219464Spjd		flags = str2flags(open_flags, STR(2));
646219464Spjd		if (flags & O_CREAT) {
647219464Spjd			if (i == 3) {
648219464Spjd				fprintf(stderr, "too few arguments\n");
649219464Spjd				exit(1);
650219464Spjd			}
651249594Spjd			rval = openat(NUM(0), STR(1), (int)flags,
652249594Spjd			    (mode_t)NUM(3));
653219464Spjd		} else {
654219464Spjd			if (i == 4) {
655219464Spjd				fprintf(stderr, "too many arguments\n");
656219464Spjd				exit(1);
657219464Spjd			}
658219464Spjd			rval = openat(NUM(0), STR(1), (int)flags);
659219464Spjd		}
660219464Spjd		if (rval >= 0)
661219464Spjd			descriptor_add(rval);
662219464Spjd		break;
663166065Spjd	case ACTION_CREATE:
664188934Spjd		rval = open(STR(0), O_CREAT | O_EXCL, (mode_t)NUM(1));
665166065Spjd		if (rval >= 0)
666166065Spjd			close(rval);
667166065Spjd		break;
668166065Spjd	case ACTION_UNLINK:
669166065Spjd		rval = unlink(STR(0));
670166065Spjd		break;
671219464Spjd	case ACTION_UNLINKAT:
672219464Spjd		rval = unlinkat(NUM(0), STR(1),
673219464Spjd		    (int)str2flags(unlinkat_flags, STR(2)));
674219464Spjd		break;
675166065Spjd	case ACTION_MKDIR:
676188934Spjd		rval = mkdir(STR(0), (mode_t)NUM(1));
677166065Spjd		break;
678219464Spjd	case ACTION_MKDIRAT:
679219464Spjd		rval = mkdirat(NUM(0), STR(1), (mode_t)NUM(2));
680219464Spjd		break;
681166065Spjd	case ACTION_RMDIR:
682166065Spjd		rval = rmdir(STR(0));
683166065Spjd		break;
684166065Spjd	case ACTION_LINK:
685166065Spjd		rval = link(STR(0), STR(1));
686166065Spjd		break;
687219464Spjd	case ACTION_LINKAT:
688219464Spjd		rval = linkat(NUM(0), STR(1), NUM(2), STR(3),
689219464Spjd		    (int)str2flags(linkat_flags, STR(4)));
690219464Spjd		break;
691166065Spjd	case ACTION_SYMLINK:
692166065Spjd		rval = symlink(STR(0), STR(1));
693166065Spjd		break;
694219464Spjd	case ACTION_SYMLINKAT:
695219464Spjd		rval = symlinkat(STR(0), NUM(1), STR(2));
696219464Spjd		break;
697166065Spjd	case ACTION_RENAME:
698166065Spjd		rval = rename(STR(0), STR(1));
699166065Spjd		break;
700219464Spjd	case ACTION_RENAMEAT:
701219464Spjd		rval = renameat(NUM(0), STR(1), NUM(2), STR(3));
702219464Spjd		break;
703166065Spjd	case ACTION_MKFIFO:
704188934Spjd		rval = mkfifo(STR(0), (mode_t)NUM(1));
705166065Spjd		break;
706219464Spjd	case ACTION_MKFIFOAT:
707219464Spjd		rval = mkfifoat(NUM(0), STR(1), (mode_t)NUM(2));
708219464Spjd		break;
709210965Spjd	case ACTION_MKNOD:
710219464Spjd	case ACTION_MKNODAT:
711210965Spjd	    {
712210965Spjd		mode_t ntype;
713210965Spjd		dev_t dev;
714219464Spjd		int fa;
715210965Spjd
716219464Spjd		switch (scall->sd_action) {
717219464Spjd		case ACTION_MKNOD:
718219464Spjd			fa = 0;
719219464Spjd			break;
720219464Spjd		case ACTION_MKNODAT:
721219464Spjd			fa = 1;
722219464Spjd			break;
723219464Spjd		default:
724219464Spjd			abort();
725219464Spjd		}
726219464Spjd
727219464Spjd		dev = makedev(NUM(fa + 3), NUM(fa + 4));
728249594Spjd		if (strcmp(STR(fa + 1), "c") == 0)	/* character device */
729210965Spjd			ntype = S_IFCHR;
730219464Spjd		else if (strcmp(STR(fa + 1), "b") == 0)	/* block device */
731210965Spjd			ntype = S_IFBLK;
732219464Spjd		else if (strcmp(STR(fa + 1), "f") == 0)	/* fifo special */
733210965Spjd			ntype = S_IFIFO;
734219464Spjd		else if (strcmp(STR(fa + 1), "d") == 0)	/* directory */
735210965Spjd			ntype = S_IFDIR;
736219464Spjd		else if (strcmp(STR(fa + 1), "o") == 0)	/* regular file */
737210965Spjd			ntype = S_IFREG;
738210965Spjd		else {
739210965Spjd			fprintf(stderr, "wrong argument 1\n");
740210965Spjd			exit(1);
741210965Spjd		}
742219464Spjd		switch (scall->sd_action) {
743219464Spjd		case ACTION_MKNOD:
744219464Spjd			rval = mknod(STR(0), ntype | NUM(2), dev);
745219464Spjd			break;
746219464Spjd		case ACTION_MKNODAT:
747219464Spjd			rval = mknodat(NUM(0), STR(1), ntype | NUM(3), dev);
748219464Spjd			break;
749219464Spjd		default:
750219464Spjd			abort();
751219464Spjd		}
752210965Spjd		break;
753210965Spjd	    }
754210951Spjd	case ACTION_BIND:
755210951Spjd	    {
756211110Spjd		struct sockaddr_un sunx;
757210951Spjd
758211110Spjd		sunx.sun_family = AF_UNIX;
759211116Spjd		strncpy(sunx.sun_path, STR(0), sizeof(sunx.sun_path) - 1);
760211116Spjd		sunx.sun_path[sizeof(sunx.sun_path) - 1] = '\0';
761210951Spjd		rval = socket(AF_UNIX, SOCK_STREAM, 0);
762210951Spjd		if (rval < 0)
763210951Spjd			break;
764211110Spjd		rval = bind(rval, (struct sockaddr *)&sunx, sizeof(sunx));
765210951Spjd		break;
766210951Spjd	    }
767247669Spjd#ifdef HAS_BINDAT
768247669Spjd	case ACTION_BINDAT:
769247669Spjd	    {
770247669Spjd		struct sockaddr_un sunx;
771247669Spjd
772247669Spjd		sunx.sun_family = AF_UNIX;
773247669Spjd		strncpy(sunx.sun_path, STR(1), sizeof(sunx.sun_path) - 1);
774247669Spjd		sunx.sun_path[sizeof(sunx.sun_path) - 1] = '\0';
775247669Spjd		rval = socket(AF_UNIX, SOCK_STREAM, 0);
776247669Spjd		if (rval < 0)
777247669Spjd			break;
778247669Spjd		rval = bindat(NUM(0), rval, (struct sockaddr *)&sunx,
779247669Spjd		    sizeof(sunx));
780247669Spjd		break;
781247669Spjd	    }
782247669Spjd#endif
783210951Spjd	case ACTION_CONNECT:
784210951Spjd	    {
785211110Spjd		struct sockaddr_un sunx;
786210951Spjd
787211110Spjd		sunx.sun_family = AF_UNIX;
788211116Spjd		strncpy(sunx.sun_path, STR(0), sizeof(sunx.sun_path) - 1);
789211116Spjd		sunx.sun_path[sizeof(sunx.sun_path) - 1] = '\0';
790210951Spjd		rval = socket(AF_UNIX, SOCK_STREAM, 0);
791210951Spjd		if (rval < 0)
792210951Spjd			break;
793211110Spjd		rval = connect(rval, (struct sockaddr *)&sunx, sizeof(sunx));
794210951Spjd		break;
795210951Spjd	    }
796247669Spjd#ifdef HAS_CONNECTAT
797247669Spjd	case ACTION_CONNECTAT:
798247669Spjd	    {
799247669Spjd		struct sockaddr_un sunx;
800247669Spjd
801247669Spjd		sunx.sun_family = AF_UNIX;
802247669Spjd		strncpy(sunx.sun_path, STR(1), sizeof(sunx.sun_path) - 1);
803247669Spjd		sunx.sun_path[sizeof(sunx.sun_path) - 1] = '\0';
804247669Spjd		rval = socket(AF_UNIX, SOCK_STREAM, 0);
805247669Spjd		if (rval < 0)
806247669Spjd			break;
807247669Spjd		rval = connectat(NUM(0), rval, (struct sockaddr *)&sunx,
808247669Spjd		    sizeof(sunx));
809247669Spjd		break;
810247669Spjd	    }
811247669Spjd#endif
812166065Spjd	case ACTION_CHMOD:
813188934Spjd		rval = chmod(STR(0), (mode_t)NUM(1));
814166065Spjd		break;
815219437Spjd	case ACTION_FCHMOD:
816219464Spjd		rval = fchmod(NUM(0), (mode_t)NUM(1));
817219437Spjd		break;
818166065Spjd#ifdef HAS_LCHMOD
819166065Spjd	case ACTION_LCHMOD:
820188934Spjd		rval = lchmod(STR(0), (mode_t)NUM(1));
821166065Spjd		break;
822166065Spjd#endif
823219464Spjd	case ACTION_FCHMODAT:
824219464Spjd		rval = fchmodat(NUM(0), STR(1), (mode_t)NUM(2),
825219464Spjd		    str2flags(fchmodat_flags, STR(3)));
826219464Spjd		break;
827166065Spjd	case ACTION_CHOWN:
828188934Spjd		rval = chown(STR(0), (uid_t)NUM(1), (gid_t)NUM(2));
829166065Spjd		break;
830219437Spjd	case ACTION_FCHOWN:
831219464Spjd		rval = fchown(NUM(0), (uid_t)NUM(1), (gid_t)NUM(2));
832219437Spjd		break;
833166065Spjd	case ACTION_LCHOWN:
834188934Spjd		rval = lchown(STR(0), (uid_t)NUM(1), (gid_t)NUM(2));
835166065Spjd		break;
836219464Spjd	case ACTION_FCHOWNAT:
837219464Spjd		rval = fchownat(NUM(0), STR(1), (uid_t)NUM(2), (gid_t)NUM(3),
838219464Spjd		    (int)str2flags(fchownat_flags, STR(4)));
839219464Spjd		break;
840166065Spjd#ifdef HAS_CHFLAGS
841166065Spjd	case ACTION_CHFLAGS:
842219464Spjd		rval = chflags(STR(0),
843219464Spjd		    (unsigned long)str2flags(chflags_flags, STR(1)));
844166065Spjd		break;
845166065Spjd#endif
846219437Spjd#ifdef HAS_FCHFLAGS
847219437Spjd	case ACTION_FCHFLAGS:
848219464Spjd		rval = fchflags(NUM(0),
849219464Spjd		    (unsigned long)str2flags(chflags_flags, STR(1)));
850219437Spjd		break;
851219437Spjd#endif
852248603Spjd#ifdef HAS_CHFLAGSAT
853248603Spjd	case ACTION_CHFLAGSAT:
854248603Spjd		rval = chflagsat(NUM(0), STR(1),
855248603Spjd		    (unsigned long)str2flags(chflags_flags, STR(2)),
856248603Spjd		    (int)str2flags(chflagsat_flags, STR(3)));
857248603Spjd		break;
858248603Spjd#endif
859166065Spjd#ifdef HAS_LCHFLAGS
860166065Spjd	case ACTION_LCHFLAGS:
861248597Spjd		rval = lchflags(STR(0),
862248597Spjd		    (unsigned long)str2flags(chflags_flags, STR(1)));
863166065Spjd		break;
864166065Spjd#endif
865166065Spjd	case ACTION_TRUNCATE:
866166065Spjd		rval = truncate64(STR(0), NUM(1));
867166065Spjd		break;
868219437Spjd	case ACTION_FTRUNCATE:
869219464Spjd		rval = ftruncate64(NUM(0), NUM(1));
870219437Spjd		break;
871166065Spjd	case ACTION_STAT:
872166065Spjd		rval = stat64(STR(0), &sb);
873166065Spjd		if (rval == 0) {
874166065Spjd			show_stats(&sb, STR(1));
875166065Spjd			return (i);
876166065Spjd		}
877166065Spjd		break;
878219437Spjd	case ACTION_FSTAT:
879219464Spjd		rval = fstat64(NUM(0), &sb);
880219437Spjd		if (rval == 0) {
881219437Spjd			show_stats(&sb, STR(1));
882219437Spjd			return (i);
883219437Spjd		}
884219437Spjd		break;
885166065Spjd	case ACTION_LSTAT:
886166065Spjd		rval = lstat64(STR(0), &sb);
887166065Spjd		if (rval == 0) {
888166065Spjd			show_stats(&sb, STR(1));
889166065Spjd			return (i);
890166065Spjd		}
891166065Spjd		break;
892219464Spjd	case ACTION_FSTATAT:
893219464Spjd		rval = fstatat(NUM(0), STR(1), &sb,
894219464Spjd		    (int)str2flags(fstatat_flags, STR(2)));
895219464Spjd		if (rval == 0) {
896219464Spjd			show_stats(&sb, STR(3));
897219464Spjd			return (i);
898219464Spjd		}
899219464Spjd		break;
900185219Spjd	case ACTION_PATHCONF:
901219437Spjd	case ACTION_FPATHCONF:
902219437Spjd	case ACTION_LPATHCONF:
903185219Spjd	    {
904185219Spjd		long lrval;
905185219Spjd
906185219Spjd		name = str2name(pathconf_names, STR(1));
907185219Spjd		if (name == -1) {
908185219Spjd			fprintf(stderr, "unknown name %s", STR(1));
909185219Spjd			exit(1);
910185219Spjd		}
911185219Spjd		errno = 0;
912219437Spjd		switch (scall->sd_action) {
913219437Spjd		case ACTION_PATHCONF:
914219437Spjd			lrval = pathconf(STR(0), name);
915219437Spjd			break;
916219437Spjd		case ACTION_FPATHCONF:
917219464Spjd			lrval = fpathconf(NUM(0), name);
918219437Spjd			break;
919219437Spjd		case ACTION_LPATHCONF:
920219437Spjd			lrval = lpathconf(STR(0), name);
921219437Spjd			break;
922219437Spjd		default:
923219437Spjd			abort();
924219437Spjd		}
925185219Spjd		if (lrval == -1 && errno == 0) {
926185219Spjd			printf("unlimited\n");
927185219Spjd			return (i);
928185219Spjd		} else if (lrval >= 0) {
929185219Spjd			printf("%ld\n", lrval);
930185219Spjd			return (i);
931185219Spjd		}
932185219Spjd		rval = -1;
933185219Spjd		break;
934185219Spjd	    }
935196948Strasz#ifdef HAS_FREEBSD_ACL
936196948Strasz	case ACTION_PREPENDACL:
937196948Strasz		rval = -1;
938196948Strasz
939196948Strasz		acl = acl_get_file(STR(0), ACL_TYPE_NFS4);
940196948Strasz		if (acl == NULL)
941196948Strasz			break;
942196948Strasz
943196948Strasz		newacl = acl_from_text(STR(1));
944196948Strasz		if (acl == NULL)
945196948Strasz			break;
946196948Strasz
947196948Strasz		while (acl_get_entry(newacl, entry_id, &newentry) == 1) {
948196948Strasz			entry_id = ACL_NEXT_ENTRY;
949196948Strasz
950196948Strasz			if (acl_create_entry_np(&acl, &entry, 0))
951196948Strasz				break;
952196948Strasz
953196948Strasz			if (acl_copy_entry(entry, newentry))
954196948Strasz				break;
955196948Strasz		}
956196948Strasz
957196948Strasz		rval = acl_set_file(STR(0), ACL_TYPE_NFS4, acl);
958196948Strasz		break;
959196948Strasz	case ACTION_READACL:
960196948Strasz		acl = acl_get_file(STR(0), ACL_TYPE_NFS4);
961196948Strasz		if (acl == NULL)
962196948Strasz			rval = -1;
963196948Strasz		else
964196948Strasz			rval = 0;
965196948Strasz		break;
966196948Strasz#endif
967196948Strasz	case ACTION_WRITE:
968219464Spjd		rval = write(NUM(0), STR(1), strlen(STR(1)));
969196948Strasz		break;
970166065Spjd	default:
971166065Spjd		fprintf(stderr, "unsupported syscall\n");
972166065Spjd		exit(1);
973166065Spjd	}
974166065Spjd#undef STR
975166065Spjd#undef NUM
976166065Spjd	if (rval < 0) {
977166065Spjd		const char *serrno;
978166065Spjd
979166065Spjd		serrno = err2str(errno);
980166065Spjd		fprintf(stderr, "%s returned %d\n", scall->sd_name, rval);
981166065Spjd		printf("%s\n", serrno);
982166065Spjd		exit(1);
983166065Spjd	}
984166065Spjd	printf("0\n");
985166065Spjd	return (i);
986166065Spjd}
987166065Spjd
988166065Spjdstatic void
989166065Spjdset_gids(char *gids)
990166065Spjd{
991166065Spjd	gid_t *gidset;
992166065Spjd	long ngroups;
993166065Spjd	char *g, *endp;
994166065Spjd	unsigned i;
995166065Spjd
996166065Spjd	ngroups = sysconf(_SC_NGROUPS_MAX);
997166065Spjd	assert(ngroups > 0);
998166065Spjd	gidset = malloc(sizeof(*gidset) * ngroups);
999166065Spjd	assert(gidset != NULL);
1000249594Spjd	for (i = 0, g = strtok(gids, ","); g != NULL;
1001249594Spjd	    g = strtok(NULL, ","), i++) {
1002166065Spjd		if (i >= ngroups) {
1003166065Spjd			fprintf(stderr, "too many gids\n");
1004166065Spjd			exit(1);
1005166065Spjd		}
1006166065Spjd		gidset[i] = strtol(g, &endp, 0);
1007166065Spjd		if (*endp != '\0' && !isspace((unsigned char)*endp)) {
1008166065Spjd			fprintf(stderr, "invalid gid '%s' - number expected\n",
1009166065Spjd			    g);
1010166065Spjd			exit(1);
1011166065Spjd		}
1012166065Spjd	}
1013166065Spjd	if (setgroups(i, gidset) < 0) {
1014166065Spjd		fprintf(stderr, "cannot change groups: %s\n", strerror(errno));
1015166065Spjd		exit(1);
1016166065Spjd	}
1017171486Spjd	if (setegid(gidset[0]) < 0) {
1018249594Spjd		fprintf(stderr, "cannot change effective gid: %s\n",
1019249594Spjd		    strerror(errno));
1020171486Spjd		exit(1);
1021171486Spjd	}
1022166065Spjd	free(gidset);
1023166065Spjd}
1024166065Spjd
1025166065Spjdint
1026166065Spjdmain(int argc, char *argv[])
1027166065Spjd{
1028166065Spjd	struct syscall_desc *scall;
1029166065Spjd	unsigned int n;
1030166065Spjd	char *gids, *endp;
1031166065Spjd	int uid, umsk, ch;
1032166065Spjd
1033166065Spjd	uid = -1;
1034166065Spjd	gids = NULL;
1035166065Spjd	umsk = 0;
1036166065Spjd
1037166065Spjd	while ((ch = getopt(argc, argv, "g:u:U:")) != -1) {
1038166065Spjd		switch(ch) {
1039166065Spjd		case 'g':
1040166065Spjd			gids = optarg;
1041166065Spjd			break;
1042166065Spjd		case 'u':
1043166065Spjd			uid = (int)strtol(optarg, &endp, 0);
1044166065Spjd			if (*endp != '\0' && !isspace((unsigned char)*endp)) {
1045166065Spjd				fprintf(stderr, "invalid uid '%s' - number "
1046166065Spjd				    "expected\n", optarg);
1047166065Spjd				exit(1);
1048166065Spjd			}
1049166065Spjd			break;
1050166065Spjd		case 'U':
1051166065Spjd			umsk = (int)strtol(optarg, &endp, 0);
1052166065Spjd			if (*endp != '\0' && !isspace((unsigned char)*endp)) {
1053166065Spjd				fprintf(stderr, "invalid umask '%s' - number "
1054166065Spjd				    "expected\n", optarg);
1055166065Spjd				exit(1);
1056166065Spjd			}
1057166065Spjd			break;
1058166065Spjd		default:
1059166065Spjd			usage();
1060166065Spjd		}
1061166065Spjd	}
1062166065Spjd	argc -= optind;
1063166065Spjd	argv += optind;
1064166065Spjd
1065166065Spjd	if (argc < 1) {
1066166065Spjd		fprintf(stderr, "too few arguments\n");
1067166065Spjd		usage();
1068166065Spjd	}
1069166065Spjd
1070166065Spjd	if (gids != NULL) {
1071166065Spjd		fprintf(stderr, "changing groups to %s\n", gids);
1072166065Spjd		set_gids(gids);
1073166065Spjd	}
1074166065Spjd	if (uid != -1) {
1075166065Spjd		fprintf(stderr, "changing uid to %d\n", uid);
1076166065Spjd		if (setuid(uid) < 0) {
1077166065Spjd			fprintf(stderr, "cannot change uid: %s\n",
1078166065Spjd			    strerror(errno));
1079166065Spjd			exit(1);
1080166065Spjd		}
1081166065Spjd	}
1082166065Spjd
1083166065Spjd	/* Change umask to requested value or to 0, if not requested. */
1084166065Spjd	umask(umsk);
1085166065Spjd
1086166065Spjd	for (;;) {
1087166065Spjd		scall = find_syscall(argv[0]);
1088166065Spjd		if (scall == NULL) {
1089249594Spjd			fprintf(stderr, "syscall '%s' not supported\n",
1090249594Spjd			    argv[0]);
1091166065Spjd			exit(1);
1092166065Spjd		}
1093166065Spjd		argc++;
1094166065Spjd		argv++;
1095166065Spjd		n = call_syscall(scall, argv);
1096166065Spjd		argc += n;
1097166065Spjd		argv += n;
1098166065Spjd		if (argv[0] == NULL)
1099166065Spjd			break;
1100166065Spjd		argc++;
1101166065Spjd		argv++;
1102166065Spjd	}
1103166065Spjd
1104166065Spjd	exit(0);
1105166065Spjd}
1106166065Spjd
1107166065Spjdstatic const char *
1108166065Spjderr2str(int error)
1109166065Spjd{
1110166065Spjd	static char errnum[8];
1111166065Spjd
1112166065Spjd	switch (error) {
1113166065Spjd#ifdef EPERM
1114166065Spjd	case EPERM:
1115166065Spjd		return ("EPERM");
1116166065Spjd#endif
1117166065Spjd#ifdef ENOENT
1118166065Spjd	case ENOENT:
1119166065Spjd		return ("ENOENT");
1120166065Spjd#endif
1121166065Spjd#ifdef ESRCH
1122166065Spjd	case ESRCH:
1123166065Spjd		return ("ESRCH");
1124166065Spjd#endif
1125166065Spjd#ifdef EINTR
1126166065Spjd	case EINTR:
1127166065Spjd		return ("EINTR");
1128166065Spjd#endif
1129166065Spjd#ifdef EIO
1130166065Spjd	case EIO:
1131166065Spjd		return ("EIO");
1132166065Spjd#endif
1133166065Spjd#ifdef ENXIO
1134166065Spjd	case ENXIO:
1135166065Spjd		return ("ENXIO");
1136166065Spjd#endif
1137166065Spjd#ifdef E2BIG
1138166065Spjd	case E2BIG:
1139166065Spjd		return ("E2BIG");
1140166065Spjd#endif
1141166065Spjd#ifdef ENOEXEC
1142166065Spjd	case ENOEXEC:
1143166065Spjd		return ("ENOEXEC");
1144166065Spjd#endif
1145166065Spjd#ifdef EBADF
1146166065Spjd	case EBADF:
1147166065Spjd		return ("EBADF");
1148166065Spjd#endif
1149166065Spjd#ifdef ECHILD
1150166065Spjd	case ECHILD:
1151166065Spjd		return ("ECHILD");
1152166065Spjd#endif
1153166065Spjd#ifdef EDEADLK
1154166065Spjd	case EDEADLK:
1155166065Spjd		return ("EDEADLK");
1156166065Spjd#endif
1157166065Spjd#ifdef ENOMEM
1158166065Spjd	case ENOMEM:
1159166065Spjd		return ("ENOMEM");
1160166065Spjd#endif
1161166065Spjd#ifdef EACCES
1162166065Spjd	case EACCES:
1163166065Spjd		return ("EACCES");
1164166065Spjd#endif
1165166065Spjd#ifdef EFAULT
1166166065Spjd	case EFAULT:
1167166065Spjd		return ("EFAULT");
1168166065Spjd#endif
1169166065Spjd#ifdef ENOTBLK
1170166065Spjd	case ENOTBLK:
1171166065Spjd		return ("ENOTBLK");
1172166065Spjd#endif
1173166065Spjd#ifdef EBUSY
1174166065Spjd	case EBUSY:
1175166065Spjd		return ("EBUSY");
1176166065Spjd#endif
1177166065Spjd#ifdef EEXIST
1178166065Spjd	case EEXIST:
1179166065Spjd		return ("EEXIST");
1180166065Spjd#endif
1181166065Spjd#ifdef EXDEV
1182166065Spjd	case EXDEV:
1183166065Spjd		return ("EXDEV");
1184166065Spjd#endif
1185166065Spjd#ifdef ENODEV
1186166065Spjd	case ENODEV:
1187166065Spjd		return ("ENODEV");
1188166065Spjd#endif
1189166065Spjd#ifdef ENOTDIR
1190166065Spjd	case ENOTDIR:
1191166065Spjd		return ("ENOTDIR");
1192166065Spjd#endif
1193166065Spjd#ifdef EISDIR
1194166065Spjd	case EISDIR:
1195166065Spjd		return ("EISDIR");
1196166065Spjd#endif
1197166065Spjd#ifdef EINVAL
1198166065Spjd	case EINVAL:
1199166065Spjd		return ("EINVAL");
1200166065Spjd#endif
1201166065Spjd#ifdef ENFILE
1202166065Spjd	case ENFILE:
1203166065Spjd		return ("ENFILE");
1204166065Spjd#endif
1205166065Spjd#ifdef EMFILE
1206166065Spjd	case EMFILE:
1207166065Spjd		return ("EMFILE");
1208166065Spjd#endif
1209166065Spjd#ifdef ENOTTY
1210166065Spjd	case ENOTTY:
1211166065Spjd		return ("ENOTTY");
1212166065Spjd#endif
1213166065Spjd#ifdef ETXTBSY
1214166065Spjd	case ETXTBSY:
1215166065Spjd		return ("ETXTBSY");
1216166065Spjd#endif
1217166065Spjd#ifdef EFBIG
1218166065Spjd	case EFBIG:
1219166065Spjd		return ("EFBIG");
1220166065Spjd#endif
1221166065Spjd#ifdef ENOSPC
1222166065Spjd	case ENOSPC:
1223166065Spjd		return ("ENOSPC");
1224166065Spjd#endif
1225166065Spjd#ifdef ESPIPE
1226166065Spjd	case ESPIPE:
1227166065Spjd		return ("ESPIPE");
1228166065Spjd#endif
1229166065Spjd#ifdef EROFS
1230166065Spjd	case EROFS:
1231166065Spjd		return ("EROFS");
1232166065Spjd#endif
1233166065Spjd#ifdef EMLINK
1234166065Spjd	case EMLINK:
1235166065Spjd		return ("EMLINK");
1236166065Spjd#endif
1237166065Spjd#ifdef EPIPE
1238166065Spjd	case EPIPE:
1239166065Spjd		return ("EPIPE");
1240166065Spjd#endif
1241166065Spjd#ifdef EDOM
1242166065Spjd	case EDOM:
1243166065Spjd		return ("EDOM");
1244166065Spjd#endif
1245166065Spjd#ifdef ERANGE
1246166065Spjd	case ERANGE:
1247166065Spjd		return ("ERANGE");
1248166065Spjd#endif
1249166065Spjd#ifdef EAGAIN
1250166065Spjd	case EAGAIN:
1251166065Spjd		return ("EAGAIN");
1252166065Spjd#endif
1253166065Spjd#ifdef EINPROGRESS
1254166065Spjd	case EINPROGRESS:
1255166065Spjd		return ("EINPROGRESS");
1256166065Spjd#endif
1257166065Spjd#ifdef EALREADY
1258166065Spjd	case EALREADY:
1259166065Spjd		return ("EALREADY");
1260166065Spjd#endif
1261166065Spjd#ifdef ENOTSOCK
1262166065Spjd	case ENOTSOCK:
1263166065Spjd		return ("ENOTSOCK");
1264166065Spjd#endif
1265166065Spjd#ifdef EDESTADDRREQ
1266166065Spjd	case EDESTADDRREQ:
1267166065Spjd		return ("EDESTADDRREQ");
1268166065Spjd#endif
1269166065Spjd#ifdef EMSGSIZE
1270166065Spjd	case EMSGSIZE:
1271166065Spjd		return ("EMSGSIZE");
1272166065Spjd#endif
1273166065Spjd#ifdef EPROTOTYPE
1274166065Spjd	case EPROTOTYPE:
1275166065Spjd		return ("EPROTOTYPE");
1276166065Spjd#endif
1277166065Spjd#ifdef ENOPROTOOPT
1278166065Spjd	case ENOPROTOOPT:
1279166065Spjd		return ("ENOPROTOOPT");
1280166065Spjd#endif
1281166065Spjd#ifdef EPROTONOSUPPORT
1282166065Spjd	case EPROTONOSUPPORT:
1283166065Spjd		return ("EPROTONOSUPPORT");
1284166065Spjd#endif
1285166065Spjd#ifdef ESOCKTNOSUPPORT
1286166065Spjd	case ESOCKTNOSUPPORT:
1287166065Spjd		return ("ESOCKTNOSUPPORT");
1288166065Spjd#endif
1289166065Spjd#ifdef EOPNOTSUPP
1290166065Spjd	case EOPNOTSUPP:
1291166065Spjd		return ("EOPNOTSUPP");
1292166065Spjd#endif
1293166065Spjd#ifdef EPFNOSUPPORT
1294166065Spjd	case EPFNOSUPPORT:
1295166065Spjd		return ("EPFNOSUPPORT");
1296166065Spjd#endif
1297166065Spjd#ifdef EAFNOSUPPORT
1298166065Spjd	case EAFNOSUPPORT:
1299166065Spjd		return ("EAFNOSUPPORT");
1300166065Spjd#endif
1301166065Spjd#ifdef EADDRINUSE
1302166065Spjd	case EADDRINUSE:
1303166065Spjd		return ("EADDRINUSE");
1304166065Spjd#endif
1305166065Spjd#ifdef EADDRNOTAVAIL
1306166065Spjd	case EADDRNOTAVAIL:
1307166065Spjd		return ("EADDRNOTAVAIL");
1308166065Spjd#endif
1309166065Spjd#ifdef ENETDOWN
1310166065Spjd	case ENETDOWN:
1311166065Spjd		return ("ENETDOWN");
1312166065Spjd#endif
1313166065Spjd#ifdef ENETUNREACH
1314166065Spjd	case ENETUNREACH:
1315166065Spjd		return ("ENETUNREACH");
1316166065Spjd#endif
1317166065Spjd#ifdef ENETRESET
1318166065Spjd	case ENETRESET:
1319166065Spjd		return ("ENETRESET");
1320166065Spjd#endif
1321166065Spjd#ifdef ECONNABORTED
1322166065Spjd	case ECONNABORTED:
1323166065Spjd		return ("ECONNABORTED");
1324166065Spjd#endif
1325166065Spjd#ifdef ECONNRESET
1326166065Spjd	case ECONNRESET:
1327166065Spjd		return ("ECONNRESET");
1328166065Spjd#endif
1329166065Spjd#ifdef ENOBUFS
1330166065Spjd	case ENOBUFS:
1331166065Spjd		return ("ENOBUFS");
1332166065Spjd#endif
1333166065Spjd#ifdef EISCONN
1334166065Spjd	case EISCONN:
1335166065Spjd		return ("EISCONN");
1336166065Spjd#endif
1337166065Spjd#ifdef ENOTCONN
1338166065Spjd	case ENOTCONN:
1339166065Spjd		return ("ENOTCONN");
1340166065Spjd#endif
1341166065Spjd#ifdef ESHUTDOWN
1342166065Spjd	case ESHUTDOWN:
1343166065Spjd		return ("ESHUTDOWN");
1344166065Spjd#endif
1345166065Spjd#ifdef ETOOMANYREFS
1346166065Spjd	case ETOOMANYREFS:
1347166065Spjd		return ("ETOOMANYREFS");
1348166065Spjd#endif
1349166065Spjd#ifdef ETIMEDOUT
1350166065Spjd	case ETIMEDOUT:
1351166065Spjd		return ("ETIMEDOUT");
1352166065Spjd#endif
1353166065Spjd#ifdef ECONNREFUSED
1354166065Spjd	case ECONNREFUSED:
1355166065Spjd		return ("ECONNREFUSED");
1356166065Spjd#endif
1357166065Spjd#ifdef ELOOP
1358166065Spjd	case ELOOP:
1359166065Spjd		return ("ELOOP");
1360166065Spjd#endif
1361166065Spjd#ifdef ENAMETOOLONG
1362166065Spjd	case ENAMETOOLONG:
1363166065Spjd		return ("ENAMETOOLONG");
1364166065Spjd#endif
1365166065Spjd#ifdef EHOSTDOWN
1366166065Spjd	case EHOSTDOWN:
1367166065Spjd		return ("EHOSTDOWN");
1368166065Spjd#endif
1369166065Spjd#ifdef EHOSTUNREACH
1370166065Spjd	case EHOSTUNREACH:
1371166065Spjd		return ("EHOSTUNREACH");
1372166065Spjd#endif
1373166065Spjd#ifdef ENOTEMPTY
1374166065Spjd	case ENOTEMPTY:
1375166065Spjd		return ("ENOTEMPTY");
1376166065Spjd#endif
1377166065Spjd#ifdef EPROCLIM
1378166065Spjd	case EPROCLIM:
1379166065Spjd		return ("EPROCLIM");
1380166065Spjd#endif
1381166065Spjd#ifdef EUSERS
1382166065Spjd	case EUSERS:
1383166065Spjd		return ("EUSERS");
1384166065Spjd#endif
1385166065Spjd#ifdef EDQUOT
1386166065Spjd	case EDQUOT:
1387166065Spjd		return ("EDQUOT");
1388166065Spjd#endif
1389166065Spjd#ifdef ESTALE
1390166065Spjd	case ESTALE:
1391166065Spjd		return ("ESTALE");
1392166065Spjd#endif
1393166065Spjd#ifdef EREMOTE
1394166065Spjd	case EREMOTE:
1395166065Spjd		return ("EREMOTE");
1396166065Spjd#endif
1397166065Spjd#ifdef EBADRPC
1398166065Spjd	case EBADRPC:
1399166065Spjd		return ("EBADRPC");
1400166065Spjd#endif
1401166065Spjd#ifdef ERPCMISMATCH
1402166065Spjd	case ERPCMISMATCH:
1403166065Spjd		return ("ERPCMISMATCH");
1404166065Spjd#endif
1405166065Spjd#ifdef EPROGUNAVAIL
1406166065Spjd	case EPROGUNAVAIL:
1407166065Spjd		return ("EPROGUNAVAIL");
1408166065Spjd#endif
1409166065Spjd#ifdef EPROGMISMATCH
1410166065Spjd	case EPROGMISMATCH:
1411166065Spjd		return ("EPROGMISMATCH");
1412166065Spjd#endif
1413166065Spjd#ifdef EPROCUNAVAIL
1414166065Spjd	case EPROCUNAVAIL:
1415166065Spjd		return ("EPROCUNAVAIL");
1416166065Spjd#endif
1417166065Spjd#ifdef ENOLCK
1418166065Spjd	case ENOLCK:
1419166065Spjd		return ("ENOLCK");
1420166065Spjd#endif
1421166065Spjd#ifdef ENOSYS
1422166065Spjd	case ENOSYS:
1423166065Spjd		return ("ENOSYS");
1424166065Spjd#endif
1425166065Spjd#ifdef EFTYPE
1426166065Spjd	case EFTYPE:
1427166065Spjd		return ("EFTYPE");
1428166065Spjd#endif
1429166065Spjd#ifdef EAUTH
1430166065Spjd	case EAUTH:
1431166065Spjd		return ("EAUTH");
1432166065Spjd#endif
1433166065Spjd#ifdef ENEEDAUTH
1434166065Spjd	case ENEEDAUTH:
1435166065Spjd		return ("ENEEDAUTH");
1436166065Spjd#endif
1437166065Spjd#ifdef EIDRM
1438166065Spjd	case EIDRM:
1439166065Spjd		return ("EIDRM");
1440166065Spjd#endif
1441166065Spjd#ifdef ENOMSG
1442166065Spjd	case ENOMSG:
1443166065Spjd		return ("ENOMSG");
1444166065Spjd#endif
1445166065Spjd#ifdef EOVERFLOW
1446166065Spjd	case EOVERFLOW:
1447166065Spjd		return ("EOVERFLOW");
1448166065Spjd#endif
1449166065Spjd#ifdef ECANCELED
1450166065Spjd	case ECANCELED:
1451166065Spjd		return ("ECANCELED");
1452166065Spjd#endif
1453166065Spjd#ifdef EILSEQ
1454166065Spjd	case EILSEQ:
1455166065Spjd		return ("EILSEQ");
1456166065Spjd#endif
1457166065Spjd#ifdef ENOATTR
1458166065Spjd	case ENOATTR:
1459166065Spjd		return ("ENOATTR");
1460166065Spjd#endif
1461166065Spjd#ifdef EDOOFUS
1462166065Spjd	case EDOOFUS:
1463166065Spjd		return ("EDOOFUS");
1464166065Spjd#endif
1465166065Spjd#ifdef EBADMSG
1466166065Spjd	case EBADMSG:
1467166065Spjd		return ("EBADMSG");
1468166065Spjd#endif
1469166065Spjd#ifdef EMULTIHOP
1470166065Spjd	case EMULTIHOP:
1471166065Spjd		return ("EMULTIHOP");
1472166065Spjd#endif
1473166065Spjd#ifdef ENOLINK
1474166065Spjd	case ENOLINK:
1475166065Spjd		return ("ENOLINK");
1476166065Spjd#endif
1477166065Spjd#ifdef EPROTO
1478166065Spjd	case EPROTO:
1479166065Spjd		return ("EPROTO");
1480166065Spjd#endif
1481166065Spjd	default:
1482166065Spjd		snprintf(errnum, sizeof(errnum), "%d", error);
1483166065Spjd		return (errnum);
1484166065Spjd	}
1485166065Spjd}
1486