aboutsummaryrefslogtreecommitdiffstats
path: root/capture.c
diff options
context:
space:
mode:
Diffstat (limited to 'capture.c')
-rw-r--r--capture.c244
1 files changed, 238 insertions, 6 deletions
diff --git a/capture.c b/capture.c
index 229ddf84c0..38242fa2bb 100644
--- a/capture.c
+++ b/capture.c
@@ -83,6 +83,8 @@ void
capture_opts_init(capture_options *capture_opts, void *cfile)
{
capture_opts->cf = cfile;
+ capture_opts->cfilter = g_strdup("");
+ capture_opts->iface = NULL;
#ifdef _WIN32
capture_opts->buffer_size = 1; /* 1 MB */
#endif
@@ -111,23 +113,253 @@ capture_opts_init(capture_options *capture_opts, void *cfile)
capture_opts->autostop_filesize = 1024 * 1024; /* 1 MB */
capture_opts->has_autostop_duration = FALSE;
capture_opts->autostop_duration = 60; /* 1 min */
+
+}
+
+static int
+get_natural_int(const char *string, const char *name)
+{
+ long number;
+ char *p;
+
+ number = strtol(string, &p, 10);
+ if (p == string || *p != '\0') {
+ fprintf(stderr, "ethereal: The specified %s \"%s\" isn't a decimal number\n",
+ name, string);
+ exit(1);
+ }
+ if (number < 0) {
+ fprintf(stderr, "ethereal: The specified %s \"%s\" is a negative number\n",
+ name, string);
+ exit(1);
+ }
+ if (number > INT_MAX) {
+ fprintf(stderr, "ethereal: The specified %s \"%s\" is too large (greater than %d)\n",
+ name, string, INT_MAX);
+ exit(1);
+ }
+ return number;
+}
+
+
+static int
+get_positive_int(const char *string, const char *name)
+{
+ long number;
+
+ number = get_natural_int(string, name);
+
+ if (number == 0) {
+ fprintf(stderr, "ethereal: The specified %s is zero\n",
+ name);
+ exit(1);
+ }
+
+ return number;
}
+/*
+ * Given a string of the form "<autostop criterion>:<value>", as might appear
+ * as an argument to a "-a" option, parse it and set the criterion in
+ * question. Return an indication of whether it succeeded or failed
+ * in some fashion.
+ */
+static gboolean
+set_autostop_criterion(capture_options *capture_opts, const char *autostoparg)
+{
+ gchar *p, *colonp;
+
+ colonp = strchr(autostoparg, ':');
+ if (colonp == NULL)
+ return FALSE;
+
+ p = colonp;
+ *p++ = '\0';
+
+ /*
+ * Skip over any white space (there probably won't be any, but
+ * as we allow it in the preferences file, we might as well
+ * allow it here).
+ */
+ while (isspace((guchar)*p))
+ p++;
+ if (*p == '\0') {
+ /*
+ * Put the colon back, so if our caller uses, in an
+ * error message, the string they passed us, the message
+ * looks correct.
+ */
+ *colonp = ':';
+ return FALSE;
+ }
+ if (strcmp(autostoparg,"duration") == 0) {
+ capture_opts->has_autostop_duration = TRUE;
+ capture_opts->autostop_duration = get_positive_int(p,"autostop duration");
+ } else if (strcmp(autostoparg,"filesize") == 0) {
+ capture_opts->has_autostop_filesize = TRUE;
+ capture_opts->autostop_filesize = get_positive_int(p,"autostop filesize");
+ } else {
+ return FALSE;
+ }
+ *colonp = ':'; /* put the colon back */
+ return TRUE;
+}
+
+/*
+ * Given a string of the form "<ring buffer file>:<duration>", as might appear
+ * as an argument to a "-b" option, parse it and set the arguments in
+ * question. Return an indication of whether it succeeded or failed
+ * in some fashion.
+ */
+static gboolean
+get_ring_arguments(capture_options *capture_opts, const char *arg)
+{
+ gchar *p = NULL, *colonp;
+
+ colonp = strchr(arg, ':');
+
+ if (colonp != NULL) {
+ p = colonp;
+ *p++ = '\0';
+ }
+
+ capture_opts->ring_num_files =
+ get_natural_int(arg, "number of ring buffer files");
+
+ if (colonp == NULL)
+ return TRUE;
+
+ /*
+ * Skip over any white space (there probably won't be any, but
+ * as we allow it in the preferences file, we might as well
+ * allow it here).
+ */
+ while (isspace((guchar)*p))
+ p++;
+ if (*p == '\0') {
+ /*
+ * Put the colon back, so if our caller uses, in an
+ * error message, the string they passed us, the message
+ * looks correct.
+ */
+ *colonp = ':';
+ return FALSE;
+ }
+
+ capture_opts->has_file_duration = TRUE;
+ capture_opts->file_duration = get_positive_int(p,
+ "ring buffer duration");
+
+ *colonp = ':'; /* put the colon back */
+ return TRUE;
+}
+
+
+void
+capture_opt_add(capture_options *capture_opts, int opt, const char *optarg, gboolean *start_capture)
+{
+ int i;
+
+
+ switch(opt) {
+ case 'a': /* autostop criteria */
+ if (set_autostop_criterion(capture_opts, optarg) == FALSE) {
+ fprintf(stderr, "ethereal: Invalid or unknown -a flag \"%s\"\n", optarg);
+ exit(1);
+ }
+ break;
+ case 'b': /* Ringbuffer option */
+ capture_opts->multi_files_on = TRUE;
+ capture_opts->has_ring_num_files = TRUE;
+ if (get_ring_arguments(capture_opts, optarg) == FALSE) {
+ fprintf(stderr, "ethereal: Invalid or unknown -b arg \"%s\"\n", optarg);
+ exit(1);
+ }
+ break;
+ case 'c': /* Capture xxx packets */
+ capture_opts->has_autostop_packets = TRUE;
+ capture_opts->autostop_packets = get_positive_int(optarg, "packet count");
+ break;
+ case 'f': /* capture filter */
+ if (capture_opts->cfilter)
+ g_free(capture_opts->cfilter);
+ capture_opts->cfilter = g_strdup(optarg);
+ break;
+ case 'H': /* Hide capture info dialog box */
+ capture_opts->show_info = FALSE;
+ break;
+ case 'i': /* Use interface xxx */
+ capture_opts->iface = g_strdup(optarg);
+ break;
+ case 'k': /* Start capture immediately */
+ *start_capture = TRUE;
+ break;
+ /*case 'l':*/ /* Automatic scrolling in live capture mode */
+ case 'p': /* Don't capture in promiscuous mode */
+ capture_opts->promisc_mode = FALSE;
+ break;
+ case 'Q': /* Quit after capture (just capture to file) */
+ capture_opts->quit_after_cap = TRUE;
+ *start_capture = TRUE; /*** -Q implies -k !! ***/
+ break;
+ case 's': /* Set the snapshot (capture) length */
+ capture_opts->has_snaplen = TRUE;
+ capture_opts->snaplen = get_positive_int(optarg, "snapshot length");
+ break;
+ case 'S': /* "Sync" mode: used for following file ala tail -f */
+ capture_opts->sync_mode = TRUE;
+ break;
+ case 'w': /* Write to capture file xxx */
+ capture_opts->save_file = g_strdup(optarg);
+ break;
+ case 'W': /* Write to capture file FD xxx */
+ capture_opts->save_file_fd = atoi(optarg);
+ break;
+ case 'y': /* Set the pcap data link type */
+#ifdef HAVE_PCAP_DATALINK_NAME_TO_VAL
+ capture_opts->linktype = pcap_datalink_name_to_val(optarg);
+ if (capture_opts->linktype == -1) {
+ fprintf(stderr, "ethereal: The specified data link type \"%s\" isn't valid\n",
+ optarg);
+ exit(1);
+ }
+#else /* HAVE_PCAP_DATALINK_NAME_TO_VAL */
+ /* XXX - just treat it as a number */
+ capture_opts->linktype = get_natural_int(optarg, "data link type");
+#endif /* HAVE_PCAP_DATALINK_NAME_TO_VAL */
+ break;
+#ifdef _WIN32
+ /* Hidden option supporting Sync mode */
+ case 'Z': /* Write to pipe FD XXX */
+ /* associate stdout with pipe */
+ i = atoi(optarg);
+ if (dup2(i, 1) < 0) {
+ fprintf(stderr, "Unable to dup pipe handle\n");
+ exit(1);
+ }
+ break;
+#endif /* _WIN32 */
+ default:
+ /* the caller is responsible to send us only the right opt's */
+ g_assert_not_reached();
+ }
+}
+
/* open the output file (temporary/specified name/ringbuffer) and close the old one */
/* Returns TRUE if the file opened successfully, FALSE otherwise. */
static gboolean
-capture_open_output(capture_options *capture_opts, const char *save_file, gboolean *is_tempfile) {
+capture_open_output(capture_options *capture_opts, gboolean *is_tempfile) {
char tmpname[128+1];
gchar *capfile_name;
- if (save_file != NULL) {
+ if (capture_opts->save_file != NULL) {
/* If the Sync option is set, we return to the caller while the capture
* is in progress. Therefore we need to take a copy of save_file in
* case the caller destroys it after we return.
*/
- capfile_name = g_strdup(save_file);
+ capfile_name = g_strdup(capture_opts->save_file);
if (capture_opts->multi_files_on) {
/* ringbuffer is enabled */
capture_opts->save_file_fd = ringbuf_init(capfile_name,
@@ -176,19 +408,19 @@ capture_open_output(capture_options *capture_opts, const char *save_file, gboole
to the file in question. */
/* Returns TRUE if the capture starts successfully, FALSE otherwise. */
gboolean
-do_capture(capture_options *capture_opts, const char *save_file)
+do_capture(capture_options *capture_opts)
{
gboolean is_tempfile;
gboolean ret;
gchar *title;
/* open the output file (temporary/specified name/ringbuffer) and close the old one */
- if(!capture_open_output(capture_opts, save_file, &is_tempfile)) {
+ if(!capture_open_output(capture_opts, &is_tempfile)) {
return FALSE;
}
title = g_strdup_printf("%s: Capturing - Ethereal",
- get_interface_descriptive_name(cf_get_iface(capture_opts->cf)));
+ get_interface_descriptive_name(capture_opts->iface));
if (capture_opts->sync_mode) {
/* sync mode: do the capture in a child process */
ret = sync_pipe_do_capture(capture_opts, is_tempfile);