Ethereal-dev: [Ethereal-dev] [patch] Feature: read trace from a spawned process

Note: This archive is from the project's previous web site, ethereal.com. This list is no longer active.

From: Thomas Steffen <steffen.list.account@xxxxxxxxx>
Date: Wed, 17 Aug 2005 15:19:20 +0200
I have done some cleanup on my patch to read a trace in real time from
a spawned process.

It supports remote tracing using a command like:

ethereal -k -i '|ssh -l root hostname tcpdump -filter -i eth0'

(note that you need to login without a password, because the child
process does not have the tty. I recommend ssh-agent or ssh-askpass
for that.)

Of course you can do much more: read the trace from a TCP or UDP
connection (using netcat), implement your own capture tools etc. The
problems I mentioned with the previous patch should be sorted out, and
it should compile (maybe even work?) on Windows.

Please give it a try, and tell we whether you think it is useful. For
me it is very helpful, so I would like to see it in the next version
of Ethereal.

I know that in theory this feature is already present, because
Ethereal can read from a named pipe. But you have to restart the
feeding process manually every time you start a new capture, which is
a big nuisance.

Thomas
Index: capture_loop.c
===================================================================
--- capture_loop.c	(revision 15243)
+++ capture_loop.c	(working copy)
@@ -177,6 +177,8 @@
   wtap_dumper   *wtap_pdh;
   gint           wtap_linktype;
 
+  gboolean       child_spawned;
+  GPid           child_pid;
 } loop_data;
 
 
@@ -241,16 +243,31 @@
   unsigned int bytes_read;
   fd_set      rfds;
   struct timeval timeout;
+  gboolean    ok;
+  GError      error;
+  char       *argv[] = { "/bin/sh", "-c", "arg", NULL };
 
-
   g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_DEBUG, "cap_pipe_open_live: %s", pipename);
 
   /*
    * XXX Ethereal blocks until we return
    */
+  ld->child_spawned = 0;
   if (strcmp(pipename, "-") == 0)
     fd = 0; /* read from stdin */
-  else {
+  else if (pipename[0] == '|') {
+    argv[2] = pipename + 1;
+    ok = g_spawn_async_with_pipes(NULL, argv, NULL, 0, NULL, NULL,
+                                  &ld->child_pid, NULL, &fd, NULL, &error);
+    if (!ok) {
+      g_snprintf(errmsg, errmsgl,
+                 "The capture child process could not be started: %s.",
+                 error.message);
+      ld->cap_pipe_err = PIPERR;
+      return -1;
+    }
+    ld->child_spawned = 1;
+  } else {
     if (stat(pipename, &pipe_stat) < 0) {
       if (errno == ENOENT || errno == ENOTDIR)
         ld->cap_pipe_err = PIPNEXIST;
@@ -392,6 +409,13 @@
   return fd;
 
 error:
+  if (ld->child_spawned) {
+#ifndef _WIN32
+    /* send the SIGTERM signal to kill the child. */
+    kill(ld->child_pid, SIGTERM);
+#endif
+    g_spawn_close_pid(ld->child_pid);
+  }
   g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_DEBUG, "cap_pipe_open_live: error %s", errmsg);
   ld->cap_pipe_err = PIPERR;
   close(fd);
@@ -702,13 +726,20 @@
   return TRUE;
 }
 
-
 /* open the capture input file (pcap or capture pipe) */
 static void capture_loop_close_input(loop_data *ld) {
 
   g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_DEBUG, "capture_loop_close_input");
 
+  if (ld->child_spawned) {
 #ifndef _WIN32
+    /* send the SIGTERM signal to kill the child. */
+    kill(ld->child_pid, SIGTERM);
+#endif
+    g_spawn_close_pid(ld->child_pid);
+  }
+
+#ifndef _WIN32
   /* if open, close the capture pipe "input file" */
   if (ld->cap_pipe_fd >= 0) {
     g_assert(ld->from_cap_pipe);
Index: capture_ui_utils.c
===================================================================
--- capture_ui_utils.c	(revision 15243)
+++ capture_ui_utils.c	(working copy)
@@ -336,6 +336,8 @@
    * (An interface name might, however, contain a colon in it, which
    * is why we don't use the colon search on UNIX.)
    */
+  if (if_text && if_text[0] == '|') 
+    return if_text;
   if_name = strrchr(if_text, ' ');
   if (if_name == NULL) {
     if_name = if_text;