diff options
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: |