]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - tools/regression/fstest/fstest.c
o Makefile BSDfication.
[FreeBSD/FreeBSD.git] / tools / regression / fstest / fstest.c
1 /*-
2  * Copyright (c) 2006-2007 Pawel Jakub Dawidek <pjd@FreeBSD.org>
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24  * SUCH DAMAGE.
25  *
26  * $FreeBSD$
27  */
28
29 #include <sys/param.h>
30 #include <sys/stat.h>
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <unistd.h>
34 #include <fcntl.h>
35 #include <grp.h>
36 #include <string.h>
37 #include <ctype.h>
38 #include <errno.h>
39 #include <assert.h>
40
41 #ifndef HAS_TRUNCATE64
42 #define truncate64      truncate
43 #endif
44 #ifndef HAS_STAT64
45 #define stat64  stat
46 #define lstat64 lstat
47 #endif
48 #ifdef HAS_FREEBSD_ACL
49 #include <sys/acl.h>
50 #endif
51
52 #ifndef ALLPERMS
53 #define ALLPERMS        (S_ISUID|S_ISGID|S_ISVTX|S_IRWXU|S_IRWXG|S_IRWXO)
54 #endif
55
56 enum action {
57         ACTION_OPEN,
58         ACTION_CREATE,
59         ACTION_UNLINK,
60         ACTION_MKDIR,
61         ACTION_RMDIR,
62         ACTION_LINK,
63         ACTION_SYMLINK,
64         ACTION_RENAME,
65         ACTION_MKFIFO,
66         ACTION_CHMOD,
67 #ifdef HAS_LCHMOD
68         ACTION_LCHMOD,
69 #endif
70         ACTION_CHOWN,
71         ACTION_LCHOWN,
72 #ifdef HAS_CHFLAGS
73         ACTION_CHFLAGS,
74 #endif
75 #ifdef HAS_LCHFLAGS
76         ACTION_LCHFLAGS,
77 #endif
78         ACTION_TRUNCATE,
79         ACTION_STAT,
80         ACTION_LSTAT,
81         ACTION_PATHCONF,
82 #ifdef HAS_FREEBSD_ACL
83         ACTION_PREPENDACL,
84         ACTION_READACL,
85 #endif
86         ACTION_WRITE,
87 };
88
89 #define TYPE_NONE       0x0000
90 #define TYPE_STRING     0x0001
91 #define TYPE_NUMBER     0x0002
92
93 #define TYPE_OPTIONAL   0x0100
94
95 #define MAX_ARGS        8
96
97 struct syscall_desc {
98         char            *sd_name;
99         enum action      sd_action;
100         int              sd_args[MAX_ARGS];
101 };
102
103 static struct syscall_desc syscalls[] = {
104         { "open", ACTION_OPEN, { TYPE_STRING, TYPE_STRING, TYPE_NUMBER | TYPE_OPTIONAL, TYPE_NONE } },
105         { "create", ACTION_CREATE, { TYPE_STRING, TYPE_NUMBER, TYPE_NONE } },
106         { "unlink", ACTION_UNLINK, { TYPE_STRING, TYPE_NONE } },
107         { "mkdir", ACTION_MKDIR, { TYPE_STRING, TYPE_NUMBER, TYPE_NONE } },
108         { "rmdir", ACTION_RMDIR, { TYPE_STRING, TYPE_NONE } },
109         { "link", ACTION_LINK, { TYPE_STRING, TYPE_STRING, TYPE_NONE } },
110         { "symlink", ACTION_SYMLINK, { TYPE_STRING, TYPE_STRING, TYPE_NONE } },
111         { "rename", ACTION_RENAME, { TYPE_STRING, TYPE_STRING, TYPE_NONE } },
112         { "mkfifo", ACTION_MKFIFO, { TYPE_STRING, TYPE_NUMBER, TYPE_NONE } },
113         { "chmod", ACTION_CHMOD, { TYPE_STRING, TYPE_NUMBER, TYPE_NONE } },
114 #ifdef HAS_LCHMOD
115         { "lchmod", ACTION_LCHMOD, { TYPE_STRING, TYPE_NUMBER, TYPE_NONE } },
116 #endif
117         { "chown", ACTION_CHOWN, { TYPE_STRING, TYPE_NUMBER, TYPE_NUMBER, TYPE_NONE } },
118         { "lchown", ACTION_LCHOWN, { TYPE_STRING, TYPE_NUMBER, TYPE_NUMBER, TYPE_NONE } },
119 #ifdef HAS_CHFLAGS
120         { "chflags", ACTION_CHFLAGS, { TYPE_STRING, TYPE_STRING, TYPE_NONE } },
121 #endif
122 #ifdef HAS_LCHFLAGS
123         { "lchflags", ACTION_LCHFLAGS, { TYPE_STRING, TYPE_STRING, TYPE_NONE } },
124 #endif
125         { "truncate", ACTION_TRUNCATE, { TYPE_STRING, TYPE_NUMBER, TYPE_NONE } },
126         { "stat", ACTION_STAT, { TYPE_STRING, TYPE_STRING, TYPE_NONE } },
127         { "lstat", ACTION_LSTAT, { TYPE_STRING, TYPE_STRING, TYPE_NONE } },
128         { "pathconf", ACTION_PATHCONF, { TYPE_STRING, TYPE_STRING, TYPE_NONE } },
129 #ifdef HAS_FREEBSD_ACL
130         { "prependacl", ACTION_PREPENDACL, { TYPE_STRING, TYPE_STRING, TYPE_NONE } },
131         { "readacl", ACTION_READACL, { TYPE_STRING, TYPE_NONE } },
132 #endif
133         { "write", ACTION_WRITE, { TYPE_STRING, TYPE_NONE } },
134         { NULL, -1, { TYPE_NONE } }
135 };
136
137 struct flag {
138         long long        f_flag;
139         char            *f_str;
140 };
141
142 static struct flag open_flags[] = {
143 #ifdef O_RDONLY
144         { O_RDONLY, "O_RDONLY" },
145 #endif
146 #ifdef O_WRONLY
147         { O_WRONLY, "O_WRONLY" },
148 #endif
149 #ifdef O_RDWR
150         { O_RDWR, "O_RDWR" },
151 #endif
152 #ifdef O_NONBLOCK
153         { O_NONBLOCK, "O_NONBLOCK" },
154 #endif
155 #ifdef O_APPEND
156         { O_APPEND, "O_APPEND" },
157 #endif
158 #ifdef O_CREAT
159         { O_CREAT, "O_CREAT" },
160 #endif
161 #ifdef O_TRUNC
162         { O_TRUNC, "O_TRUNC" },
163 #endif
164 #ifdef O_EXCL
165         { O_EXCL, "O_EXCL" },
166 #endif
167 #ifdef O_SHLOCK
168         { O_SHLOCK, "O_SHLOCK" },
169 #endif
170 #ifdef O_EXLOCK
171         { O_EXLOCK, "O_EXLOCK" },
172 #endif
173 #ifdef O_DIRECT
174         { O_DIRECT, "O_DIRECT" },
175 #endif
176 #ifdef O_FSYNC
177         { O_FSYNC, "O_FSYNC" },
178 #endif
179 #ifdef O_SYNC
180         { O_SYNC, "O_SYNC" },
181 #endif
182 #ifdef O_NOFOLLOW
183         { O_NOFOLLOW, "O_NOFOLLOW" },
184 #endif
185 #ifdef O_NOCTTY
186         { O_NOCTTY, "O_NOCTTY" },
187 #endif
188         { 0, NULL }
189 };
190
191 #ifdef HAS_CHFLAGS
192 static struct flag chflags_flags[] = {
193 #ifdef UF_NODUMP
194         { UF_NODUMP, "UF_NODUMP" },
195 #endif
196 #ifdef UF_IMMUTABLE
197         { UF_IMMUTABLE, "UF_IMMUTABLE" },
198 #endif
199 #ifdef UF_APPEND
200         { UF_APPEND, "UF_APPEND" },
201 #endif
202 #ifdef UF_NOUNLINK
203         { UF_NOUNLINK, "UF_NOUNLINK" },
204 #endif
205 #ifdef UF_OPAQUE
206         { UF_OPAQUE, "UF_OPAQUE" },
207 #endif
208 #ifdef SF_ARCHIVED
209         { SF_ARCHIVED, "SF_ARCHIVED" },
210 #endif
211 #ifdef SF_IMMUTABLE
212         { SF_IMMUTABLE, "SF_IMMUTABLE" },
213 #endif
214 #ifdef SF_APPEND
215         { SF_APPEND, "SF_APPEND" },
216 #endif
217 #ifdef SF_NOUNLINK
218         { SF_NOUNLINK, "SF_NOUNLINK" },
219 #endif
220 #ifdef SF_SNAPSHOT
221         { SF_SNAPSHOT, "SF_SNAPSHOT" },
222 #endif
223         { 0, NULL }
224 };
225 #endif
226
227 struct name {
228         int      n_name;
229         char    *n_str;
230 };
231
232 static struct name pathconf_names[] = {
233 #ifdef _PC_LINK_MAX
234         { _PC_LINK_MAX, "_PC_LINK_MAX" },
235 #endif
236 #ifdef _PC_NAME_MAX
237         { _PC_NAME_MAX, "_PC_NAME_MAX" },
238 #endif
239 #ifdef _PC_PATH_MAX
240         { _PC_PATH_MAX, "_PC_PATH_MAX" },
241 #endif
242 #ifdef _PC_SYMLINK_MAX
243         { _PC_SYMLINK_MAX, "_PC_SYMLINK_MAX" },
244 #endif
245         { 0, NULL }
246 };
247
248 static const char *err2str(int error);
249
250 static void
251 usage(void)
252 {
253
254         fprintf(stderr, "usage: fstest [-u uid] [-g gid1[,gid2[...]]] syscall args ...\n");
255         exit(1);
256 }
257
258 static long long
259 str2flags(struct flag *tflags, char *sflags)
260 {
261         long long flags = 0;
262         unsigned int i;
263         char *f;
264
265         for (f = strtok(sflags, ","); f != NULL; f = strtok(NULL, ",")) {
266                 /* Support magic 'none' flag which just reset all flags. */
267                 if (strcmp(f, "none") == 0)
268                         return (0);
269                 for (i = 0; tflags[i].f_str != NULL; i++) {
270                         if (strcmp(tflags[i].f_str, f) == 0)
271                                 break;
272                 }
273                 if (tflags[i].f_str == NULL) {
274                         fprintf(stderr, "unknown flag '%s'\n", f);
275                         exit(1);
276                 }
277                 flags |= tflags[i].f_flag;
278         }
279         return (flags);
280 }
281
282 #ifdef HAS_CHFLAGS
283 static char *
284 flags2str(struct flag *tflags, long long flags)
285 {
286         static char sflags[1024];
287         unsigned int i;
288
289         sflags[0] = '\0';
290         for (i = 0; tflags[i].f_str != NULL; i++) {
291                 if (flags & tflags[i].f_flag) {
292                         if (sflags[0] != '\0')
293                                 strlcat(sflags, ",", sizeof(sflags));
294                         strlcat(sflags, tflags[i].f_str, sizeof(sflags));
295                 }
296         }
297         if (sflags[0] == '\0')
298                 strlcpy(sflags, "none", sizeof(sflags));
299         return (sflags);
300 }
301 #endif
302
303 static int
304 str2name(struct name *names, char *name)
305 {
306         unsigned int i;
307
308         for (i = 0; names[i].n_str != NULL; i++) {
309                 if (strcmp(names[i].n_str, name) == 0)
310                         return (names[i].n_name);
311         }
312         return (-1);
313 }
314
315 static struct syscall_desc *
316 find_syscall(const char *name)
317 {
318         int i;
319
320         for (i = 0; syscalls[i].sd_name != NULL; i++) {
321                 if (strcmp(syscalls[i].sd_name, name) == 0)
322                         return (&syscalls[i]);
323         }
324         return (NULL);
325 }
326
327 static void
328 show_stat(struct stat64 *sp, const char *what)
329 {
330
331         if (strcmp(what, "mode") == 0)
332                 printf("0%o", (unsigned int)(sp->st_mode & ALLPERMS));
333         else if (strcmp(what, "inode") == 0)
334                 printf("%lld", (long long)sp->st_ino);
335         else if (strcmp(what, "nlink") == 0)
336                 printf("%lld", (long long)sp->st_nlink);
337         else if (strcmp(what, "uid") == 0)
338                 printf("%d", (int)sp->st_uid);
339         else if (strcmp(what, "gid") == 0)
340                 printf("%d", (int)sp->st_gid);
341         else if (strcmp(what, "size") == 0)
342                 printf("%lld", (long long)sp->st_size);
343         else if (strcmp(what, "blocks") == 0)
344                 printf("%lld", (long long)sp->st_blocks);
345         else if (strcmp(what, "atime") == 0)
346                 printf("%lld", (long long)sp->st_atime);
347         else if (strcmp(what, "mtime") == 0)
348                 printf("%lld", (long long)sp->st_mtime);
349         else if (strcmp(what, "ctime") == 0)
350                 printf("%lld", (long long)sp->st_ctime);
351 #ifdef HAS_CHFLAGS
352         else if (strcmp(what, "flags") == 0)
353                 printf("%s", flags2str(chflags_flags, (long long)sp->st_flags));
354 #endif
355         else if (strcmp(what, "type") == 0) {
356                 switch (sp->st_mode & S_IFMT) {
357                 case S_IFIFO:
358                         printf("fifo");
359                         break;
360                 case S_IFCHR:
361                         printf("char");
362                         break;
363                 case S_IFDIR:
364                         printf("dir");
365                         break;
366                 case S_IFBLK:
367                         printf("block");
368                         break;
369                 case S_IFREG:
370                         printf("regular");
371                         break;
372                 case S_IFLNK:
373                         printf("symlink");
374                         break;
375                 case S_IFSOCK:
376                         printf("socket");
377                         break;
378                 default:
379                         printf("unknown");
380                         break;
381                 }
382         } else {
383                 printf("unknown");
384         }
385 }
386
387 static void
388 show_stats(struct stat64 *sp, char *what)
389 {
390         const char *s = "";
391         char *w;
392
393         for (w = strtok(what, ","); w != NULL; w = strtok(NULL, ",")) {
394                 printf("%s", s);
395                 show_stat(sp, w);
396                 s = ",";
397         }
398         printf("\n");
399 }
400
401 static unsigned int
402 call_syscall(struct syscall_desc *scall, char *argv[])
403 {
404         struct stat64 sb;
405         long long flags;
406         unsigned int i;
407         char *endp;
408         int name, rval;
409         union {
410                 char *str;
411                 long long num;
412         } args[MAX_ARGS];
413 #ifdef HAS_FREEBSD_ACL
414         int entry_id = ACL_FIRST_ENTRY;
415         acl_t acl, newacl;
416         acl_entry_t entry, newentry;
417 #endif
418
419         /*
420          * Verify correctness of the arguments.
421          */
422         for (i = 0; i < sizeof(args)/sizeof(args[0]); i++) {
423                 if (scall->sd_args[i] == TYPE_NONE) {
424                         if (argv[i] == NULL || strcmp(argv[i], ":") == 0)
425                                 break;
426                         fprintf(stderr, "too many arguments [%s]\n", argv[i]);
427                         exit(1);
428                 } else {
429                         if (argv[i] == NULL || strcmp(argv[i], ":") == 0) {
430                                 if (scall->sd_args[i] & TYPE_OPTIONAL)
431                                         break;
432                                 fprintf(stderr, "too few arguments\n");
433                                 exit(1);
434                         }
435                         if (scall->sd_args[i] & TYPE_STRING) {
436                                 if (strcmp(argv[i], "NULL") == 0)
437                                         args[i].str = NULL;
438                                 else if (strcmp(argv[i], "DEADCODE") == 0)
439                                         args[i].str = (void *)0xdeadc0de;
440                                 else
441                                         args[i].str = argv[i];
442                         } else if (scall->sd_args[i] & TYPE_NUMBER) {
443                                 args[i].num = strtoll(argv[i], &endp, 0);
444                                 if (*endp != '\0' && !isspace((unsigned char)*endp)) {
445                                         fprintf(stderr, "invalid argument %u, number expected [%s]\n", i, endp);
446                                         exit(1);
447                                 }
448                         }
449                 }
450         }
451         /*
452          * Call the given syscall.
453          */
454 #define NUM(n)  (args[(n)].num)
455 #define STR(n)  (args[(n)].str)
456         switch (scall->sd_action) {
457         case ACTION_OPEN:
458                 flags = str2flags(open_flags, STR(1));
459                 if (flags & O_CREAT) {
460                         if (i == 2) {
461                                 fprintf(stderr, "too few arguments\n");
462                                 exit(1);
463                         }
464                         rval = open(STR(0), (int)flags, (mode_t)NUM(2));
465                 } else {
466                         if (i == 3) {
467                                 fprintf(stderr, "too many arguments\n");
468                                 exit(1);
469                         }
470                         rval = open(STR(0), (int)flags);
471                 }
472                 break;
473         case ACTION_CREATE:
474                 rval = open(STR(0), O_CREAT | O_EXCL, (mode_t)NUM(1));
475                 if (rval >= 0)
476                         close(rval);
477                 break;
478         case ACTION_UNLINK:
479                 rval = unlink(STR(0));
480                 break;
481         case ACTION_MKDIR:
482                 rval = mkdir(STR(0), (mode_t)NUM(1));
483                 break;
484         case ACTION_RMDIR:
485                 rval = rmdir(STR(0));
486                 break;
487         case ACTION_LINK:
488                 rval = link(STR(0), STR(1));
489                 break;
490         case ACTION_SYMLINK:
491                 rval = symlink(STR(0), STR(1));
492                 break;
493         case ACTION_RENAME:
494                 rval = rename(STR(0), STR(1));
495                 break;
496         case ACTION_MKFIFO:
497                 rval = mkfifo(STR(0), (mode_t)NUM(1));
498                 break;
499         case ACTION_CHMOD:
500                 rval = chmod(STR(0), (mode_t)NUM(1));
501                 break;
502 #ifdef HAS_LCHMOD
503         case ACTION_LCHMOD:
504                 rval = lchmod(STR(0), (mode_t)NUM(1));
505                 break;
506 #endif
507         case ACTION_CHOWN:
508                 rval = chown(STR(0), (uid_t)NUM(1), (gid_t)NUM(2));
509                 break;
510         case ACTION_LCHOWN:
511                 rval = lchown(STR(0), (uid_t)NUM(1), (gid_t)NUM(2));
512                 break;
513 #ifdef HAS_CHFLAGS
514         case ACTION_CHFLAGS:
515                 rval = chflags(STR(0), (unsigned long)str2flags(chflags_flags, STR(1)));
516                 break;
517 #endif
518 #ifdef HAS_LCHFLAGS
519         case ACTION_LCHFLAGS:
520                 rval = lchflags(STR(0), (int)str2flags(chflags_flags, STR(1)));
521                 break;
522 #endif
523         case ACTION_TRUNCATE:
524                 rval = truncate64(STR(0), NUM(1));
525                 break;
526         case ACTION_STAT:
527                 rval = stat64(STR(0), &sb);
528                 if (rval == 0) {
529                         show_stats(&sb, STR(1));
530                         return (i);
531                 }
532                 break;
533         case ACTION_LSTAT:
534                 rval = lstat64(STR(0), &sb);
535                 if (rval == 0) {
536                         show_stats(&sb, STR(1));
537                         return (i);
538                 }
539                 break;
540         case ACTION_PATHCONF:
541             {
542                 long lrval;
543
544                 name = str2name(pathconf_names, STR(1));
545                 if (name == -1) {
546                         fprintf(stderr, "unknown name %s", STR(1));
547                         exit(1);
548                 }
549                 errno = 0;
550                 lrval = pathconf(STR(0), name);
551                 if (lrval == -1 && errno == 0) {
552                         printf("unlimited\n");
553                         return (i);
554                 } else if (lrval >= 0) {
555                         printf("%ld\n", lrval);
556                         return (i);
557                 }
558                 rval = -1;
559                 break;
560             }
561 #ifdef HAS_FREEBSD_ACL
562         case ACTION_PREPENDACL:
563                 rval = -1;
564
565                 acl = acl_get_file(STR(0), ACL_TYPE_NFS4);
566                 if (acl == NULL)
567                         break;
568
569                 newacl = acl_from_text(STR(1));
570                 if (acl == NULL)
571                         break;
572
573                 while (acl_get_entry(newacl, entry_id, &newentry) == 1) {
574                         entry_id = ACL_NEXT_ENTRY;
575
576                         if (acl_create_entry_np(&acl, &entry, 0))
577                                 break;
578
579                         if (acl_copy_entry(entry, newentry))
580                                 break;
581                 }
582
583                 rval = acl_set_file(STR(0), ACL_TYPE_NFS4, acl);
584                 break;
585
586         case ACTION_READACL:
587                 acl = acl_get_file(STR(0), ACL_TYPE_NFS4);
588                 if (acl == NULL)
589                         rval = -1;
590                 else
591                         rval = 0;
592                 break;
593 #endif
594
595         case ACTION_WRITE:
596                 rval = open(STR(0), O_WRONLY);
597                 if (rval < 0)
598                         break;
599
600                 rval = write(rval, "x", 1);
601                 break;
602
603         default:
604                 fprintf(stderr, "unsupported syscall\n");
605                 exit(1);
606         }
607 #undef STR
608 #undef NUM
609         if (rval < 0) {
610                 const char *serrno;
611
612                 serrno = err2str(errno);
613                 fprintf(stderr, "%s returned %d\n", scall->sd_name, rval);
614                 printf("%s\n", serrno);
615                 exit(1);
616         }
617         printf("0\n");
618         return (i);
619 }
620
621 static void
622 set_gids(char *gids)
623 {
624         gid_t *gidset;
625         long ngroups;
626         char *g, *endp;
627         unsigned i;
628
629         ngroups = sysconf(_SC_NGROUPS_MAX);
630         assert(ngroups > 0);
631         gidset = malloc(sizeof(*gidset) * ngroups);
632         assert(gidset != NULL);
633         for (i = 0, g = strtok(gids, ","); g != NULL; g = strtok(NULL, ","), i++) {
634                 if (i >= ngroups) {
635                         fprintf(stderr, "too many gids\n");
636                         exit(1);
637                 }
638                 gidset[i] = strtol(g, &endp, 0);
639                 if (*endp != '\0' && !isspace((unsigned char)*endp)) {
640                         fprintf(stderr, "invalid gid '%s' - number expected\n",
641                             g);
642                         exit(1);
643                 }
644         }
645         if (setgroups(i, gidset) < 0) {
646                 fprintf(stderr, "cannot change groups: %s\n", strerror(errno));
647                 exit(1);
648         }
649         if (setegid(gidset[0]) < 0) {
650                 fprintf(stderr, "cannot change effective gid: %s\n", strerror(errno));
651                 exit(1);
652         }
653         free(gidset);
654 }
655
656 int
657 main(int argc, char *argv[])
658 {
659         struct syscall_desc *scall;
660         unsigned int n;
661         char *gids, *endp;
662         int uid, umsk, ch;
663
664         uid = -1;
665         gids = NULL;
666         umsk = 0;
667
668         while ((ch = getopt(argc, argv, "g:u:U:")) != -1) {
669                 switch(ch) {
670                 case 'g':
671                         gids = optarg;
672                         break;
673                 case 'u':
674                         uid = (int)strtol(optarg, &endp, 0);
675                         if (*endp != '\0' && !isspace((unsigned char)*endp)) {
676                                 fprintf(stderr, "invalid uid '%s' - number "
677                                     "expected\n", optarg);
678                                 exit(1);
679                         }
680                         break;
681                 case 'U':
682                         umsk = (int)strtol(optarg, &endp, 0);
683                         if (*endp != '\0' && !isspace((unsigned char)*endp)) {
684                                 fprintf(stderr, "invalid umask '%s' - number "
685                                     "expected\n", optarg);
686                                 exit(1);
687                         }
688                         break;
689                 default:
690                         usage();
691                 }
692         }
693         argc -= optind;
694         argv += optind;
695
696         if (argc < 1) {
697                 fprintf(stderr, "too few arguments\n");
698                 usage();
699         }
700
701         if (gids != NULL) {
702                 fprintf(stderr, "changing groups to %s\n", gids);
703                 set_gids(gids);
704         }
705         if (uid != -1) {
706                 fprintf(stderr, "changing uid to %d\n", uid);
707                 if (setuid(uid) < 0) {
708                         fprintf(stderr, "cannot change uid: %s\n",
709                             strerror(errno));
710                         exit(1);
711                 }
712         }
713
714         /* Change umask to requested value or to 0, if not requested. */
715         umask(umsk);
716
717         for (;;) {
718                 scall = find_syscall(argv[0]);
719                 if (scall == NULL) {
720                         fprintf(stderr, "syscall '%s' not supported\n", argv[0]);
721                         exit(1);
722                 }
723                 argc++;
724                 argv++;
725                 n = call_syscall(scall, argv);
726                 argc += n;
727                 argv += n;
728                 if (argv[0] == NULL)
729                         break;
730                 argc++;
731                 argv++;
732         }
733
734         exit(0);
735 }
736
737 static const char *
738 err2str(int error)
739 {
740         static char errnum[8];
741
742         switch (error) {
743 #ifdef EPERM
744         case EPERM:
745                 return ("EPERM");
746 #endif
747 #ifdef ENOENT
748         case ENOENT:
749                 return ("ENOENT");
750 #endif
751 #ifdef ESRCH
752         case ESRCH:
753                 return ("ESRCH");
754 #endif
755 #ifdef EINTR
756         case EINTR:
757                 return ("EINTR");
758 #endif
759 #ifdef EIO
760         case EIO:
761                 return ("EIO");
762 #endif
763 #ifdef ENXIO
764         case ENXIO:
765                 return ("ENXIO");
766 #endif
767 #ifdef E2BIG
768         case E2BIG:
769                 return ("E2BIG");
770 #endif
771 #ifdef ENOEXEC
772         case ENOEXEC:
773                 return ("ENOEXEC");
774 #endif
775 #ifdef EBADF
776         case EBADF:
777                 return ("EBADF");
778 #endif
779 #ifdef ECHILD
780         case ECHILD:
781                 return ("ECHILD");
782 #endif
783 #ifdef EDEADLK
784         case EDEADLK:
785                 return ("EDEADLK");
786 #endif
787 #ifdef ENOMEM
788         case ENOMEM:
789                 return ("ENOMEM");
790 #endif
791 #ifdef EACCES
792         case EACCES:
793                 return ("EACCES");
794 #endif
795 #ifdef EFAULT
796         case EFAULT:
797                 return ("EFAULT");
798 #endif
799 #ifdef ENOTBLK
800         case ENOTBLK:
801                 return ("ENOTBLK");
802 #endif
803 #ifdef EBUSY
804         case EBUSY:
805                 return ("EBUSY");
806 #endif
807 #ifdef EEXIST
808         case EEXIST:
809                 return ("EEXIST");
810 #endif
811 #ifdef EXDEV
812         case EXDEV:
813                 return ("EXDEV");
814 #endif
815 #ifdef ENODEV
816         case ENODEV:
817                 return ("ENODEV");
818 #endif
819 #ifdef ENOTDIR
820         case ENOTDIR:
821                 return ("ENOTDIR");
822 #endif
823 #ifdef EISDIR
824         case EISDIR:
825                 return ("EISDIR");
826 #endif
827 #ifdef EINVAL
828         case EINVAL:
829                 return ("EINVAL");
830 #endif
831 #ifdef ENFILE
832         case ENFILE:
833                 return ("ENFILE");
834 #endif
835 #ifdef EMFILE
836         case EMFILE:
837                 return ("EMFILE");
838 #endif
839 #ifdef ENOTTY
840         case ENOTTY:
841                 return ("ENOTTY");
842 #endif
843 #ifdef ETXTBSY
844         case ETXTBSY:
845                 return ("ETXTBSY");
846 #endif
847 #ifdef EFBIG
848         case EFBIG:
849                 return ("EFBIG");
850 #endif
851 #ifdef ENOSPC
852         case ENOSPC:
853                 return ("ENOSPC");
854 #endif
855 #ifdef ESPIPE
856         case ESPIPE:
857                 return ("ESPIPE");
858 #endif
859 #ifdef EROFS
860         case EROFS:
861                 return ("EROFS");
862 #endif
863 #ifdef EMLINK
864         case EMLINK:
865                 return ("EMLINK");
866 #endif
867 #ifdef EPIPE
868         case EPIPE:
869                 return ("EPIPE");
870 #endif
871 #ifdef EDOM
872         case EDOM:
873                 return ("EDOM");
874 #endif
875 #ifdef ERANGE
876         case ERANGE:
877                 return ("ERANGE");
878 #endif
879 #ifdef EAGAIN
880         case EAGAIN:
881                 return ("EAGAIN");
882 #endif
883 #ifdef EINPROGRESS
884         case EINPROGRESS:
885                 return ("EINPROGRESS");
886 #endif
887 #ifdef EALREADY
888         case EALREADY:
889                 return ("EALREADY");
890 #endif
891 #ifdef ENOTSOCK
892         case ENOTSOCK:
893                 return ("ENOTSOCK");
894 #endif
895 #ifdef EDESTADDRREQ
896         case EDESTADDRREQ:
897                 return ("EDESTADDRREQ");
898 #endif
899 #ifdef EMSGSIZE
900         case EMSGSIZE:
901                 return ("EMSGSIZE");
902 #endif
903 #ifdef EPROTOTYPE
904         case EPROTOTYPE:
905                 return ("EPROTOTYPE");
906 #endif
907 #ifdef ENOPROTOOPT
908         case ENOPROTOOPT:
909                 return ("ENOPROTOOPT");
910 #endif
911 #ifdef EPROTONOSUPPORT
912         case EPROTONOSUPPORT:
913                 return ("EPROTONOSUPPORT");
914 #endif
915 #ifdef ESOCKTNOSUPPORT
916         case ESOCKTNOSUPPORT:
917                 return ("ESOCKTNOSUPPORT");
918 #endif
919 #ifdef EOPNOTSUPP
920         case EOPNOTSUPP:
921                 return ("EOPNOTSUPP");
922 #endif
923 #ifdef EPFNOSUPPORT
924         case EPFNOSUPPORT:
925                 return ("EPFNOSUPPORT");
926 #endif
927 #ifdef EAFNOSUPPORT
928         case EAFNOSUPPORT:
929                 return ("EAFNOSUPPORT");
930 #endif
931 #ifdef EADDRINUSE
932         case EADDRINUSE:
933                 return ("EADDRINUSE");
934 #endif
935 #ifdef EADDRNOTAVAIL
936         case EADDRNOTAVAIL:
937                 return ("EADDRNOTAVAIL");
938 #endif
939 #ifdef ENETDOWN
940         case ENETDOWN:
941                 return ("ENETDOWN");
942 #endif
943 #ifdef ENETUNREACH
944         case ENETUNREACH:
945                 return ("ENETUNREACH");
946 #endif
947 #ifdef ENETRESET
948         case ENETRESET:
949                 return ("ENETRESET");
950 #endif
951 #ifdef ECONNABORTED
952         case ECONNABORTED:
953                 return ("ECONNABORTED");
954 #endif
955 #ifdef ECONNRESET
956         case ECONNRESET:
957                 return ("ECONNRESET");
958 #endif
959 #ifdef ENOBUFS
960         case ENOBUFS:
961                 return ("ENOBUFS");
962 #endif
963 #ifdef EISCONN
964         case EISCONN:
965                 return ("EISCONN");
966 #endif
967 #ifdef ENOTCONN
968         case ENOTCONN:
969                 return ("ENOTCONN");
970 #endif
971 #ifdef ESHUTDOWN
972         case ESHUTDOWN:
973                 return ("ESHUTDOWN");
974 #endif
975 #ifdef ETOOMANYREFS
976         case ETOOMANYREFS:
977                 return ("ETOOMANYREFS");
978 #endif
979 #ifdef ETIMEDOUT
980         case ETIMEDOUT:
981                 return ("ETIMEDOUT");
982 #endif
983 #ifdef ECONNREFUSED
984         case ECONNREFUSED:
985                 return ("ECONNREFUSED");
986 #endif
987 #ifdef ELOOP
988         case ELOOP:
989                 return ("ELOOP");
990 #endif
991 #ifdef ENAMETOOLONG
992         case ENAMETOOLONG:
993                 return ("ENAMETOOLONG");
994 #endif
995 #ifdef EHOSTDOWN
996         case EHOSTDOWN:
997                 return ("EHOSTDOWN");
998 #endif
999 #ifdef EHOSTUNREACH
1000         case EHOSTUNREACH:
1001                 return ("EHOSTUNREACH");
1002 #endif
1003 #ifdef ENOTEMPTY
1004         case ENOTEMPTY:
1005                 return ("ENOTEMPTY");
1006 #endif
1007 #ifdef EPROCLIM
1008         case EPROCLIM:
1009                 return ("EPROCLIM");
1010 #endif
1011 #ifdef EUSERS
1012         case EUSERS:
1013                 return ("EUSERS");
1014 #endif
1015 #ifdef EDQUOT
1016         case EDQUOT:
1017                 return ("EDQUOT");
1018 #endif
1019 #ifdef ESTALE
1020         case ESTALE:
1021                 return ("ESTALE");
1022 #endif
1023 #ifdef EREMOTE
1024         case EREMOTE:
1025                 return ("EREMOTE");
1026 #endif
1027 #ifdef EBADRPC
1028         case EBADRPC:
1029                 return ("EBADRPC");
1030 #endif
1031 #ifdef ERPCMISMATCH
1032         case ERPCMISMATCH:
1033                 return ("ERPCMISMATCH");
1034 #endif
1035 #ifdef EPROGUNAVAIL
1036         case EPROGUNAVAIL:
1037                 return ("EPROGUNAVAIL");
1038 #endif
1039 #ifdef EPROGMISMATCH
1040         case EPROGMISMATCH:
1041                 return ("EPROGMISMATCH");
1042 #endif
1043 #ifdef EPROCUNAVAIL
1044         case EPROCUNAVAIL:
1045                 return ("EPROCUNAVAIL");
1046 #endif
1047 #ifdef ENOLCK
1048         case ENOLCK:
1049                 return ("ENOLCK");
1050 #endif
1051 #ifdef ENOSYS
1052         case ENOSYS:
1053                 return ("ENOSYS");
1054 #endif
1055 #ifdef EFTYPE
1056         case EFTYPE:
1057                 return ("EFTYPE");
1058 #endif
1059 #ifdef EAUTH
1060         case EAUTH:
1061                 return ("EAUTH");
1062 #endif
1063 #ifdef ENEEDAUTH
1064         case ENEEDAUTH:
1065                 return ("ENEEDAUTH");
1066 #endif
1067 #ifdef EIDRM
1068         case EIDRM:
1069                 return ("EIDRM");
1070 #endif
1071 #ifdef ENOMSG
1072         case ENOMSG:
1073                 return ("ENOMSG");
1074 #endif
1075 #ifdef EOVERFLOW
1076         case EOVERFLOW:
1077                 return ("EOVERFLOW");
1078 #endif
1079 #ifdef ECANCELED
1080         case ECANCELED:
1081                 return ("ECANCELED");
1082 #endif
1083 #ifdef EILSEQ
1084         case EILSEQ:
1085                 return ("EILSEQ");
1086 #endif
1087 #ifdef ENOATTR
1088         case ENOATTR:
1089                 return ("ENOATTR");
1090 #endif
1091 #ifdef EDOOFUS
1092         case EDOOFUS:
1093                 return ("EDOOFUS");
1094 #endif
1095 #ifdef EBADMSG
1096         case EBADMSG:
1097                 return ("EBADMSG");
1098 #endif
1099 #ifdef EMULTIHOP
1100         case EMULTIHOP:
1101                 return ("EMULTIHOP");
1102 #endif
1103 #ifdef ENOLINK
1104         case ENOLINK:
1105                 return ("ENOLINK");
1106 #endif
1107 #ifdef EPROTO
1108         case EPROTO:
1109                 return ("EPROTO");
1110 #endif
1111         default:
1112                 snprintf(errnum, sizeof(errnum), "%d", error);
1113                 return (errnum);
1114         }
1115 }