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