about summary refs log tree commit diff
diff options
context:
space:
mode:
authorLeah Neukirchen <leah@vuxu.org>2017-07-14 18:56:21 +0200
committerLeah Neukirchen <leah@vuxu.org>2017-07-14 18:56:21 +0200
commit91b81929ea84209cd82aa2a02b9b63174577a5b1 (patch)
tree0210b05e65eff0480786353d5d1e3f391863f66d
parent5f1bc1d7305ba486ac015956b1e17652adac96a5 (diff)
downloadextrace-91b81929ea84209cd82aa2a02b9b63174577a5b1.tar.gz
extrace-91b81929ea84209cd82aa2a02b9b63174577a5b1.tar.xz
extrace-91b81929ea84209cd82aa2a02b9b63174577a5b1.zip
add -t for tracing process exit and duration
-rw-r--r--README4
-rw-r--r--extrace.14
-rw-r--r--extrace.c72
3 files changed, 75 insertions, 5 deletions
diff --git a/README b/README
index f9c20a5..83265a7 100644
--- a/README
+++ b/README
@@ -4,7 +4,7 @@ NAME
      extrace – trace exec() calls system-wide
 
 SYNOPSIS
-     extrace [-deflq] [-o file] [-p pid | cmd ...]
+     extrace [-deflqt] [-o file] [-p pid | cmd ...]
 
 DESCRIPTION
      extrace traces all program executions occurring on a system.
@@ -23,6 +23,8 @@ DESCRIPTION
 
      -q      Suppress printing of exec(3) arguments.
 
+     -t      Also display process exit and duration.
+
      -o file
              Redirect trace output to file.
 
diff --git a/extrace.1 b/extrace.1
index 139b507..d84050c 100644
--- a/extrace.1
+++ b/extrace.1
@@ -6,7 +6,7 @@
 .Nd trace exec() calls system-wide
 .Sh SYNOPSIS
 .Nm
-.Op Fl deflq
+.Op Fl deflqt
 .Op Fl o Ar file
 .Op Fl p Ar pid | cmd\ ...
 .Sh DESCRIPTION
@@ -33,6 +33,8 @@ is shown.
 Suppress printing of
 .Xr exec 3
 arguments.
+.It Fl t
+Also display process exit status and duration.
 .It Fl o Ar file
 Redirect trace output to
 .Ar file .
diff --git a/extrace.c b/extrace.c
index baa8710..b82a6a0 100644
--- a/extrace.c
+++ b/extrace.c
@@ -57,6 +57,7 @@
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
+#include <time.h>
 #include <unistd.h>
 
 #include <sys/socket.h>
@@ -82,6 +83,7 @@
 #define MIN_RECV_SIZE (min(SEND_MESSAGE_SIZE, RECV_MESSAGE_SIZE))
 
 #define CMDLINE_MAX 32768
+#define CMDLINE_DB_MAX 32
 pid_t parent = 1;
 int flat = 0;
 int run = 0;
@@ -89,9 +91,18 @@ int full_path = 0;
 int show_args = 1;
 int show_cwd = 0;
 int show_env = 0;
+int show_exit = 0;
 FILE *output;
 sig_atomic_t quit = 0;
 
