Ethereal-dev: [Ethereal-dev] [PATCH] Allow tethereal to write packet data to stdout
Note: This archive is from the project's previous web site, ethereal.com. This list is no longer active.
From: Graeme Hewson <ghewson@xxxxxxxxxxxxxxxxxxx>
Date: Sun, 14 Jul 2002 19:03:39 +0100
These patches allow the user to specify "-w -" to tethereal. There's also some optimisation of the capture loop. Graeme Hewson
--- tethereal.c.orig Sun Jul 7 22:52:48 2002
+++ tethereal.c Sun Jul 14 10:54:59 2002
@@ -675,23 +675,30 @@
/* See if we're writing a capture file and the file is a pipe */
ld.output_to_pipe = FALSE;
if (cfile.save_file != NULL) {
- err = test_for_fifo(cfile.save_file);
- switch (err) {
-
- case ENOENT: /* it doesn't exist, so we'll be creating it,
- and it won't be a FIFO */
- case 0: /* found it, but it's not a FIFO */
- break;
-
- case ESPIPE: /* it is a FIFO */
+ if (!strcmp(cfile.save_file, "-")) {
+ /* stdout */
+ g_free(cfile.save_file);
+ cfile.save_file = g_strdup("");
ld.output_to_pipe = TRUE;
- break;
-
- default: /* couldn't stat it */
- fprintf(stderr,
- "tethereal: Error testing whether capture file is a pipe: %s\n",
- strerror(errno));
- exit(2);
+ } else {
+ err = test_for_fifo(cfile.save_file);
+ switch (err) {
+
+ case ENOENT: /* it doesn't exist, so we'll be creating it,
+ and it won't be a FIFO */
+ case 0: /* found it, but it's not a FIFO */
+ break;
+
+ case ESPIPE: /* it is a FIFO */
+ ld.output_to_pipe = TRUE;
+ break;
+
+ default: /* couldn't stat it */
+ fprintf(stderr,
+ "tethereal: Error testing whether capture file is a pipe: %s\n",
+ strerror(errno));
+ exit(2);
+ }
}
}
@@ -699,7 +706,8 @@
/* If they didn't specify a "-w" flag, but specified a maximum capture
file size, tell them that this doesn't work, and exit. */
if (capture_opts.has_autostop_filesize && cfile.save_file == NULL) {
- fprintf(stderr, "tethereal: Maximum capture file size specified, but capture isn't being saved to a file.\n");
+ fprintf(stderr, "tethereal: Maximum capture file size specified, but "
+ "capture isn't being saved to a file.\n");
exit(2);
}
@@ -882,7 +890,8 @@
struct bpf_program fcode;
void (*oldhandler)(int);
int err = 0;
- volatile int inpkts = 0;
+ int volatile volatile_err = 0;
+ int volatile inpkts = 0;
int pcap_cnt;
char errmsg[1024+1];
condition *volatile cnd_stop_capturesize = NULL;
@@ -892,7 +901,7 @@
char *libpcap_warn;
#endif
struct pcap_stat stats;
- gboolean volatile write_err = FALSE;
+ gboolean write_err;
gboolean dump_ok;
/* Initialize all data structures used for dissection. */
@@ -1001,7 +1010,8 @@
if (ld.pdh == NULL) {
snprintf(errmsg, sizeof errmsg, file_open_error_message(errno, TRUE),
- cfile.save_file);
+ *cfile.save_file == '\0' ?
+ "stdout" : cfile.save_file);
goto error;
}
}
@@ -1044,6 +1054,33 @@
ld.go = FALSE;
ld.packet_count = 0;
while (ld.go) {
+ /* We need to be careful with automatic variables defined in the
+ outer scope which are changed inside the loop. Most compilers
+ don't try to roll them back to their original values after the
+ longjmp which causes the loop to finish, but all that the
+ standards say is that their values are indeterminate. If we
+ don't want them to be rolled back, we should define them with the
+ volatile attribute (paraphrasing W. Richard Stevens, Advanced
+ Programming in the UNIX Environment, p. 178).
+
+ The "err" variable causes a particular problem. If we give it
+ the volatile attribute, then when we pass a reference to it (as
+ in "&err") to a function, GCC warns: "passing arg <n> of
+ <function> discards qualifiers from pointer target type".
+ Therefore within the loop and just beyond we don't use "err".
+ Within the loop we define "loop_err", and assign its value to
+ "volatile_err", which is in the outer scope and is checked when
+ the loop finishes.
+
+ We also define "packet_count_prev" here to keep things tidy,
+ since it's used only inside the loop. If it were defined in the
+ outer scope, GCC would give a warning (unnecessary in this case)
+ that it might be clobbered, and we'd need to give it the volatile
+ attribute to suppress the warning. */
+
+ int loop_err = 0;
+ int packet_count_prev = 0;
+
if (cnd_stop_capturesize == NULL && cnd_stop_timeout == NULL) {
/* We're not stopping at a particular capture file size, and we're
not stopping after some particular amount of time has expired,
@@ -1064,6 +1101,7 @@
pcap_cnt = -1;
else {
if (ld.packet_count >= capture_opts.autostop_count) {
+ /* XXX do we need this test here? */
/* It appears there's nothing more to capture. */
break;
}
@@ -1078,43 +1116,47 @@
if (inpkts < 0) {
/* Error from "pcap_dispatch()". */
ld.go = FALSE;
- } else if (capture_opts.autostop_count != 0 &&
- ld.packet_count >= capture_opts.autostop_count) {
- /* The specified number of packets have been captured and have
- passed both any capture filter in effect and any read filter
- in effect. */
- ld.go = FALSE;
} else if (cnd_stop_timeout != NULL && cnd_eval(cnd_stop_timeout)) {
/* The specified capture time has elapsed; stop the capture. */
ld.go = FALSE;
- } else if (cnd_stop_capturesize != NULL &&
- cnd_eval(cnd_stop_capturesize,
- (guint32)wtap_get_bytes_dumped(ld.pdh))) {
- /* We're saving the capture to a file, and the capture file reached
- its maximum size. */
- if (capture_opts.ringbuffer_on) {
- /* Switch to the next ringbuffer file */
- if (ringbuf_switch_file(&cfile, &ld.pdh, &err)) {
- /* File switch succeeded: reset the condition */
- cnd_reset(cnd_stop_capturesize);
+ } else if (inpkts > 0) {
+ if (capture_opts.autostop_count != 0 &&
+ ld.packet_count >= capture_opts.autostop_count) {
+ /* The specified number of packets have been captured and have
+ passed both any capture filter in effect and any read filter
+ in effect. */
+ ld.go = FALSE;
+ } else if (cnd_stop_capturesize != NULL &&
+ cnd_eval(cnd_stop_capturesize,
+ (guint32)wtap_get_bytes_dumped(ld.pdh))) {
+ /* We're saving the capture to a file, and the capture file reached
+ its maximum size. */
+ if (capture_opts.ringbuffer_on) {
+ /* Switch to the next ringbuffer file */
+ if (ringbuf_switch_file(&cfile, &ld.pdh, &loop_err)) {
+ /* File switch succeeded: reset the condition */
+ cnd_reset(cnd_stop_capturesize);
+ } else {
+ /* File switch failed: stop here */
+ volatile_err = loop_err;
+ ld.go = FALSE;
+ }
} else {
- /* File switch failed: stop here */
+ /* No ringbuffer - just stop. */
ld.go = FALSE;
- continue;
}
- } else {
- /* No ringbuffer - just stop. */
- ld.go = FALSE;
}
- }
- if (ld.output_to_pipe) {
- /* XXX - flush only if ld.packet_count changed? */
- if (fflush(wtap_dump_file(ld.pdh))) {
- err = errno;
- ld.go = FALSE;
+ if (ld.output_to_pipe) {
+ if (ld.packet_count > packet_count_prev) {
+ if (fflush(wtap_dump_file(ld.pdh))) {
+ volatile_err = errno;
+ ld.go = FALSE;
+ }
+ packet_count_prev = ld.packet_count;
+ }
}
- }
- }
+ } /* inpkts > 0 */
+ } /* while (ld.go) */
/* delete stop conditions */
if (cnd_stop_capturesize != NULL)
@@ -1124,7 +1166,7 @@
if ((cfile.save_file != NULL) && !quiet) {
/* We're saving to a file, which means we're printing packet counts
- to the standard output if we are not running silent and deep.
+ to stderr if we are not running silent and deep.
Send a newline so that we move to the line after the packet count. */
fprintf(stderr, "\n");
}
@@ -1135,8 +1177,10 @@
pcap_geterr(ld.pch));
}
- if (err != 0) {
- show_capture_file_io_error(cfile.save_file, err, FALSE);
+ if (volatile_err == 0)
+ write_err = FALSE;
+ else {
+ show_capture_file_io_error(cfile.save_file, volatile_err, FALSE);
write_err = TRUE;
}
@@ -1147,7 +1191,9 @@
} else {
dump_ok = wtap_dump_close(ld.pdh, &err);
}
- if (!dump_ok && ! write_err)
+ /* If we've displayed a message about a write error, there's no point
+ in displaying another message about an error on close. */
+ if (!dump_ok && !write_err)
show_capture_file_io_error(cfile.save_file, err, TRUE);
}
@@ -1195,8 +1241,8 @@
int err;
/* Convert from libpcap to Wiretap format.
- If that fails, ignore the packet.
- XXX - print a message. */
+ If that fails, ignore the packet (wtap_process_pcap_packet has
+ written an error message). */
pd = wtap_process_pcap_packet(ld->linktype, phdr, pd, &pseudo_header,
&whdr, &err);
if (pd == NULL) {
@@ -1295,30 +1341,33 @@
case WTAP_ERR_UNSUPPORTED_ENCAP:
case WTAP_ERR_ENCAP_PER_PACKET_UNSUPPORTED:
fprintf(stderr,
-"tethereal: The capture file being read cannot be written in that format.\n");
+ "tethereal: The capture file being read cannot be written in "
+ "that format.\n");
break;
case WTAP_ERR_CANT_OPEN:
fprintf(stderr,
-"tethereal: The file \"%s\" couldn't be created for some unknown reason.\n",
- cf->save_file);
+ "tethereal: The file \"%s\" couldn't be created for some "
+ "unknown reason.\n",
+ *cf->save_file == '\0' ? "stdout" : cf->save_file);
break;
case WTAP_ERR_SHORT_WRITE:
fprintf(stderr,
-"tethereal: A full header couldn't be written to the file \"%s\".\n",
- cf->save_file);
+ "tethereal: A full header couldn't be written to the file \"%s\".\n",
+ *cf->save_file == '\0' ? "stdout" : cf->save_file);
break;
default:
if (err < 0) {
fprintf(stderr,
"tethereal: The file \"%s\" could not be opened: Error %d.\n",
- cf->save_file, err);
+ *cf->save_file == '\0' ? "stdout" : cf->save_file, err);
} else {
fprintf(stderr,
"tethereal: The file \"%s\" could not be opened: %s\n.",
- cf->save_file, strerror(err));
+ *cf->save_file == '\0' ? "stdout" : cf->save_file,
+ strerror(err));
}
break;
}
@@ -1499,6 +1548,9 @@
static void
show_capture_file_io_error(const char *fname, int err, gboolean is_close)
{
+ if (*fname == '\0')
+ fname = "stdout";
+
switch (err) {
case ENOSPC:
--- file.c.orig Thu Jun 27 23:46:47 2002
+++ file.c Sun Jul 14 11:32:36 2002
@@ -513,20 +513,26 @@
if (wdh == NULL)
return NULL; /* couldn't allocate it */
- /* In case "fopen()" fails but doesn't set "errno", set "errno"
- to a generic "the open failed" error. */
- errno = WTAP_ERR_CANT_OPEN;
- fh = fopen(filename, "wb");
- if (fh == NULL) {
- *err = errno;
- return NULL; /* can't create file */
+ /* Empty filename means stdout */
+ if (*filename == '\0')
+ wdh->fh = stdout;
+ else {
+ /* In case "fopen()" fails but doesn't set "errno", set "errno"
+ to a generic "the open failed" error. */
+ errno = WTAP_ERR_CANT_OPEN;
+ fh = fopen(filename, "wb");
+ if (fh == NULL) {
+ *err = errno;
+ return NULL; /* can't create file */
+ }
+ wdh->fh = fh;
}
- wdh->fh = fh;
if (!wtap_dump_open_finish(wdh, filetype, err)) {
/* Get rid of the file we created; we couldn't finish
opening it. */
- unlink(filename);
+ if (wdh->fh != stdout)
+ unlink(filename);
return NULL;
}
return wdh;
@@ -609,7 +615,8 @@
/* The attempt failed. Close the stream for the file.
NOTE: this means the FD handed to "wtap_dump_fdopen()"
will be closed if the open fails. */
- fclose(wdh->fh);
+ if (wdh->fh != stdout)
+ fclose(wdh->fh);
/* Now free up the dumper handle. */
g_free(wdh);
@@ -640,15 +647,18 @@
ret = FALSE;
}
errno = WTAP_ERR_CANT_CLOSE;
- if (fclose(wdh->fh) == EOF) {
- if (ret) {
- /* The per-format close function succeeded,
- but the fclose didn't. Save the reason
- why, if our caller asked for it. */
- if (err != NULL)
- *err = errno;
+ /* Don't close stdout */
+ if (wdh->fh != stdout) {
+ if (fclose(wdh->fh) == EOF) {
+ if (ret) {
+ /* The per-format close function succeeded,
+ but the fclose didn't. Save the reason
+ why, if our caller asked for it. */
+ if (err != NULL)
+ *err = errno;
+ }
+ ret = FALSE;
}
- ret = FALSE;
}
if (wdh->dump.opaque != NULL)
g_free(wdh->dump.opaque);
--- tethereal.pod.template.orig Sun May 26 22:18:17 2002 +++ tethereal.pod.template Sun Jul 14 11:40:30 2002 @@ -288,7 +288,7 @@ =item -w -Write packet data to I<savefile>. +Write packet data to I<savefile> or to stdout if I<savefile> is "-". =item -x
- Follow-Ups:
- Prev by Date: [Ethereal-dev] Saving files overwrites existing files without asking the user, I think
- Next by Date: [Ethereal-dev] [PATCH] Prevent duplicate error message
- Previous by thread: [Ethereal-dev] Saving files overwrites existing files without asking the user, I think
- Next by thread: Re: [Ethereal-dev] [PATCH] Allow tethereal to write packet data to stdout
- Index(es):