diff options
Diffstat (limited to 'capture.c')
-rw-r--r-- | capture.c | 244 |
1 files changed, 238 insertions, 6 deletions
@@ -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); |