+#define PID_DB_SIZE 1024
+struct {
+  pid_t pid;
+  int depth;
+  struct timespec start;
+  char cmdline[CMDLINE_DB_MAX];
+} pid_db[PID_DB_SIZE];
+
 static int
 pid_depth(pid_t pid)
 {
@@ -171,13 +182,28 @@ handle_msg(struct cn_msg *cn_hdr)
 
   int r = 0, r2 = 0, r3 = 0, fd, d;
   struct proc_event *ev = (struct proc_event *)cn_hdr->data;
-  pid_t pid = ev->event_data.exec.process_pid;
 
   if (ev->what == PROC_EVENT_EXEC) {
+    pid_t pid = ev->event_data.exec.process_pid;
+    int i = 0;
+
     d = pid_depth(pid);
     if (d < 0)
       return;
 
+    if (show_exit) {
+      for (i = 0; i < PID_DB_SIZE - 1; i++)
+        if (pid_db[i].pid == 0)
+           break;
+      if (i == PID_DB_SIZE - 1)
+        fprintf(stderr,
+          "extrace: warning pid_db of size %d overflowed\n", PID_DB_SIZE);
+
+      pid_db[i].pid = pid;
+      pid_db[i].depth = d;
+      clock_gettime(CLOCK_MONOTONIC_RAW, &pid_db[i].start);
+    }
+
     snprintf(name, sizeof name, "/proc/%d/cmdline", pid);
 
     memset(&cmdline, 0, sizeof cmdline);
@@ -208,7 +234,13 @@ handle_msg(struct cn_msg *cn_hdr)
 
     if (!flat)
       fprintf(output, "%*s", 2*d, "");
-    fprintf(output, "%d ", pid);
+    fprintf(output, "%d", pid);
+    if (show_exit) {
+      putc('+', output);
+      strncpy(pid_db[i].cmdline, cmdline, CMDLINE_DB_MAX-1);
+      pid_db[i].cmdline[CMDLINE_DB_MAX-1] = 0;
+    }
+    putc(' ', output);
     if (show_cwd) {
       print_shquoted(cwd);
       fprintf(output, " %% ");
@@ -259,6 +291,39 @@ handle_msg(struct cn_msg *cn_hdr)
 
     fprintf(output, "\n");
     fflush(output);
+  } else if (show_exit && ev->what == PROC_EVENT_EXIT) {
+    pid_t pid = ev->event_data.exit.process_pid;
+    int i;
+
+    for (i = 0; i < PID_DB_SIZE; i++)
+      if (pid_db[i].pid == pid) {
+        struct timespec now, diff;
+
+        pid_db[i].pid = 0;
+        if (!flat)
+          fprintf(output, "%*s", 2*pid_db[i].depth, "");
+        clock_gettime(CLOCK_MONOTONIC_RAW, &now);
+        
+        if ((now.tv_nsec - pid_db[i].start.tv_nsec) < 0) {
+          diff.tv_sec = now.tv_sec - pid_db[i].start.tv_sec - 1;
+          diff.tv_nsec = 1000000000 + now.tv_nsec - pid_db[i].start.tv_nsec;
+        } else {
+          diff.tv_sec = now.tv_sec - pid_db[i].start.tv_sec;
+          diff.tv_nsec = now.tv_nsec - pid_db[i].start.tv_nsec;
+        }
+
+        fprintf(output, "%d- ", pid);
+        print_shquoted(pid_db[i].cmdline);
+        fprintf(output, " exited %s=%d time=%ld.%03lds\n",
+            ev->event_data.exit.exit_code >= 256 ? "signal" : "status",
+            ev->event_data.exit.exit_code >= 256 ?
+              ev->event_data.exit.exit_signal :
+              ev->event_data.exit.exit_code,
+            diff.tv_sec,
+            diff.tv_nsec / 1000000);
+        fflush(output);
+        break;
+      }
   }
 }
 
@@ -277,7 +342,7 @@ main(int argc, char *argv[])
 
   output = stdout;
 
-  while ((opt = getopt(argc, argv, "+deflo:p:qw")) != -1)
+  while ((opt = getopt(argc, argv, "+deflo:p:qtw")) != -1)
     switch (opt) {
     case 'd': show_cwd = 1; break;
     case 'e': show_env = 1; break;
@@ -285,6 +350,7 @@ main(int argc, char *argv[])
     case 'l': full_path = 1; break;
     case 'p': parent = atoi(optarg); break;
     case 'q': show_args = 0; break;
+    case 't': show_exit = 1; break;
     case 'o':
       output = fopen(optarg, "w");
       if (!output) {