2 * Copyright (c) 2006-2007 Pawel Jakub Dawidek <pjd@FreeBSD.org>
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
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.
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
29 #include <sys/param.h>
41 #ifndef HAS_TRUNCATE64
42 #define truncate64 truncate
50 #define ALLPERMS (S_ISUID|S_ISGID|S_ISVTX|S_IRWXU|S_IRWXG|S_IRWXO)
80 #define TYPE_NONE 0x0000
81 #define TYPE_STRING 0x0001
82 #define TYPE_NUMBER 0x0002
84 #define TYPE_OPTIONAL 0x0100
90 enum action sd_action;
91 int sd_args[MAX_ARGS];
94 static struct syscall_desc syscalls[] = {
95 { "open", ACTION_OPEN, { TYPE_STRING, TYPE_STRING, TYPE_NUMBER | TYPE_OPTIONAL, TYPE_NONE } },
96 { "create", ACTION_CREATE, { TYPE_STRING, TYPE_NUMBER, TYPE_NONE } },
97 { "unlink", ACTION_UNLINK, { TYPE_STRING, TYPE_NONE } },
98 { "mkdir", ACTION_MKDIR, { TYPE_STRING, TYPE_NUMBER, TYPE_NONE } },
99 { "rmdir", ACTION_RMDIR, { TYPE_STRING, TYPE_NONE } },
100 { "link", ACTION_LINK, { TYPE_STRING, TYPE_STRING, TYPE_NONE } },
101 { "symlink", ACTION_SYMLINK, { TYPE_STRING, TYPE_STRING, TYPE_NONE } },
102 { "rename", ACTION_RENAME, { TYPE_STRING, TYPE_STRING, TYPE_NONE } },
103 { "mkfifo", ACTION_MKFIFO, { TYPE_STRING, TYPE_NUMBER, TYPE_NONE } },
104 { "chmod", ACTION_CHMOD, { TYPE_STRING, TYPE_NUMBER, TYPE_NONE } },
106 { "lchmod", ACTION_LCHMOD, { TYPE_STRING, TYPE_NUMBER, TYPE_NONE } },
108 { "chown", ACTION_CHOWN, { TYPE_STRING, TYPE_NUMBER, TYPE_NUMBER, TYPE_NONE } },
109 { "lchown", ACTION_LCHOWN, { TYPE_STRING, TYPE_NUMBER, TYPE_NUMBER, TYPE_NONE } },
111 { "chflags", ACTION_CHFLAGS, { TYPE_STRING, TYPE_STRING, TYPE_NONE } },
114 { "lchflags", ACTION_LCHFLAGS, { TYPE_STRING, TYPE_STRING, TYPE_NONE } },
116 { "truncate", ACTION_TRUNCATE, { TYPE_STRING, TYPE_NUMBER, TYPE_NONE } },
117 { "stat", ACTION_STAT, { TYPE_STRING, TYPE_STRING, TYPE_NONE } },
118 { "lstat", ACTION_LSTAT, { TYPE_STRING, TYPE_STRING, TYPE_NONE } },
119 { NULL, -1, { TYPE_NONE } }
127 static struct flag open_flags[] = {
129 { O_RDONLY, "O_RDONLY" },
132 { O_WRONLY, "O_WRONLY" },
135 { O_RDWR, "O_RDWR" },
138 { O_NONBLOCK, "O_NONBLOCK" },
141 { O_APPEND, "O_APPEND" },
144 { O_CREAT, "O_CREAT" },
147 { O_TRUNC, "O_TRUNC" },
150 { O_EXCL, "O_EXCL" },
153 { O_SHLOCK, "O_SHLOCK" },
156 { O_EXLOCK, "O_EXLOCK" },
159 { O_DIRECT, "O_DIRECT" },
162 { O_FSYNC, "O_FSYNC" },
165 { O_SYNC, "O_SYNC" },
168 { O_NOFOLLOW, "O_NOFOLLOW" },
171 { O_NOCTTY, "O_NOCTTY" },
177 static struct flag chflags_flags[] = {
179 { UF_NODUMP, "UF_NODUMP" },
182 { UF_IMMUTABLE, "UF_IMMUTABLE" },
185 { UF_APPEND, "UF_APPEND" },
188 { UF_NOUNLINK, "UF_NOUNLINK" },
191 { UF_OPAQUE, "UF_OPAQUE" },
194 { SF_ARCHIVED, "SF_ARCHIVED" },
197 { SF_IMMUTABLE, "SF_IMMUTABLE" },
200 { SF_APPEND, "SF_APPEND" },
203 { SF_NOUNLINK, "SF_NOUNLINK" },
206 { SF_SNAPSHOT, "SF_SNAPSHOT" },
212 static const char *err2str(int error);
218 fprintf(stderr, "usage: fstest [-u uid] [-g gid1[,gid2[...]]] syscall args ...\n");
223 str2flags(struct flag *tflags, char *sflags)
229 for (f = strtok(sflags, ","); f != NULL; f = strtok(NULL, ",")) {
230 /* Support magic 'none' flag which just reset all flags. */
231 if (strcmp(f, "none") == 0)
233 for (i = 0; tflags[i].f_str != NULL; i++) {
234 if (strcmp(tflags[i].f_str, f) == 0)
237 if (tflags[i].f_str == NULL) {
238 fprintf(stderr, "unknown flag '%s'\n", f);
241 flags |= tflags[i].f_flag;
248 flags2str(struct flag *tflags, long long flags)
250 static char sflags[1024];
254 for (i = 0; tflags[i].f_str != NULL; i++) {
255 if (flags & tflags[i].f_flag) {
256 if (sflags[0] != '\0')
257 strlcat(sflags, ",", sizeof(sflags));
258 strlcat(sflags, tflags[i].f_str, sizeof(sflags));
261 if (sflags[0] == '\0')
262 strlcpy(sflags, "none", sizeof(sflags));
267 static struct syscall_desc *
268 find_syscall(const char *name)
272 for (i = 0; syscalls[i].sd_name != NULL; i++) {
273 if (strcmp(syscalls[i].sd_name, name) == 0)
274 return (&syscalls[i]);
280 show_stat(struct stat64 *sp, const char *what)
283 if (strcmp(what, "mode") == 0)
284 printf("0%o", (unsigned int)(sp->st_mode & ALLPERMS));
285 else if (strcmp(what, "inode") == 0)
286 printf("%lld", (long long)sp->st_ino);
287 else if (strcmp(what, "nlink") == 0)
288 printf("%lld", (long long)sp->st_nlink);
289 else if (strcmp(what, "uid") == 0)
290 printf("%d", (int)sp->st_uid);
291 else if (strcmp(what, "gid") == 0)
292 printf("%d", (int)sp->st_gid);
293 else if (strcmp(what, "size") == 0)
294 printf("%lld", (long long)sp->st_size);
295 else if (strcmp(what, "blocks") == 0)
296 printf("%lld", (long long)sp->st_blocks);
297 else if (strcmp(what, "atime") == 0)
298 printf("%lld", (long long)sp->st_atime);
299 else if (strcmp(what, "mtime") == 0)
300 printf("%lld", (long long)sp->st_mtime);
301 else if (strcmp(what, "ctime") == 0)
302 printf("%lld", (long long)sp->st_ctime);
304 else if (strcmp(what, "flags") == 0)
305 printf("%s", flags2str(chflags_flags, sp->st_flags));
307 else if (strcmp(what, "type") == 0) {
308 switch (sp->st_mode & S_IFMT) {
340 show_stats(struct stat64 *sp, char *what)
345 for (w = strtok(what, ","); w != NULL; w = strtok(NULL, ",")) {
354 call_syscall(struct syscall_desc *scall, char *argv[])
367 * Verify correctness of the arguments.
369 for (i = 0; i < sizeof(args)/sizeof(args[0]); i++) {
370 if (scall->sd_args[i] == TYPE_NONE) {
371 if (argv[i] == NULL || strcmp(argv[i], ":") == 0)
373 fprintf(stderr, "too many arguments [%s]\n", argv[i]);
376 if (argv[i] == NULL || strcmp(argv[i], ":") == 0) {
377 if (scall->sd_args[i] & TYPE_OPTIONAL)
379 fprintf(stderr, "too few arguments\n");
382 if (scall->sd_args[i] & TYPE_STRING) {
383 if (strcmp(argv[i], "NULL") == 0)
385 else if (strcmp(argv[i], "DEADCODE") == 0)
386 args[i].str = (void *)0xdeadc0de;
388 args[i].str = argv[i];
389 } else if (scall->sd_args[i] & TYPE_NUMBER) {
390 args[i].num = strtoll(argv[i], &endp, 0);
391 if (*endp != '\0' && !isspace((unsigned char)*endp)) {
392 fprintf(stderr, "invalid argument %u, number expected [%s]\n", i, endp);
399 * Call the given syscall.
401 #define NUM(n) (args[(n)].num)
402 #define STR(n) (args[(n)].str)
403 switch (scall->sd_action) {
405 flags = str2flags(open_flags, STR(1));
406 if (flags & O_CREAT) {
408 fprintf(stderr, "too few arguments\n");
411 rval = open(STR(0), flags, (mode_t)NUM(2));
414 fprintf(stderr, "too many arguments\n");
417 rval = open(STR(0), flags);
421 rval = open(STR(0), O_CREAT | O_EXCL, NUM(1));
426 rval = unlink(STR(0));
429 rval = mkdir(STR(0), NUM(1));
432 rval = rmdir(STR(0));
435 rval = link(STR(0), STR(1));
438 rval = symlink(STR(0), STR(1));
441 rval = rename(STR(0), STR(1));
444 rval = mkfifo(STR(0), NUM(1));
447 rval = chmod(STR(0), NUM(1));
451 rval = lchmod(STR(0), NUM(1));
455 rval = chown(STR(0), NUM(1), NUM(2));
458 rval = lchown(STR(0), NUM(1), NUM(2));
462 rval = chflags(STR(0), str2flags(chflags_flags, STR(1)));
466 case ACTION_LCHFLAGS:
467 rval = lchflags(STR(0), str2flags(chflags_flags, STR(1)));
470 case ACTION_TRUNCATE:
471 rval = truncate64(STR(0), NUM(1));
474 rval = stat64(STR(0), &sb);
476 show_stats(&sb, STR(1));
481 rval = lstat64(STR(0), &sb);
483 show_stats(&sb, STR(1));
488 fprintf(stderr, "unsupported syscall\n");
496 serrno = err2str(errno);
497 fprintf(stderr, "%s returned %d\n", scall->sd_name, rval);
498 printf("%s\n", serrno);
513 ngroups = sysconf(_SC_NGROUPS_MAX);
515 gidset = malloc(sizeof(*gidset) * ngroups);
516 assert(gidset != NULL);
517 for (i = 0, g = strtok(gids, ","); g != NULL; g = strtok(NULL, ","), i++) {
519 fprintf(stderr, "too many gids\n");
522 gidset[i] = strtol(g, &endp, 0);
523 if (*endp != '\0' && !isspace((unsigned char)*endp)) {
524 fprintf(stderr, "invalid gid '%s' - number expected\n",
529 if (setgroups(i, gidset) < 0) {
530 fprintf(stderr, "cannot change groups: %s\n", strerror(errno));
533 if (setegid(gidset[0]) < 0) {
534 fprintf(stderr, "cannot change effective gid: %s\n", strerror(errno));
541 main(int argc, char *argv[])
543 struct syscall_desc *scall;
552 while ((ch = getopt(argc, argv, "g:u:U:")) != -1) {
558 uid = (int)strtol(optarg, &endp, 0);
559 if (*endp != '\0' && !isspace((unsigned char)*endp)) {
560 fprintf(stderr, "invalid uid '%s' - number "
561 "expected\n", optarg);
566 umsk = (int)strtol(optarg, &endp, 0);
567 if (*endp != '\0' && !isspace((unsigned char)*endp)) {
568 fprintf(stderr, "invalid umask '%s' - number "
569 "expected\n", optarg);
581 fprintf(stderr, "too few arguments\n");
586 fprintf(stderr, "changing groups to %s\n", gids);
590 fprintf(stderr, "changing uid to %d\n", uid);
591 if (setuid(uid) < 0) {
592 fprintf(stderr, "cannot change uid: %s\n",
598 /* Change umask to requested value or to 0, if not requested. */
602 scall = find_syscall(argv[0]);
604 fprintf(stderr, "syscall '%s' not supported\n", argv[0]);
609 n = call_syscall(scall, argv);
624 static char errnum[8];
769 return ("EINPROGRESS");
781 return ("EDESTADDRREQ");
789 return ("EPROTOTYPE");
793 return ("ENOPROTOOPT");
795 #ifdef EPROTONOSUPPORT
796 case EPROTONOSUPPORT:
797 return ("EPROTONOSUPPORT");
799 #ifdef ESOCKTNOSUPPORT
800 case ESOCKTNOSUPPORT:
801 return ("ESOCKTNOSUPPORT");
805 return ("EOPNOTSUPP");
809 return ("EPFNOSUPPORT");
813 return ("EAFNOSUPPORT");
817 return ("EADDRINUSE");
821 return ("EADDRNOTAVAIL");
829 return ("ENETUNREACH");
833 return ("ENETRESET");
837 return ("ECONNABORTED");
841 return ("ECONNRESET");
857 return ("ESHUTDOWN");
861 return ("ETOOMANYREFS");
865 return ("ETIMEDOUT");
869 return ("ECONNREFUSED");
877 return ("ENAMETOOLONG");
881 return ("EHOSTDOWN");
885 return ("EHOSTUNREACH");
889 return ("ENOTEMPTY");
917 return ("ERPCMISMATCH");
921 return ("EPROGUNAVAIL");
925 return ("EPROGMISMATCH");
929 return ("EPROCUNAVAIL");
949 return ("ENEEDAUTH");
961 return ("EOVERFLOW");
965 return ("ECANCELED");
985 return ("EMULTIHOP");
996 snprintf(errnum, sizeof(errnum), "%d", error);