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
usage(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
str2flags(struct flag * tflags,char * sflags)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 *
flags2str(struct flag * tflags,long long flags)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
str2name(struct name * names,char * name)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 *
find_syscall(const char * name)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
show_stat(stat_t * sp,const char * what)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
show_stats(stat_t * sp,char * what)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
descriptor_add(int fd)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
descriptor_get(int pos)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
call_syscall(struct syscall_desc * scall,char * argv[])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
set_gids(char * gids)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
main(int argc,char * argv[])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 *
err2str(int error)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 }
1689