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;