1166065Spjd/*- 2211351Spjd * Copyright (c) 2006-2010 Pawel Jakub Dawidek <pjd@FreeBSD.org> 3166065Spjd * All rights reserved. 4166065Spjd * 5166065Spjd * Redistribution and use in source and binary forms, with or without 6166065Spjd * modification, are permitted provided that the following conditions 7166065Spjd * are met: 8166065Spjd * 1. Redistributions of source code must retain the above copyright 9166065Spjd * notice, this list of conditions and the following disclaimer. 10166065Spjd * 2. Redistributions in binary form must reproduce the above copyright 11166065Spjd * notice, this list of conditions and the following disclaimer in the 12166065Spjd * documentation and/or other materials provided with the distribution. 13166065Spjd * 14166065Spjd * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND 15166065Spjd * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16166065Spjd * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17166065Spjd * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE 18166065Spjd * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19166065Spjd * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20166065Spjd * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21166065Spjd * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22166065Spjd * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23166065Spjd * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24166065Spjd * SUCH DAMAGE. 25166065Spjd * 26166065Spjd * $FreeBSD$ 27166065Spjd */ 28166065Spjd 29166065Spjd#include <sys/param.h> 30210965Spjd#include <sys/types.h> 31166065Spjd#include <sys/stat.h> 32210951Spjd#include <sys/socket.h> 33210951Spjd#include <sys/un.h> 34210965Spjd#ifndef makedev 35210965Spjd#include <sys/mkdev.h> 36210965Spjd#endif 37210964Spjd 38210964Spjd#include <assert.h> 39210964Spjd#include <ctype.h> 40210964Spjd#include <errno.h> 41210964Spjd#include <fcntl.h> 42210964Spjd#include <grp.h> 43166065Spjd#include <stdio.h> 44166065Spjd#include <stdlib.h> 45210964Spjd#include <string.h> 46166065Spjd#include <unistd.h> 47166065Spjd 48166065Spjd#ifndef HAS_TRUNCATE64 49166065Spjd#define truncate64 truncate 50219437Spjd#define ftruncate64 ftruncate 51166065Spjd#endif 52166065Spjd#ifndef HAS_STAT64 53166065Spjd#define stat64 stat 54219437Spjd#define fstat64 fstat 55166065Spjd#define lstat64 lstat 56166065Spjd#endif 57196948Strasz#ifdef HAS_FREEBSD_ACL 58196948Strasz#include <sys/acl.h> 59196948Strasz#endif 60166065Spjd 61166065Spjd#ifndef ALLPERMS 62166065Spjd#define ALLPERMS (S_ISUID|S_ISGID|S_ISVTX|S_IRWXU|S_IRWXG|S_IRWXO) 63166065Spjd#endif 64166065Spjd 65166065Spjdenum action { 66166065Spjd ACTION_OPEN, 67219464Spjd ACTION_OPENAT, 68166065Spjd ACTION_CREATE, 69166065Spjd ACTION_UNLINK, 70219464Spjd ACTION_UNLINKAT, 71166065Spjd ACTION_MKDIR, 72219464Spjd ACTION_MKDIRAT, 73166065Spjd ACTION_RMDIR, 74166065Spjd ACTION_LINK, 75219464Spjd ACTION_LINKAT, 76166065Spjd ACTION_SYMLINK, 77219464Spjd ACTION_SYMLINKAT, 78166065Spjd ACTION_RENAME, 79219464Spjd ACTION_RENAMEAT, 80166065Spjd ACTION_MKFIFO, 81219464Spjd ACTION_MKFIFOAT, 82210965Spjd ACTION_MKNOD, 83219464Spjd ACTION_MKNODAT, 84210951Spjd ACTION_BIND, 85210951Spjd ACTION_CONNECT, 86166065Spjd ACTION_CHMOD, 87219437Spjd ACTION_FCHMOD, 88166065Spjd#ifdef HAS_LCHMOD 89166065Spjd ACTION_LCHMOD, 90166065Spjd#endif 91219464Spjd ACTION_FCHMODAT, 92166065Spjd ACTION_CHOWN, 93219437Spjd ACTION_FCHOWN, 94166065Spjd ACTION_LCHOWN, 95219464Spjd ACTION_FCHOWNAT, 96166065Spjd#ifdef HAS_CHFLAGS 97166065Spjd ACTION_CHFLAGS, 98166065Spjd#endif 99219437Spjd#ifdef HAS_FCHFLAGS 100219437Spjd ACTION_FCHFLAGS, 101219437Spjd#endif 102166065Spjd#ifdef HAS_LCHFLAGS 103166065Spjd ACTION_LCHFLAGS, 104166065Spjd#endif 105166065Spjd ACTION_TRUNCATE, 106219437Spjd ACTION_FTRUNCATE, 107166065Spjd ACTION_STAT, 108219437Spjd ACTION_FSTAT, 109166065Spjd ACTION_LSTAT, 110219464Spjd ACTION_FSTATAT, 111196948Strasz ACTION_PATHCONF, 112219437Spjd ACTION_FPATHCONF, 113219437Spjd ACTION_LPATHCONF, 114196948Strasz#ifdef HAS_FREEBSD_ACL 115196948Strasz ACTION_PREPENDACL, 116196948Strasz ACTION_READACL, 117196948Strasz#endif 118196948Strasz ACTION_WRITE, 119166065Spjd}; 120166065Spjd 121166065Spjd#define TYPE_NONE 0x0000 122166065Spjd#define TYPE_STRING 0x0001 123166065Spjd#define TYPE_NUMBER 0x0002 124219464Spjd#define TYPE_DESCRIPTOR 0x0003 125219464Spjd#define TYPE_MASK 0x000f 126166065Spjd 127166065Spjd#define TYPE_OPTIONAL 0x0100 128166065Spjd 129166065Spjd#define MAX_ARGS 8 130166065Spjd 131166065Spjdstruct syscall_desc { 132219566Spjd const char *sd_name; 133166065Spjd enum action sd_action; 134166065Spjd int sd_args[MAX_ARGS]; 135166065Spjd}; 136166065Spjd 137166065Spjdstatic struct syscall_desc syscalls[] = { 138166065Spjd { "open", ACTION_OPEN, { TYPE_STRING, TYPE_STRING, TYPE_NUMBER | TYPE_OPTIONAL, TYPE_NONE } }, 139219464Spjd { "openat", ACTION_OPENAT, { TYPE_DESCRIPTOR, TYPE_STRING, TYPE_STRING, TYPE_NUMBER | TYPE_OPTIONAL, TYPE_NONE } }, 140166065Spjd { "create", ACTION_CREATE, { TYPE_STRING, TYPE_NUMBER, TYPE_NONE } }, 141166065Spjd { "unlink", ACTION_UNLINK, { TYPE_STRING, TYPE_NONE } }, 142219464Spjd { "unlinkat", ACTION_UNLINKAT, { TYPE_DESCRIPTOR, TYPE_STRING, TYPE_STRING, TYPE_NONE } }, 143166065Spjd { "mkdir", ACTION_MKDIR, { TYPE_STRING, TYPE_NUMBER, TYPE_NONE } }, 144219464Spjd { "mkdirat", ACTION_MKDIRAT, { TYPE_DESCRIPTOR, TYPE_STRING, TYPE_NUMBER, TYPE_NONE } }, 145166065Spjd { "rmdir", ACTION_RMDIR, { TYPE_STRING, TYPE_NONE } }, 146166065Spjd { "link", ACTION_LINK, { TYPE_STRING, TYPE_STRING, TYPE_NONE } }, 147219464Spjd { "linkat", ACTION_LINKAT, { TYPE_DESCRIPTOR, TYPE_STRING, TYPE_DESCRIPTOR, TYPE_STRING, TYPE_STRING, TYPE_NONE } }, 148166065Spjd { "symlink", ACTION_SYMLINK, { TYPE_STRING, TYPE_STRING, TYPE_NONE } }, 149219464Spjd { "symlinkat", ACTION_SYMLINKAT, { TYPE_STRING, TYPE_DESCRIPTOR, TYPE_STRING, TYPE_NONE } }, 150166065Spjd { "rename", ACTION_RENAME, { TYPE_STRING, TYPE_STRING, TYPE_NONE } }, 151219464Spjd { "renameat", ACTION_RENAMEAT, { TYPE_DESCRIPTOR, TYPE_STRING, TYPE_DESCRIPTOR, TYPE_STRING, TYPE_NONE } }, 152166065Spjd { "mkfifo", ACTION_MKFIFO, { TYPE_STRING, TYPE_NUMBER, TYPE_NONE } }, 153219464Spjd { "mkfifoat", ACTION_MKFIFOAT, { TYPE_DESCRIPTOR, TYPE_STRING, TYPE_NUMBER, TYPE_NONE } }, 154210965Spjd { "mknod", ACTION_MKNOD, { TYPE_STRING, TYPE_STRING, TYPE_NUMBER, TYPE_NUMBER, TYPE_NUMBER, TYPE_NONE} }, 155219464Spjd { "mknodat", ACTION_MKNODAT, { TYPE_DESCRIPTOR, TYPE_STRING, TYPE_STRING, TYPE_NUMBER, TYPE_NUMBER, TYPE_NUMBER, TYPE_NONE} }, 156210951Spjd { "bind", ACTION_BIND, { TYPE_STRING, TYPE_NONE } }, 157210951Spjd { "connect", ACTION_CONNECT, { TYPE_STRING, TYPE_NONE } }, 158166065Spjd { "chmod", ACTION_CHMOD, { TYPE_STRING, TYPE_NUMBER, TYPE_NONE } }, 159219464Spjd { "fchmod", ACTION_FCHMOD, { TYPE_DESCRIPTOR, TYPE_NUMBER, TYPE_NONE } }, 160166065Spjd#ifdef HAS_LCHMOD 161166065Spjd { "lchmod", ACTION_LCHMOD, { TYPE_STRING, TYPE_NUMBER, TYPE_NONE } }, 162166065Spjd#endif 163219464Spjd { "fchmodat", ACTION_FCHMODAT, { TYPE_DESCRIPTOR, TYPE_STRING, TYPE_NUMBER, TYPE_STRING, TYPE_NONE } }, 164166065Spjd { "chown", ACTION_CHOWN, { TYPE_STRING, TYPE_NUMBER, TYPE_NUMBER, TYPE_NONE } }, 165219464Spjd { "fchown", ACTION_FCHOWN, { TYPE_DESCRIPTOR, TYPE_NUMBER, TYPE_NUMBER, TYPE_NONE } }, 166166065Spjd { "lchown", ACTION_LCHOWN, { TYPE_STRING, TYPE_NUMBER, TYPE_NUMBER, TYPE_NONE } }, 167219464Spjd { "fchownat", ACTION_FCHOWNAT, { TYPE_DESCRIPTOR, TYPE_STRING, TYPE_NUMBER, TYPE_NUMBER, TYPE_STRING, TYPE_NONE } }, 168166065Spjd#ifdef HAS_CHFLAGS 169166065Spjd { "chflags", ACTION_CHFLAGS, { TYPE_STRING, TYPE_STRING, TYPE_NONE } }, 170166065Spjd#endif 171219437Spjd#ifdef HAS_FCHFLAGS 172219464Spjd { "fchflags", ACTION_FCHFLAGS, { TYPE_DESCRIPTOR, TYPE_STRING, TYPE_NONE } }, 173219437Spjd#endif 174166065Spjd#ifdef HAS_LCHFLAGS 175166065Spjd { "lchflags", ACTION_LCHFLAGS, { TYPE_STRING, TYPE_STRING, TYPE_NONE } }, 176166065Spjd#endif 177166065Spjd { "truncate", ACTION_TRUNCATE, { TYPE_STRING, TYPE_NUMBER, TYPE_NONE } }, 178219464Spjd { "ftruncate", ACTION_FTRUNCATE, { TYPE_DESCRIPTOR, TYPE_NUMBER, TYPE_NONE } }, 179166065Spjd { "stat", ACTION_STAT, { TYPE_STRING, TYPE_STRING, TYPE_NONE } }, 180219464Spjd { "fstat", ACTION_FSTAT, { TYPE_DESCRIPTOR, TYPE_STRING, TYPE_NONE } }, 181166065Spjd { "lstat", ACTION_LSTAT, { TYPE_STRING, TYPE_STRING, TYPE_NONE } }, 182219464Spjd { "fstatat", ACTION_FSTATAT, { TYPE_DESCRIPTOR, TYPE_STRING, TYPE_STRING, TYPE_STRING, TYPE_NONE } }, 183185219Spjd { "pathconf", ACTION_PATHCONF, { TYPE_STRING, TYPE_STRING, TYPE_NONE } }, 184219464Spjd { "fpathconf", ACTION_FPATHCONF, { TYPE_DESCRIPTOR, TYPE_STRING, TYPE_NONE } }, 185219437Spjd { "lpathconf", ACTION_LPATHCONF, { TYPE_STRING, TYPE_STRING, TYPE_NONE } }, 186196948Strasz#ifdef HAS_FREEBSD_ACL 187196948Strasz { "prependacl", ACTION_PREPENDACL, { TYPE_STRING, TYPE_STRING, TYPE_NONE } }, 188196948Strasz { "readacl", ACTION_READACL, { TYPE_STRING, TYPE_NONE } }, 189196948Strasz#endif 190219464Spjd { "write", ACTION_WRITE, { TYPE_DESCRIPTOR, TYPE_STRING, TYPE_NONE } }, 191166065Spjd { NULL, -1, { TYPE_NONE } } 192166065Spjd}; 193166065Spjd 194166065Spjdstruct flag { 195166065Spjd long long f_flag; 196219566Spjd const char *f_str; 197166065Spjd}; 198166065Spjd 199166065Spjdstatic struct flag open_flags[] = { 200166065Spjd#ifdef O_RDONLY 201166065Spjd { O_RDONLY, "O_RDONLY" }, 202166065Spjd#endif 203166065Spjd#ifdef O_WRONLY 204166065Spjd { O_WRONLY, "O_WRONLY" }, 205166065Spjd#endif 206166065Spjd#ifdef O_RDWR 207166065Spjd { O_RDWR, "O_RDWR" }, 208166065Spjd#endif 209166065Spjd#ifdef O_NONBLOCK 210166065Spjd { O_NONBLOCK, "O_NONBLOCK" }, 211166065Spjd#endif 212166065Spjd#ifdef O_APPEND 213166065Spjd { O_APPEND, "O_APPEND" }, 214166065Spjd#endif 215166065Spjd#ifdef O_CREAT 216166065Spjd { O_CREAT, "O_CREAT" }, 217166065Spjd#endif 218166065Spjd#ifdef O_TRUNC 219166065Spjd { O_TRUNC, "O_TRUNC" }, 220166065Spjd#endif 221166065Spjd#ifdef O_EXCL 222166065Spjd { O_EXCL, "O_EXCL" }, 223166065Spjd#endif 224166065Spjd#ifdef O_SHLOCK 225166065Spjd { O_SHLOCK, "O_SHLOCK" }, 226166065Spjd#endif 227166065Spjd#ifdef O_EXLOCK 228166065Spjd { O_EXLOCK, "O_EXLOCK" }, 229166065Spjd#endif 230166065Spjd#ifdef O_DIRECT 231166065Spjd { O_DIRECT, "O_DIRECT" }, 232166065Spjd#endif 233166065Spjd#ifdef O_FSYNC 234166065Spjd { O_FSYNC, "O_FSYNC" }, 235166065Spjd#endif 236166065Spjd#ifdef O_SYNC 237166065Spjd { O_SYNC, "O_SYNC" }, 238166065Spjd#endif 239166065Spjd#ifdef O_NOFOLLOW 240166065Spjd { O_NOFOLLOW, "O_NOFOLLOW" }, 241166065Spjd#endif 242166065Spjd#ifdef O_NOCTTY 243166065Spjd { O_NOCTTY, "O_NOCTTY" }, 244166065Spjd#endif 245219464Spjd#ifdef O_DIRECTORY 246219464Spjd { O_DIRECTORY, "O_DIRECTORY" }, 247219464Spjd#endif 248166065Spjd { 0, NULL } 249166065Spjd}; 250166065Spjd 251166065Spjd#ifdef HAS_CHFLAGS 252166065Spjdstatic struct flag chflags_flags[] = { 253166065Spjd#ifdef UF_NODUMP 254166065Spjd { UF_NODUMP, "UF_NODUMP" }, 255166065Spjd#endif 256166065Spjd#ifdef UF_IMMUTABLE 257166065Spjd { UF_IMMUTABLE, "UF_IMMUTABLE" }, 258166065Spjd#endif 259166065Spjd#ifdef UF_APPEND 260166065Spjd { UF_APPEND, "UF_APPEND" }, 261166065Spjd#endif 262166065Spjd#ifdef UF_NOUNLINK 263166065Spjd { UF_NOUNLINK, "UF_NOUNLINK" }, 264166065Spjd#endif 265166065Spjd#ifdef UF_OPAQUE 266166065Spjd { UF_OPAQUE, "UF_OPAQUE" }, 267166065Spjd#endif 268166065Spjd#ifdef SF_ARCHIVED 269166065Spjd { SF_ARCHIVED, "SF_ARCHIVED" }, 270166065Spjd#endif 271166065Spjd#ifdef SF_IMMUTABLE 272166065Spjd { SF_IMMUTABLE, "SF_IMMUTABLE" }, 273166065Spjd#endif 274166065Spjd#ifdef SF_APPEND 275166065Spjd { SF_APPEND, "SF_APPEND" }, 276166065Spjd#endif 277166065Spjd#ifdef SF_NOUNLINK 278166065Spjd { SF_NOUNLINK, "SF_NOUNLINK" }, 279166065Spjd#endif 280166065Spjd#ifdef SF_SNAPSHOT 281166065Spjd { SF_SNAPSHOT, "SF_SNAPSHOT" }, 282166065Spjd#endif 283166065Spjd { 0, NULL } 284166065Spjd}; 285166065Spjd#endif 286166065Spjd 287219464Spjdstatic struct flag unlinkat_flags[] = { 288219464Spjd { AT_REMOVEDIR, "AT_REMOVEDIR" }, 289219464Spjd { 0, NULL } 290219464Spjd}; 291219464Spjd 292219464Spjdstatic struct flag linkat_flags[] = { 293219464Spjd { AT_SYMLINK_FOLLOW, "AT_SYMLINK_FOLLOW" }, 294219464Spjd { 0, NULL } 295219464Spjd}; 296219464Spjd 297219464Spjdstatic struct flag fchmodat_flags[] = { 298219464Spjd { AT_SYMLINK_NOFOLLOW, "AT_SYMLINK_NOFOLLOW" }, 299219464Spjd { 0, NULL } 300219464Spjd}; 301219464Spjd 302219464Spjdstatic struct flag fchownat_flags[] = { 303219464Spjd { AT_SYMLINK_NOFOLLOW, "AT_SYMLINK_NOFOLLOW" }, 304219464Spjd { 0, NULL } 305219464Spjd}; 306219464Spjd 307219464Spjdstatic struct flag fstatat_flags[] = { 308219464Spjd { AT_SYMLINK_NOFOLLOW, "AT_SYMLINK_NOFOLLOW" }, 309219464Spjd { 0, NULL } 310219464Spjd}; 311219464Spjd 312185219Spjdstruct name { 313219566Spjd int n_name; 314219566Spjd const char *n_str; 315185219Spjd}; 316185219Spjd 317185219Spjdstatic struct name pathconf_names[] = { 318185219Spjd#ifdef _PC_LINK_MAX 319185219Spjd { _PC_LINK_MAX, "_PC_LINK_MAX" }, 320185219Spjd#endif 321185219Spjd#ifdef _PC_NAME_MAX 322185219Spjd { _PC_NAME_MAX, "_PC_NAME_MAX" }, 323185219Spjd#endif 324185219Spjd#ifdef _PC_PATH_MAX 325185219Spjd { _PC_PATH_MAX, "_PC_PATH_MAX" }, 326185219Spjd#endif 327185219Spjd#ifdef _PC_SYMLINK_MAX 328185219Spjd { _PC_SYMLINK_MAX, "_PC_SYMLINK_MAX" }, 329185219Spjd#endif 330185219Spjd { 0, NULL } 331185219Spjd}; 332185219Spjd 333166065Spjdstatic const char *err2str(int error); 334166065Spjd 335219437Spjdstatic int *descriptors; 336219437Spjdstatic int ndescriptors; 337219437Spjd 338166065Spjdstatic void 339166065Spjdusage(void) 340166065Spjd{ 341166065Spjd 342211354Spjd fprintf(stderr, "usage: pjdfstest [-U umask] [-u uid] [-g gid1[,gid2[...]]] syscall args ...\n"); 343166065Spjd exit(1); 344166065Spjd} 345166065Spjd 346166065Spjdstatic long long 347166065Spjdstr2flags(struct flag *tflags, char *sflags) 348166065Spjd{ 349166065Spjd long long flags = 0; 350166065Spjd unsigned int i; 351166065Spjd char *f; 352166065Spjd 353166065Spjd for (f = strtok(sflags, ","); f != NULL; f = strtok(NULL, ",")) { 354166065Spjd /* Support magic 'none' flag which just reset all flags. */ 355166065Spjd if (strcmp(f, "none") == 0) 356166065Spjd return (0); 357166065Spjd for (i = 0; tflags[i].f_str != NULL; i++) { 358166065Spjd if (strcmp(tflags[i].f_str, f) == 0) 359166065Spjd break; 360166065Spjd } 361166065Spjd if (tflags[i].f_str == NULL) { 362166065Spjd fprintf(stderr, "unknown flag '%s'\n", f); 363166065Spjd exit(1); 364166065Spjd } 365166065Spjd flags |= tflags[i].f_flag; 366166065Spjd } 367166065Spjd return (flags); 368166065Spjd} 369166065Spjd 370166065Spjd#ifdef HAS_CHFLAGS 371166065Spjdstatic char * 372166065Spjdflags2str(struct flag *tflags, long long flags) 373166065Spjd{ 374166065Spjd static char sflags[1024]; 375166065Spjd unsigned int i; 376166065Spjd 377166065Spjd sflags[0] = '\0'; 378166065Spjd for (i = 0; tflags[i].f_str != NULL; i++) { 379166065Spjd if (flags & tflags[i].f_flag) { 380166065Spjd if (sflags[0] != '\0') 381166065Spjd strlcat(sflags, ",", sizeof(sflags)); 382166065Spjd strlcat(sflags, tflags[i].f_str, sizeof(sflags)); 383166065Spjd } 384166065Spjd } 385166065Spjd if (sflags[0] == '\0') 386166065Spjd strlcpy(sflags, "none", sizeof(sflags)); 387166065Spjd return (sflags); 388166065Spjd} 389166065Spjd#endif 390166065Spjd 391185219Spjdstatic int 392185219Spjdstr2name(struct name *names, char *name) 393185219Spjd{ 394185219Spjd unsigned int i; 395185219Spjd 396185219Spjd for (i = 0; names[i].n_str != NULL; i++) { 397185219Spjd if (strcmp(names[i].n_str, name) == 0) 398185219Spjd return (names[i].n_name); 399185219Spjd } 400185219Spjd return (-1); 401185219Spjd} 402185219Spjd 403166065Spjdstatic struct syscall_desc * 404166065Spjdfind_syscall(const char *name) 405166065Spjd{ 406166065Spjd int i; 407166065Spjd 408166065Spjd for (i = 0; syscalls[i].sd_name != NULL; i++) { 409166065Spjd if (strcmp(syscalls[i].sd_name, name) == 0) 410166065Spjd return (&syscalls[i]); 411166065Spjd } 412166065Spjd return (NULL); 413166065Spjd} 414166065Spjd 415166065Spjdstatic void 416166065Spjdshow_stat(struct stat64 *sp, const char *what) 417166065Spjd{ 418166065Spjd 419166065Spjd if (strcmp(what, "mode") == 0) 420166065Spjd printf("0%o", (unsigned int)(sp->st_mode & ALLPERMS)); 421166065Spjd else if (strcmp(what, "inode") == 0) 422166065Spjd printf("%lld", (long long)sp->st_ino); 423166065Spjd else if (strcmp(what, "nlink") == 0) 424166065Spjd printf("%lld", (long long)sp->st_nlink); 425166065Spjd else if (strcmp(what, "uid") == 0) 426166065Spjd printf("%d", (int)sp->st_uid); 427166065Spjd else if (strcmp(what, "gid") == 0) 428166065Spjd printf("%d", (int)sp->st_gid); 429166065Spjd else if (strcmp(what, "size") == 0) 430166065Spjd printf("%lld", (long long)sp->st_size); 431166065Spjd else if (strcmp(what, "blocks") == 0) 432166065Spjd printf("%lld", (long long)sp->st_blocks); 433166065Spjd else if (strcmp(what, "atime") == 0) 434166065Spjd printf("%lld", (long long)sp->st_atime); 435166065Spjd else if (strcmp(what, "mtime") == 0) 436166065Spjd printf("%lld", (long long)sp->st_mtime); 437166065Spjd else if (strcmp(what, "ctime") == 0) 438166065Spjd printf("%lld", (long long)sp->st_ctime); 439166065Spjd#ifdef HAS_CHFLAGS 440166065Spjd else if (strcmp(what, "flags") == 0) 441188934Spjd printf("%s", flags2str(chflags_flags, (long long)sp->st_flags)); 442166065Spjd#endif 443210965Spjd else if (strcmp(what, "major") == 0) 444210965Spjd printf("%u", (unsigned int)major(sp->st_rdev)); 445210965Spjd else if (strcmp(what, "minor") == 0) 446210965Spjd printf("%u", (unsigned int)minor(sp->st_rdev)); 447166065Spjd else if (strcmp(what, "type") == 0) { 448166065Spjd switch (sp->st_mode & S_IFMT) { 449166065Spjd case S_IFIFO: 450166065Spjd printf("fifo"); 451166065Spjd break; 452166065Spjd case S_IFCHR: 453166065Spjd printf("char"); 454166065Spjd break; 455166065Spjd case S_IFDIR: 456166065Spjd printf("dir"); 457166065Spjd break; 458166065Spjd case S_IFBLK: 459166065Spjd printf("block"); 460166065Spjd break; 461166065Spjd case S_IFREG: 462166065Spjd printf("regular"); 463166065Spjd break; 464166065Spjd case S_IFLNK: 465166065Spjd printf("symlink"); 466166065Spjd break; 467166065Spjd case S_IFSOCK: 468166065Spjd printf("socket"); 469166065Spjd break; 470166065Spjd default: 471166065Spjd printf("unknown"); 472166065Spjd break; 473166065Spjd } 474166065Spjd } else { 475166065Spjd printf("unknown"); 476166065Spjd } 477166065Spjd} 478166065Spjd 479166065Spjdstatic void 480166065Spjdshow_stats(struct stat64 *sp, char *what) 481166065Spjd{ 482166065Spjd const char *s = ""; 483166065Spjd char *w; 484166065Spjd 485166065Spjd for (w = strtok(what, ","); w != NULL; w = strtok(NULL, ",")) { 486166065Spjd printf("%s", s); 487166065Spjd show_stat(sp, w); 488166065Spjd s = ","; 489166065Spjd } 490166065Spjd printf("\n"); 491166065Spjd} 492166065Spjd 493219437Spjdstatic void 494219437Spjddescriptor_add(int fd) 495219437Spjd{ 496219437Spjd 497219437Spjd ndescriptors++; 498219437Spjd if (descriptors == NULL) { 499219437Spjd descriptors = malloc(sizeof(descriptors[0]) * ndescriptors); 500219437Spjd } else { 501219437Spjd descriptors = realloc(descriptors, 502219437Spjd sizeof(descriptors[0]) * ndescriptors); 503219437Spjd } 504219437Spjd assert(descriptors != NULL); 505219437Spjd descriptors[ndescriptors - 1] = fd; 506219437Spjd} 507219437Spjd 508219437Spjdstatic int 509219437Spjddescriptor_get(int pos) 510219437Spjd{ 511219437Spjd 512219437Spjd if (pos < 0 || pos >= ndescriptors) { 513219437Spjd fprintf(stderr, "invalid descriptor %d\n", pos); 514219437Spjd exit(1); 515219437Spjd } 516219437Spjd 517219437Spjd return (descriptors[pos]); 518219437Spjd} 519219437Spjd 520166065Spjdstatic unsigned int 521166065Spjdcall_syscall(struct syscall_desc *scall, char *argv[]) 522166065Spjd{ 523166065Spjd struct stat64 sb; 524166065Spjd long long flags; 525166065Spjd unsigned int i; 526166065Spjd char *endp; 527185219Spjd int name, rval; 528166065Spjd union { 529166065Spjd char *str; 530166065Spjd long long num; 531166065Spjd } args[MAX_ARGS]; 532196948Strasz#ifdef HAS_FREEBSD_ACL 533196948Strasz int entry_id = ACL_FIRST_ENTRY; 534196948Strasz acl_t acl, newacl; 535196948Strasz acl_entry_t entry, newentry; 536196948Strasz#endif 537166065Spjd 538166065Spjd /* 539166065Spjd * Verify correctness of the arguments. 540166065Spjd */ 541166065Spjd for (i = 0; i < sizeof(args)/sizeof(args[0]); i++) { 542166065Spjd if (scall->sd_args[i] == TYPE_NONE) { 543166065Spjd if (argv[i] == NULL || strcmp(argv[i], ":") == 0) 544166065Spjd break; 545166065Spjd fprintf(stderr, "too many arguments [%s]\n", argv[i]); 546166065Spjd exit(1); 547166065Spjd } else { 548166065Spjd if (argv[i] == NULL || strcmp(argv[i], ":") == 0) { 549166065Spjd if (scall->sd_args[i] & TYPE_OPTIONAL) 550166065Spjd break; 551166065Spjd fprintf(stderr, "too few arguments\n"); 552166065Spjd exit(1); 553166065Spjd } 554219464Spjd if ((scall->sd_args[i] & TYPE_MASK) == TYPE_STRING) { 555166065Spjd if (strcmp(argv[i], "NULL") == 0) 556166065Spjd args[i].str = NULL; 557166065Spjd else if (strcmp(argv[i], "DEADCODE") == 0) 558166065Spjd args[i].str = (void *)0xdeadc0de; 559166065Spjd else 560166065Spjd args[i].str = argv[i]; 561219464Spjd } else if ((scall->sd_args[i] & TYPE_MASK) == TYPE_NUMBER) { 562166065Spjd args[i].num = strtoll(argv[i], &endp, 0); 563166065Spjd if (*endp != '\0' && !isspace((unsigned char)*endp)) { 564166065Spjd fprintf(stderr, "invalid argument %u, number expected [%s]\n", i, endp); 565166065Spjd exit(1); 566166065Spjd } 567219464Spjd } else if ((scall->sd_args[i] & TYPE_MASK) == TYPE_DESCRIPTOR) { 568219464Spjd if (strcmp(argv[i], "AT_FDCWD") == 0) { 569219464Spjd args[i].num = AT_FDCWD; 570219464Spjd } else if (strcmp(argv[i], "BADFD") == 0) { 571219464Spjd /* In case AT_FDCWD is -1 on some systems... */ 572219464Spjd if (AT_FDCWD == -1) 573219464Spjd args[i].num = -2; 574219464Spjd else 575219464Spjd args[i].num = -1; 576219464Spjd } else { 577219464Spjd int pos; 578219464Spjd 579219464Spjd pos = strtoll(argv[i], &endp, 0); 580219464Spjd if (*endp != '\0' && !isspace((unsigned char)*endp)) { 581219464Spjd fprintf(stderr, "invalid argument %u, number expected [%s]\n", i, endp); 582219464Spjd exit(1); 583219464Spjd } 584219464Spjd args[i].num = descriptor_get(pos); 585219464Spjd } 586166065Spjd } 587166065Spjd } 588166065Spjd } 589166065Spjd /* 590166065Spjd * Call the given syscall. 591166065Spjd */ 592166065Spjd#define NUM(n) (args[(n)].num) 593166065Spjd#define STR(n) (args[(n)].str) 594166065Spjd switch (scall->sd_action) { 595166065Spjd case ACTION_OPEN: 596166065Spjd flags = str2flags(open_flags, STR(1)); 597166065Spjd if (flags & O_CREAT) { 598166065Spjd if (i == 2) { 599166065Spjd fprintf(stderr, "too few arguments\n"); 600166065Spjd exit(1); 601166065Spjd } 602188934Spjd rval = open(STR(0), (int)flags, (mode_t)NUM(2)); 603166065Spjd } else { 604166065Spjd if (i == 3) { 605166065Spjd fprintf(stderr, "too many arguments\n"); 606166065Spjd exit(1); 607166065Spjd } 608188934Spjd rval = open(STR(0), (int)flags); 609166065Spjd } 610219437Spjd if (rval >= 0) 611219437Spjd descriptor_add(rval); 612166065Spjd break; 613219464Spjd case ACTION_OPENAT: 614219464Spjd flags = str2flags(open_flags, STR(2)); 615219464Spjd if (flags & O_CREAT) { 616219464Spjd if (i == 3) { 617219464Spjd fprintf(stderr, "too few arguments\n"); 618219464Spjd exit(1); 619219464Spjd } 620219464Spjd rval = openat(NUM(0), STR(1), (int)flags, (mode_t)NUM(3)); 621219464Spjd } else { 622219464Spjd if (i == 4) { 623219464Spjd fprintf(stderr, "too many arguments\n"); 624219464Spjd exit(1); 625219464Spjd } 626219464Spjd rval = openat(NUM(0), STR(1), (int)flags); 627219464Spjd } 628219464Spjd if (rval >= 0) 629219464Spjd descriptor_add(rval); 630219464Spjd break; 631166065Spjd case ACTION_CREATE: 632188934Spjd rval = open(STR(0), O_CREAT | O_EXCL, (mode_t)NUM(1)); 633166065Spjd if (rval >= 0) 634166065Spjd close(rval); 635166065Spjd break; 636166065Spjd case ACTION_UNLINK: 637166065Spjd rval = unlink(STR(0)); 638166065Spjd break; 639219464Spjd case ACTION_UNLINKAT: 640219464Spjd rval = unlinkat(NUM(0), STR(1), 641219464Spjd (int)str2flags(unlinkat_flags, STR(2))); 642219464Spjd break; 643166065Spjd case ACTION_MKDIR: 644188934Spjd rval = mkdir(STR(0), (mode_t)NUM(1)); 645166065Spjd break; 646219464Spjd case ACTION_MKDIRAT: 647219464Spjd rval = mkdirat(NUM(0), STR(1), (mode_t)NUM(2)); 648219464Spjd break; 649166065Spjd case ACTION_RMDIR: 650166065Spjd rval = rmdir(STR(0)); 651166065Spjd break; 652166065Spjd case ACTION_LINK: 653166065Spjd rval = link(STR(0), STR(1)); 654166065Spjd break; 655219464Spjd case ACTION_LINKAT: 656219464Spjd rval = linkat(NUM(0), STR(1), NUM(2), STR(3), 657219464Spjd (int)str2flags(linkat_flags, STR(4))); 658219464Spjd break; 659166065Spjd case ACTION_SYMLINK: 660166065Spjd rval = symlink(STR(0), STR(1)); 661166065Spjd break; 662219464Spjd case ACTION_SYMLINKAT: 663219464Spjd rval = symlinkat(STR(0), NUM(1), STR(2)); 664219464Spjd break; 665166065Spjd case ACTION_RENAME: 666166065Spjd rval = rename(STR(0), STR(1)); 667166065Spjd break; 668219464Spjd case ACTION_RENAMEAT: 669219464Spjd rval = renameat(NUM(0), STR(1), NUM(2), STR(3)); 670219464Spjd break; 671166065Spjd case ACTION_MKFIFO: 672188934Spjd rval = mkfifo(STR(0), (mode_t)NUM(1)); 673166065Spjd break; 674219464Spjd case ACTION_MKFIFOAT: 675219464Spjd rval = mkfifoat(NUM(0), STR(1), (mode_t)NUM(2)); 676219464Spjd break; 677210965Spjd case ACTION_MKNOD: 678219464Spjd case ACTION_MKNODAT: 679210965Spjd { 680210965Spjd mode_t ntype; 681210965Spjd dev_t dev; 682219464Spjd int fa; 683210965Spjd 684219464Spjd switch (scall->sd_action) { 685219464Spjd case ACTION_MKNOD: 686219464Spjd fa = 0; 687219464Spjd break; 688219464Spjd case ACTION_MKNODAT: 689219464Spjd fa = 1; 690219464Spjd break; 691219464Spjd default: 692219464Spjd abort(); 693219464Spjd } 694219464Spjd 695219464Spjd dev = makedev(NUM(fa + 3), NUM(fa + 4)); 696219464Spjd if (strcmp(STR(fa + 1), "c") == 0) /* character device */ 697210965Spjd ntype = S_IFCHR; 698219464Spjd else if (strcmp(STR(fa + 1), "b") == 0) /* block device */ 699210965Spjd ntype = S_IFBLK; 700219464Spjd else if (strcmp(STR(fa + 1), "f") == 0) /* fifo special */ 701210965Spjd ntype = S_IFIFO; 702219464Spjd else if (strcmp(STR(fa + 1), "d") == 0) /* directory */ 703210965Spjd ntype = S_IFDIR; 704219464Spjd else if (strcmp(STR(fa + 1), "o") == 0) /* regular file */ 705210965Spjd ntype = S_IFREG; 706210965Spjd else { 707210965Spjd fprintf(stderr, "wrong argument 1\n"); 708210965Spjd exit(1); 709210965Spjd } 710219464Spjd switch (scall->sd_action) { 711219464Spjd case ACTION_MKNOD: 712219464Spjd rval = mknod(STR(0), ntype | NUM(2), dev); 713219464Spjd break; 714219464Spjd case ACTION_MKNODAT: 715219464Spjd rval = mknodat(NUM(0), STR(1), ntype | NUM(3), dev); 716219464Spjd break; 717219464Spjd default: 718219464Spjd abort(); 719219464Spjd } 720210965Spjd break; 721210965Spjd } 722210951Spjd case ACTION_BIND: 723210951Spjd { 724211110Spjd struct sockaddr_un sunx; 725210951Spjd 726211110Spjd sunx.sun_family = AF_UNIX; 727211116Spjd strncpy(sunx.sun_path, STR(0), sizeof(sunx.sun_path) - 1); 728211116Spjd sunx.sun_path[sizeof(sunx.sun_path) - 1] = '\0'; 729210951Spjd rval = socket(AF_UNIX, SOCK_STREAM, 0); 730210951Spjd if (rval < 0) 731210951Spjd break; 732211110Spjd rval = bind(rval, (struct sockaddr *)&sunx, sizeof(sunx)); 733210951Spjd break; 734210951Spjd } 735210951Spjd case ACTION_CONNECT: 736210951Spjd { 737211110Spjd struct sockaddr_un sunx; 738210951Spjd 739211110Spjd sunx.sun_family = AF_UNIX; 740211116Spjd strncpy(sunx.sun_path, STR(0), sizeof(sunx.sun_path) - 1); 741211116Spjd sunx.sun_path[sizeof(sunx.sun_path) - 1] = '\0'; 742210951Spjd rval = socket(AF_UNIX, SOCK_STREAM, 0); 743210951Spjd if (rval < 0) 744210951Spjd break; 745211110Spjd rval = connect(rval, (struct sockaddr *)&sunx, sizeof(sunx)); 746210951Spjd break; 747210951Spjd } 748166065Spjd case ACTION_CHMOD: 749188934Spjd rval = chmod(STR(0), (mode_t)NUM(1)); 750166065Spjd break; 751219437Spjd case ACTION_FCHMOD: 752219464Spjd rval = fchmod(NUM(0), (mode_t)NUM(1)); 753219437Spjd break; 754166065Spjd#ifdef HAS_LCHMOD 755166065Spjd case ACTION_LCHMOD: 756188934Spjd rval = lchmod(STR(0), (mode_t)NUM(1)); 757166065Spjd break; 758166065Spjd#endif 759219464Spjd case ACTION_FCHMODAT: 760219464Spjd rval = fchmodat(NUM(0), STR(1), (mode_t)NUM(2), 761219464Spjd str2flags(fchmodat_flags, STR(3))); 762219464Spjd break; 763166065Spjd case ACTION_CHOWN: 764188934Spjd rval = chown(STR(0), (uid_t)NUM(1), (gid_t)NUM(2)); 765166065Spjd break; 766219437Spjd case ACTION_FCHOWN: 767219464Spjd rval = fchown(NUM(0), (uid_t)NUM(1), (gid_t)NUM(2)); 768219437Spjd break; 769166065Spjd case ACTION_LCHOWN: 770188934Spjd rval = lchown(STR(0), (uid_t)NUM(1), (gid_t)NUM(2)); 771166065Spjd break; 772219464Spjd case ACTION_FCHOWNAT: 773219464Spjd rval = fchownat(NUM(0), STR(1), (uid_t)NUM(2), (gid_t)NUM(3), 774219464Spjd (int)str2flags(fchownat_flags, STR(4))); 775219464Spjd break; 776166065Spjd#ifdef HAS_CHFLAGS 777166065Spjd case ACTION_CHFLAGS: 778219464Spjd rval = chflags(STR(0), 779219464Spjd (unsigned long)str2flags(chflags_flags, STR(1))); 780166065Spjd break; 781166065Spjd#endif 782219437Spjd#ifdef HAS_FCHFLAGS 783219437Spjd case ACTION_FCHFLAGS: 784219464Spjd rval = fchflags(NUM(0), 785219464Spjd (unsigned long)str2flags(chflags_flags, STR(1))); 786219437Spjd break; 787219437Spjd#endif 788166065Spjd#ifdef HAS_LCHFLAGS 789166065Spjd case ACTION_LCHFLAGS: 790193373Spjd rval = lchflags(STR(0), (int)str2flags(chflags_flags, STR(1))); 791166065Spjd break; 792166065Spjd#endif 793166065Spjd case ACTION_TRUNCATE: 794166065Spjd rval = truncate64(STR(0), NUM(1)); 795166065Spjd break; 796219437Spjd case ACTION_FTRUNCATE: 797219464Spjd rval = ftruncate64(NUM(0), NUM(1)); 798219437Spjd break; 799166065Spjd case ACTION_STAT: 800166065Spjd rval = stat64(STR(0), &sb); 801166065Spjd if (rval == 0) { 802166065Spjd show_stats(&sb, STR(1)); 803166065Spjd return (i); 804166065Spjd } 805166065Spjd break; 806219437Spjd case ACTION_FSTAT: 807219464Spjd rval = fstat64(NUM(0), &sb); 808219437Spjd if (rval == 0) { 809219437Spjd show_stats(&sb, STR(1)); 810219437Spjd return (i); 811219437Spjd } 812219437Spjd break; 813166065Spjd case ACTION_LSTAT: 814166065Spjd rval = lstat64(STR(0), &sb); 815166065Spjd if (rval == 0) { 816166065Spjd show_stats(&sb, STR(1)); 817166065Spjd return (i); 818166065Spjd } 819166065Spjd break; 820219464Spjd case ACTION_FSTATAT: 821219464Spjd rval = fstatat(NUM(0), STR(1), &sb, 822219464Spjd (int)str2flags(fstatat_flags, STR(2))); 823219464Spjd if (rval == 0) { 824219464Spjd show_stats(&sb, STR(3)); 825219464Spjd return (i); 826219464Spjd } 827219464Spjd break; 828185219Spjd case ACTION_PATHCONF: 829219437Spjd case ACTION_FPATHCONF: 830219437Spjd case ACTION_LPATHCONF: 831185219Spjd { 832185219Spjd long lrval; 833185219Spjd 834185219Spjd name = str2name(pathconf_names, STR(1)); 835185219Spjd if (name == -1) { 836185219Spjd fprintf(stderr, "unknown name %s", STR(1)); 837185219Spjd exit(1); 838185219Spjd } 839185219Spjd errno = 0; 840219437Spjd switch (scall->sd_action) { 841219437Spjd case ACTION_PATHCONF: 842219437Spjd lrval = pathconf(STR(0), name); 843219437Spjd break; 844219437Spjd case ACTION_FPATHCONF: 845219464Spjd lrval = fpathconf(NUM(0), name); 846219437Spjd break; 847219437Spjd case ACTION_LPATHCONF: 848219437Spjd lrval = lpathconf(STR(0), name); 849219437Spjd break; 850219437Spjd default: 851219437Spjd abort(); 852219437Spjd } 853185219Spjd if (lrval == -1 && errno == 0) { 854185219Spjd printf("unlimited\n"); 855185219Spjd return (i); 856185219Spjd } else if (lrval >= 0) { 857185219Spjd printf("%ld\n", lrval); 858185219Spjd return (i); 859185219Spjd } 860185219Spjd rval = -1; 861185219Spjd break; 862185219Spjd } 863196948Strasz#ifdef HAS_FREEBSD_ACL 864196948Strasz case ACTION_PREPENDACL: 865196948Strasz rval = -1; 866196948Strasz 867196948Strasz acl = acl_get_file(STR(0), ACL_TYPE_NFS4); 868196948Strasz if (acl == NULL) 869196948Strasz break; 870196948Strasz 871196948Strasz newacl = acl_from_text(STR(1)); 872196948Strasz if (acl == NULL) 873196948Strasz break; 874196948Strasz 875196948Strasz while (acl_get_entry(newacl, entry_id, &newentry) == 1) { 876196948Strasz entry_id = ACL_NEXT_ENTRY; 877196948Strasz 878196948Strasz if (acl_create_entry_np(&acl, &entry, 0)) 879196948Strasz break; 880196948Strasz 881196948Strasz if (acl_copy_entry(entry, newentry)) 882196948Strasz break; 883196948Strasz } 884196948Strasz 885196948Strasz rval = acl_set_file(STR(0), ACL_TYPE_NFS4, acl); 886196948Strasz break; 887196948Strasz case ACTION_READACL: 888196948Strasz acl = acl_get_file(STR(0), ACL_TYPE_NFS4); 889196948Strasz if (acl == NULL) 890196948Strasz rval = -1; 891196948Strasz else 892196948Strasz rval = 0; 893196948Strasz break; 894196948Strasz#endif 895196948Strasz case ACTION_WRITE: 896219464Spjd rval = write(NUM(0), STR(1), strlen(STR(1))); 897196948Strasz break; 898166065Spjd default: 899166065Spjd fprintf(stderr, "unsupported syscall\n"); 900166065Spjd exit(1); 901166065Spjd } 902166065Spjd#undef STR 903166065Spjd#undef NUM 904166065Spjd if (rval < 0) { 905166065Spjd const char *serrno; 906166065Spjd 907166065Spjd serrno = err2str(errno); 908166065Spjd fprintf(stderr, "%s returned %d\n", scall->sd_name, rval); 909166065Spjd printf("%s\n", serrno); 910166065Spjd exit(1); 911166065Spjd } 912166065Spjd printf("0\n"); 913166065Spjd return (i); 914166065Spjd} 915166065Spjd 916166065Spjdstatic void 917166065Spjdset_gids(char *gids) 918166065Spjd{ 919166065Spjd gid_t *gidset; 920166065Spjd long ngroups; 921166065Spjd char *g, *endp; 922166065Spjd unsigned i; 923166065Spjd 924166065Spjd ngroups = sysconf(_SC_NGROUPS_MAX); 925166065Spjd assert(ngroups > 0); 926166065Spjd gidset = malloc(sizeof(*gidset) * ngroups); 927166065Spjd assert(gidset != NULL); 928166065Spjd for (i = 0, g = strtok(gids, ","); g != NULL; g = strtok(NULL, ","), i++) { 929166065Spjd if (i >= ngroups) { 930166065Spjd fprintf(stderr, "too many gids\n"); 931166065Spjd exit(1); 932166065Spjd } 933166065Spjd gidset[i] = strtol(g, &endp, 0); 934166065Spjd if (*endp != '\0' && !isspace((unsigned char)*endp)) { 935166065Spjd fprintf(stderr, "invalid gid '%s' - number expected\n", 936166065Spjd g); 937166065Spjd exit(1); 938166065Spjd } 939166065Spjd } 940166065Spjd if (setgroups(i, gidset) < 0) { 941166065Spjd fprintf(stderr, "cannot change groups: %s\n", strerror(errno)); 942166065Spjd exit(1); 943166065Spjd } 944171486Spjd if (setegid(gidset[0]) < 0) { 945171486Spjd fprintf(stderr, "cannot change effective gid: %s\n", strerror(errno)); 946171486Spjd exit(1); 947171486Spjd } 948166065Spjd free(gidset); 949166065Spjd} 950166065Spjd 951166065Spjdint 952166065Spjdmain(int argc, char *argv[]) 953166065Spjd{ 954166065Spjd struct syscall_desc *scall; 955166065Spjd unsigned int n; 956166065Spjd char *gids, *endp; 957166065Spjd int uid, umsk, ch; 958166065Spjd 959166065Spjd uid = -1; 960166065Spjd gids = NULL; 961166065Spjd umsk = 0; 962166065Spjd 963166065Spjd while ((ch = getopt(argc, argv, "g:u:U:")) != -1) { 964166065Spjd switch(ch) { 965166065Spjd case 'g': 966166065Spjd gids = optarg; 967166065Spjd break; 968166065Spjd case 'u': 969166065Spjd uid = (int)strtol(optarg, &endp, 0); 970166065Spjd if (*endp != '\0' && !isspace((unsigned char)*endp)) { 971166065Spjd fprintf(stderr, "invalid uid '%s' - number " 972166065Spjd "expected\n", optarg); 973166065Spjd exit(1); 974166065Spjd } 975166065Spjd break; 976166065Spjd case 'U': 977166065Spjd umsk = (int)strtol(optarg, &endp, 0); 978166065Spjd if (*endp != '\0' && !isspace((unsigned char)*endp)) { 979166065Spjd fprintf(stderr, "invalid umask '%s' - number " 980166065Spjd "expected\n", optarg); 981166065Spjd exit(1); 982166065Spjd } 983166065Spjd break; 984166065Spjd default: 985166065Spjd usage(); 986166065Spjd } 987166065Spjd } 988166065Spjd argc -= optind; 989166065Spjd argv += optind; 990166065Spjd 991166065Spjd if (argc < 1) { 992166065Spjd fprintf(stderr, "too few arguments\n"); 993166065Spjd usage(); 994166065Spjd } 995166065Spjd 996166065Spjd if (gids != NULL) { 997166065Spjd fprintf(stderr, "changing groups to %s\n", gids); 998166065Spjd set_gids(gids); 999166065Spjd } 1000166065Spjd if (uid != -1) { 1001166065Spjd fprintf(stderr, "changing uid to %d\n", uid); 1002166065Spjd if (setuid(uid) < 0) { 1003166065Spjd fprintf(stderr, "cannot change uid: %s\n", 1004166065Spjd strerror(errno)); 1005166065Spjd exit(1); 1006166065Spjd } 1007166065Spjd } 1008166065Spjd 1009166065Spjd /* Change umask to requested value or to 0, if not requested. */ 1010166065Spjd umask(umsk); 1011166065Spjd 1012166065Spjd for (;;) { 1013166065Spjd scall = find_syscall(argv[0]); 1014166065Spjd if (scall == NULL) { 1015166065Spjd fprintf(stderr, "syscall '%s' not supported\n", argv[0]); 1016166065Spjd exit(1); 1017166065Spjd } 1018166065Spjd argc++; 1019166065Spjd argv++; 1020166065Spjd n = call_syscall(scall, argv); 1021166065Spjd argc += n; 1022166065Spjd argv += n; 1023166065Spjd if (argv[0] == NULL) 1024166065Spjd break; 1025166065Spjd argc++; 1026166065Spjd argv++; 1027166065Spjd } 1028166065Spjd 1029166065Spjd exit(0); 1030166065Spjd} 1031166065Spjd 1032166065Spjdstatic const char * 1033166065Spjderr2str(int error) 1034166065Spjd{ 1035166065Spjd static char errnum[8]; 1036166065Spjd 1037166065Spjd switch (error) { 1038166065Spjd#ifdef EPERM 1039166065Spjd case EPERM: 1040166065Spjd return ("EPERM"); 1041166065Spjd#endif 1042166065Spjd#ifdef ENOENT 1043166065Spjd case ENOENT: 1044166065Spjd return ("ENOENT"); 1045166065Spjd#endif 1046166065Spjd#ifdef ESRCH 1047166065Spjd case ESRCH: 1048166065Spjd return ("ESRCH"); 1049166065Spjd#endif 1050166065Spjd#ifdef EINTR 1051166065Spjd case EINTR: 1052166065Spjd return ("EINTR"); 1053166065Spjd#endif 1054166065Spjd#ifdef EIO 1055166065Spjd case EIO: 1056166065Spjd return ("EIO"); 1057166065Spjd#endif 1058166065Spjd#ifdef ENXIO 1059166065Spjd case ENXIO: 1060166065Spjd return ("ENXIO"); 1061166065Spjd#endif 1062166065Spjd#ifdef E2BIG 1063166065Spjd case E2BIG: 1064166065Spjd return ("E2BIG"); 1065166065Spjd#endif 1066166065Spjd#ifdef ENOEXEC 1067166065Spjd case ENOEXEC: 1068166065Spjd return ("ENOEXEC"); 1069166065Spjd#endif 1070166065Spjd#ifdef EBADF 1071166065Spjd case EBADF: 1072166065Spjd return ("EBADF"); 1073166065Spjd#endif 1074166065Spjd#ifdef ECHILD 1075166065Spjd case ECHILD: 1076166065Spjd return ("ECHILD"); 1077166065Spjd#endif 1078166065Spjd#ifdef EDEADLK 1079166065Spjd case EDEADLK: 1080166065Spjd return ("EDEADLK"); 1081166065Spjd#endif 1082166065Spjd#ifdef ENOMEM 1083166065Spjd case ENOMEM: 1084166065Spjd return ("ENOMEM"); 1085166065Spjd#endif 1086166065Spjd#ifdef EACCES 1087166065Spjd case EACCES: 1088166065Spjd return ("EACCES"); 1089166065Spjd#endif 1090166065Spjd#ifdef EFAULT 1091166065Spjd case EFAULT: 1092166065Spjd return ("EFAULT"); 1093166065Spjd#endif 1094166065Spjd#ifdef ENOTBLK 1095166065Spjd case ENOTBLK: 1096166065Spjd return ("ENOTBLK"); 1097166065Spjd#endif 1098166065Spjd#ifdef EBUSY 1099166065Spjd case EBUSY: 1100166065Spjd return ("EBUSY"); 1101166065Spjd#endif 1102166065Spjd#ifdef EEXIST 1103166065Spjd case EEXIST: 1104166065Spjd return ("EEXIST"); 1105166065Spjd#endif 1106166065Spjd#ifdef EXDEV 1107166065Spjd case EXDEV: 1108166065Spjd return ("EXDEV"); 1109166065Spjd#endif 1110166065Spjd#ifdef ENODEV 1111166065Spjd case ENODEV: 1112166065Spjd return ("ENODEV"); 1113166065Spjd#endif 1114166065Spjd#ifdef ENOTDIR 1115166065Spjd case ENOTDIR: 1116166065Spjd return ("ENOTDIR"); 1117166065Spjd#endif 1118166065Spjd#ifdef EISDIR 1119166065Spjd case EISDIR: 1120166065Spjd return ("EISDIR"); 1121166065Spjd#endif 1122166065Spjd#ifdef EINVAL 1123166065Spjd case EINVAL: 1124166065Spjd return ("EINVAL"); 1125166065Spjd#endif 1126166065Spjd#ifdef ENFILE 1127166065Spjd case ENFILE: 1128166065Spjd return ("ENFILE"); 1129166065Spjd#endif 1130166065Spjd#ifdef EMFILE 1131166065Spjd case EMFILE: 1132166065Spjd return ("EMFILE"); 1133166065Spjd#endif 1134166065Spjd#ifdef ENOTTY 1135166065Spjd case ENOTTY: 1136166065Spjd return ("ENOTTY"); 1137166065Spjd#endif 1138166065Spjd#ifdef ETXTBSY 1139166065Spjd case ETXTBSY: 1140166065Spjd return ("ETXTBSY"); 1141166065Spjd#endif 1142166065Spjd#ifdef EFBIG 1143166065Spjd case EFBIG: 1144166065Spjd return ("EFBIG"); 1145166065Spjd#endif 1146166065Spjd#ifdef ENOSPC 1147166065Spjd case ENOSPC: 1148166065Spjd return ("ENOSPC"); 1149166065Spjd#endif 1150166065Spjd#ifdef ESPIPE 1151166065Spjd case ESPIPE: 1152166065Spjd return ("ESPIPE"); 1153166065Spjd#endif 1154166065Spjd#ifdef EROFS 1155166065Spjd case EROFS: 1156166065Spjd return ("EROFS"); 1157166065Spjd#endif 1158166065Spjd#ifdef EMLINK 1159166065Spjd case EMLINK: 1160166065Spjd return ("EMLINK"); 1161166065Spjd#endif 1162166065Spjd#ifdef EPIPE 1163166065Spjd case EPIPE: 1164166065Spjd return ("EPIPE"); 1165166065Spjd#endif 1166166065Spjd#ifdef EDOM 1167166065Spjd case EDOM: 1168166065Spjd return ("EDOM"); 1169166065Spjd#endif 1170166065Spjd#ifdef ERANGE 1171166065Spjd case ERANGE: 1172166065Spjd return ("ERANGE"); 1173166065Spjd#endif 1174166065Spjd#ifdef EAGAIN 1175166065Spjd case EAGAIN: 1176166065Spjd return ("EAGAIN"); 1177166065Spjd#endif 1178166065Spjd#ifdef EINPROGRESS 1179166065Spjd case EINPROGRESS: 1180166065Spjd return ("EINPROGRESS"); 1181166065Spjd#endif 1182166065Spjd#ifdef EALREADY 1183166065Spjd case EALREADY: 1184166065Spjd return ("EALREADY"); 1185166065Spjd#endif 1186166065Spjd#ifdef ENOTSOCK 1187166065Spjd case ENOTSOCK: 1188166065Spjd return ("ENOTSOCK"); 1189166065Spjd#endif 1190166065Spjd#ifdef EDESTADDRREQ 1191166065Spjd case EDESTADDRREQ: 1192166065Spjd return ("EDESTADDRREQ"); 1193166065Spjd#endif 1194166065Spjd#ifdef EMSGSIZE 1195166065Spjd case EMSGSIZE: 1196166065Spjd return ("EMSGSIZE"); 1197166065Spjd#endif 1198166065Spjd#ifdef EPROTOTYPE 1199166065Spjd case EPROTOTYPE: 1200166065Spjd return ("EPROTOTYPE"); 1201166065Spjd#endif 1202166065Spjd#ifdef ENOPROTOOPT 1203166065Spjd case ENOPROTOOPT: 1204166065Spjd return ("ENOPROTOOPT"); 1205166065Spjd#endif 1206166065Spjd#ifdef EPROTONOSUPPORT 1207166065Spjd case EPROTONOSUPPORT: 1208166065Spjd return ("EPROTONOSUPPORT"); 1209166065Spjd#endif 1210166065Spjd#ifdef ESOCKTNOSUPPORT 1211166065Spjd case ESOCKTNOSUPPORT: 1212166065Spjd return ("ESOCKTNOSUPPORT"); 1213166065Spjd#endif 1214166065Spjd#ifdef EOPNOTSUPP 1215166065Spjd case EOPNOTSUPP: 1216166065Spjd return ("EOPNOTSUPP"); 1217166065Spjd#endif 1218166065Spjd#ifdef EPFNOSUPPORT 1219166065Spjd case EPFNOSUPPORT: 1220166065Spjd return ("EPFNOSUPPORT"); 1221166065Spjd#endif 1222166065Spjd#ifdef EAFNOSUPPORT 1223166065Spjd case EAFNOSUPPORT: 1224166065Spjd return ("EAFNOSUPPORT"); 1225166065Spjd#endif 1226166065Spjd#ifdef EADDRINUSE 1227166065Spjd case EADDRINUSE: 1228166065Spjd return ("EADDRINUSE"); 1229166065Spjd#endif 1230166065Spjd#ifdef EADDRNOTAVAIL 1231166065Spjd case EADDRNOTAVAIL: 1232166065Spjd return ("EADDRNOTAVAIL"); 1233166065Spjd#endif 1234166065Spjd#ifdef ENETDOWN 1235166065Spjd case ENETDOWN: 1236166065Spjd return ("ENETDOWN"); 1237166065Spjd#endif 1238166065Spjd#ifdef ENETUNREACH 1239166065Spjd case ENETUNREACH: 1240166065Spjd return ("ENETUNREACH"); 1241166065Spjd#endif 1242166065Spjd#ifdef ENETRESET 1243166065Spjd case ENETRESET: 1244166065Spjd return ("ENETRESET"); 1245166065Spjd#endif 1246166065Spjd#ifdef ECONNABORTED 1247166065Spjd case ECONNABORTED: 1248166065Spjd return ("ECONNABORTED"); 1249166065Spjd#endif 1250166065Spjd#ifdef ECONNRESET 1251166065Spjd case ECONNRESET: 1252166065Spjd return ("ECONNRESET"); 1253166065Spjd#endif 1254166065Spjd#ifdef ENOBUFS 1255166065Spjd case ENOBUFS: 1256166065Spjd return ("ENOBUFS"); 1257166065Spjd#endif 1258166065Spjd#ifdef EISCONN 1259166065Spjd case EISCONN: 1260166065Spjd return ("EISCONN"); 1261166065Spjd#endif 1262166065Spjd#ifdef ENOTCONN 1263166065Spjd case ENOTCONN: 1264166065Spjd return ("ENOTCONN"); 1265166065Spjd#endif 1266166065Spjd#ifdef ESHUTDOWN 1267166065Spjd case ESHUTDOWN: 1268166065Spjd return ("ESHUTDOWN"); 1269166065Spjd#endif 1270166065Spjd#ifdef ETOOMANYREFS 1271166065Spjd case ETOOMANYREFS: 1272166065Spjd return ("ETOOMANYREFS"); 1273166065Spjd#endif 1274166065Spjd#ifdef ETIMEDOUT 1275166065Spjd case ETIMEDOUT: 1276166065Spjd return ("ETIMEDOUT"); 1277166065Spjd#endif 1278166065Spjd#ifdef ECONNREFUSED 1279166065Spjd case ECONNREFUSED: 1280166065Spjd return ("ECONNREFUSED"); 1281166065Spjd#endif 1282166065Spjd#ifdef ELOOP 1283166065Spjd case ELOOP: 1284166065Spjd return ("ELOOP"); 1285166065Spjd#endif 1286166065Spjd#ifdef ENAMETOOLONG 1287166065Spjd case ENAMETOOLONG: 1288166065Spjd return ("ENAMETOOLONG"); 1289166065Spjd#endif 1290166065Spjd#ifdef EHOSTDOWN 1291166065Spjd case EHOSTDOWN: 1292166065Spjd return ("EHOSTDOWN"); 1293166065Spjd#endif 1294166065Spjd#ifdef EHOSTUNREACH 1295166065Spjd case EHOSTUNREACH: 1296166065Spjd return ("EHOSTUNREACH"); 1297166065Spjd#endif 1298166065Spjd#ifdef ENOTEMPTY 1299166065Spjd case ENOTEMPTY: 1300166065Spjd return ("ENOTEMPTY"); 1301166065Spjd#endif 1302166065Spjd#ifdef EPROCLIM 1303166065Spjd case EPROCLIM: 1304166065Spjd return ("EPROCLIM"); 1305166065Spjd#endif 1306166065Spjd#ifdef EUSERS 1307166065Spjd case EUSERS: 1308166065Spjd return ("EUSERS"); 1309166065Spjd#endif 1310166065Spjd#ifdef EDQUOT 1311166065Spjd case EDQUOT: 1312166065Spjd return ("EDQUOT"); 1313166065Spjd#endif 1314166065Spjd#ifdef ESTALE 1315166065Spjd case ESTALE: 1316166065Spjd return ("ESTALE"); 1317166065Spjd#endif 1318166065Spjd#ifdef EREMOTE 1319166065Spjd case EREMOTE: 1320166065Spjd return ("EREMOTE"); 1321166065Spjd#endif 1322166065Spjd#ifdef EBADRPC 1323166065Spjd case EBADRPC: 1324166065Spjd return ("EBADRPC"); 1325166065Spjd#endif 1326166065Spjd#ifdef ERPCMISMATCH 1327166065Spjd case ERPCMISMATCH: 1328166065Spjd return ("ERPCMISMATCH"); 1329166065Spjd#endif 1330166065Spjd#ifdef EPROGUNAVAIL 1331166065Spjd case EPROGUNAVAIL: 1332166065Spjd return ("EPROGUNAVAIL"); 1333166065Spjd#endif 1334166065Spjd#ifdef EPROGMISMATCH 1335166065Spjd case EPROGMISMATCH: 1336166065Spjd return ("EPROGMISMATCH"); 1337166065Spjd#endif 1338166065Spjd#ifdef EPROCUNAVAIL 1339166065Spjd case EPROCUNAVAIL: 1340166065Spjd return ("EPROCUNAVAIL"); 1341166065Spjd#endif 1342166065Spjd#ifdef ENOLCK 1343166065Spjd case ENOLCK: 1344166065Spjd return ("ENOLCK"); 1345166065Spjd#endif 1346166065Spjd#ifdef ENOSYS 1347166065Spjd case ENOSYS: 1348166065Spjd return ("ENOSYS"); 1349166065Spjd#endif 1350166065Spjd#ifdef EFTYPE 1351166065Spjd case EFTYPE: 1352166065Spjd return ("EFTYPE"); 1353166065Spjd#endif 1354166065Spjd#ifdef EAUTH 1355166065Spjd case EAUTH: 1356166065Spjd return ("EAUTH"); 1357166065Spjd#endif 1358166065Spjd#ifdef ENEEDAUTH 1359166065Spjd case ENEEDAUTH: 1360166065Spjd return ("ENEEDAUTH"); 1361166065Spjd#endif 1362166065Spjd#ifdef EIDRM 1363166065Spjd case EIDRM: 1364166065Spjd return ("EIDRM"); 1365166065Spjd#endif 1366166065Spjd#ifdef ENOMSG 1367166065Spjd case ENOMSG: 1368166065Spjd return ("ENOMSG"); 1369166065Spjd#endif 1370166065Spjd#ifdef EOVERFLOW 1371166065Spjd case EOVERFLOW: 1372166065Spjd return ("EOVERFLOW"); 1373166065Spjd#endif 1374166065Spjd#ifdef ECANCELED 1375166065Spjd case ECANCELED: 1376166065Spjd return ("ECANCELED"); 1377166065Spjd#endif 1378166065Spjd#ifdef EILSEQ 1379166065Spjd case EILSEQ: 1380166065Spjd return ("EILSEQ"); 1381166065Spjd#endif 1382166065Spjd#ifdef ENOATTR 1383166065Spjd case ENOATTR: 1384166065Spjd return ("ENOATTR"); 1385166065Spjd#endif 1386166065Spjd#ifdef EDOOFUS 1387166065Spjd case EDOOFUS: 1388166065Spjd return ("EDOOFUS"); 1389166065Spjd#endif 1390166065Spjd#ifdef EBADMSG 1391166065Spjd case EBADMSG: 1392166065Spjd return ("EBADMSG"); 1393166065Spjd#endif 1394166065Spjd#ifdef EMULTIHOP 1395166065Spjd case EMULTIHOP: 1396166065Spjd return ("EMULTIHOP"); 1397166065Spjd#endif 1398166065Spjd#ifdef ENOLINK 1399166065Spjd case ENOLINK: 1400166065Spjd return ("ENOLINK"); 1401166065Spjd#endif 1402166065Spjd#ifdef EPROTO 1403166065Spjd case EPROTO: 1404166065Spjd return ("EPROTO"); 1405166065Spjd#endif 1406166065Spjd default: 1407166065Spjd snprintf(errnum, sizeof(errnum), "%d", error); 1408166065Spjd return (errnum); 1409166065Spjd } 1410166065Spjd} 1411