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