1 /* $OpenBSD: fstest.c,v 1.4 2014/10/18 03:13:04 doug Exp $ */ 2 3 /* 4 * Copyright (c) 2006-2007 Pawel Jakub Dawidek <pjd@FreeBSD.org> 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND 17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE 20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26 * SUCH DAMAGE. 27 * 28 * $FreeBSD: src/tools/regression/fstest/fstest.c,v 1.1 2007/01/17 01:42:07 pjd Exp $ 29 */ 30 31 #include <sys/param.h> 32 #include <sys/stat.h> 33 #include <sys/sysctl.h> 34 35 #include <stdio.h> 36 #include <stdlib.h> 37 #include <unistd.h> 38 #include <fcntl.h> 39 #include <grp.h> 40 #include <string.h> 41 #include <ctype.h> 42 #include <errno.h> 43 #include <assert.h> 44 45 enum action { 46 ACTION_OPEN, 47 ACTION_CREATE, 48 ACTION_UNLINK, 49 ACTION_MKDIR, 50 ACTION_RMDIR, 51 ACTION_LINK, 52 ACTION_SYMLINK, 53 ACTION_RENAME, 54 ACTION_MKFIFO, 55 ACTION_CHMOD, 56 ACTION_CHOWN, 57 ACTION_LCHOWN, 58 ACTION_CHFLAGS, 59 ACTION_TRUNCATE, 60 ACTION_STAT, 61 ACTION_LSTAT, 62 }; 63 64 #define TYPE_NONE 0x0000 65 #define TYPE_STRING 0x0001 66 #define TYPE_NUMBER 0x0002 67 #define TYPE_OPTIONAL 0x0100 68 #define MAX_ARGS 8 69 70 struct syscall_desc { 71 char *sd_name; 72 enum action sd_action; 73 int sd_args[MAX_ARGS]; 74 }; 75 76 static struct syscall_desc syscalls[] = { 77 { "open", ACTION_OPEN, { TYPE_STRING, TYPE_STRING, 78 TYPE_NUMBER | TYPE_OPTIONAL, TYPE_NONE } }, 79 { "create", ACTION_CREATE, { TYPE_STRING, TYPE_NUMBER, TYPE_NONE } }, 80 { "unlink", ACTION_UNLINK, { TYPE_STRING, TYPE_NONE } }, 81 { "mkdir", ACTION_MKDIR, { TYPE_STRING, TYPE_NUMBER, TYPE_NONE } }, 82 { "rmdir", ACTION_RMDIR, { TYPE_STRING, TYPE_NONE } }, 83 { "link", ACTION_LINK, { TYPE_STRING, TYPE_STRING, TYPE_NONE } }, 84 { "symlink", ACTION_SYMLINK, { TYPE_STRING, TYPE_STRING, TYPE_NONE } }, 85 { "rename", ACTION_RENAME, { TYPE_STRING, TYPE_STRING, TYPE_NONE } }, 86 { "mkfifo", ACTION_MKFIFO, { TYPE_STRING, TYPE_NUMBER, TYPE_NONE } }, 87 { "chmod", ACTION_CHMOD, { TYPE_STRING, TYPE_NUMBER, TYPE_NONE } }, 88 { "chown", ACTION_CHOWN, { TYPE_STRING, TYPE_NUMBER, 89 TYPE_NUMBER, TYPE_NONE } }, 90 { "lchown", ACTION_LCHOWN, { TYPE_STRING, TYPE_NUMBER, 91 TYPE_NUMBER, TYPE_NONE } }, 92 { "chflags", ACTION_CHFLAGS, { TYPE_STRING, TYPE_STRING, TYPE_NONE } }, 93 { "truncate", ACTION_TRUNCATE, { TYPE_STRING, TYPE_NUMBER, 94 TYPE_NONE } }, 95 { "stat", ACTION_STAT, { TYPE_STRING, TYPE_STRING, TYPE_NONE } }, 96 { "lstat", ACTION_LSTAT, { TYPE_STRING, TYPE_STRING, TYPE_NONE } }, 97 { NULL, -1, { TYPE_NONE } } 98 }; 99 100 struct flag { 101 long long f_flag; 102 char *f_str; 103 }; 104 105 static struct flag open_flags[] = { 106 { O_RDONLY, "O_RDONLY" }, 107 { O_WRONLY, "O_WRONLY" }, 108 { O_RDWR, "O_RDWR" }, 109 { O_NONBLOCK, "O_NONBLOCK" }, 110 { O_APPEND, "O_APPEND" }, 111 { O_CREAT, "O_CREAT" }, 112 { O_TRUNC, "O_TRUNC" }, 113 { O_EXCL, "O_EXCL" }, 114 { O_SHLOCK, "O_SHLOCK" }, 115 { O_EXLOCK, "O_EXLOCK" }, 116 { O_FSYNC, "O_FSYNC" }, 117 { O_SYNC, "O_SYNC" }, 118 { O_NOFOLLOW, "O_NOFOLLOW" }, 119 { O_NOCTTY, "O_NOCTTY" }, 120 { 0, NULL } 121 }; 122 123 static struct flag chflags_flags[] = { 124 { UF_NODUMP, "UF_NODUMP" }, 125 { UF_IMMUTABLE, "UF_IMMUTABLE" }, 126 { UF_APPEND, "UF_APPEND" }, 127 { UF_OPAQUE, "UF_OPAQUE" }, 128 { SF_ARCHIVED, "SF_ARCHIVED" }, 129 { SF_IMMUTABLE, "SF_IMMUTABLE" }, 130 { SF_APPEND, "SF_APPEND" }, 131 { 0, NULL } 132 }; 133 134 static const char *err2str(int error); 135 int use_appimm; /* use the SF_APPEND and SF_IMMUTABLE chflags */ 136 137 __dead static void 138 usage(void) 139 { 140 fprintf(stderr, "usage: fstest [-u uid] [-g gid1[,gid2[...]]] syscall " 141 "args ...\n"); 142 exit(1); 143 } 144 145 static long long 146 str2flags(struct flag *tflags, char *sflags) 147 { 148 long long flags = 0; 149 unsigned int i; 150 char *f; 151 152 for (f = strtok(sflags, ","); f != NULL; f = strtok(NULL, ",")) { 153 /* Support magic 'none' flag which just reset all flags. */ 154 if (strcmp(f, "none") == 0) 155 return (0); 156 for (i = 0; tflags[i].f_str != NULL; i++) { 157 if (strcmp(tflags[i].f_str, f) == 0) 158 break; 159 } 160 if (tflags[i].f_str == NULL) { 161 fprintf(stderr, "unknown flag '%s'\n", f); 162 exit(1); 163 } 164 flags |= tflags[i].f_flag; 165 } 166 return (flags); 167 } 168 169 static char * 170 flags2str(struct flag *tflags, long long flags) 171 { 172 static char sflags[1024]; 173 unsigned int i; 174 175 sflags[0] = '\0'; 176 for (i = 0; tflags[i].f_str != NULL; i++) { 177 if (flags & tflags[i].f_flag) { 178 if (sflags[0] != '\0') 179 strlcat(sflags, ",", sizeof(sflags)); 180 strlcat(sflags, tflags[i].f_str, sizeof(sflags)); 181 } 182 } 183 if (sflags[0] == '\0') 184 strlcpy(sflags, "none", sizeof(sflags)); 185 return (sflags); 186 } 187 188 static struct syscall_desc * 189 find_syscall(const char *name) 190 { 191 int i; 192 193 for (i = 0; syscalls[i].sd_name != NULL; i++) { 194 if (strcmp(syscalls[i].sd_name, name) == 0) 195 return (&syscalls[i]); 196 } 197 return (NULL); 198 } 199 200 static void 201 show_stat(struct stat *sp, const char *what) 202 { 203 204 if (strcmp(what, "mode") == 0) 205 printf("0%o", (unsigned int)(sp->st_mode & ALLPERMS)); 206 else if (strcmp(what, "inode") == 0) 207 printf("%llu", (unsigned long long)sp->st_ino); 208 else if (strcmp(what, "nlink") == 0) 209 printf("%lld", (long long)sp->st_nlink); 210 else if (strcmp(what, "uid") == 0) 211 printf("%d", (int)sp->st_uid); 212 else if (strcmp(what, "gid") == 0) 213 printf("%d", (int)sp->st_gid); 214 else if (strcmp(what, "size") == 0) 215 printf("%lld", (long long)sp->st_size); 216 else if (strcmp(what, "blocks") == 0) 217 printf("%lld", (long long)sp->st_blocks); 218 else if (strcmp(what, "atime") == 0) 219 printf("%lld", (long long)sp->st_atime); 220 else if (strcmp(what, "mtime") == 0) 221 printf("%lld", (long long)sp->st_mtime); 222 else if (strcmp(what, "ctime") == 0) 223 printf("%lld", (long long)sp->st_ctime); 224 else if (strcmp(what, "flags") == 0) 225 printf("%s", flags2str(chflags_flags, sp->st_flags)); 226 else if (strcmp(what, "type") == 0) { 227 switch (sp->st_mode & S_IFMT) { 228 case S_IFIFO: 229 printf("fifo"); 230 break; 231 case S_IFCHR: 232 printf("char"); 233 break; 234 case S_IFDIR: 235 printf("dir"); 236 break; 237 case S_IFBLK: 238 printf("block"); 239 break; 240 case S_IFREG: 241 printf("regular"); 242 break; 243 case S_IFLNK: 244 printf("symlink"); 245 break; 246 case S_IFSOCK: 247 printf("socket"); 248 break; 249 default: 250 printf("unknown"); 251 break; 252 } 253 } else { 254 printf("unknown"); 255 } 256 } 257 258 static void 259 show_stats(struct stat *sp, char *what) 260 { 261 const char *s = ""; 262 char *w; 263 264 for (w = strtok(what, ","); w != NULL; w = strtok(NULL, ",")) { 265 printf("%s", s); 266 show_stat(sp, w); 267 s = ","; 268 } 269 printf("\n"); 270 } 271 272 static unsigned int 273 call_syscall(struct syscall_desc *scall, char *argv[]) 274 { 275 struct stat sb; 276 long long flags; 277 unsigned int i; 278 char *endp; 279 int rval; 280 union { 281 char *str; 282 long long num; 283 } args[MAX_ARGS]; 284 unsigned int ch_flags; 285 286 /* 287 * Verify correctness of the arguments. 288 */ 289 for (i = 0; i < sizeof(args)/sizeof(args[0]); i++) { 290 if (scall->sd_args[i] == TYPE_NONE) { 291 if (argv[i] == NULL || strcmp(argv[i], ":") == 0) 292 break; 293 fprintf(stderr, "too many arguments [%s]\n", argv[i]); 294 exit(1); 295 } else { 296 if (argv[i] == NULL || strcmp(argv[i], ":") == 0) { 297 if (scall->sd_args[i] & TYPE_OPTIONAL) 298 break; 299 fprintf(stderr, "too few arguments\n"); 300 exit(1); 301 } 302 if (scall->sd_args[i] & TYPE_STRING) { 303 if (strcmp(argv[i], "NULL") == 0) 304 args[i].str = NULL; 305 else if (strcmp(argv[i], "DEADCODE") == 0) 306 args[i].str = (void *)0xdeadc0de; 307 else 308 args[i].str = argv[i]; 309 } else if (scall->sd_args[i] & TYPE_NUMBER) { 310 args[i].num = strtoll(argv[i], &endp, 0); 311 if (*endp != '\0' && 312 !isspace((unsigned char)*endp)) { 313 fprintf(stderr, "invalid argument %u, " 314 "number expected [%s]\n", i, endp); 315 exit(1); 316 } 317 } 318 } 319 } 320 /* 321 * Call the given syscall. 322 */ 323 #define NUM(n) (args[(n)].num) 324 #define STR(n) (args[(n)].str) 325 switch (scall->sd_action) { 326 case ACTION_OPEN: 327 flags = str2flags(open_flags, STR(1)); 328 if (flags & O_CREAT) { 329 if (i == 2) { 330 fprintf(stderr, "too few arguments\n"); 331 exit(1); 332 } 333 rval = open(STR(0), flags, (mode_t)NUM(2)); 334 } else { 335 if (i == 3) { 336 fprintf(stderr, "too many arguments\n"); 337 exit(1); 338 } 339 rval = open(STR(0), flags); 340 } 341 break; 342 case ACTION_CREATE: 343 rval = open(STR(0), O_CREAT | O_EXCL, NUM(1)); 344 if (rval >= 0) 345 close(rval); 346 break; 347 case ACTION_UNLINK: 348 rval = unlink(STR(0)); 349 break; 350 case ACTION_MKDIR: 351 rval = mkdir(STR(0), NUM(1)); 352 break; 353 case ACTION_RMDIR: 354 rval = rmdir(STR(0)); 355 break; 356 case ACTION_LINK: 357 rval = link(STR(0), STR(1)); 358 break; 359 case ACTION_SYMLINK: 360 rval = symlink(STR(0), STR(1)); 361 break; 362 case ACTION_RENAME: 363 rval = rename(STR(0), STR(1)); 364 break; 365 case ACTION_MKFIFO: 366 rval = mkfifo(STR(0), NUM(1)); 367 break; 368 case ACTION_CHMOD: 369 rval = chmod(STR(0), NUM(1)); 370 break; 371 case ACTION_CHOWN: 372 rval = chown(STR(0), NUM(1), NUM(2)); 373 break; 374 case ACTION_LCHOWN: 375 rval = lchown(STR(0), NUM(1), NUM(2)); 376 break; 377 case ACTION_CHFLAGS: 378 ch_flags = str2flags(chflags_flags, STR(1)); 379 if (!use_appimm) 380 ch_flags &= ~(SF_APPEND|SF_IMMUTABLE); 381 382 rval = chflags(STR(0), ch_flags); 383 break; 384 case ACTION_TRUNCATE: 385 rval = truncate(STR(0), NUM(1)); 386 break; 387 case ACTION_STAT: 388 rval = stat(STR(0), &sb); 389 if (rval == 0) { 390 show_stats(&sb, STR(1)); 391 return (i); 392 } 393 break; 394 case ACTION_LSTAT: 395 rval = lstat(STR(0), &sb); 396 if (rval == 0) { 397 show_stats(&sb, STR(1)); 398 return (i); 399 } 400 break; 401 default: 402 fprintf(stderr, "unsupported syscall\n"); 403 exit(1); 404 } 405 #undef STR 406 #undef NUM 407 if (rval < 0) { 408 const char *serrno; 409 410 serrno = err2str(errno); 411 fprintf(stderr, "%s returned %d\n", scall->sd_name, rval); 412 printf("%s\n", serrno); 413 exit(1); 414 } 415 printf("0\n"); 416 return (i); 417 } 418 419 static void 420 set_gids(char *gids) 421 { 422 gid_t *gidset; 423 long ngroups; 424 char *g, *endp; 425 unsigned i; 426 427 ngroups = sysconf(_SC_NGROUPS_MAX); 428 assert(ngroups > 0); 429 gidset = reallocarray(NULL, ngroups, sizeof(*gidset)); 430 assert(gidset != NULL); 431 for (i = 0, g = strtok(gids, ","); g != NULL; 432 g = strtok(NULL, ","), i++) { 433 if (i >= ngroups) { 434 fprintf(stderr, "too many gids\n"); 435 exit(1); 436 } 437 gidset[i] = strtol(g, &endp, 0); 438 if (*endp != '\0' && !isspace((unsigned char)*endp)) { 439 fprintf(stderr, "invalid gid '%s' - number expected\n", 440 g); 441 exit(1); 442 } 443 } 444 if (setgroups(i, gidset) < 0) { 445 fprintf(stderr, "cannot change groups: %s\n", strerror(errno)); 446 exit(1); 447 } 448 free(gidset); 449 } 450 451 int 452 main(int argc, char *argv[]) 453 { 454 struct syscall_desc *scall; 455 unsigned int n; 456 char *gids, *endp; 457 int uid, umsk, ch; 458 int mib[2]; 459 size_t len; 460 int securelevel; 461 462 uid = -1; 463 gids = NULL; 464 umsk = 0; 465 466 while ((ch = getopt(argc, argv, "g:u:U:")) != -1) { 467 switch(ch) { 468 case 'g': 469 gids = optarg; 470 break; 471 case 'u': 472 uid = (int)strtol(optarg, &endp, 0); 473 if (*endp != '\0' && !isspace((unsigned char)*endp)) { 474 fprintf(stderr, "invalid uid '%s' - number " 475 "expected\n", optarg); 476 exit(1); 477 } 478 break; 479 case 'U': 480 umsk = (int)strtol(optarg, &endp, 0); 481 if (*endp != '\0' && !isspace((unsigned char)*endp)) { 482 fprintf(stderr, "invalid umask '%s' - number " 483 "expected\n", optarg); 484 exit(1); 485 } 486 break; 487 default: 488 usage(); 489 } 490 } 491 argc -= optind; 492 argv += optind; 493 494 if (argc < 1) { 495 fprintf(stderr, "too few arguments\n"); 496 usage(); 497 } 498 499 if (gids != NULL) { 500 fprintf(stderr, "changing groups to %s\n", gids); 501 set_gids(gids); 502 } 503 if (uid != -1) { 504 fprintf(stderr, "changing uid to %d\n", uid); 505 if (setuid(uid) < 0) { 506 fprintf(stderr, "cannot change uid: %s\n", 507 strerror(errno)); 508 exit(1); 509 } 510 } 511 512 /* 513 * Find out if we should use the SF_IMMUTABLE and SF_APPEND flags; 514 * Since we run by default on kern.securelevel=1 these cause false 515 * positives. 516 */ 517 mib[0] = CTL_KERN; 518 mib[1] = KERN_SECURELVL; 519 len = sizeof(securelevel); 520 if (sysctl(mib, 2, &securelevel, &len, NULL, 0) == -1) { 521 fprintf(stderr, "cannot get kernel securelevel\n"); 522 exit(1); 523 } 524 if (securelevel == 0 || securelevel == -1) 525 use_appimm = 1; 526 else 527 use_appimm = 0; 528 529 /* Change umask to requested value or to 0, if not requested. */ 530 umask(umsk); 531 532 for (;;) { 533 scall = find_syscall(argv[0]); 534 if (scall == NULL) { 535 fprintf(stderr, "syscall '%s' not supported\n", argv[0]); 536 exit(1); 537 } 538 argc++; 539 argv++; 540 n = call_syscall(scall, argv); 541 argc += n; 542 argv += n; 543 if (argv[0] == NULL) 544 break; 545 argc++; 546 argv++; 547 } 548 549 exit(0); 550 } 551 552 static const char * 553 err2str(int error) 554 { 555 static char errnum[8]; 556 557 switch (error) { 558 case EPERM: 559 return ("EPERM"); 560 case ENOENT: 561 return ("ENOENT"); 562 case ESRCH: 563 return ("ESRCH"); 564 case EINTR: 565 return ("EINTR"); 566 case EIO: 567 return ("EIO"); 568 case ENXIO: 569 return ("ENXIO"); 570 case E2BIG: 571 return ("E2BIG"); 572 case ENOEXEC: 573 return ("ENOEXEC"); 574 case EBADF: 575 return ("EBADF"); 576 case ECHILD: 577 return ("ECHILD"); 578 case EDEADLK: 579 return ("EDEADLK"); 580 case ENOMEM: 581 return ("ENOMEM"); 582 case EACCES: 583 return ("EACCES"); 584 case EFAULT: 585 return ("EFAULT"); 586 case ENOTBLK: 587 return ("ENOTBLK"); 588 case EBUSY: 589 return ("EBUSY"); 590 case EEXIST: 591 return ("EEXIST"); 592 case EXDEV: 593 return ("EXDEV"); 594 case ENODEV: 595 return ("ENODEV"); 596 case ENOTDIR: 597 return ("ENOTDIR"); 598 case EISDIR: 599 return ("EISDIR"); 600 case EINVAL: 601 return ("EINVAL"); 602 case ENFILE: 603 return ("ENFILE"); 604 case EMFILE: 605 return ("EMFILE"); 606 case ENOTTY: 607 return ("ENOTTY"); 608 case ETXTBSY: 609 return ("ETXTBSY"); 610 case EFBIG: 611 return ("EFBIG"); 612 case ENOSPC: 613 return ("ENOSPC"); 614 case ESPIPE: 615 return ("ESPIPE"); 616 case EROFS: 617 return ("EROFS"); 618 case EMLINK: 619 return ("EMLINK"); 620 case EPIPE: 621 return ("EPIPE"); 622 case EDOM: 623 return ("EDOM"); 624 case ERANGE: 625 return ("ERANGE"); 626 case EAGAIN: 627 return ("EAGAIN"); 628 case EINPROGRESS: 629 return ("EINPROGRESS"); 630 case EALREADY: 631 return ("EALREADY"); 632 case ENOTSOCK: 633 return ("ENOTSOCK"); 634 case EDESTADDRREQ: 635 return ("EDESTADDRREQ"); 636 case EMSGSIZE: 637 return ("EMSGSIZE"); 638 case EPROTOTYPE: 639 return ("EPROTOTYPE"); 640 case ENOPROTOOPT: 641 return ("ENOPROTOOPT"); 642 case EPROTONOSUPPORT: 643 return ("EPROTONOSUPPORT"); 644 case ESOCKTNOSUPPORT: 645 return ("ESOCKTNOSUPPORT"); 646 case EOPNOTSUPP: 647 return ("EOPNOTSUPP"); 648 case EPFNOSUPPORT: 649 return ("EPFNOSUPPORT"); 650 case EAFNOSUPPORT: 651 return ("EAFNOSUPPORT"); 652 case EADDRINUSE: 653 return ("EADDRINUSE"); 654 case EADDRNOTAVAIL: 655 return ("EADDRNOTAVAIL"); 656 case ENETDOWN: 657 return ("ENETDOWN"); 658 case ENETUNREACH: 659 return ("ENETUNREACH"); 660 case ENETRESET: 661 return ("ENETRESET"); 662 case ECONNABORTED: 663 return ("ECONNABORTED"); 664 case ECONNRESET: 665 return ("ECONNRESET"); 666 case ENOBUFS: 667 return ("ENOBUFS"); 668 case EISCONN: 669 return ("EISCONN"); 670 case ENOTCONN: 671 return ("ENOTCONN"); 672 case ESHUTDOWN: 673 return ("ESHUTDOWN"); 674 case ETOOMANYREFS: 675 return ("ETOOMANYREFS"); 676 case ETIMEDOUT: 677 return ("ETIMEDOUT"); 678 case ECONNREFUSED: 679 return ("ECONNREFUSED"); 680 case ELOOP: 681 return ("ELOOP"); 682 case ENAMETOOLONG: 683 return ("ENAMETOOLONG"); 684 case EHOSTDOWN: 685 return ("EHOSTDOWN"); 686 case EHOSTUNREACH: 687 return ("EHOSTUNREACH"); 688 case ENOTEMPTY: 689 return ("ENOTEMPTY"); 690 case EPROCLIM: 691 return ("EPROCLIM"); 692 case EUSERS: 693 return ("EUSERS"); 694 case EDQUOT: 695 return ("EDQUOT"); 696 case ESTALE: 697 return ("ESTALE"); 698 case EREMOTE: 699 return ("EREMOTE"); 700 case EBADRPC: 701 return ("EBADRPC"); 702 case ERPCMISMATCH: 703 return ("ERPCMISMATCH"); 704 case EPROGUNAVAIL: 705 return ("EPROGUNAVAIL"); 706 case EPROGMISMATCH: 707 return ("EPROGMISMATCH"); 708 case EPROCUNAVAIL: 709 return ("EPROCUNAVAIL"); 710 case ENOLCK: 711 return ("ENOLCK"); 712 case ENOSYS: 713 return ("ENOSYS"); 714 case EFTYPE: 715 return ("EFTYPE"); 716 case EAUTH: 717 return ("EAUTH"); 718 case ENEEDAUTH: 719 return ("ENEEDAUTH"); 720 case EILSEQ: 721 return ("EILSEQ"); 722 case ENOATTR: 723 return ("ENOATTR"); 724 default: 725 snprintf(errnum, sizeof(errnum), "%d", error); 726 return (errnum); 727 } 728 } 729