Add support for *at syscalls:

- openat(2)
- unlinkat(2)
- mkdirat(2)
- linkat(2)
- symlinkat(2)
- renameat(2)
- mkfifoat(2)
- mknodat(2)
- fchmodat(2)
- fchownat(2)
- fstatat(2)
This commit is contained in:
Pawel Jakub Dawidek 2011-03-10 21:00:30 +00:00
parent 97b700501b
commit 7ab5d09839
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=219464

View file

@ -64,15 +64,23 @@
enum action {
ACTION_OPEN,
ACTION_OPENAT,
ACTION_CREATE,
ACTION_UNLINK,
ACTION_UNLINKAT,
ACTION_MKDIR,
ACTION_MKDIRAT,
ACTION_RMDIR,
ACTION_LINK,
ACTION_LINKAT,
ACTION_SYMLINK,
ACTION_SYMLINKAT,
ACTION_RENAME,
ACTION_RENAMEAT,
ACTION_MKFIFO,
ACTION_MKFIFOAT,
ACTION_MKNOD,
ACTION_MKNODAT,
ACTION_BIND,
ACTION_CONNECT,
ACTION_CHMOD,
@ -80,9 +88,11 @@ enum action {
#ifdef HAS_LCHMOD
ACTION_LCHMOD,
#endif
ACTION_FCHMODAT,
ACTION_CHOWN,
ACTION_FCHOWN,
ACTION_LCHOWN,
ACTION_FCHOWNAT,
#ifdef HAS_CHFLAGS
ACTION_CHFLAGS,
#endif
@ -97,6 +107,7 @@ enum action {
ACTION_STAT,
ACTION_FSTAT,
ACTION_LSTAT,
ACTION_FSTATAT,
ACTION_PATHCONF,
ACTION_FPATHCONF,
ACTION_LPATHCONF,
@ -110,6 +121,8 @@ enum action {
#define TYPE_NONE 0x0000
#define TYPE_STRING 0x0001
#define TYPE_NUMBER 0x0002
#define TYPE_DESCRIPTOR 0x0003
#define TYPE_MASK 0x000f
#define TYPE_OPTIONAL 0x0100
@ -123,47 +136,58 @@ struct syscall_desc {
static struct syscall_desc syscalls[] = {
{ "open", ACTION_OPEN, { TYPE_STRING, TYPE_STRING, TYPE_NUMBER | TYPE_OPTIONAL, TYPE_NONE } },
{ "openat", ACTION_OPENAT, { TYPE_DESCRIPTOR, TYPE_STRING, TYPE_STRING, TYPE_NUMBER | TYPE_OPTIONAL, TYPE_NONE } },
{ "create", ACTION_CREATE, { TYPE_STRING, TYPE_NUMBER, TYPE_NONE } },
{ "unlink", ACTION_UNLINK, { TYPE_STRING, TYPE_NONE } },
{ "unlinkat", ACTION_UNLINKAT, { TYPE_DESCRIPTOR, TYPE_STRING, TYPE_STRING, TYPE_NONE } },
{ "mkdir", ACTION_MKDIR, { TYPE_STRING, TYPE_NUMBER, TYPE_NONE } },
{ "mkdirat", ACTION_MKDIRAT, { TYPE_DESCRIPTOR, TYPE_STRING, TYPE_NUMBER, TYPE_NONE } },
{ "rmdir", ACTION_RMDIR, { TYPE_STRING, TYPE_NONE } },
{ "link", ACTION_LINK, { TYPE_STRING, TYPE_STRING, TYPE_NONE } },
{ "linkat", ACTION_LINKAT, { TYPE_DESCRIPTOR, TYPE_STRING, TYPE_DESCRIPTOR, TYPE_STRING, TYPE_STRING, TYPE_NONE } },
{ "symlink", ACTION_SYMLINK, { TYPE_STRING, TYPE_STRING, TYPE_NONE } },
{ "symlinkat", ACTION_SYMLINKAT, { TYPE_STRING, TYPE_DESCRIPTOR, TYPE_STRING, TYPE_NONE } },
{ "rename", ACTION_RENAME, { TYPE_STRING, TYPE_STRING, TYPE_NONE } },
{ "renameat", ACTION_RENAMEAT, { TYPE_DESCRIPTOR, TYPE_STRING, TYPE_DESCRIPTOR, TYPE_STRING, TYPE_NONE } },
{ "mkfifo", ACTION_MKFIFO, { TYPE_STRING, TYPE_NUMBER, TYPE_NONE } },
{ "mkfifoat", ACTION_MKFIFOAT, { TYPE_DESCRIPTOR, TYPE_STRING, TYPE_NUMBER, TYPE_NONE } },
{ "mknod", ACTION_MKNOD, { TYPE_STRING, TYPE_STRING, TYPE_NUMBER, TYPE_NUMBER, TYPE_NUMBER, TYPE_NONE} },
{ "mknodat", ACTION_MKNODAT, { TYPE_DESCRIPTOR, TYPE_STRING, TYPE_STRING, TYPE_NUMBER, TYPE_NUMBER, TYPE_NUMBER, TYPE_NONE} },
{ "bind", ACTION_BIND, { TYPE_STRING, TYPE_NONE } },
{ "connect", ACTION_CONNECT, { TYPE_STRING, TYPE_NONE } },
{ "chmod", ACTION_CHMOD, { TYPE_STRING, TYPE_NUMBER, TYPE_NONE } },
{ "fchmod", ACTION_FCHMOD, { TYPE_NUMBER, TYPE_NUMBER, TYPE_NONE } },
{ "fchmod", ACTION_FCHMOD, { TYPE_DESCRIPTOR, TYPE_NUMBER, TYPE_NONE } },
#ifdef HAS_LCHMOD
{ "lchmod", ACTION_LCHMOD, { TYPE_STRING, TYPE_NUMBER, TYPE_NONE } },
#endif
{ "fchmodat", ACTION_FCHMODAT, { TYPE_DESCRIPTOR, TYPE_STRING, TYPE_NUMBER, TYPE_STRING, TYPE_NONE } },
{ "chown", ACTION_CHOWN, { TYPE_STRING, TYPE_NUMBER, TYPE_NUMBER, TYPE_NONE } },
{ "fchown", ACTION_FCHOWN, { TYPE_NUMBER, TYPE_NUMBER, TYPE_NUMBER, TYPE_NONE } },
{ "fchown", ACTION_FCHOWN, { TYPE_DESCRIPTOR, TYPE_NUMBER, TYPE_NUMBER, TYPE_NONE } },
{ "lchown", ACTION_LCHOWN, { TYPE_STRING, TYPE_NUMBER, TYPE_NUMBER, TYPE_NONE } },
{ "fchownat", ACTION_FCHOWNAT, { TYPE_DESCRIPTOR, TYPE_STRING, TYPE_NUMBER, TYPE_NUMBER, TYPE_STRING, TYPE_NONE } },
#ifdef HAS_CHFLAGS
{ "chflags", ACTION_CHFLAGS, { TYPE_STRING, TYPE_STRING, TYPE_NONE } },
#endif
#ifdef HAS_FCHFLAGS
{ "fchflags", ACTION_FCHFLAGS, { TYPE_NUMBER, TYPE_STRING, TYPE_NONE } },
{ "fchflags", ACTION_FCHFLAGS, { TYPE_DESCRIPTOR, TYPE_STRING, TYPE_NONE } },
#endif
#ifdef HAS_LCHFLAGS
{ "lchflags", ACTION_LCHFLAGS, { TYPE_STRING, TYPE_STRING, TYPE_NONE } },
#endif
{ "truncate", ACTION_TRUNCATE, { TYPE_STRING, TYPE_NUMBER, TYPE_NONE } },
{ "ftruncate", ACTION_FTRUNCATE, { TYPE_NUMBER, TYPE_NUMBER, TYPE_NONE } },
{ "ftruncate", ACTION_FTRUNCATE, { TYPE_DESCRIPTOR, TYPE_NUMBER, TYPE_NONE } },
{ "stat", ACTION_STAT, { TYPE_STRING, TYPE_STRING, TYPE_NONE } },
{ "fstat", ACTION_FSTAT, { TYPE_NUMBER, TYPE_STRING, TYPE_NONE } },
{ "fstat", ACTION_FSTAT, { TYPE_DESCRIPTOR, TYPE_STRING, TYPE_NONE } },
{ "lstat", ACTION_LSTAT, { TYPE_STRING, TYPE_STRING, TYPE_NONE } },
{ "fstatat", ACTION_FSTATAT, { TYPE_DESCRIPTOR, TYPE_STRING, TYPE_STRING, TYPE_STRING, TYPE_NONE } },
{ "pathconf", ACTION_PATHCONF, { TYPE_STRING, TYPE_STRING, TYPE_NONE } },
{ "fpathconf", ACTION_FPATHCONF, { TYPE_NUMBER, TYPE_STRING, TYPE_NONE } },
{ "fpathconf", ACTION_FPATHCONF, { TYPE_DESCRIPTOR, TYPE_STRING, TYPE_NONE } },
{ "lpathconf", ACTION_LPATHCONF, { TYPE_STRING, TYPE_STRING, TYPE_NONE } },
#ifdef HAS_FREEBSD_ACL
{ "prependacl", ACTION_PREPENDACL, { TYPE_STRING, TYPE_STRING, TYPE_NONE } },
{ "readacl", ACTION_READACL, { TYPE_STRING, TYPE_NONE } },
#endif
{ "write", ACTION_WRITE, { TYPE_NUMBER, TYPE_STRING, TYPE_NONE } },
{ "write", ACTION_WRITE, { TYPE_DESCRIPTOR, TYPE_STRING, TYPE_NONE } },
{ NULL, -1, { TYPE_NONE } }
};
@ -217,6 +241,9 @@ static struct flag open_flags[] = {
#endif
#ifdef O_NOCTTY
{ O_NOCTTY, "O_NOCTTY" },
#endif
#ifdef O_DIRECTORY
{ O_DIRECTORY, "O_DIRECTORY" },
#endif
{ 0, NULL }
};
@ -257,6 +284,31 @@ static struct flag chflags_flags[] = {
};
#endif
static struct flag unlinkat_flags[] = {
{ AT_REMOVEDIR, "AT_REMOVEDIR" },
{ 0, NULL }
};
static struct flag linkat_flags[] = {
{ AT_SYMLINK_FOLLOW, "AT_SYMLINK_FOLLOW" },
{ 0, NULL }
};
static struct flag fchmodat_flags[] = {
{ AT_SYMLINK_NOFOLLOW, "AT_SYMLINK_NOFOLLOW" },
{ 0, NULL }
};
static struct flag fchownat_flags[] = {
{ AT_SYMLINK_NOFOLLOW, "AT_SYMLINK_NOFOLLOW" },
{ 0, NULL }
};
static struct flag fstatat_flags[] = {
{ AT_SYMLINK_NOFOLLOW, "AT_SYMLINK_NOFOLLOW" },
{ 0, NULL }
};
struct name {
int n_name;
char *n_str;
@ -499,19 +551,38 @@ call_syscall(struct syscall_desc *scall, char *argv[])
fprintf(stderr, "too few arguments\n");
exit(1);
}
if (scall->sd_args[i] & TYPE_STRING) {
if ((scall->sd_args[i] & TYPE_MASK) == TYPE_STRING) {
if (strcmp(argv[i], "NULL") == 0)
args[i].str = NULL;
else if (strcmp(argv[i], "DEADCODE") == 0)
args[i].str = (void *)0xdeadc0de;
else
args[i].str = argv[i];
} else if (scall->sd_args[i] & TYPE_NUMBER) {
} else if ((scall->sd_args[i] & TYPE_MASK) == TYPE_NUMBER) {
args[i].num = strtoll(argv[i], &endp, 0);
if (*endp != '\0' && !isspace((unsigned char)*endp)) {
fprintf(stderr, "invalid argument %u, number expected [%s]\n", i, endp);
exit(1);
}
} else if ((scall->sd_args[i] & TYPE_MASK) == TYPE_DESCRIPTOR) {
if (strcmp(argv[i], "AT_FDCWD") == 0) {
args[i].num = AT_FDCWD;
} else if (strcmp(argv[i], "BADFD") == 0) {
/* In case AT_FDCWD is -1 on some systems... */
if (AT_FDCWD == -1)
args[i].num = -2;
else
args[i].num = -1;
} else {
int pos;
pos = strtoll(argv[i], &endp, 0);
if (*endp != '\0' && !isspace((unsigned char)*endp)) {
fprintf(stderr, "invalid argument %u, number expected [%s]\n", i, endp);
exit(1);
}
args[i].num = descriptor_get(pos);
}
}
}
}
@ -520,7 +591,6 @@ call_syscall(struct syscall_desc *scall, char *argv[])
*/
#define NUM(n) (args[(n)].num)
#define STR(n) (args[(n)].str)
#define DESC(n) (descriptor_get((int)NUM(n)))
switch (scall->sd_action) {
case ACTION_OPEN:
flags = str2flags(open_flags, STR(1));
@ -540,6 +610,24 @@ call_syscall(struct syscall_desc *scall, char *argv[])
if (rval >= 0)
descriptor_add(rval);
break;
case ACTION_OPENAT:
flags = str2flags(open_flags, STR(2));
if (flags & O_CREAT) {
if (i == 3) {
fprintf(stderr, "too few arguments\n");
exit(1);
}
rval = openat(NUM(0), STR(1), (int)flags, (mode_t)NUM(3));
} else {
if (i == 4) {
fprintf(stderr, "too many arguments\n");
exit(1);
}
rval = openat(NUM(0), STR(1), (int)flags);
}
if (rval >= 0)
descriptor_add(rval);
break;
case ACTION_CREATE:
rval = open(STR(0), O_CREAT | O_EXCL, (mode_t)NUM(1));
if (rval >= 0)
@ -548,45 +636,87 @@ call_syscall(struct syscall_desc *scall, char *argv[])
case ACTION_UNLINK:
rval = unlink(STR(0));
break;
case ACTION_UNLINKAT:
rval = unlinkat(NUM(0), STR(1),
(int)str2flags(unlinkat_flags, STR(2)));
break;
case ACTION_MKDIR:
rval = mkdir(STR(0), (mode_t)NUM(1));
break;
case ACTION_MKDIRAT:
rval = mkdirat(NUM(0), STR(1), (mode_t)NUM(2));
break;
case ACTION_RMDIR:
rval = rmdir(STR(0));
break;
case ACTION_LINK:
rval = link(STR(0), STR(1));
break;
case ACTION_LINKAT:
rval = linkat(NUM(0), STR(1), NUM(2), STR(3),
(int)str2flags(linkat_flags, STR(4)));
break;
case ACTION_SYMLINK:
rval = symlink(STR(0), STR(1));
break;
case ACTION_SYMLINKAT:
rval = symlinkat(STR(0), NUM(1), STR(2));
break;
case ACTION_RENAME:
rval = rename(STR(0), STR(1));
break;
case ACTION_RENAMEAT:
rval = renameat(NUM(0), STR(1), NUM(2), STR(3));
break;
case ACTION_MKFIFO:
rval = mkfifo(STR(0), (mode_t)NUM(1));
break;
case ACTION_MKFIFOAT:
rval = mkfifoat(NUM(0), STR(1), (mode_t)NUM(2));
break;
case ACTION_MKNOD:
case ACTION_MKNODAT:
{
mode_t ntype;
dev_t dev;
int fa;
dev = makedev(NUM(3), NUM(4));
if (strcmp(STR(1), "c") == 0) /* character device */
switch (scall->sd_action) {
case ACTION_MKNOD:
fa = 0;
break;
case ACTION_MKNODAT:
fa = 1;
break;
default:
abort();
}
dev = makedev(NUM(fa + 3), NUM(fa + 4));
if (strcmp(STR(fa + 1), "c") == 0) /* character device */
ntype = S_IFCHR;
else if (strcmp(STR(1), "b") == 0) /* block device */
else if (strcmp(STR(fa + 1), "b") == 0) /* block device */
ntype = S_IFBLK;
else if (strcmp(STR(1), "f") == 0) /* fifo special */
else if (strcmp(STR(fa + 1), "f") == 0) /* fifo special */
ntype = S_IFIFO;
else if (strcmp(STR(1), "d") == 0) /* directory */
else if (strcmp(STR(fa + 1), "d") == 0) /* directory */
ntype = S_IFDIR;
else if (strcmp(STR(1), "o") == 0) /* regular file */
else if (strcmp(STR(fa + 1), "o") == 0) /* regular file */
ntype = S_IFREG;
else {
fprintf(stderr, "wrong argument 1\n");
exit(1);
}
rval = mknod(STR(0), ntype | NUM(2), dev);
switch (scall->sd_action) {
case ACTION_MKNOD:
rval = mknod(STR(0), ntype | NUM(2), dev);
break;
case ACTION_MKNODAT:
rval = mknodat(NUM(0), STR(1), ntype | NUM(3), dev);
break;
default:
abort();
}
break;
}
case ACTION_BIND:
@ -619,30 +749,40 @@ call_syscall(struct syscall_desc *scall, char *argv[])
rval = chmod(STR(0), (mode_t)NUM(1));
break;
case ACTION_FCHMOD:
rval = fchmod(DESC(0), (mode_t)NUM(1));
rval = fchmod(NUM(0), (mode_t)NUM(1));
break;
#ifdef HAS_LCHMOD
case ACTION_LCHMOD:
rval = lchmod(STR(0), (mode_t)NUM(1));
break;
#endif
case ACTION_FCHMODAT:
rval = fchmodat(NUM(0), STR(1), (mode_t)NUM(2),
str2flags(fchmodat_flags, STR(3)));
break;
case ACTION_CHOWN:
rval = chown(STR(0), (uid_t)NUM(1), (gid_t)NUM(2));
break;
case ACTION_FCHOWN:
rval = fchown(DESC(0), (uid_t)NUM(1), (gid_t)NUM(2));
rval = fchown(NUM(0), (uid_t)NUM(1), (gid_t)NUM(2));
break;
case ACTION_LCHOWN:
rval = lchown(STR(0), (uid_t)NUM(1), (gid_t)NUM(2));
break;
case ACTION_FCHOWNAT:
rval = fchownat(NUM(0), STR(1), (uid_t)NUM(2), (gid_t)NUM(3),
(int)str2flags(fchownat_flags, STR(4)));
break;
#ifdef HAS_CHFLAGS
case ACTION_CHFLAGS:
rval = chflags(STR(0), (unsigned long)str2flags(chflags_flags, STR(1)));
rval = chflags(STR(0),
(unsigned long)str2flags(chflags_flags, STR(1)));
break;
#endif
#ifdef HAS_FCHFLAGS
case ACTION_FCHFLAGS:
rval = fchflags(DESC(0), (unsigned long)str2flags(chflags_flags, STR(1)));
rval = fchflags(NUM(0),
(unsigned long)str2flags(chflags_flags, STR(1)));
break;
#endif
#ifdef HAS_LCHFLAGS
@ -654,7 +794,7 @@ call_syscall(struct syscall_desc *scall, char *argv[])
rval = truncate64(STR(0), NUM(1));
break;
case ACTION_FTRUNCATE:
rval = ftruncate64(DESC(0), NUM(1));
rval = ftruncate64(NUM(0), NUM(1));
break;
case ACTION_STAT:
rval = stat64(STR(0), &sb);
@ -664,7 +804,7 @@ call_syscall(struct syscall_desc *scall, char *argv[])
}
break;
case ACTION_FSTAT:
rval = fstat64(DESC(0), &sb);
rval = fstat64(NUM(0), &sb);
if (rval == 0) {
show_stats(&sb, STR(1));
return (i);
@ -677,6 +817,14 @@ call_syscall(struct syscall_desc *scall, char *argv[])
return (i);
}
break;
case ACTION_FSTATAT:
rval = fstatat(NUM(0), STR(1), &sb,
(int)str2flags(fstatat_flags, STR(2)));
if (rval == 0) {
show_stats(&sb, STR(3));
return (i);
}
break;
case ACTION_PATHCONF:
case ACTION_FPATHCONF:
case ACTION_LPATHCONF:
@ -694,7 +842,7 @@ call_syscall(struct syscall_desc *scall, char *argv[])
lrval = pathconf(STR(0), name);
break;
case ACTION_FPATHCONF:
lrval = fpathconf(DESC(0), name);
lrval = fpathconf(NUM(0), name);
break;
case ACTION_LPATHCONF:
lrval = lpathconf(STR(0), name);
@ -745,7 +893,7 @@ call_syscall(struct syscall_desc *scall, char *argv[])
break;
#endif
case ACTION_WRITE:
rval = write(DESC(0), STR(1), strlen(STR(1)));
rval = write(NUM(0), STR(1), strlen(STR(1)));
break;
default:
fprintf(stderr, "unsupported syscall\n");