aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--pseudo.c14
-rw-r--r--pseudo.h4
-rw-r--r--pseudo_client.c19
-rw-r--r--pseudo_db.c110
-rw-r--r--pseudo_db.h6
-rw-r--r--pseudo_ipc.h4
-rw-r--r--pseudo_server.c187
-rw-r--r--pseudo_server.h2
-rw-r--r--pseudo_table.c35
-rw-r--r--pseudolog.140
-rw-r--r--pseudolog.c49
11 files changed, 322 insertions, 148 deletions
diff --git a/pseudo.c b/pseudo.c
index 45537dc..e0e9098 100644
--- a/pseudo.c
+++ b/pseudo.c
@@ -45,7 +45,7 @@ long opt_p = 0;
char *opt_r = NULL;
int opt_S = 0;
-static int pseudo_op(pseudo_msg_t *msg, const char *tag);
+static int pseudo_op(pseudo_msg_t *msg, const char *program, const char *tag);
void
usage(int status) {
@@ -273,7 +273,7 @@ main(int argc, char *argv[]) {
* sanity checks, then implements the fairly small DB changes required.
*/
int
-pseudo_op(pseudo_msg_t *msg, const char *tag) {
+pseudo_op(pseudo_msg_t *msg, const char *program, const char *tag) {
pseudo_msg_t msg_header;
pseudo_msg_t by_path = { .op = 0 }, by_ino = { .op = 0 };
pseudo_msg_t db_header;
@@ -678,27 +678,27 @@ pseudo_op(pseudo_msg_t *msg, const char *tag) {
free(path_by_ino);
pseudo_debug(2, "completed %s.\n", pseudo_op_name(msg->op));
if (opt_l)
- pdb_log_msg(SEVERITY_INFO, msg, tag, NULL);
+ pdb_log_msg(SEVERITY_INFO, msg, program, tag, NULL);
return 0;
}
/* SHUTDOWN does not get this far, it's handled in pseudo_server.c */
int
-pseudo_server_response(pseudo_msg_t *msg, const char *tag) {
+pseudo_server_response(pseudo_msg_t *msg, const char *program, const char *tag) {
switch (msg->type) {
case PSEUDO_MSG_PING:
msg->result = RESULT_SUCCEED;
if (opt_l)
- pdb_log_msg(SEVERITY_INFO, msg, tag, "ping");
+ pdb_log_msg(SEVERITY_INFO, msg, program, tag, NULL);
return 0;
break;
case PSEUDO_MSG_OP:
- return pseudo_op(msg, tag);
+ return pseudo_op(msg, program, tag);
break;
case PSEUDO_MSG_ACK: /* FALLTHROUGH */
case PSEUDO_MSG_NAK: /* FALLTHROUGH */
default:
- pdb_log_msg(SEVERITY_WARN, msg, tag, "invalid message");
+ pdb_log_msg(SEVERITY_WARN, msg, program, tag, "invalid message");
return 1;
}
}
diff --git a/pseudo.h b/pseudo.h
index 85fd3d1..1eed2ce 100644
--- a/pseudo.h
+++ b/pseudo.h
@@ -99,8 +99,8 @@ typedef enum pseudo_query_field {
PSQF_CLIENT, PSQF_DEV, PSQF_FD, PSQF_FTYPE,
PSQF_GID, PSQF_ID, PSQF_INODE, PSQF_MODE,
PSQF_OP, PSQF_ORDER, PSQF_PATH, PSQF_PERM,
- PSQF_RESULT, PSQF_SEVERITY, PSQF_STAMP, PSQF_TAG,
- PSQF_TEXT, PSQF_UID,
+ PSQF_PROGRAM, PSQF_RESULT, PSQF_SEVERITY, PSQF_STAMP,
+ PSQF_TAG, PSQF_TEXT, PSQF_TYPE, PSQF_UID,
PSQF_MAX
} pseudo_query_field_t;
extern char *pseudo_query_field_name(pseudo_query_field_t id);
diff --git a/pseudo_client.c b/pseudo_client.c
index a8550ef..67510db 100644
--- a/pseudo_client.c
+++ b/pseudo_client.c
@@ -37,6 +37,9 @@
#include "pseudo_ipc.h"
#include "pseudo_client.h"
+/* GNU extension */
+extern char *program_invocation_name;
+
static char *base_path(int dirfd, const char *path, int leave_last);
static int connect_fd = -1;
@@ -465,20 +468,24 @@ static int
client_ping(void) {
pseudo_msg_t ping;
pseudo_msg_t *ack;
+ char tagbuf[pseudo_path_max()];
char *tag = getenv("PSEUDO_TAG");
ping.type = PSEUDO_MSG_PING;
ping.op = OP_NONE;
- if (tag) {
- ping.pathlen = strlen(tag);
- } else {
- ping.pathlen = 0;
- }
+
+ if (!tag)
+ tag = "";
+
+ ping.pathlen = snprintf(tagbuf, sizeof(tagbuf), "%s%c%s",
+ program_invocation_name ? program_invocation_name : "<unknown>",
+ 0,
+ tag);
ping.client = getpid();
ping.result = 0;
errno = 0;
pseudo_debug(4, "sending ping\n");
- if (pseudo_msg_send(connect_fd, &ping, ping.pathlen, tag)) {
+ if (pseudo_msg_send(connect_fd, &ping, ping.pathlen, tagbuf)) {
pseudo_debug(3, "error pinging server: %s\n", strerror(errno));
return 1;
}
diff --git a/pseudo_db.c b/pseudo_db.c
index 88fa96a..c256b4a 100644
--- a/pseudo_db.c
+++ b/pseudo_db.c
@@ -223,6 +223,10 @@ static struct sql_migration {
{ "ALTER TABLE logs ADD gid INTEGER;" },
/* track access types (read/write, etc) */
{ "ALTER TABLE logs ADD access INTEGER;" },
+ /* client program/path */
+ { "ALTER TABLE logs ADD program VARCHAR;" },
+ /* message type (ping, op) */
+ { "ALTER TABLE logs ADD type INTEGER;" },
{ NULL },
};
@@ -595,6 +599,10 @@ pdb_log_traits(pseudo_query_t *traits) {
case PSQF_PERM:
e->mode |= (trait->data.ivalue & ~(S_IFMT) & 0177777);
break;
+ case PSQF_PROGRAM:
+ e->program = trait->data.svalue ?
+ strdup(trait->data.svalue) : NULL;
+ break;
case PSQF_RESULT:
e->result = trait->data.ivalue;
break;
@@ -612,6 +620,9 @@ pdb_log_traits(pseudo_query_t *traits) {
e->text = trait->data.svalue ?
strdup(trait->data.svalue) : NULL;
break;
+ case PSQF_TYPE:
+ e->type = trait->data.ivalue;
+ break;
case PSQF_UID:
e->uid = trait->data.ivalue;
break;
@@ -634,9 +645,9 @@ pdb_log_traits(pseudo_query_t *traits) {
int
pdb_log_entry(log_entry *e) {
char *sql = "INSERT INTO logs "
- "(stamp, op, access, client, dev, gid, ino, mode, path, result, severity, text, tag, uid)"
+ "(stamp, op, access, client, dev, gid, ino, mode, path, result, severity, text, program, tag, type, uid)"
" VALUES "
- "(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?);";
+ "(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?);";
static sqlite3_stmt *insert;
int field;
int rc;
@@ -680,11 +691,17 @@ pdb_log_entry(log_entry *e) {
} else {
sqlite3_bind_null(insert, field++);
}
+ if (e->program) {
+ sqlite3_bind_text(insert, field++, e->program, -1, SQLITE_STATIC);
+ } else {
+ sqlite3_bind_null(insert, field++);
+ }
if (e->tag) {
sqlite3_bind_text(insert, field++, e->tag, -1, SQLITE_STATIC);
} else {
sqlite3_bind_null(insert, field++);
}
+ sqlite3_bind_int(insert, field++, e->type);
sqlite3_bind_int(insert, field++, e->uid);
} else {
sqlite3_bind_int(insert, field++, (unsigned long) time(NULL));
@@ -700,6 +717,8 @@ pdb_log_entry(log_entry *e) {
sqlite3_bind_int(insert, field++, 0);
sqlite3_bind_null(insert, field++);
sqlite3_bind_null(insert, field++);
+ sqlite3_bind_null(insert, field++);
+ sqlite3_bind_int(insert, field++, 0);
sqlite3_bind_int(insert, field++, 0);
}
@@ -713,11 +732,11 @@ pdb_log_entry(log_entry *e) {
}
/* create a log from a given message, with tag and text */
int
-pdb_log_msg(sev_id_t severity, pseudo_msg_t *msg, const char *tag, const char *text, ...) {
+pdb_log_msg(sev_id_t severity, pseudo_msg_t *msg, const char *program, const char *tag, const char *text, ...) {
char *sql = "INSERT INTO logs "
- "(stamp, op, access, client, dev, gid, ino, mode, path, result, uid, severity, text, tag)"
+ "(stamp, op, access, client, dev, gid, ino, mode, path, result, uid, severity, text, program, tag, type)"
" VALUES "
- "(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?);";
+ "(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?);";
static sqlite3_stmt *insert;
char buffer[8192];
int field;
@@ -779,11 +798,21 @@ pdb_log_msg(sev_id_t severity, pseudo_msg_t *msg, const char *tag, const char *t
} else {
sqlite3_bind_null(insert, field++);
}
+ if (program) {
+ sqlite3_bind_text(insert, field++, program, -1, SQLITE_STATIC);
+ } else {
+ sqlite3_bind_null(insert, field++);
+ }
if (tag) {
sqlite3_bind_text(insert, field++, tag, -1, SQLITE_STATIC);
} else {
sqlite3_bind_null(insert, field++);
}
+ if (msg) {
+ sqlite3_bind_int(insert, field++, msg->type);
+ } else {
+ sqlite3_bind_int(insert, field++, 0);
+ }
rc = sqlite3_step(insert);
if (rc != SQLITE_DONE) {
@@ -844,7 +873,7 @@ frag(buffer *b, char *fmt, ...) {
}
log_history
-pdb_history(pseudo_query_t *traits, unsigned long fields, int distinct) {
+pdb_history(pseudo_query_t *traits, unsigned long fields, int unique, int do_delete) {
log_history h = NULL;
pseudo_query_t *trait;
sqlite3_stmt *select;
@@ -856,7 +885,6 @@ pdb_history(pseudo_query_t *traits, unsigned long fields, int distinct) {
pseudo_query_field_t f;
static buffer *sql;
- /* this column arrangement is used by pdb_history_entry() */
if (!sql) {
sql = malloc(sizeof *sql);
if (!sql) {
@@ -872,23 +900,28 @@ pdb_history(pseudo_query_t *traits, unsigned long fields, int distinct) {
}
}
sql->tail = sql->data;
- frag(sql, "SELECT ");
+ if (do_delete)
+ frag(sql, "DELETE ");
+ else
+ frag(sql, "SELECT ");
if (!log_db && get_db(&log_db)) {
pseudo_diag("database error.\n");
return 0;
}
- if (distinct)
- frag(sql, "DISTINCT ");
+ if (!do_delete) {
+ if (unique)
+ frag(sql, "DISTINCT ");
- done_any = 0;
- for (f = PSQF_NONE + 1; f < PSQF_MAX; ++f) {
- if (fields & (1 << f)) {
- frag(sql, "%s%s",
- done_any ? ", " : "",
- pseudo_query_field_name(f));
- done_any = 1;
+ done_any = 0;
+ for (f = PSQF_NONE + 1; f < PSQF_MAX; ++f) {
+ if (fields & (1 << f)) {
+ frag(sql, "%s%s",
+ done_any ? ", " : "",
+ pseudo_query_field_name(f));
+ done_any = 1;
+ }
}
}
@@ -905,6 +938,7 @@ pdb_history(pseudo_query_t *traits, unsigned long fields, int distinct) {
}
}
switch (trait->field) {
+ case PSQF_PROGRAM: /* FALLTHROUGH */
case PSQF_TEXT: /* FALLTHROUGH */
case PSQF_TAG: /* FALLTHROUGH */
case PSQF_PATH:
@@ -996,13 +1030,14 @@ pdb_history(pseudo_query_t *traits, unsigned long fields, int distinct) {
break;
}
}
- frag(sql, "ORDER BY %s %s;", order_by, order_dir);
+ if (!do_delete)
+ frag(sql, "ORDER BY %s %s;", order_by, order_dir);
pseudo_debug(1, "created SQL: <%s>\n", sql->data);
/* second, prepare it */
rc = sqlite3_prepare_v2(log_db, sql->data, strlen(sql->data), &select, NULL);
if (rc) {
- dberr(log_db, "couldn't prepare SELECT statement");
+ dberr(log_db, "couldn't prepare %s statement", do_delete ? "DELETE" : "SELECT");
return 0;
}
@@ -1013,6 +1048,7 @@ pdb_history(pseudo_query_t *traits, unsigned long fields, int distinct) {
case PSQF_ORDER:
/* this just creates a hunk of SQL above */
break;
+ case PSQF_PROGRAM: /* FALLTHROUGH */
case PSQF_PATH: /* FALLTHROUGH */
case PSQF_TAG: /* FALLTHROUGH */
case PSQF_TEXT:
@@ -1032,6 +1068,7 @@ pdb_history(pseudo_query_t *traits, unsigned long fields, int distinct) {
case PSQF_RESULT: /* FALLTHROUGH */
case PSQF_SEVERITY: /* FALLTHROUGH */
case PSQF_STAMP: /* FALLTHROUGH */
+ case PSQF_TYPE: /* FALLTHROUGH */
case PSQF_UID: /* FALLTHROUGH */
sqlite3_bind_int(select, field++, trait->data.ivalue);
break;
@@ -1042,6 +1079,16 @@ pdb_history(pseudo_query_t *traits, unsigned long fields, int distinct) {
}
}
+ if (do_delete) {
+ /* no need to return it, so... */
+ int rc = sqlite3_step(select);
+ if (rc != SQLITE_DONE) {
+ dberr(log_db, "deletion failed");
+ }
+ sqlite3_finalize(select);
+ return 0;
+ }
+
/* fourth, return the statement, now ready to be stepped through */
h = malloc(sizeof(*h));
if (h) {
@@ -1114,6 +1161,11 @@ pdb_history_entry(log_history h) {
if (s)
l->path = strdup((char *) s);
break;
+ case PSQF_PROGRAM:
+ s = sqlite3_column_text(h->stmt, column++);
+ if (s)
+ l->program = strdup((char *) s);
+ break;
case PSQF_RESULT:
l->result = sqlite3_column_int64(h->stmt, column++);
break;
@@ -1133,6 +1185,9 @@ pdb_history_entry(log_history h) {
if (s)
l->text = strdup((char *) s);
break;
+ case PSQF_TYPE:
+ l->type = sqlite3_column_int64(h->stmt, column++);
+ break;
case PSQF_UID:
l->uid = sqlite3_column_int64(h->stmt, column++);
break;
@@ -1170,6 +1225,7 @@ log_entry_free(log_entry *e) {
return;
free(e->text);
free(e->path);
+ free(e->program);
free(e->tag);
free(e);
}
@@ -1228,7 +1284,7 @@ pdb_link_file(pseudo_msg_t *msg) {
/* pdb_unlink_file_dev: Delete every instance of a dev/inode pair. */
int
pdb_unlink_file_dev(pseudo_msg_t *msg) {
- static sqlite3_stmt *delete;
+ static sqlite3_stmt *sql_delete;
int rc;
char *sql = "DELETE FROM files WHERE dev = ? AND ino = ?;";
@@ -1236,8 +1292,8 @@ pdb_unlink_file_dev(pseudo_msg_t *msg) {
pseudo_diag("database error.\n");
return 0;
}
- if (!delete) {
- rc = sqlite3_prepare_v2(file_db, sql, strlen(sql), &delete, NULL);
+ if (!sql_delete) {
+ rc = sqlite3_prepare_v2(file_db, sql, strlen(sql), &sql_delete, NULL);
if (rc) {
dberr(file_db, "couldn't prepare DELETE statement");
return 1;
@@ -1246,14 +1302,14 @@ pdb_unlink_file_dev(pseudo_msg_t *msg) {
if (!msg) {
return 1;
}
- sqlite3_bind_int(delete, 1, msg->dev);
- sqlite3_bind_int(delete, 2, msg->ino);
- rc = sqlite3_step(delete);
+ sqlite3_bind_int(sql_delete, 1, msg->dev);
+ sqlite3_bind_int(sql_delete, 2, msg->ino);
+ rc = sqlite3_step(sql_delete);
if (rc != SQLITE_DONE) {
dberr(file_db, "delete by inode may have failed");
}
- sqlite3_reset(delete);
- sqlite3_clear_bindings(delete);
+ sqlite3_reset(sql_delete);
+ sqlite3_clear_bindings(sql_delete);
return rc != SQLITE_DONE;
}
diff --git a/pseudo_db.h b/pseudo_db.h
index 9b82c53..aeacc95 100644
--- a/pseudo_db.h
+++ b/pseudo_db.h
@@ -19,6 +19,7 @@
*/
typedef struct {
time_t stamp;
+ pseudo_msg_type_t type;
op_id_t op;
int access;
unsigned long client;
@@ -33,6 +34,7 @@ typedef struct {
sev_id_t severity;
char *text;
char *tag;
+ char *program;
} log_entry;
extern int pdb_link_file(pseudo_msg_t *msg);
@@ -63,10 +65,10 @@ typedef struct pseudo_query {
} pseudo_query_t;
extern int pdb_log_entry(log_entry *e);
-extern int pdb_log_msg(sev_id_t severity, pseudo_msg_t *msg, const char *tag, const char *text, ...);
+extern int pdb_log_msg(sev_id_t severity, pseudo_msg_t *msg, const char *program, const char *tag, const char *text, ...);
extern int pdb_log_traits(pseudo_query_t *traits);
-extern log_history pdb_history(pseudo_query_t *traits, unsigned long fields, int distinct);
+extern log_history pdb_history(pseudo_query_t *traits, unsigned long fields, int unique, int delete);
extern log_entry *pdb_history_entry(log_history h);
extern void pdb_history_free(log_history h);
extern void log_entry_free(log_entry *);
diff --git a/pseudo_ipc.h b/pseudo_ipc.h
index 063a1ef..664cbd2 100644
--- a/pseudo_ipc.h
+++ b/pseudo_ipc.h
@@ -18,6 +18,8 @@
*
*/
typedef enum {
+ PSEUDO_MSG_UNKNOWN = -1,
+ PSEUDO_MSG_NONE,
PSEUDO_MSG_PING,
PSEUDO_MSG_SHUTDOWN,
PSEUDO_MSG_OP,
@@ -25,6 +27,8 @@ typedef enum {
PSEUDO_MSG_NAK,
PSEUDO_MSG_MAX
} pseudo_msg_type_t;
+extern char *pseudo_msg_type_name(pseudo_msg_type_t id);
+extern pseudo_msg_type_t pseudo_msg_type_id(char *name);
/* The [] item at the end of the struct is a C99 feature, replacing the
* old (and unportable) "struct hack".
diff --git a/pseudo_server.c b/pseudo_server.c
index 4a474d0..931f77c 100644
--- a/pseudo_server.c
+++ b/pseudo_server.c
@@ -42,9 +42,15 @@
static int listen_fd = -1;
-int *client_fds;
-pid_t *client_pids;
-char **client_tags;
+typedef struct {
+ int fd;
+ pid_t pid;
+ char *tag;
+ char *program;
+} pseudo_client_t;
+
+pseudo_client_t *clients;
+
/* active_clients: Number of clients we actually have right now.
* highest_client: Highest index into clients table of an active client.
* max_clients: Size of table.
@@ -178,18 +184,17 @@ pseudo_server_start(int daemonize) {
/* mess with internal tables as needed */
static void
open_client(int fd) {
- int *new_client_fds;
- pid_t *new_client_pids;
- char **new_client_tags;
+ pseudo_client_t *new_clients;
int i;
/* if possible, use first open client slot */
for (i = 0; i < max_clients; ++i) {
- if (client_fds[i] == -1) {
+ if (clients[i].fd == -1) {
pseudo_debug(2, "reusing client %d for fd %d\n", i, fd);
- client_fds[i] = fd;
- client_pids[i] = 0;
- client_tags[i] = 0;
+ clients[i].fd = fd;
+ clients[i].pid = 0;
+ clients[i].tag = NULL;
+ clients[i].program = NULL;
++active_clients;
if (i > highest_client)
highest_client = i;
@@ -198,37 +203,26 @@ open_client(int fd) {
}
/* otherwise, allocate a new one */
- new_client_fds = malloc(sizeof(int) * (max_clients + 16));
- new_client_pids = malloc(sizeof(pid_t) * (max_clients + 16));
- new_client_tags = malloc(sizeof(char *) * (max_clients + 16));
- if (new_client_fds && new_client_pids && new_client_tags) {
- memcpy(new_client_fds, client_fds, max_clients * sizeof(int));
- memcpy(new_client_pids, client_pids, max_clients * sizeof(pid_t));
- memcpy(new_client_tags, client_tags, max_clients * sizeof(char *));
- free(client_fds);
- free(client_pids);
- free(client_tags);
+ new_clients = malloc(sizeof(*new_clients) * (max_clients + 16));
+ if (new_clients) {
+ memcpy(new_clients, clients, max_clients * sizeof(*clients));
+ free(clients);
for (i = max_clients; i < max_clients + 16; ++i) {
- new_client_fds[i] = -1;
- new_client_pids[i] = 0;
- new_client_tags[i] = 0;
+ new_clients[i].fd = -1;
+ new_clients[i].pid = 0;
+ new_clients[i].tag = NULL;
+ new_clients[i].program = NULL;
}
- client_fds = new_client_fds;
- client_pids = new_client_pids;
- client_tags = new_client_tags;
-
- client_fds[max_clients] = fd;
- client_pids[max_clients] = 0;
- client_tags[max_clients] = 0;
+ clients = new_clients;
+ clients[max_clients].fd = fd;
+ clients[max_clients].pid = 0;
+ clients[max_clients].tag = NULL;
+ clients[max_clients].program = NULL;
highest_client = max_clients + 1;
max_clients += 16;
++active_clients;
} else {
- /* if something got allocated, free it */
- free(new_client_fds);
- free(new_client_pids);
- free(new_client_tags);
pseudo_diag("error allocating new client, fd %d\n", fd);
close(fd);
}
@@ -239,16 +233,24 @@ open_client(int fd) {
*/
static void
close_client(int client) {
- pseudo_debug(2, "lost client %d [%d], closing fd %d\n", client, client_pids[client], client_fds[client]);
+ pseudo_debug(2, "lost client %d [%d], closing fd %d\n", client,
+ clients[client].pid, clients[client].fd);
/* client went away... */
- close(client_fds[client]);
- client_fds[client] = -1;
- free(client_tags[client]);
- client_tags[client] = 0;
- client_pids[client] = 0;
+ if (client > highest_client || client <= 0) {
+ pseudo_diag("tried to close client %d (highest is %d)\n",
+ client, highest_client);
+ return;
+ }
+ close(clients[client].fd);
+ clients[client].fd = -1;
+ free(clients[client].tag);
+ free(clients[client].program);
+ clients[client].pid = 0;
+ clients[client].tag = NULL;
+ clients[client].program = NULL;
--active_clients;
if (client == highest_client)
- while (client_fds[highest_client] != -1 && highest_client > 0)
+ while (clients[highest_client].fd != -1 && highest_client > 0)
--highest_client;
}
@@ -259,34 +261,50 @@ serve_client(int i) {
pseudo_msg_t *in;
int rc;
- pseudo_debug(2, "message from client %d [%d:%s] fd %d\n",
- i, (int) client_pids[i],
- client_tags[i] ? client_tags[i] : "NO TAG",
- client_fds[i]);
- in = pseudo_msg_receive(client_fds[i]);
+ pseudo_debug(2, "message from client %d [%d:%s - %s] fd %d\n",
+ i, (int) clients[i].pid,
+ clients[i].program ? clients[i].program : "???",
+ clients[i].tag ? clients[i].tag : "NO TAG",
+ clients[i].fd);
+ in = pseudo_msg_receive(clients[i].fd);
if (in) {
char *response_path = 0;
pseudo_debug(4, "got a message (%d): %s\n", in->type, (in->pathlen ? in->path : "<no path>"));
/* handle incoming ping */
- if (in->type == PSEUDO_MSG_PING && !client_pids[i]) {
- pseudo_debug(2, "new client: %d -> %d\n",
+ if (in->type == PSEUDO_MSG_PING && !clients[i].pid) {
+ pseudo_debug(2, "new client: %d -> %d",
i, in->client);
- client_pids[i] = in->client;
+ clients[i].pid = in->client;
if (in->pathlen) {
- free(client_tags[i]);
- client_tags[i] = strdup(in->path);
+ size_t proglen;
+ proglen = strlen(in->path);
+
+ pseudo_debug(2, " <%s>", in->path);
+ free(clients[i].program);
+ clients[i].program = malloc(proglen + 1);
+ if (clients[i].program) {
+ snprintf(clients[i].program, proglen + 1, "%s", in->path);
+ }
+ if (in->pathlen > proglen) {
+ pseudo_debug(2, " [%s]", in->path + proglen + 1);
+ clients[i].tag = malloc(in->pathlen - proglen);
+ if (clients[i].tag)
+ snprintf(clients[i].tag, in->pathlen - proglen,
+ "%s", in->path + proglen + 1);
+ }
}
+ pseudo_debug(2, "\n");
}
/* sanity-check client ID */
- if (in->client != client_pids[i]) {
+ if (in->client != clients[i].pid) {
pseudo_debug(1, "uh-oh, expected pid %d for client %d, got %d\n",
- (int) client_pids[i], i, in->client);
+ (int) clients[i].pid, i, in->client);
}
/* regular requests are processed in place by
* pseudo_server_response.
*/
if (in->type != PSEUDO_MSG_SHUTDOWN) {
- if (pseudo_server_response(in, client_tags[i])) {
+ if (pseudo_server_response(in, clients[i].program, clients[i].tag)) {
in->type = PSEUDO_MSG_NAK;
} else {
in->type = PSEUDO_MSG_ACK;
@@ -312,8 +330,8 @@ serve_client(int i) {
in->fd = active_clients - 2;
s = response_path;
for (j = 1; j <= highest_client; ++j) {
- if (client_fds[j] != -1 && j != i) {
- s += snprintf(s, 8, "%d ", (int) client_pids[j]);
+ if (clients[j].fd != -1 && j != i) {
+ s += snprintf(s, 8, "%d ", (int) clients[j].pid);
}
}
in->pathlen = (s - response_path) + 1;
@@ -328,7 +346,7 @@ serve_client(int i) {
}
if ((rc = pseudo_msg_send(clients[i].fd, in, -1, response_path)) != 0)
pseudo_debug(1, "failed to send response to client %d [%d]: %d (%s)\n",
- i, (int) client_pids[i], rc, strerror(errno));
+ i, (int) clients[i].pid, rc, strerror(errno));
rc = in->op;
free(response_path);
return rc;
@@ -336,7 +354,7 @@ serve_client(int i) {
/* this should not be happening, but the exceptions aren't
* being detected in select() for some reason.
*/
- pseudo_debug(2, "client %d: no message\n", (int) client_pids[i]);
+ pseudo_debug(2, "client %d: no message\n", (int) clients[i].pid);
close_client(i);
return 0;
}
@@ -358,17 +376,16 @@ pseudo_server_loop(void) {
int fd;
int loop_timeout = pseudo_server_timeout;
- client_fds = malloc(sizeof(int) * 16);
- client_pids = malloc(sizeof(pid_t) * 16);
- client_tags = malloc(sizeof(char *) * 16);
+ clients = malloc(16 * sizeof(*clients));
- client_fds[0] = listen_fd;
- client_pids[0] = getpid();
+ clients[0].fd = listen_fd;
+ clients[0].pid = getpid();
for (i = 1; i < 16; ++i) {
- client_fds[i] = -1;
- client_pids[i] = 0;
- client_tags[i] = 0;
+ clients[i].fd = -1;
+ clients[i].pid = 0;
+ clients[i].tag = NULL;
+ clients[i].program = NULL;
}
active_clients = 1;
@@ -380,14 +397,14 @@ pseudo_server_loop(void) {
pseudo_diag("got into loop with no valid listen fd.\n");
exit(1);
}
- pdb_log_msg(SEVERITY_INFO, NULL, NULL, "server started (pid %d)", getpid());
+ pdb_log_msg(SEVERITY_INFO, NULL, NULL, NULL, "server started (pid %d)", getpid());
FD_ZERO(&reads);
FD_ZERO(&writes);
FD_ZERO(&events);
- FD_SET(client_fds[0], &reads);
- FD_SET(client_fds[0], &events);
- max_fd = client_fds[0];
+ FD_SET(clients[0].fd, &reads);
+ FD_SET(clients[0].fd, &events);
+ max_fd = clients[0].fd;
timeout = (struct timeval) { .tv_sec = LOOP_DELAY, .tv_usec = 0 };
/* EINTR tends to come from profiling, so it is not a good reason to
@@ -414,12 +431,12 @@ pseudo_server_loop(void) {
} else if (rc > 0) {
loop_timeout = pseudo_server_timeout;
for (i = 1; i <= highest_client; ++i) {
- if (client_fds[i] == -1)
+ if (clients[i].fd == -1)
continue;
- if (FD_ISSET(client_fds[i], &events)) {
+ if (FD_ISSET(clients[i].fd, &events)) {
/* this should happen but doesn't... */
close_client(i);
- } else if (FD_ISSET(client_fds[i], &reads)) {
+ } else if (FD_ISSET(clients[i].fd, &reads)) {
struct timeval tv1, tv2;
int op;
gettimeofday(&tv1, NULL);
@@ -440,8 +457,8 @@ pseudo_server_loop(void) {
break;
}
if (!(die_peacefully || die_forcefully) &&
- (FD_ISSET(client_fds[0], &events) ||
- FD_ISSET(client_fds[0], &reads))) {
+ (FD_ISSET(clients[0].fd, &events) ||
+ FD_ISSET(clients[0].fd, &reads))) {
len = sizeof(client);
if ((fd = accept(listen_fd, (struct sockaddr *) &client, &len)) != -1) {
pseudo_debug(2, "new client fd %d\n", fd);
@@ -456,31 +473,31 @@ pseudo_server_loop(void) {
getpid(), messages,
(double) message_time.tv_sec +
(double) message_time.tv_usec / 1000000.0);
- pdb_log_msg(SEVERITY_INFO, NULL, NULL, "server %d exiting: handled %d messages in %.4f seconds",
+ pdb_log_msg(SEVERITY_INFO, NULL, NULL, NULL, "server %d exiting: handled %d messages in %.4f seconds",
getpid(), messages,
(double) message_time.tv_sec +
(double) message_time.tv_usec / 1000000.0);
- close(client_fds[0]);
+ close(clients[0].fd);
exit(0);
}
FD_ZERO(&reads);
FD_ZERO(&writes);
FD_ZERO(&events);
- FD_SET(client_fds[0], &reads);
- FD_SET(client_fds[0], &events);
- max_fd = client_fds[0];
+ FD_SET(clients[0].fd, &reads);
+ FD_SET(clients[0].fd, &events);
+ max_fd = clients[0].fd;
/* current_clients is a sanity check; note that for
* purposes of select(), the server is one of the fds,
* and thus, "a client".
*/
current_clients = 1;
for (i = 1; i <= highest_client; ++i) {
- if (client_fds[i] != -1) {
+ if (clients[i].fd != -1) {
++current_clients;
- FD_SET(client_fds[i], &reads);
- FD_SET(client_fds[i], &events);
- if (client_fds[i] > max_fd)
- max_fd = client_fds[i];
+ FD_SET(clients[i].fd, &reads);
+ FD_SET(clients[i].fd, &events);
+ if (clients[i].fd > max_fd)
+ max_fd = clients[i].fd;
}
}
if (current_clients != active_clients) {
diff --git a/pseudo_server.h b/pseudo_server.h
index 5e2ea6b..5c595ea 100644
--- a/pseudo_server.h
+++ b/pseudo_server.h
@@ -18,6 +18,6 @@
*
*/
extern int pseudo_server_start(int);
-extern int pseudo_server_response(pseudo_msg_t *msg, const char *tag);
+extern int pseudo_server_response(pseudo_msg_t *msg, const char *program, const char *tag);
extern int pseudo_server_timeout;
extern int opt_l;
diff --git a/pseudo_table.c b/pseudo_table.c
index 7225422..4c49f3d 100644
--- a/pseudo_table.c
+++ b/pseudo_table.c
@@ -17,9 +17,12 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
-#include "pseudo.h"
#include <stdlib.h>
#include <string.h>
+#include <sys/stat.h>
+
+#include "pseudo.h"
+#include "pseudo_ipc.h"
/* just a bunch of handy lookups for pretty-printing stuff */
@@ -106,15 +109,27 @@ static char *query_field_names[] = {
"order",
"path",
"perm",
+ "program",
"result",
"severity",
"stamp",
"tag",
"text",
+ "type",
"uid",
NULL
};
+static char *pseudo_msg_type_names[] = {
+ "none",
+ "ping",
+ "halt",
+ "op",
+ "ack",
+ "nak",
+ NULL
+};
+
char *
pseudo_op_name(op_id_t id) {
if (id >= OP_NONE && id < OP_MAX) {
@@ -163,6 +178,14 @@ pseudo_query_field_name(pseudo_query_field_t id) {
return "unknown";
}
+char *
+pseudo_msg_type_name(pseudo_msg_type_t id) {
+ if (id >= PSEUDO_MSG_NONE && id < PSEUDO_MSG_MAX) {
+ return pseudo_msg_type_names[id];
+ }
+ return "????";
+}
+
op_id_t
pseudo_op_id(char *name) {
int id;
@@ -212,3 +235,13 @@ pseudo_query_field(char *name) {
}
return PSQF_UNKNOWN;
}
+
+pseudo_msg_type_t
+pseudo_msg_type_id(char *name) {
+ int id;
+ for (id = PSEUDO_MSG_NONE; id < PSEUDO_MSG_MAX; ++id) {
+ if (!strcmp(name, pseudo_msg_type_names[id]))
+ return id;
+ }
+ return PSEUDO_MSG_NONE;;
+}
diff --git a/pseudolog.1 b/pseudolog.1
index b7c9bbb..f11751f 100644
--- a/pseudolog.1
+++ b/pseudolog.1
@@ -26,7 +26,7 @@
.RI [ SPECIFICATIONS ]
.PP
.B pseudolog
-.RB [ \-DPv ]
+.RB [ \-UPv ]
[
.B \-E
.I timeformat
@@ -37,13 +37,21 @@
]
.PP
.B pseudolog \-h
+.PP
+.B pseudolog \-D
+.RB [ \-Pv ]
+[
+.B \-E
+.I timeformat
+]
+.RI [ SPECIFICATIONS ]
.RI [ SPECIFICATIONS ]
.SH DESCRIPTION
The
.I pseudolog
-utility displays log entries created by the
+utility displays, creates, or deletes log entries associated with the
.I pseudo
-daemon, or creates log entries. Creation of log entries is useful only to
+daemon. Creation of log entries is useful only to
create timestamps or notes; for instance, you could create a log entry before
beginning a process, so there would be a timestamp for the beginning of
that process. There are a number of special options used to match or create
@@ -60,11 +68,7 @@ The following other options are supported:
Print a usage message and exit.
.TP 8
.B \-D
-Restrict query output to distinct rows. Rows will have members defined by
-the
-.B \-F
-(format) option. If all members are the same between two rows, only one
-is displayed. Applies only to queries.
+Delete rows selected by the query. This is not reversible.
.TP 8
.BI \-E \ timeformat
Specify a format string (for
@@ -97,6 +101,13 @@ should be used as the
.B PSEUDO_PREFIX
value, overriding any environment setting.
.TP 8
+.B \-U
+Restrict query output to unique rows. Rows will have members defined by
+the
+.B \-F
+(format) option. If all members are the same between two rows, only one
+is displayed. Applies only to queries.
+.TP 8
.B \-v
Increase verbosity (debug level). Not useful except when debugging pseudo.
@@ -261,6 +272,12 @@ usually means that there was no entry in the
.I pseudo
database.
.TP 8
+.B R
+Program. This is the program name (as retrieved by glibc's
+.I program_invocation_name
+variable), which has the full path if and only if the program
+was invoked by full path name.
+.TP 8
.B s
Timestamp. The format of this field is controlled by the
.B \-E
@@ -291,6 +308,13 @@ logged. It is, of course, a text field.
.TP 8
.B u
UID. The user ID associated with an entry.
+.TP 8
+.B y
+Type. This is usually "op" for operations, or "ping" for the ping
+messages clients send to confirm server availability. Other types
+should rarely occur, but include "ack" and "nak" for server
+responses (which are never logged), and "halt" for shutdown messages
+(currently not logged).
.SH EXAMPLES
The following examples illustrate some of the likely usage patterns for
diff --git a/pseudolog.c b/pseudolog.c
index 9cf2134..aaaab28 100644
--- a/pseudolog.c
+++ b/pseudolog.c
@@ -35,6 +35,7 @@
#include "pseudo_db.h"
static int opt_D = 0;
+static int opt_U = 0;
static int opt_l = 0;
static void display(log_entry *, char *format);
@@ -56,12 +57,14 @@ usage(int status) {
"o operation (e.g. 'open')",
"O order by (< DESC > ASC)",
"p file path",
+ "P program",
"r result (e.g. 'succeed')",
"s timestamp",
"S severity",
"t type (like find -type)",
"T text (text field)",
"u uid",
+ "y type (op/ping/shutown)",
NULL,
};
FILE *f = (status == EXIT_SUCCESS) ? stdout : stderr;
@@ -69,7 +72,8 @@ usage(int status) {
fputs("pseudolog: create or report log entries. usage:\n", f);
fputs("pseudolog -l [-E timeformat] [SPECIFIERS] -- create entries\n", f);
- fputs("pseudolog [-D] [-F format] [-E timeformat] [SPECIFIERS] -- report entries\n", f);
+ fputs("pseudolog [-U] [-F format] [-E timeformat] [SPECIFIERS] -- report entries\n", f);
+ fputs("pseudolog -D [-E timeformat] [SPECIFIERS] -- delete entries\n", f);
fputs(" format is a printf-like format string using the option letters\n", f);
fputs(" listed below as format specifiers for the corresponding field.\n", f);
fputs(" timeformat is a strftime-like format string, the default is '%x %X'.\n", f);
@@ -85,6 +89,9 @@ usage(int status) {
for (i = 0; options[i]; ++i) {
fprintf(f, " %-28s%s", options[i], (i % 2) ? "\n" : " ");
}
+ if (i % 2 == 1) {
+ fprintf(f, "\n");
+ }
exit(status);
}
@@ -103,11 +110,13 @@ pseudo_query_field_t opt_to_field[UCHAR_MAX + 1] = {
['O'] = PSQF_ORDER,
['p'] = PSQF_PATH,
['r'] = PSQF_RESULT,
+ ['R'] = PSQF_PROGRAM,
['s'] = PSQF_STAMP,
['S'] = PSQF_SEVERITY,
['t'] = PSQF_FTYPE,
['T'] = PSQF_TEXT,
['u'] = PSQF_UID,
+ ['y'] = PSQF_TYPE,
};
pseudo_query_type_t
@@ -175,7 +184,7 @@ static char *time_formats[] = {
"%T",
NULL,
};
-static char *timeformat = "%x %X";
+static char *timeformat = "%X";
mode_t
parse_file_type(char *string) {
@@ -432,6 +441,9 @@ plog_trait(int opt, char *string) {
return 0;
}
break;
+ case PSQF_TYPE:
+ new_trait->data.ivalue = pseudo_msg_type_id(string);
+ break;
case PSQF_CLIENT:
case PSQF_DEV:
case PSQF_FD:
@@ -464,6 +476,7 @@ plog_trait(int opt, char *string) {
}
break;
case PSQF_PATH: /* FALLTHROUGH */
+ case PSQF_PROGRAM: /* FALLTHROUGH */
case PSQF_TEXT: /* FALLTHROUGH */
case PSQF_TAG:
/* Plain strings */
@@ -495,9 +508,9 @@ main(int argc, char **argv) {
int query_only = 0;
int o;
int bad_args = 0;
- char *format = "%s %-7o %7r: [mode %04m, %2a] %p %T";
+ char *format = "%s %-12.12R %-4y %7o: [mode %04m, %2a] %p %T";
- 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) {
+ while ((o = getopt(argc, argv, "vla:c:d:DE:f:F:g:G:hi:I:m:M:o:O:p:r:R:s:S:t:T:u:Uy:")) != -1) {
switch (o) {
case 'P':
setenv("PSEUDO_PREFIX", optarg, 1);
@@ -520,6 +533,10 @@ main(int argc, char **argv) {
format = strdup(optarg);
query_only = 1;
break;
+ case 'U':
+ opt_U = 1;
+ query_only = 1;
+ break;
case 'I': /* PSQF_ID */
query_only = 1;
/* FALLTHROUGH */
@@ -536,11 +553,13 @@ main(int argc, char **argv) {
case 'O': /* PSQF_ORDER */
case 'p': /* PSQF_PATH */
case 'r': /* PSQF_RESULT */
+ case 'R': /* PSQF_PROGRAM */
case 's': /* PSQF_STAMP */
case 'S': /* PSQF_SEVERITY */
case 't': /* PSQF_FTYPE */
case 'T': /* PSQF_TEXT */
case 'u': /* PSQF_UID */
+ case 'y': /* PSQF_TYPE */
new_trait = plog_trait(o, optarg);
if (!new_trait) {
bad_args = 1;
@@ -595,7 +614,7 @@ main(int argc, char **argv) {
pseudo_diag("couldn't parse format string (%s).\n", format);
return EXIT_FAILURE;
}
- history = pdb_history(traits, fields, opt_D);
+ history = pdb_history(traits, fields, opt_U, opt_D);
if (history) {
log_entry *e;
while ((e = pdb_history_entry(history)) != NULL) {
@@ -604,8 +623,10 @@ main(int argc, char **argv) {
}
pdb_history_free(history);
} else {
- pseudo_diag("could not retrieve history.\n");
- return EXIT_FAILURE;
+ if (!opt_D) {
+ pseudo_diag("could not retrieve history.\n");
+ return EXIT_FAILURE;
+ }
}
}
return 0;
@@ -617,7 +638,7 @@ main(int argc, char **argv) {
static char *
format_one(log_entry *e, char *format) {
char fmtbuf[256];
- size_t len = strcspn(format, "acdfgGimMoprsStTu"), real_len;
+ size_t len = strcspn(format, "acdfgGimMoprRsStTuy"), real_len;
char scratch[4096];
time_t stamp_sec;
struct tm stamp_tm;
@@ -719,6 +740,10 @@ format_one(log_entry *e, char *format) {
strcpy(s, "s");
printf(fmtbuf, pseudo_res_name(e->result));
break;
+ case 'R': /* PSQF_PROGRAM */
+ strcpy(s, "s");
+ printf(fmtbuf, e->program ? e->program : "");
+ break;
case 's': /* PSQF_STAMP */
strcpy(s, "s");
stamp_sec = e->stamp;
@@ -757,6 +782,10 @@ format_one(log_entry *e, char *format) {
strcpy(s, "d");
printf(fmtbuf, (int) e->uid);
break;
+ case 'y': /* PSQF_TYPE */
+ strcpy(s, "s");
+ printf(fmtbuf, pseudo_msg_type_name(e->type));
+ break;
}
return format + len;
}
@@ -769,7 +798,7 @@ format_scan(char *format) {
pseudo_query_field_t field;
for (s = format; (s = strchr(s, '%')) != NULL; ++s) {
- len = strcspn(s, "acdfgGimMoprsStTu");
+ len = strcspn(s, "acdfgGimMoprRsStTuy");
s += len;
if (!*s) {
pseudo_diag("Unknown format: '%.3s'\n",
@@ -792,10 +821,12 @@ format_scan(char *format) {
case PSQF_MODE: /* FALLTHROUGH */
case PSQF_OP: /* FALLTHROUGH */
case PSQF_PATH: /* FALLTHROUGH */
+ case PSQF_PROGRAM: /* FALLTHROUGH */
case PSQF_RESULT: /* FALLTHROUGH */
case PSQF_STAMP: /* FALLTHROUGH */
case PSQF_SEVERITY: /* FALLTHROUGH */
case PSQF_TEXT: /* FALLTHROUGH */
+ case PSQF_TYPE: /* FALLTHROUGH */
case PSQF_UID:
fields |= (1 << field);
break;