aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--doc/database9
-rw-r--r--doc/pseudo_ipc9
-rw-r--r--guts/__fxstat64.c2
-rw-r--r--guts/__fxstatat64.c2
-rw-r--r--guts/__xmknodat.c4
-rw-r--r--guts/chdir.c2
-rw-r--r--guts/chroot.c2
-rw-r--r--guts/close.c2
-rw-r--r--guts/dup.c2
-rw-r--r--guts/dup2.c4
-rw-r--r--guts/fchdir.c2
-rw-r--r--guts/fchmod.c4
-rw-r--r--guts/fchmodat.c6
-rw-r--r--guts/fchown.c6
-rw-r--r--guts/fchownat.c6
-rw-r--r--guts/fclose.c2
-rw-r--r--guts/fcntl.c2
-rw-r--r--guts/fopen.c6
-rw-r--r--guts/fopen64.c6
-rw-r--r--guts/freopen.c6
-rw-r--r--guts/freopen64.c6
-rw-r--r--guts/link.c4
-rw-r--r--guts/mkdirat.c2
-rw-r--r--guts/mkdtemp.c2
-rw-r--r--guts/mkstemp.c6
-rw-r--r--guts/openat.c6
-rw-r--r--guts/rename.c8
-rw-r--r--guts/rmdir.c2
-rw-r--r--guts/symlinkat.c2
-rw-r--r--guts/unlinkat.c2
-rw-r--r--offsets.c28
-rw-r--r--pseudo.c1
-rw-r--r--pseudo.h1
-rw-r--r--pseudo_client.c3
-rw-r--r--pseudo_client.h2
-rw-r--r--pseudo_db.c139
-rw-r--r--pseudo_db.h1
-rw-r--r--pseudo_ipc.h18
-rw-r--r--pseudo_table.c1
-rw-r--r--pseudo_util.c30
-rw-r--r--pseudolog.19
-rw-r--r--pseudolog.c54
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;
diff --git a/guts/dup.c b/guts/dup.c
index 51ba15f..941a5d9 100644
--- a/guts/dup.c
+++ b/guts/dup.c
@@ -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;
diff --git a/offsets.c b/offsets.c
index baf63da..58298ef 100644
--- a/offsets.c
+++ b/offsets.c
@@ -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;
}
diff --git a/pseudo.c b/pseudo.c
index 7e2b3fe..e6e6a39 100644
--- a/pseudo.c
+++ b/pseudo.c
@@ -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) {
diff --git a/pseudo.h b/pseudo.h
index c3a6f31..aec6f60 100644
--- a/pseudo.h
+++ b/pseudo.h
@@ -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: