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 } 1689