diff options
author | Peter Seebach <seebs@eee12.(none)> | 2010-03-26 14:48:36 -0500 |
---|---|---|
committer | Peter Seebach <seebs@eee12.(none)> | 2010-03-26 14:50:04 -0500 |
commit | 80259da816b82c5bdfbf9515935823a157f5d0e9 (patch) | |
tree | f5120633e788d0d36ea2133d436d52c563d08d98 | |
parent | caeebc0dd6ff538629687b55a5ce72554a7c3f34 (diff) | |
download | pseudo-80259da816b82c5bdfbf9515935823a157f5d0e9.tar.gz pseudo-80259da816b82c5bdfbf9515935823a157f5d0e9.tar.bz2 pseudo-80259da816b82c5bdfbf9515935823a157f5d0e9.zip |
Track file open flags
This patch adds support for checking whether a file was opened for
reading, writing, or both, as well as tracking append flags. It is
not very well tested. This is preparation for improved host
contamination checking.
42 files changed, 270 insertions, 141 deletions
diff --git a/doc/database b/doc/database index cac7a3a..da8f750 100644 --- a/doc/database +++ b/doc/database @@ -64,6 +64,7 @@ LOGS severity (severity id) text (anything else you wanted to say) tag (identifier for operations) + access (integer) The log database contains a primary table (logs). As of this writing it is not indexed, because indexing is expensive during writes (common, for @@ -79,3 +80,11 @@ The log database "tag" field, added since the initial release of pseudo, is available for tagging operations. When a client connects to the pseudo server, it passes the value of the environment variable PSEUDO_TAG; this tag is then recorded for all log entries pertaining to that client. + +The log database "access" field, added since the initial release of pseudo, +stores values which are bitwise masks of the values 1 (execute), 2 (write), +4 (read), and 8 (append), used to report the modes with which a file was +opened. These values are not completely reliable. A value of 0 is typical +for non-open operations, and a value outside the 0-15 range (usually -1) +indicates that something went wrong trying to identify the mode of a given +open. diff --git a/doc/pseudo_ipc b/doc/pseudo_ipc index 6a73ec8..150a43e 100644 --- a/doc/pseudo_ipc +++ b/doc/pseudo_ipc @@ -4,7 +4,7 @@ typedef struct { pseudo_msg_type_t type; op_id_t op; res_id_t result; - int xerrno; + int access; int client; dev_t dev; unsigned long long ino; @@ -59,9 +59,10 @@ uid/gid/mode/rdev on response, and never sends a path back. Dev and inode are currently changed by stat-by-path operations, but this may turn out to be wrong. -xerrno is used to contain a changed errno if, at some point, the server wants -to override the default errno. Normally, the client just uses its existing -errno. +access holds information about the open mode of a file (read, write, append, +etc.), but is not fully implemented. + +A field "xerrno" used to exist; it was never actually implemented. nlink is used to forward the number of links. The server DOES NOT modify this. Rather, nlink is used to provide better diagnostics when checking diff --git a/guts/__fxstat64.c b/guts/__fxstat64.c index 2e7919c..59f8a59 100644 --- a/guts/__fxstat64.c +++ b/guts/__fxstat64.c @@ -16,7 +16,7 @@ errno = save_errno; return rc; } - msg = pseudo_client_op(OP_FSTAT, fd, -1, 0, buf); + msg = pseudo_client_op(OP_FSTAT, 0, fd, -1, 0, buf); if (msg) { if (msg->result == RESULT_SUCCEED) pseudo_stat_msg(buf, msg); diff --git a/guts/__fxstatat64.c b/guts/__fxstatat64.c index b8054f2..349b48e 100644 --- a/guts/__fxstatat64.c +++ b/guts/__fxstatat64.c @@ -56,7 +56,7 @@ * note that symlink canonicalizing is now automatic, so we * don't need to check for a symlink on this end */ - msg = pseudo_client_op(OP_STAT, -1, dirfd, path, buf); + msg = pseudo_client_op(OP_STAT, 0, -1, dirfd, path, buf); if (msg) { pseudo_stat_msg(buf, msg); if (save_mode) { diff --git a/guts/__xmknodat.c b/guts/__xmknodat.c index 6bd0761..cca6a96 100644 --- a/guts/__xmknodat.c +++ b/guts/__xmknodat.c @@ -44,12 +44,12 @@ buf.st_mode = (PSEUDO_DB_MODE(buf.st_mode, mode) & 07777) | (mode & ~07777); buf.st_rdev = *dev; - msg = pseudo_client_op(OP_MKNOD, -1, dirfd, path, &buf); + msg = pseudo_client_op(OP_MKNOD, 0, -1, dirfd, path, &buf); if (!msg) { errno = ENOSYS; rc = -1; } else if (msg->result != RESULT_SUCCEED) { - errno = msg->xerrno; + errno = EPERM; rc = -1; } else { rc = 0; diff --git a/guts/chdir.c b/guts/chdir.c index ca48738..2cc9019 100644 --- a/guts/chdir.c +++ b/guts/chdir.c @@ -13,7 +13,7 @@ rc = real_chdir(path); if (rc != -1) { - pseudo_client_op(OP_CHDIR, -1, -1, path, 0); + pseudo_client_op(OP_CHDIR, 0, -1, -1, path, 0); } /* return rc; diff --git a/guts/chroot.c b/guts/chroot.c index 5f68482..14f5043 100644 --- a/guts/chroot.c +++ b/guts/chroot.c @@ -4,7 +4,7 @@ * int rc = -1; */ pseudo_debug(2, "chroot: %s\n", path); - if (!pseudo_client_op(OP_CHROOT, -1, -1, path, 0)) { + if (!pseudo_client_op(OP_CHROOT, 0, -1, -1, path, 0)) { pseudo_debug(1, "chroot failed: %s\n", strerror(errno)); rc = -1; } else { diff --git a/guts/close.c b/guts/close.c index 34b279e..8edbee9 100644 --- a/guts/close.c +++ b/guts/close.c @@ -6,7 +6,7 @@ /* this cleans up an internal table, and shouldn't even * make it to the server. */ - pseudo_client_op(OP_CLOSE, fd, -1, 0, 0); + pseudo_client_op(OP_CLOSE, 0, fd, -1, 0, 0); rc = real_close(fd); /* return rc; @@ -8,7 +8,7 @@ rc = real_dup(fd); save_errno = errno; pseudo_debug(2, "dup: %d->%d\n", fd, rc); - pseudo_client_op(OP_DUP, fd, rc, 0, 0); + pseudo_client_op(OP_DUP, 0, fd, rc, 0, 0); errno = save_errno; /* return rc; diff --git a/guts/dup2.c b/guts/dup2.c index 59d5293..360c3ad 100644 --- a/guts/dup2.c +++ b/guts/dup2.c @@ -8,10 +8,10 @@ /* close existing one first - this also causes the socket to the * server to get moved around if someone tries to overwrite it. */ pseudo_debug(2, "dup2: %d->%d\n", oldfd, newfd); - pseudo_client_op(OP_CLOSE, newfd, -1, 0, 0); + pseudo_client_op(OP_CLOSE, 0, newfd, -1, 0, 0); rc = real_dup2(oldfd, newfd); save_errno = errno; - pseudo_client_op(OP_DUP, oldfd, newfd, 0, 0); + pseudo_client_op(OP_DUP, 0, oldfd, newfd, 0, 0); errno = save_errno; /* return rc; diff --git a/guts/fchdir.c b/guts/fchdir.c index b255511..5289f4c 100644 --- a/guts/fchdir.c +++ b/guts/fchdir.c @@ -7,7 +7,7 @@ rc = real_fchdir(dirfd); if (rc != -1) { - pseudo_client_op(OP_CHDIR, -1, dirfd, 0, 0); + pseudo_client_op(OP_CHDIR, 0, -1, dirfd, 0, 0); } /* return rc; diff --git a/guts/fchmod.c b/guts/fchmod.c index 663a026..b479e8d 100644 --- a/guts/fchmod.c +++ b/guts/fchmod.c @@ -12,13 +12,13 @@ return -1; } buf.st_mode = (buf.st_mode & ~07777) | (mode & 07777); - msg = pseudo_client_op(OP_FCHMOD, fd, -1, 0, &buf); + msg = pseudo_client_op(OP_FCHMOD, 0, fd, -1, 0, &buf); real_fchmod(fd, PSEUDO_FS_MODE(mode)); if (!msg) { errno = ENOSYS; rc = -1; } else if (msg->result != RESULT_SUCCEED) { - errno = msg->xerrno; + errno = EPERM; rc = -1; } else { errno = save_errno; diff --git a/guts/fchmodat.c b/guts/fchmodat.c index 9804711..78637ee 100644 --- a/guts/fchmodat.c +++ b/guts/fchmodat.c @@ -33,7 +33,7 @@ /* purely for debugging purposes: check whether file * is already in database. */ - msg = pseudo_client_op(OP_STAT, -1, -1, path, &buf); + msg = pseudo_client_op(OP_STAT, 0, -1, -1, path, &buf); if (!msg || msg->result != RESULT_SUCCEED) { pseudo_debug(2, "chmodat to 0%o on %d/%s, ino %llu, new file.\n", mode, dirfd, path, (unsigned long long) buf.st_ino); @@ -54,12 +54,12 @@ */ buf.st_mode = (buf.st_mode & ~07777) | (mode & 07777); - msg = pseudo_client_op(OP_CHMOD, -1, dirfd, path, &buf); + msg = pseudo_client_op(OP_CHMOD, 0, -1, dirfd, path, &buf); if (!msg) { errno = ENOSYS; rc = -1; } else if (msg->result != RESULT_SUCCEED) { - errno = msg->xerrno; + errno = EPERM; rc = -1; } else { rc = 0; diff --git a/guts/fchown.c b/guts/fchown.c index 4e717ea..433d359 100644 --- a/guts/fchown.c +++ b/guts/fchown.c @@ -15,7 +15,7 @@ return -1; } if (owner == (uid_t) -1 || group == (gid_t) -1) { - msg = pseudo_client_op(OP_STAT, fd, -1, NULL, &buf); + msg = pseudo_client_op(OP_STAT, 0, fd, -1, NULL, &buf); /* copy in any existing values... */ if (msg) { if (msg->result == RESULT_SUCCEED) { @@ -38,12 +38,12 @@ } pseudo_debug(2, "fchown, fd %d: %d:%d -> %d:%d\n", fd, owner, group, buf.st_uid, buf.st_gid); - msg = pseudo_client_op(OP_FCHOWN, fd, -1, 0, &buf); + msg = pseudo_client_op(OP_FCHOWN, 0, fd, -1, 0, &buf); if (!msg) { errno = ENOSYS; rc = -1; } else if (msg->result != RESULT_SUCCEED) { - errno = msg->xerrno; + errno = EPERM; rc = -1; } else { rc = 0; diff --git a/guts/fchownat.c b/guts/fchownat.c index 23dac7b..fc81d4f 100644 --- a/guts/fchownat.c +++ b/guts/fchownat.c @@ -31,7 +31,7 @@ save_errno = errno; if (owner == (uid_t) -1 || group == (gid_t) -1) { - msg = pseudo_client_op(OP_STAT, -1, -1, path, &buf); + msg = pseudo_client_op(OP_STAT, 0, -1, -1, path, &buf); /* copy in any existing values... */ if (msg) { if (msg->result == RESULT_SUCCEED) { @@ -50,12 +50,12 @@ if (group != (gid_t) -1) { buf.st_gid = group; } - msg = pseudo_client_op(OP_CHOWN, -1, dirfd, path, &buf); + msg = pseudo_client_op(OP_CHOWN, 0, -1, dirfd, path, &buf); if (!msg) { errno = ENOSYS; rc = -1; } else if (msg->result != RESULT_SUCCEED) { - errno = msg->xerrno; + errno = EPERM; rc = -1; } else { rc = 0; diff --git a/guts/fclose.c b/guts/fclose.c index bcf4ace..e0c5681 100644 --- a/guts/fclose.c +++ b/guts/fclose.c @@ -9,7 +9,7 @@ return -1; } int fd = fileno(fp); - pseudo_client_op(OP_CLOSE, fd, -1, 0, 0); + pseudo_client_op(OP_CLOSE, 0, fd, -1, 0, 0); rc = real_fclose(fp); /* return rc; diff --git a/guts/fcntl.c b/guts/fcntl.c index ec7277d..d03d40c 100644 --- a/guts/fcntl.c +++ b/guts/fcntl.c @@ -22,7 +22,7 @@ save_errno = errno; if (rc != -1) { pseudo_debug(2, "fcntl_dup: %d->%d\n", fd, rc); - pseudo_client_op(OP_DUP, fd, rc, 0, 0); + pseudo_client_op(OP_DUP, 0, fd, rc, 0, 0); } errno = save_errno; break; diff --git a/guts/fopen.c b/guts/fopen.c index 6495d69..69d9ce6 100644 --- a/guts/fopen.c +++ b/guts/fopen.c @@ -16,13 +16,13 @@ pseudo_debug(2, "fopen '%s': fd %d\n", path, fd); if (real___fxstat64(_STAT_VER, fd, &buf) != -1) { if (!existed) { - pseudo_client_op(OP_CREAT, -1, -1, path, &buf); + pseudo_client_op(OP_CREAT, 0, -1, -1, path, &buf); } - pseudo_client_op(OP_OPEN, fd, -1, path, &buf); + pseudo_client_op(OP_OPEN, pseudo_access_fopen(mode), fd, -1, path, &buf); } else { pseudo_debug(1, "fopen (fd %d) succeeded, but fstat failed (%s).\n", fd, strerror(errno)); - pseudo_client_op(OP_OPEN, fd, -1, path, 0); + pseudo_client_op(OP_OPEN, pseudo_access_fopen(mode), fd, -1, path, 0); } errno = save_errno; } diff --git a/guts/fopen64.c b/guts/fopen64.c index c6de09c..c2286f2 100644 --- a/guts/fopen64.c +++ b/guts/fopen64.c @@ -17,13 +17,13 @@ pseudo_debug(2, "fopen64 '%s': fd %d\n", path, fd); if (real___fxstat64(_STAT_VER, fd, &buf) != -1) { if (!existed) { - pseudo_client_op(OP_CREAT, -1, -1, path, &buf); + pseudo_client_op(OP_CREAT, 0, -1, -1, path, &buf); } - pseudo_client_op(OP_OPEN, fd, -1, path, &buf); + pseudo_client_op(OP_OPEN, pseudo_access_fopen(mode), fd, -1, path, &buf); } else { pseudo_debug(1, "fopen64 (fd %d) succeeded, but fstat failed (%s).\n", fd, strerror(errno)); - pseudo_client_op(OP_OPEN, fd, -1, path, 0); + pseudo_client_op(OP_OPEN, pseudo_access_fopen(mode), fd, -1, path, 0); } errno = save_errno; } diff --git a/guts/freopen.c b/guts/freopen.c index 92c9d87..2701926 100644 --- a/guts/freopen.c +++ b/guts/freopen.c @@ -16,13 +16,13 @@ pseudo_debug(2, "freopen '%s': fd %d\n", path, fd); if (real___fxstat64(_STAT_VER, fd, &buf) != -1) { if (!existed) { - pseudo_client_op(OP_CREAT, -1, -1, path, &buf); + pseudo_client_op(OP_CREAT, 0, -1, -1, path, &buf); } - pseudo_client_op(OP_OPEN, fd, -1, path, &buf); + pseudo_client_op(OP_OPEN, pseudo_access_fopen(mode), fd, -1, path, &buf); } else { pseudo_debug(1, "fopen (fd %d) succeeded, but stat failed (%s).\n", fd, strerror(errno)); - pseudo_client_op(OP_OPEN, fd, -1, path, 0); + pseudo_client_op(OP_OPEN, pseudo_access_fopen(mode), fd, -1, path, 0); } errno = save_errno; } diff --git a/guts/freopen64.c b/guts/freopen64.c index 1f83b07..7487a7b 100644 --- a/guts/freopen64.c +++ b/guts/freopen64.c @@ -16,13 +16,13 @@ pseudo_debug(2, "freopen64 '%s': fd %d\n", path, fd); if (real___fxstat64(_STAT_VER, fd, &buf) != -1) { if (!existed) { - pseudo_client_op(OP_CREAT, -1, -1, path, &buf); + pseudo_client_op(OP_CREAT, 0, -1, -1, path, &buf); } - pseudo_client_op(OP_OPEN, fd, -1, path, &buf); + pseudo_client_op(OP_OPEN, pseudo_access_fopen(mode), fd, -1, path, &buf); } else { pseudo_debug(1, "fopen (fd %d) succeeded, but stat failed (%s).\n", fd, strerror(errno)); - pseudo_client_op(OP_OPEN, fd, -1, path, 0); + pseudo_client_op(OP_OPEN, pseudo_access_fopen(mode), fd, -1, path, 0); } errno = save_errno; } diff --git a/guts/link.c b/guts/link.c index a68a1c1..278edd7 100644 --- a/guts/link.c +++ b/guts/link.c @@ -17,11 +17,11 @@ * there is one. OP_LINK is also used to insert unseen * files, though, so it can't be implicit. */ - msg = pseudo_client_op(OP_STAT, -1, -1, oldpath, &buf); + msg = pseudo_client_op(OP_STAT, 0, -1, -1, oldpath, &buf); if (msg) { pseudo_stat_msg(&buf, msg); } - pseudo_client_op(OP_LINK, -1, -1, newpath, &buf); + pseudo_client_op(OP_LINK, 0, -1, -1, newpath, &buf); } /* return rc; diff --git a/guts/mkdirat.c b/guts/mkdirat.c index 188e66b..80ca5a0 100644 --- a/guts/mkdirat.c +++ b/guts/mkdirat.c @@ -22,7 +22,7 @@ stat_rc = real___fxstatat64(_STAT_VER, dirfd, path, &buf, AT_SYMLINK_NOFOLLOW); #endif if (stat_rc != -1) { - pseudo_client_op(OP_MKDIR, -1, dirfd, path, &buf); + pseudo_client_op(OP_MKDIR, 0, -1, dirfd, path, &buf); } else { pseudo_debug(1, "mkdir of %s succeeded, but stat failed: %s\n", path, strerror(errno)); diff --git a/guts/mkdtemp.c b/guts/mkdtemp.c index 32fe4ef..3c97118 100644 --- a/guts/mkdtemp.c +++ b/guts/mkdtemp.c @@ -27,7 +27,7 @@ save_errno = errno; if (real___xstat64(_STAT_VER, rc, &buf) != -1) { - pseudo_client_op(OP_CREAT, -1, -1, tmp_template, &buf); + pseudo_client_op(OP_CREAT, 0, -1, -1, tmp_template, &buf); } else { pseudo_debug(1, "mkstemp (path %s) succeeded, but fstat failed (%s).\n", rc, strerror(errno)); diff --git a/guts/mkstemp.c b/guts/mkstemp.c index a8f5915..ee8c742 100644 --- a/guts/mkstemp.c +++ b/guts/mkstemp.c @@ -27,12 +27,12 @@ save_errno = errno; if (real___fxstat64(_STAT_VER, rc, &buf) != -1) { - pseudo_client_op(OP_CREAT, -1, -1, tmp_template, &buf); - pseudo_client_op(OP_OPEN, rc, -1, tmp_template, &buf); + pseudo_client_op(OP_CREAT, 0, -1, -1, tmp_template, &buf); + pseudo_client_op(OP_OPEN, PSA_READ | PSA_WRITE, rc, -1, tmp_template, &buf); } else { pseudo_debug(1, "mkstemp (fd %d) succeeded, but fstat failed (%s).\n", rc, strerror(errno)); - pseudo_client_op(OP_OPEN, rc, -1, tmp_template, 0); + pseudo_client_op(OP_OPEN, PSA_READ | PSA_WRITE, rc, -1, tmp_template, 0); } errno = save_errno; } diff --git a/guts/openat.c b/guts/openat.c index 801f1e3..20d8d8d 100644 --- a/guts/openat.c +++ b/guts/openat.c @@ -48,13 +48,13 @@ if (stat_rc != -1) { buf.st_mode = PSEUDO_DB_MODE(buf.st_mode, mode); if (!existed) { - pseudo_client_op(OP_CREAT, -1, dirfd, path, &buf); + pseudo_client_op(OP_CREAT, 0, -1, dirfd, path, &buf); } - pseudo_client_op(OP_OPEN, rc, dirfd, path, &buf); + pseudo_client_op(OP_OPEN, PSEUDO_ACCESS(flags), rc, dirfd, path, &buf); } else { pseudo_debug(1, "openat (fd %d, path %d/%s, flags %d) succeeded, but stat failed (%s).\n", rc, dirfd, path, flags, strerror(errno)); - pseudo_client_op(OP_OPEN, rc, dirfd, path, 0); + pseudo_client_op(OP_OPEN, PSEUDO_ACCESS(flags), rc, dirfd, path, 0); } errno = save_errno; } diff --git a/guts/rename.c b/guts/rename.c index 117eb78..4ed3527 100644 --- a/guts/rename.c +++ b/guts/rename.c @@ -53,10 +53,10 @@ */ /* newpath must be removed. */ - pseudo_client_op(OP_UNLINK, -1, -1, newpath, &newbuf); + pseudo_client_op(OP_UNLINK, 0, -1, -1, newpath, &newbuf); /* fill in "correct" details from server */ - msg = pseudo_client_op(OP_STAT, -1, -1, oldpath, &oldbuf); + msg = pseudo_client_op(OP_STAT, 0, -1, -1, oldpath, &oldbuf); if (msg && msg->result == RESULT_SUCCEED) { pseudo_stat_msg(&oldbuf, msg); pseudo_debug(1, "renaming %s, got old mode of 0%o\n", oldpath, (int) msg->mode); @@ -67,9 +67,9 @@ */ pseudo_debug(1, "renaming new '%s' [%llu]\n", oldpath, (unsigned long long) oldbuf.st_ino); - pseudo_client_op(OP_LINK, -1, -1, oldpath, &oldbuf); + pseudo_client_op(OP_LINK, 0, -1, -1, oldpath, &oldbuf); } - pseudo_client_op(OP_RENAME, -1, -1, newpath, &oldbuf, oldpath); + pseudo_client_op(OP_RENAME, 0, -1, -1, newpath, &oldbuf, oldpath); errno = save_errno; /* return rc; diff --git a/guts/rmdir.c b/guts/rmdir.c index 94de46a..d69fb7e 100644 --- a/guts/rmdir.c +++ b/guts/rmdir.c @@ -13,7 +13,7 @@ rc = real_rmdir(path); save_errno = errno; if (rc != -1) { - pseudo_client_op(OP_UNLINK, -1, -1, path, &buf); + pseudo_client_op(OP_UNLINK, 0, -1, -1, path, &buf); } errno = save_errno; diff --git a/guts/symlinkat.c b/guts/symlinkat.c index 577b1e7..ca12cd5 100644 --- a/guts/symlinkat.c +++ b/guts/symlinkat.c @@ -40,7 +40,7 @@ return rc; } /* just record the entry */ - pseudo_client_op(OP_SYMLINK, -1, dirfd, newpath, &buf); + pseudo_client_op(OP_SYMLINK, 0, -1, dirfd, newpath, &buf); free(roldname); diff --git a/guts/unlinkat.c b/guts/unlinkat.c index 1c2868a..4f5b363 100644 --- a/guts/unlinkat.c +++ b/guts/unlinkat.c @@ -35,7 +35,7 @@ rc = real_unlinkat(dirfd, path, rflags); #endif if (rc != -1) { - pseudo_client_op(OP_UNLINK, -1, dirfd, path, &buf); + pseudo_client_op(OP_UNLINK, 0, -1, dirfd, path, &buf); } /* return rc; @@ -33,20 +33,20 @@ int main(void) { - printf("type: %d\n", offsetof(pseudo_msg_t, type)); - printf("op: %d\n", offsetof(pseudo_msg_t, op)); - printf("result: %d\n", offsetof(pseudo_msg_t, result)); - printf("xerrno: %d\n", offsetof(pseudo_msg_t, xerrno)); - printf("client: %d\n", offsetof(pseudo_msg_t, client)); - printf("dev: %d\n", offsetof(pseudo_msg_t, dev)); - printf("ino: %d\n", offsetof(pseudo_msg_t, ino)); - printf("uid: %d\n", offsetof(pseudo_msg_t, uid)); - printf("gid: %d\n", offsetof(pseudo_msg_t, gid)); - printf("mode: %d\n", offsetof(pseudo_msg_t, mode)); - printf("rdev: %d\n", offsetof(pseudo_msg_t, rdev)); - printf("pathlen: %d\n", offsetof(pseudo_msg_t, pathlen)); - printf("path: %d\n", offsetof(pseudo_msg_t, path)); - printf("size: %d\n", sizeof(pseudo_msg_t)); + printf("type: %d\n", (int) offsetof(pseudo_msg_t, type)); + printf("op: %d\n", (int) offsetof(pseudo_msg_t, op)); + printf("result: %d\n", (int) offsetof(pseudo_msg_t, result)); + printf("rwx: %d\n", (int) offsetof(pseudo_msg_t, rwx)); + printf("client: %d\n", (int) offsetof(pseudo_msg_t, client)); + printf("dev: %d\n", (int) offsetof(pseudo_msg_t, dev)); + printf("ino: %d\n", (int) offsetof(pseudo_msg_t, ino)); + printf("uid: %d\n", (int) offsetof(pseudo_msg_t, uid)); + printf("gid: %d\n", (int) offsetof(pseudo_msg_t, gid)); + printf("mode: %d\n", (int) offsetof(pseudo_msg_t, mode)); + printf("rdev: %d\n", (int) offsetof(pseudo_msg_t, rdev)); + printf("pathlen: %d\n", (int) offsetof(pseudo_msg_t, pathlen)); + printf("path: %d\n", (int) offsetof(pseudo_msg_t, path)); + printf("size: %d\n", (int) sizeof(pseudo_msg_t)); return 0; } @@ -278,7 +278,6 @@ pseudo_op(pseudo_msg_t *msg, const char *tag) { return 1; msg->result = RESULT_SUCCEED; - msg->xerrno = 0; /* debugging message. Primary key first. */ switch (msg->op) { @@ -91,6 +91,7 @@ extern pseudo_query_type_t pseudo_query_type_id(char *name); typedef enum pseudo_query_field { PSQF_UNKNOWN = -1, PSQF_NONE, /* so that these are always non-zero */ + PSQF_ACCESS, PSQF_CLIENT, PSQF_DEV, PSQF_FD, PSQF_FTYPE, PSQF_GID, PSQF_ID, PSQF_INODE, PSQF_MODE, PSQF_OP, PSQF_ORDER, PSQF_PATH, PSQF_PERM, diff --git a/pseudo_client.c b/pseudo_client.c index 3b47a35..3066570 100644 --- a/pseudo_client.c +++ b/pseudo_client.c @@ -687,7 +687,7 @@ base_path(int dirfd, const char *path, int leave_last) { } pseudo_msg_t * -pseudo_client_op(op_id_t op, int fd, int dirfd, const char *path, const struct stat64 *buf, ...) { +pseudo_client_op(op_id_t op, int access, int fd, int dirfd, const char *path, const struct stat64 *buf, ...) { pseudo_msg_t *result = 0; pseudo_msg_t msg = { .type = PSEUDO_MSG_OP }; size_t pathlen = -1; @@ -774,6 +774,7 @@ pseudo_client_op(op_id_t op, int fd, int dirfd, const char *path, const struct s msg.type = PSEUDO_MSG_OP; msg.op = op; msg.fd = fd; + msg.access = access; msg.result = RESULT_NONE; msg.client = getpid(); diff --git a/pseudo_client.h b/pseudo_client.h index c55e5b0..11d5a0c 100644 --- a/pseudo_client.h +++ b/pseudo_client.h @@ -17,7 +17,7 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ -extern pseudo_msg_t *pseudo_client_op(op_id_t op, int fd, int dirfd, const char *path, const struct stat64 *buf, ...); +extern pseudo_msg_t *pseudo_client_op(op_id_t op, int access, int fd, int dirfd, const char *path, const struct stat64 *buf, ...); extern void pseudo_antimagic(void); extern void pseudo_magic(void); extern void pseudo_client_reset(void); diff --git a/pseudo_db.c b/pseudo_db.c index feda002..84a9103 100644 --- a/pseudo_db.c +++ b/pseudo_db.c @@ -220,6 +220,8 @@ static struct sql_migration { */ { "ALTER TABLE logs ADD uid INTEGER;" }, { "ALTER TABLE logs ADD gid INTEGER;" }, + /* track access types (read/write, etc) */ + { "ALTER TABLE logs ADD access INTEGER;" }, { NULL }, }; @@ -558,6 +560,9 @@ pdb_log_traits(pseudo_query_t *traits) { } for (trait = traits; trait; trait = trait->next) { switch (trait->field) { + case PSQF_ACCESS: + e->access = trait->data.ivalue; + break; case PSQF_CLIENT: e->client = trait->data.ivalue; break; @@ -628,10 +633,11 @@ pdb_log_traits(pseudo_query_t *traits) { int pdb_log_entry(log_entry *e) { char *sql = "INSERT INTO logs " - "(stamp, op, client, dev, gid, ino, mode, path, result, severity, text, tag, uid)" + "(stamp, op, access, client, dev, gid, ino, mode, path, result, severity, text, tag, uid)" " VALUES " - "(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?);"; + "(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?);"; static sqlite3_stmt *insert; + int field; int rc; if (!log_db && get_db(&log_db)) { @@ -647,50 +653,53 @@ pdb_log_entry(log_entry *e) { } } + field = 1; if (e) { if (e->stamp) { - sqlite3_bind_int(insert, 1, e->stamp); + sqlite3_bind_int(insert, field++, e->stamp); } else { - sqlite3_bind_int(insert, 1, (unsigned long) time(NULL)); + sqlite3_bind_int(insert, field++, (unsigned long) time(NULL)); } - sqlite3_bind_int(insert, 2, e->op); - sqlite3_bind_int(insert, 3, e->client); - sqlite3_bind_int(insert, 4, e->dev); - sqlite3_bind_int(insert, 5, e->gid); - sqlite3_bind_int(insert, 6, e->ino); - sqlite3_bind_int(insert, 7, e->mode); + sqlite3_bind_int(insert, field++, e->op); + sqlite3_bind_int(insert, field++, e->access); + sqlite3_bind_int(insert, field++, e->client); + sqlite3_bind_int(insert, field++, e->dev); + sqlite3_bind_int(insert, field++, e->gid); + sqlite3_bind_int(insert, field++, e->ino); + sqlite3_bind_int(insert, field++, e->mode); if (e->path) { - sqlite3_bind_text(insert, 8, e->path, -1, SQLITE_STATIC); + sqlite3_bind_text(insert, field++, e->path, -1, SQLITE_STATIC); } else { - sqlite3_bind_null(insert, 8); + sqlite3_bind_null(insert, field++); } - sqlite3_bind_int(insert, 9, e->result); - sqlite3_bind_int(insert, 10, e->severity); + sqlite3_bind_int(insert, field++, e->result); + sqlite3_bind_int(insert, field++, e->severity); if (e->text) { - sqlite3_bind_text(insert, 11, e->text, -1, SQLITE_STATIC); + sqlite3_bind_text(insert, field++, e->text, -1, SQLITE_STATIC); } else { - sqlite3_bind_null(insert, 11); + sqlite3_bind_null(insert, field++); } if (e->tag) { - sqlite3_bind_text(insert, 12, e->tag, -1, SQLITE_STATIC); + sqlite3_bind_text(insert, field++, e->tag, -1, SQLITE_STATIC); } else { - sqlite3_bind_null(insert, 12); + sqlite3_bind_null(insert, field++); } - sqlite3_bind_int(insert, 13, e->uid); + sqlite3_bind_int(insert, field++, e->uid); } else { - sqlite3_bind_int(insert, 1, (unsigned long) time(NULL)); - sqlite3_bind_int(insert, 2, 0); - sqlite3_bind_int(insert, 3, 0); - sqlite3_bind_int(insert, 4, 0); - sqlite3_bind_int(insert, 5, 0); - sqlite3_bind_int(insert, 6, 0); - sqlite3_bind_int(insert, 7, 0); - sqlite3_bind_null(insert, 8); - sqlite3_bind_int(insert, 9, 0); - sqlite3_bind_int(insert, 10, 0); - sqlite3_bind_null(insert, 11); - sqlite3_bind_null(insert, 12); - sqlite3_bind_int(insert, 13, 0); + sqlite3_bind_int(insert, field++, (unsigned long) time(NULL)); + sqlite3_bind_int(insert, field++, 0); + sqlite3_bind_int(insert, field++, 0); + sqlite3_bind_int(insert, field++, 0); + sqlite3_bind_int(insert, field++, 0); + sqlite3_bind_int(insert, field++, 0); + sqlite3_bind_int(insert, field++, 0); + sqlite3_bind_int(insert, field++, 0); + sqlite3_bind_null(insert, field++); + sqlite3_bind_int(insert, field++, 0); + sqlite3_bind_int(insert, field++, 0); + sqlite3_bind_null(insert, field++); + sqlite3_bind_null(insert, field++); + sqlite3_bind_int(insert, field++, 0); } rc = sqlite3_step(insert); @@ -705,11 +714,12 @@ pdb_log_entry(log_entry *e) { int pdb_log_msg(sev_id_t severity, pseudo_msg_t *msg, const char *tag, const char *text, ...) { char *sql = "INSERT INTO logs " - "(stamp, op, client, dev, gid, ino, mode, path, result, severity, text, tag, uid)" + "(stamp, op, access, client, dev, gid, ino, mode, path, result, uid, severity, text, tag)" " VALUES " - "(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?);"; + "(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?);"; static sqlite3_stmt *insert; char buffer[8192]; + int field; int rc; va_list ap; @@ -733,42 +743,45 @@ pdb_log_msg(sev_id_t severity, pseudo_msg_t *msg, const char *tag, const char *t } } + field = 1; + sqlite3_bind_int(insert, field++, (unsigned long) time(NULL)); if (msg) { - sqlite3_bind_int(insert, 2, msg->op); - sqlite3_bind_int(insert, 3, msg->client); - sqlite3_bind_int(insert, 4, msg->dev); - sqlite3_bind_int(insert, 5, msg->gid); - sqlite3_bind_int(insert, 6, msg->ino); - sqlite3_bind_int(insert, 7, msg->mode); + sqlite3_bind_int(insert, field++, msg->op); + sqlite3_bind_int(insert, field++, msg->access); + sqlite3_bind_int(insert, field++, msg->client); + sqlite3_bind_int(insert, field++, msg->dev); + sqlite3_bind_int(insert, field++, msg->gid); + sqlite3_bind_int(insert, field++, msg->ino); + sqlite3_bind_int(insert, field++, msg->mode); if (msg->pathlen) { - sqlite3_bind_text(insert, 8, msg->path, -1, SQLITE_STATIC); + sqlite3_bind_text(insert, field++, msg->path, -1, SQLITE_STATIC); } else { - sqlite3_bind_null(insert, 8); + sqlite3_bind_null(insert, field++); } - sqlite3_bind_int(insert, 9, msg->result); - sqlite3_bind_int(insert, 13, msg->uid); + sqlite3_bind_int(insert, field++, msg->result); + sqlite3_bind_int(insert, field++, msg->uid); } else { - sqlite3_bind_int(insert, 2, 0); - sqlite3_bind_int(insert, 3, 0); - sqlite3_bind_int(insert, 4, 0); - sqlite3_bind_int(insert, 5, 0); - sqlite3_bind_int(insert, 6, 0); - sqlite3_bind_int(insert, 7, 0); - sqlite3_bind_null(insert, 8); - sqlite3_bind_int(insert, 9, 0); - sqlite3_bind_int(insert, 13, 0); - } - sqlite3_bind_int(insert, 1, (unsigned long) time(NULL)); - sqlite3_bind_int(insert, 10, severity); + sqlite3_bind_int(insert, field++, 0); + sqlite3_bind_int(insert, field++, 0); + sqlite3_bind_int(insert, field++, 0); + sqlite3_bind_int(insert, field++, 0); + sqlite3_bind_int(insert, field++, 0); + sqlite3_bind_int(insert, field++, 0); + sqlite3_bind_int(insert, field++, 0); + sqlite3_bind_null(insert, field++); + sqlite3_bind_int(insert, field++, 0); + sqlite3_bind_int(insert, field++, 0); + } + sqlite3_bind_int(insert, field++, severity); if (text) { - sqlite3_bind_text(insert, 11, text, -1, SQLITE_STATIC); + sqlite3_bind_text(insert, field++, text, -1, SQLITE_STATIC); } else { - sqlite3_bind_null(insert, 11); + sqlite3_bind_null(insert, field++); } if (tag) { - sqlite3_bind_text(insert, 12, tag, -1, SQLITE_STATIC); + sqlite3_bind_text(insert, field++, tag, -1, SQLITE_STATIC); } else { - sqlite3_bind_null(insert, 12); + sqlite3_bind_null(insert, field++); } rc = sqlite3_step(insert); @@ -1005,10 +1018,11 @@ pdb_history(pseudo_query_t *traits, unsigned long fields, int distinct) { sqlite3_bind_text(select, field++, trait->data.svalue, -1, SQLITE_STATIC); break; - case PSQF_FTYPE: /* FALLTHROUGH */ + case PSQF_ACCESS: /* FALLTHROUGH */ case PSQF_CLIENT: /* FALLTHROUGH */ case PSQF_DEV: /* FALLTHROUGH */ case PSQF_FD: /* FALLTHROUGH */ + case PSQF_FTYPE: /* FALLTHROUGH */ case PSQF_INODE: /* FALLTHROUGH */ case PSQF_GID: /* FALLTHROUGH */ case PSQF_PERM: /* FALLTHROUGH */ @@ -1070,6 +1084,9 @@ pdb_history_entry(log_history h) { if (!(h->fields & (1 << f))) continue; switch (f) { + case PSQF_ACCESS: + l->access = sqlite3_column_int64(h->stmt, column++); + break; case PSQF_CLIENT: l->client = sqlite3_column_int64(h->stmt, column++); break; diff --git a/pseudo_db.h b/pseudo_db.h index 2085335..9b82c53 100644 --- a/pseudo_db.h +++ b/pseudo_db.h @@ -20,6 +20,7 @@ typedef struct { time_t stamp; op_id_t op; + int access; unsigned long client; unsigned long fd; unsigned long long dev; diff --git a/pseudo_ipc.h b/pseudo_ipc.h index 50794a1..063a1ef 100644 --- a/pseudo_ipc.h +++ b/pseudo_ipc.h @@ -33,7 +33,7 @@ typedef struct { pseudo_msg_type_t type; op_id_t op; res_id_t result; - int xerrno; + int access; int client; int fd; dev_t dev; @@ -47,6 +47,22 @@ typedef struct { char path[]; } pseudo_msg_t; +enum { + PSA_EXEC = 1, + PSA_WRITE = (PSA_EXEC << 1), + PSA_READ = (PSA_WRITE << 1), + PSA_APPEND = (PSA_READ << 1), +} pseudo_access_t; + +#define PSEUDO_ACCESS_MAP(mode, fcntl_access, pseudo_access) ((((mode) & O_ACCMODE) == (fcntl_access)) ? (pseudo_access) : (0)) +#define PSEUDO_ACCESS_FLAG(mode, fcntl_access, pseudo_access) (((mode) & (fcntl_access)) ? (pseudo_access) : (0)) +#define PSEUDO_ACCESS(mode) ( \ + PSEUDO_ACCESS_MAP(mode, O_RDONLY, PSA_READ) | \ + PSEUDO_ACCESS_MAP(mode, O_WRONLY, PSA_WRITE) | \ + PSEUDO_ACCESS_MAP(mode, O_RDWR, PSA_READ | PSA_WRITE) | \ + PSEUDO_ACCESS_FLAG(mode, O_APPEND, PSA_APPEND)) +extern int pseudo_access_fopen(const char *); + #define PSEUDO_HEADER_SIZE (offsetof(pseudo_msg_t, path)) extern pseudo_msg_t *pseudo_msg_receive(int fd); diff --git a/pseudo_table.c b/pseudo_table.c index c5c0aec..171ba7b 100644 --- a/pseudo_table.c +++ b/pseudo_table.c @@ -92,6 +92,7 @@ static char *query_type_sql[] = { static char *query_field_names[] = { "zero", + "access", "client", "dev", "fd", diff --git a/pseudo_util.c b/pseudo_util.c index a57f8ac..55e0488 100644 --- a/pseudo_util.c +++ b/pseudo_util.c @@ -580,3 +580,33 @@ pseudo_sys_path_max(void) { } return pseudo_sys_max_pathlen; } + +/* complicated because in theory you can have modes like * 'ab+' + * which is the same as 'a+' in POSIX. The first letter really does have + * to be one of r, w, a, though. + */ +int +pseudo_access_fopen(const char *mode) { + int access = 0; + switch (*mode) { + case 'a': + access |= (PSA_APPEND | PSA_WRITE); + if (mode[1] == '+' || (mode[1] == 'b' && mode[2] == '+')) + access |= PSA_READ; + break; + case 'r': + access |= PSA_READ; + if (mode[1] == '+' || (mode[1] == 'b' && mode[2] == '+')) + access |= PSA_WRITE; + break; + case 'w': + access |= PSA_WRITE; + if (mode[1] == '+' || (mode[1] == 'b' && mode[2] == '+')) + access |= PSA_READ; + break; + default: + access = -1; + break; + } + return access; +} diff --git a/pseudolog.1 b/pseudolog.1 index 21b2908..8aaf9c8 100644 --- a/pseudolog.1 +++ b/pseudolog.1 @@ -178,6 +178,15 @@ few fields are parsed or displayed in other ways, as detailed in their entries. .TP 8 +.B a +Access mode. This is an access mode specified in the form used by +.IR fopen(3) , +such as "r+" to indicate read/write access. Note that specifying +.B \&a +as an access mode will include non-append writes, as the "a" mode +implies write and append both. This feature is slightly experimental +and may not correctly identify the access type of every access. +.TP 8 .B c Client ID (the PID of a client). .TP 8 diff --git a/pseudolog.c b/pseudolog.c index ae405c5..4d189b6 100644 --- a/pseudolog.c +++ b/pseudolog.c @@ -43,6 +43,7 @@ static int format_scan(char *format); void usage(int status) { static char *options[] = { + "a access (rwax)", "c client pid", "d device number", "f file descriptor", @@ -88,6 +89,7 @@ usage(int status) { } pseudo_query_field_t opt_to_field[UCHAR_MAX + 1] = { + ['a'] = PSQF_ACCESS, ['c'] = PSQF_CLIENT, ['d'] = PSQF_DEV, ['f'] = PSQF_FD, @@ -377,6 +379,14 @@ plog_trait(int opt, char *string) { return 0; } switch (new_trait->field) { + case PSQF_ACCESS: + new_trait->data.ivalue = pseudo_access_fopen(string); + if (new_trait->data.ivalue == (unsigned long long) -1) { + pseudo_diag("access flags should be specified like fopen(3) mode strings.\n"); + free(new_trait); + return 0; + } + break; case PSQF_FTYPE: /* special magic: allow file types ala find */ /* This is implemented by additional magic over in the database code */ @@ -485,9 +495,9 @@ main(int argc, char **argv) { int query_only = 0; int o; int bad_args = 0; - char *format = "%s %-5o %7r: [mode %04m] %p %T"; + char *format = "%s %-5o %7r: [mode %04m, %2a] %p %T"; - while ((o = getopt(argc, argv, "vlc:d:DE:f:F:g:G:hi:I:m:M:o:O:p:r:s:S:t:T:u:")) != -1) { + while ((o = getopt(argc, argv, "vla:c:d:DE:f:F:g:G:hi:I:m:M:o:O:p:r:s:S:t:T:u:")) != -1) { switch (o) { case 'P': setenv("PSEUDO_PREFIX", optarg, 1); @@ -513,6 +523,7 @@ main(int argc, char **argv) { case 'I': /* PSQF_ID */ query_only = 1; /* FALLTHROUGH */ + case 'a': /* PSQF_ACCESS */ case 'c': /* PSQF_CLIENT */ case 'd': /* PSQF_DEV */ case 'f': /* PSQF_FD */ @@ -606,7 +617,7 @@ main(int argc, char **argv) { static char * format_one(log_entry *e, char *format) { char fmtbuf[256]; - size_t len = strcspn(format, "cdfgGimMoprsStTu"), real_len; + size_t len = strcspn(format, "acdfgGimMoprsStTu"), real_len; char scratch[4096]; time_t stamp_sec; struct tm stamp_tm; @@ -634,6 +645,33 @@ format_one(log_entry *e, char *format) { } switch (*s) { + case 'a': /* PSQF_ACCESS */ + if (e->access == -1) { + strcpy(scratch, "invalid"); + } else if (e->access != 0) { + if (e->access & PSA_READ) { + strcpy(scratch, "r"); + if (e->access & PSA_WRITE) + strcat(scratch, "+"); + } else if (e->access & PSA_WRITE) { + if (e->access & PSA_APPEND) { + strcpy(scratch, "a"); + } else { + strcpy(scratch, "w"); + } + if (e->access & PSA_READ) + strcat(scratch, "+"); + } + /* this should be impossible... should. */ + if (e->access & PSA_APPEND && !(e->access & PSA_WRITE)) { + strcat(scratch, "?a"); + } + } else { + strcpy(scratch, "-"); + } + strcpy(s, "s"); + printf(fmtbuf, scratch); + break; case 'c': /* PSQF_CLIENT */ strcpy(s, "d"); printf(fmtbuf, (int) e->client); @@ -690,7 +728,7 @@ format_one(log_entry *e, char *format) { printf(fmtbuf, pseudo_sev_name(e->severity)); break; case 't': /* PSQF_FTYPE */ - strcpy(s, "s"); + strcpy(s, "s"); if (S_ISREG(e->mode)) { strcpy(scratch, "file"); } if (S_ISLNK(e->mode)) { @@ -728,14 +766,20 @@ format_scan(char *format) { pseudo_query_field_t field; for (s = format; (s = strchr(s, '%')) != NULL; ++s) { - len = strcspn(s, "cdfgGimMoprsStTu"); + len = strcspn(s, "acdfgGimMoprsStTu"); s += len; + if (!*s) { + pseudo_diag("Unknown format: '%.3s'\n", + (s - len)); + return -1; + } field = opt_to_field[(unsigned char) *s]; switch (field) { case PSQF_PERM: case PSQF_FTYPE: fields |= (1 << PSQF_MODE); break; + case PSQF_ACCESS: case PSQF_CLIENT: case PSQF_DEV: case PSQF_FD: |