aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPeter Seebach <peter.seebach@windriver.com>2010-04-26 17:11:15 -0700
committerPeter Seebach <peter.seebach@windriver.com>2010-04-26 17:13:45 -0700
commit2cc5cc8fb02ce787753f2b3903864c7e1b98bd4d (patch)
tree16456f1998a2e3754393951e569292c0bea09ccf
parent4038d0599e135ea0099a2392e0421bcc1d053825 (diff)
downloadpseudo-2cc5cc8fb02ce787753f2b3903864c7e1b98bd4d.tar.gz
pseudo-2cc5cc8fb02ce787753f2b3903864c7e1b98bd4d.tar.bz2
pseudo-2cc5cc8fb02ce787753f2b3903864c7e1b98bd4d.zip
Updates/improvements for logging
Send program name (program_invocation_name from glibc) along with the tag. Along the way, restructure the fds/pids/tags arrays to be an array of client structures in pseudo_server, and add the message type to the set of things logged -- logging that a message was a ping is more useful than appending the text "ping" to it. Add support for type and program to pseudolog. Add deletion to pseudolog. Handle usage message formatting when there's an odd number of known specifiers for pseudolog. Conflicts: ChangeLog.txt pseudo_server.c
-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;