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):