diff options
author | Gerald Combs <gerald@wireshark.org> | 2007-06-11 03:58:58 +0000 |
---|---|---|
committer | Gerald Combs <gerald@wireshark.org> | 2007-06-11 03:58:58 +0000 |
commit | e9f1a0b692e19854f9e550e56e6a4dd392d316ac (patch) | |
tree | 34b32715c097282a72bc20784529bf82c5e01b0e | |
parent | f07a01dd510a6ae5fb963123195c4f0e203216aa (diff) |
One more step in privilege separation.
Add a capture_interface_list(), which works similar to
get_interface_list() except that it forks dumpcap instead of calling
the pcap routines directly. Use it in the GUI.
Add a "-I" flag to dumpcap, which prints out verbose interface
information.
Tested under Windows and Linux.
svn path=/trunk/; revision=22071
-rw-r--r-- | capture-pcap-util.h | 7 | ||||
-rw-r--r-- | capture.c | 135 | ||||
-rw-r--r-- | capture.h | 7 | ||||
-rw-r--r-- | capture_opts.c | 96 | ||||
-rw-r--r-- | capture_opts.h | 8 | ||||
-rw-r--r-- | capture_sync.c | 254 | ||||
-rw-r--r-- | capture_sync.h | 19 | ||||
-rw-r--r-- | doc/dumpcap.pod | 9 | ||||
-rw-r--r-- | dumpcap.c | 30 | ||||
-rw-r--r-- | gtk/capture_dlg.c | 4 | ||||
-rw-r--r-- | gtk/capture_if_dlg.c | 4 | ||||
-rw-r--r-- | gtk/capture_prefs.c | 119 | ||||
-rw-r--r-- | gtk/main.c | 2 | ||||
-rw-r--r-- | tshark.c | 18 |
14 files changed, 566 insertions, 146 deletions
diff --git a/capture-pcap-util.h b/capture-pcap-util.h index 545231704d..72b1f6742c 100644 --- a/capture-pcap-util.h +++ b/capture-pcap-util.h @@ -69,9 +69,10 @@ typedef struct { GList *get_interface_list(int *err, char **err_str); -/* Error values from "get_interface_list()". */ -#define CANT_GET_INTERFACE_LIST 0 /* error getting list */ -#define NO_INTERFACES_FOUND 1 /* list is empty */ +/* Error values from "get_interface_list()/capture_interface_list()". */ +#define CANT_GET_INTERFACE_LIST 1 /* error getting list */ +#define NO_INTERFACES_FOUND 2 /* list is empty */ +#define CANT_RUN_DUMPCAP 3 /* problem running 'dumpcap -I l' */ void free_interface_list(GList *if_list); @@ -40,6 +40,18 @@ #include <fcntl.h> #endif +#ifdef HAVE_SYS_TYPES_H +#include <sys/types.h> +#endif + +#ifdef HAVE_SYS_SOCKET_H +#include <sys/socket.h> +#endif + +#ifdef HAVE_NETDB_H +#include <netdb.h> +#endif + #include <signal.h> #include <errno.h> @@ -47,6 +59,7 @@ #include <epan/packet.h> #include <epan/dfilter/dfilter.h> +#include <epan/ws_strsplit.h> #include "file.h" #include "capture.h" #include "capture_sync.h" @@ -69,7 +82,7 @@ -/** +/** * Start a capture. * * @return TRUE if the capture starts successfully, FALSE otherwise. @@ -142,7 +155,7 @@ capture_kill_child(capture_options *capture_opts) g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_INFO, "Capture Kill"); /* kill the capture child */ - sync_pipe_kill(capture_opts); + sync_pipe_kill(capture_opts->fork_child); } @@ -209,7 +222,7 @@ guint32 drops) break; case CF_READ_ABORTED: - /* User wants to quit program. Exit by leaving the main loop, + /* User wants to quit program. Exit by leaving the main loop, so that any quit functions we registered get called. */ main_window_nested_quit(); return FALSE; @@ -217,7 +230,7 @@ guint32 drops) /* if we didn't captured even a single packet, close the file again */ if(cf_get_packet_count(capture_opts->cf) == 0 && !capture_opts->restart) { - simple_dialog(ESD_TYPE_INFO, ESD_BTN_OK, + simple_dialog(ESD_TYPE_INFO, ESD_BTN_OK, "%sNo packets captured!%s\n" "\n" "As no data was captured, closing the %scapture file!\n" @@ -283,7 +296,7 @@ capture_input_new_file(capture_options *capture_opts, gchar *new_file) case CF_OK: break; case CF_ERROR: - /* Don't unlink (delete) the save file - leave it around, + /* Don't unlink (delete) the save file - leave it around, for debugging purposes. */ g_free(capture_opts->save_file); capture_opts->save_file = NULL; @@ -307,7 +320,7 @@ capture_input_new_file(capture_options *capture_opts, gchar *new_file) return TRUE; } - + /* capture child tells us we have new packets to read */ void capture_input_new_packets(capture_options *capture_opts, int to_read) @@ -339,7 +352,7 @@ capture_input_new_packets(capture_options *capture_opts, int to_read) } } else { /* increase capture file packet counter by the number or incoming packets */ - cf_set_packet_count(capture_opts->cf, + cf_set_packet_count(capture_opts->cf, cf_get_packet_count(capture_opts->cf) + to_read); cf_callback_invoke(cf_cb_live_capture_fixed_continue, capture_opts->cf); @@ -479,7 +492,7 @@ capture_input_closed(capture_options *capture_opts) /* XXX: If -Q (quit-after-cap) then cf->count clr'd below so save it first */ packet_count_save = cf_get_packet_count(capture_opts->cf); /* Tell the GUI, we are not doing a capture any more. - Must be done after the cf_finish_tail(), so file lengths are displayed + Must be done after the cf_finish_tail(), so file lengths are displayed correct. */ cf_callback_invoke(cf_cb_live_capture_update_finished, capture_opts->cf); @@ -488,7 +501,7 @@ capture_input_closed(capture_options *capture_opts) case CF_READ_OK: if ((packet_count_save == 0) && !capture_opts->restart) { - simple_dialog(ESD_TYPE_INFO, ESD_BTN_OK, + simple_dialog(ESD_TYPE_INFO, ESD_BTN_OK, "%sNo packets captured!%s\n" "\n" "As no data was captured, closing the %scapture file!\n" @@ -526,7 +539,7 @@ capture_input_closed(capture_options *capture_opts) /* this is a normal mode capture and if no error happened, read in the capture file data */ if(capture_opts->save_file != NULL) { - capture_input_read_all(capture_opts, cf_is_tempfile(capture_opts->cf), + capture_input_read_all(capture_opts, cf_is_tempfile(capture_opts->cf), cf_get_drops_known(capture_opts->cf), cf_get_drops(capture_opts->cf)); } } @@ -563,5 +576,107 @@ capture_input_closed(capture_options *capture_opts) } } +/** + * Fetch the interface list from a child process (dumpcap). + * + * @return A GList containing if_info_t structs if successful, NULL otherwise. + */ + +/* XXX - We parse simple text output to get our interface list. Should + * we use "real" data serialization instead, e.g. via XML? */ +GList * +capture_interface_list(int *err, char **err_str) +{ + GList *if_list = NULL; + int i, j; + gchar *msg; + gchar **raw_list, **if_parts, **addr_parts; + gchar *name; + if_info_t *if_info; + if_addr_t *if_addr; + struct addrinfo *ai; + struct sockaddr_in *sa4; + struct sockaddr_in6 *sa6; + + g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_MESSAGE, "Capture Interface List ..."); + + /* Try to get our interface list */ + *err = sync_interface_list_open(&msg); + if(*err != 0) { + g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_MESSAGE, "Capture Interface List failed!"); + if (*err_str) + *err_str = msg; + else + g_free(msg); + return NULL; + } + + /* Split our lines */ + raw_list = g_strsplit(msg, "\n", 0); + g_free(msg); + + for (i = 0; raw_list[i] != NULL; i++) { + if_parts = g_strsplit(raw_list[i], "\t", 4); + if (if_parts[0] == NULL || if_parts[1] == NULL || if_parts[2] == NULL || + if_parts[3] == NULL) { + g_strfreev(if_parts); + continue; + } + + /* Number followed by the name, e.g "1. eth0" */ + name = strchr(if_parts[0], ' '); + if (name) { + name++; + } else { + g_strfreev(if_parts); + continue; + } + + if_info = g_malloc0(sizeof(if_info_t)); + if_info->name = g_strdup(name); + if (strlen(if_parts[1]) > 0) + if_info->description = g_strdup(if_parts[1]); + addr_parts = g_strsplit(if_parts[2], ",", 0); + for (j = 0; addr_parts[j] != NULL; j++) { + /* XXX - We're failing to convert IPv6 addresses (on Ubuntu, at least) */ + if (getaddrinfo(addr_parts[j], NULL, NULL, &ai) == 0) { + if_addr = NULL; + switch (ai->ai_family) { + case AF_INET: + if_addr = g_malloc0(sizeof(if_addr_t)); + if_addr->type = AT_IPv4; + sa4 = (struct sockaddr_in *) ai->ai_addr; + if_addr->ip_addr.ip4_addr = sa4->sin_addr.s_addr; + break; + case AF_INET6: + if_addr = g_malloc0(sizeof(if_addr_t)); + if_addr->type = AT_IPv6; + sa6 = (struct sockaddr_in6 *) ai->ai_addr; + memcpy(&if_addr->ip_addr.ip6_addr, sa6->sin6_addr.s6_addr, 16); + break; + } + if (if_addr) { + if_info->ip_addr = g_slist_append(if_info->ip_addr, if_addr); + } + freeaddrinfo(ai); + } + } + if (strcmp(if_parts[3], "loopback") == 0) + if_info->loopback = TRUE; + g_strfreev(if_parts); + g_strfreev(addr_parts); + if_list = g_list_append(if_list, if_info); + } + g_strfreev(raw_list); + + /* Check to see if we built a list */ + if (if_list == NULL) { + if (*err_str) + *err_str = g_strdup("No interfaces found"); + *err = NO_INTERFACES_FOUND; + } + return if_list; +} + #endif /* HAVE_LIBPCAP */ @@ -33,7 +33,7 @@ #include "capture_opts.h" -/** +/** * Start a capture session. * * @param capture_opts the numerous capture options @@ -81,5 +81,10 @@ extern void capture_input_cfilter_error_message(capture_options *capture_opts, c */ extern void capture_input_closed(capture_options *capture_opts); +/** + * Fetch the interface list from a child process. + */ +extern GList *capture_interface_list(int *err, char **err_str); + #endif /* capture.h */ diff --git a/capture_opts.c b/capture_opts.c index 804b15deb5..e3005cea0e 100644 --- a/capture_opts.c +++ b/capture_opts.c @@ -31,6 +31,10 @@ #include <string.h> #include <ctype.h> +#ifdef HAVE_NETDB_H +#include <netdb.h> +#endif + #include <glib.h> #include <epan/packet.h> @@ -51,7 +55,7 @@ static gboolean capture_opts_output_to_pipe(const char *save_file, gboolean *is_ void capture_opts_init(capture_options *capture_opts, void *cfile) { - capture_opts->cf = cfile; + capture_opts->cf = cfile; capture_opts->cfilter = g_strdup(""); /* No capture filter string specified */ capture_opts->iface = NULL; /* Default is "pick the first interface" */ #ifdef _WIN32 @@ -77,7 +81,7 @@ capture_opts_init(capture_options *capture_opts, void *cfile) capture_opts->has_autostop_files = FALSE; capture_opts->autostop_files = 1; - capture_opts->has_autostop_packets = FALSE; + capture_opts->has_autostop_packets = FALSE; capture_opts->autostop_packets = 0; capture_opts->has_autostop_filesize = FALSE; capture_opts->autostop_filesize = 1024; /* 1 MB */ @@ -425,8 +429,9 @@ int capture_opts_list_link_layer_types(capture_options *capture_opts) return 0; } - -int capture_opts_list_interfaces() +/* Return an ASCII-formatted list of interfaces. */ +int +capture_opts_list_interfaces(gboolean verbose) { GList *if_list; GList *if_entry; @@ -434,12 +439,11 @@ int capture_opts_list_interfaces() int err; gchar *err_str; int i; -#if 0 GSList *ip_addr; if_addr_t *if_addr; - guint8 ipv4[4]; -#endif - + char addr_str[NI_MAXHOST]; + struct sockaddr_in sa4; + struct sockaddr_in6 sa6; if_list = get_interface_list(&err, &err_str); if (if_list == NULL) { @@ -453,7 +457,7 @@ int capture_opts_list_interfaces() cmdarg_err("There are no interfaces on which a capture can be done"); break; } - return 2; + return err; } i = 1; /* Interface id number */ @@ -461,28 +465,62 @@ int capture_opts_list_interfaces() if_entry = g_list_next(if_entry)) { if_info = if_entry->data; printf("%d. %s", i++, if_info->name); - if (if_info->description != NULL) - printf(" (%s)", if_info->description); -#if 0 - for(ip_addr = g_slist_nth(if_info->ip_addr, 0); ip_addr != NULL; - ip_addr = g_slist_next(ip_addr)) { - if_addr = ip_addr->data; - switch(if_addr->type) { - case AT_IPv4: - memcpy(ipv4, (void *) &if_addr->ip_addr.ip4_addr, 4); - printf(" %u.%u.%u.%u", ipv4[0], ipv4[1], ipv4[2], ipv4[3]); - break; - case AT_IPv6: - /* XXX - display the IPv6 address without using stuff from epan */ - printf(" XXX-IPv6"); - break; - default: - printf(" unknown address type %u", if_addr->type); + + if (!verbose) { + /* Add the description if it exists */ + if (if_info->description != NULL) + printf(" (%s)", if_info->description); + } else { + /* + * Add the contents of the if_entry struct in a parseable format. + * Each if_entry element is tab-separated. Addresses are comma- + * separated. + */ + /* XXX - Make sure our description doesn't contain a tab */ + if (if_info->description != NULL) + printf("\t%s\t", if_info->description); + else + printf("\t\t"); + + for(ip_addr = g_slist_nth(if_info->ip_addr, 0); ip_addr != NULL; + ip_addr = g_slist_next(ip_addr)) { + if (ip_addr != g_slist_nth(if_info->ip_addr, 0)) + printf(","); + + if_addr = ip_addr->data; + switch(if_addr->type) { + case AT_IPv4: + sa4.sin_family = AF_INET; + sa4.sin_addr.s_addr = if_addr->ip_addr.ip4_addr; + if (getnameinfo((struct sockaddr *) &sa4, sizeof(sa4), + addr_str, NI_MAXHOST, NULL, 0, NI_NUMERICHOST) == 0) { + printf(addr_str); + } else { + printf("<unknown IPv4>"); + } + break; + case AT_IPv6: + sa6.sin6_family = AF_INET6; + memcpy(&sa6.sin6_addr.s6_addr, &if_addr->ip_addr.ip6_addr, 16); + if (getnameinfo((struct sockaddr *) &sa6, sizeof(sa6), + addr_str, NI_MAXHOST, NULL, 0, NI_NUMERICHOST) == 0) { + printf(addr_str); + } else { + printf("<unknown IPv6>"); + } + break; + default: + printf("<type unknown %u>", if_addr->type); + } } - } -#endif - printf("\n"); + if (if_info->loopback) + printf("\tloopback"); + else + printf("\tnetwork"); + + } + printf("\n"); } free_interface_list(if_list); diff --git a/capture_opts.h b/capture_opts.h index ed797e6ea7..4cb76eb1a3 100644 --- a/capture_opts.h +++ b/capture_opts.h @@ -24,7 +24,7 @@ /** @file - * + * * Capture options (all parameters needed to do the actual capture) * */ @@ -118,14 +118,14 @@ capture_opts_list_link_layer_types(capture_options *capture_opts); /* list interfaces */ extern int -capture_opts_list_interfaces(void); +capture_opts_list_interfaces(gboolean verbose); /* trim the snaplen entry */ -extern void +extern void capture_opts_trim_snaplen(capture_options *capture_opts, int snaplen_min); /* trim the ring_num_files entry */ -extern void +extern void capture_opts_trim_ring_num_files(capture_options *capture_opts); /* trim the interface entry */ diff --git a/capture_sync.c b/capture_sync.c index 4b67d0cd58..4dac5a371a 100644 --- a/capture_sync.c +++ b/capture_sync.c @@ -508,6 +508,242 @@ sync_pipe_start(capture_options *capture_opts) { return TRUE; } +/* + * Get an interface list using dumpcap. On success, msg points to + * a buffer containing the dumpcap output and returns 0. On failure, msg + * points to the error message returned by dumpcap, and returns dumpcap's + * exit value. In either case, msg must be freed with g_free(). + */ +/* XXX - This duplicates a lot of code in sync_pipe_start() and sync_interface_list_open() */ +#define PIPE_BUF_SIZE 5120 +int +sync_interface_list_open(gchar **msg) { +#ifdef _WIN32 + HANDLE sync_pipe_read; /* pipe used to send messages from child to parent */ + HANDLE sync_pipe_write; /* pipe used to send messages from parent to child */ + GString *args = g_string_sized_new(200); + gchar *quoted_arg; + SECURITY_ATTRIBUTES sa; + STARTUPINFO si; + PROCESS_INFORMATION pi; + int i; +#else + int sync_pipe[2]; /* pipe used to send messages from child to parent */ + enum PIPES { PIPE_READ, PIPE_WRITE }; /* Constants 0 and 1 for PIPE_READ and PIPE_WRITE */ +#endif + int fork_child = -1, fork_child_status; + int sync_pipe_read_fd = -1; + const char *progfile_dir; + char *exename; + int argc; + const char **argv; + GString *msg_buf = NULL; + gchar buf[PIPE_BUF_SIZE+1]; + int count; + + g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_DEBUG, "sync_interface_list_open"); + + if (!msg) { + /* We can't return anything */ +#ifdef _WIN32 + g_string_free(args, TRUE); +#endif + return -1; + } + + progfile_dir = get_progfile_dir(); + if (progfile_dir == NULL) { + /* We don't know where to find dumpcap. */ + *msg = g_strdup("We don't know where to find dumpcap."); + return CANT_RUN_DUMPCAP; + } + + /* Allocate the string pointer array with enough space for the + terminating NULL pointer. */ + argc = 0; + argv = g_malloc(sizeof (char *)); + *argv = NULL; + + /* take Wireshark's absolute program path and replace "Wireshark" with "dumpcap" */ + exename = g_strdup_printf("%s" G_DIR_SEPARATOR_S "dumpcap", progfile_dir); + + /* Make that the first argument in the argument list (argv[0]). */ + argv = sync_pipe_add_arg(argv, &argc, exename); + + /* Ask for the interface list */ + argv = sync_pipe_add_arg(argv, &argc, "-I"); + argv = sync_pipe_add_arg(argv, &argc, "l"); + + + /* dumpcap should be running in capture child mode (hidden feature) */ +#ifndef DEBUG_CHILD + argv = sync_pipe_add_arg(argv, &argc, "-Z"); +#endif + + +#ifdef _WIN32 + /* init SECURITY_ATTRIBUTES */ + sa.nLength = sizeof(SECURITY_ATTRIBUTES); + sa.bInheritHandle = TRUE; + sa.lpSecurityDescriptor = NULL; + + /* Create a pipe for the child process */ + /* (inrease this value if you have trouble while fast capture file switches) */ + if (! CreatePipe(&sync_pipe_read, &sync_pipe_write, &sa, 5120)) { + /* Couldn't create the pipe between parent and child. */ + *msg = g_strdup_printf("Couldn't create sync pipe: %s", strerror(errno)); + g_free( (gpointer) argv); + return CANT_RUN_DUMPCAP; + } + + /* init STARTUPINFO */ + memset(&si, 0, sizeof(si)); + si.cb = sizeof(si); +#ifdef DEBUG_CHILD + si.dwFlags = STARTF_USESHOWWINDOW; + si.wShowWindow = SW_SHOW; +#else + si.dwFlags = STARTF_USESTDHANDLES|STARTF_USESHOWWINDOW; + si.wShowWindow = SW_HIDE; /* this hides the console window */ + si.hStdInput = NULL; + si.hStdOutput = sync_pipe_write; + si.hStdError = sync_pipe_write; + /*si.hStdError = (HANDLE) _get_osfhandle(2);*/ +#endif + + /* convert args array into a single string */ + /* XXX - could change sync_pipe_add_arg() instead */ + /* there is a drawback here: the length is internally limited to 1024 bytes */ + for(i=0; argv[i] != 0; i++) { + if(i != 0) g_string_append_c(args, ' '); /* don't prepend a space before the path!!! */ + quoted_arg = protect_arg(argv[i]); + g_string_append(args, quoted_arg); + g_free(quoted_arg); + } + + /* call dumpcap */ + if(!CreateProcess(NULL, utf_8to16(args->str), NULL, NULL, TRUE, + CREATE_NEW_CONSOLE, NULL, NULL, &si, &pi)) { + *msg = g_strdup_printf("Couldn't run %s in child process: error %u", + args->str, GetLastError()); + CloseHandle(sync_pipe_read); + CloseHandle(sync_pipe_write); + g_free( (gpointer) argv); + return CANT_RUN_DUMPCAP; + } + fork_child = (int) pi.hProcess; + g_string_free(args, TRUE); + + /* associate the operating system filehandle to a C run-time file handle */ + /* (good file handle infos at: http://www.flounder.com/handles.htm) */ + sync_pipe_read_fd = _open_osfhandle( (long) sync_pipe_read, _O_BINARY); + +#else /* _WIN32 */ + if (pipe(sync_pipe) < 0) { + /* Couldn't create the pipe between parent and child. */ + *msg = g_strdup_printf("Couldn't create sync pipe: %s", strerror(errno)); + g_free(argv); + return CANT_RUN_DUMPCAP; + } + + if ((fork_child = fork()) == 0) { + /* + * Child process - run dumpcap with the right arguments to make + * it just capture with the specified capture parameters + */ + eth_close(1); + dup(sync_pipe[PIPE_WRITE]); + eth_close(sync_pipe[PIPE_READ]); + execv(exename, (gpointer)argv); + *msg = g_strdup_printf("Couldn't run %s in child process: %s", + exename, strerror(errno)); + return CANT_RUN_DUMPCAP; + } + + sync_pipe_read_fd = sync_pipe[PIPE_READ]; +#endif + + g_free(exename); + + /* Parent process - read messages from the child process over the + sync pipe. */ + g_free( (gpointer) argv); /* free up arg array */ + + /* Close the write side of the pipe, so that only the child has it + open, and thus it completely closes, and thus returns to us + an EOF indication, if the child closes it (either deliberately + or by exiting abnormally). */ +#ifdef _WIN32 + CloseHandle(sync_pipe_write); +#else + eth_close(sync_pipe[PIPE_WRITE]); +#endif + + if (fork_child == -1) { + /* We couldn't even create the child process. */ + *msg = g_strdup_printf("Couldn't create child process: %s", strerror(errno)); + eth_close(sync_pipe_read_fd); + return CANT_RUN_DUMPCAP; + } + + /* we might wait for a moment till child is ready, so update screen now */ + main_window_update(); + + /* We were able to set up to read dumpcap's output. Do so and + return its exit value. */ + msg_buf = g_string_new(""); + while ((count = eth_read(sync_pipe_read_fd, buf, PIPE_BUF_SIZE)) > 0) { + buf[count] = '\0'; + g_string_append(msg_buf, buf); + } + + eth_close(sync_pipe_read_fd); + + g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_DEBUG, "sync_interface_list_open: wait till child closed"); + +#ifdef _WIN32 + if (_cwait(&fork_child_status, fork_child, _WAIT_CHILD) == -1) { + g_string_free(msg_buf, TRUE); + *msg = g_strdup_printf("Child capture process stopped unexpectedly " + "(errno:%u)", errno); + return CANT_RUN_DUMPCAP; + } +#else + if (wait(&fork_child_status) != -1) { + if (WIFEXITED(fork_child_status)) { + /* The child exited. */ + fork_child_status = WEXITSTATUS(fork_child_status); + } else { + g_string_free(msg_buf, TRUE); + if (WIFSTOPPED(fork_child_status)) { + /* It stopped, rather than exiting. "Should not happen." */ + *msg = g_strdup_printf("Child capture process stopped: %s", + sync_pipe_signame(WSTOPSIG(fork_child_status))); + } else if (WIFSIGNALED(fork_child_status)) { + /* It died with a signal. */ + *msg = g_strdup_printf("Child capture process died: %s%s", + sync_pipe_signame(WTERMSIG(fork_child_status)), + WCOREDUMP(fork_child_status) ? " - core dumped" : ""); + } else { + /* What? It had to either have exited, or stopped, or died with + a signal; what happened here? */ + *msg = g_strdup_printf("Child capture process died: wait status %#o", + fork_child_status); + } + return CANT_RUN_DUMPCAP; + } + } else { + g_string_free(msg_buf, TRUE); + *msg = g_strdup_printf("Child capture process stopped unexpectedly " + "(errno:%u)", errno); + return CANT_RUN_DUMPCAP; + } +#endif + + *msg = msg_buf->str; + g_string_free(msg_buf, FALSE); + return fork_child_status; +} /* read a number of bytes from a pipe */ @@ -542,7 +778,7 @@ pipe_read_bytes(int pipe, char *bytes, int required) { /* convert header values (indicator and 4-byte length) */ static void -pipe_convert_header(const guchar *header, int header_len, char *indicator, int *block_len) { +pipe_convert_header(const guchar *header, int header_len, char *indicator, int *block_len) { g_assert(header_len == 4); @@ -636,10 +872,10 @@ sync_pipe_input_cb(gint source, gpointer user_data) capturing any more packets. Pick up its exit status, and complain if it did anything other than exit with status 0. - We don't have to worry about killing the child, if the sync pipe - returned an error. Usually this error is caused as the child killed itself - while going down. Even in the rare cases that this isn't the case, - the child will get an error when writing to the broken pipe the next time, + We don't have to worry about killing the child, if the sync pipe + returned an error. Usually this error is caused as the child killed itself + while going down. Even in the rare cases that this isn't the case, + the child will get an error when writing to the broken pipe the next time, cleaning itself up then. */ sync_pipe_wait_for_child(capture_opts); @@ -896,11 +1132,11 @@ sync_pipe_stop(capture_options *capture_opts) /* Wireshark has to exit, force the capture child to close */ void -sync_pipe_kill(capture_options *capture_opts) +sync_pipe_kill(int fork_child) { - if (capture_opts->fork_child != -1) { + if (fork_child != -1) { #ifndef _WIN32 - kill(capture_opts->fork_child, SIGTERM); /* SIGTERM so it can clean up if necessary */ + kill(fork_child, SIGTERM); /* SIGTERM so it can clean up if necessary */ #else /* Remark: This is not the preferred method of closing a process! * the clean way would be getting the process id of the child process, @@ -920,7 +1156,7 @@ sync_pipe_kill(capture_options *capture_opts) * us, as we might not be running in a console. * And this also will require to have the process id. */ - TerminateProcess((HANDLE) (capture_opts->fork_child), 0); + TerminateProcess((HANDLE) (fork_child), 0); #endif } } diff --git a/capture_sync.h b/capture_sync.h index a8b6e6edaf..5e3cb7c9e5 100644 --- a/capture_sync.h +++ b/capture_sync.h @@ -24,10 +24,10 @@ /** @file - * + * * Sync mode capture (internal interface). * - * Will start a new Wireshark child instance which will do the actual capture + * Will start a new Wireshark child instance which will do the actual capture * work. */ @@ -35,10 +35,10 @@ #define __CAPTURE_SYNC_H__ -/** +/** * Start a new capture session. * Create a capture child which is doing the real capture work. - * The various capture_input_... functions will be called, if something had + * The various capture_input_... functions will be called, if something had * happened. * * Most of the parameters are passed through the global capture_opts. @@ -46,7 +46,7 @@ * @param capture_opts the options * @return TRUE if a capture could be started, FALSE if not */ -extern gboolean +extern gboolean sync_pipe_start(capture_options *capture_opts); /** User wants to stop capturing, gracefully close the capture child */ @@ -55,12 +55,17 @@ sync_pipe_stop(capture_options *capture_opts); /** User wants to stop the program, just kill the child as soon as possible */ extern void -sync_pipe_kill(capture_options *capture_opts); +sync_pipe_kill(int fork_child); -/** does the parent signalled the child to stop */ +/** Has the parent signalled the child to stop? */ #ifdef _WIN32 extern gboolean signal_pipe_check_running(void); #endif +/** Get an interface list using dumpcap */ +extern int +sync_interface_list_open(gchar **msg); + + #endif /* capture_sync.h */ diff --git a/doc/dumpcap.pod b/doc/dumpcap.pod index 765c8c9712..9e9ed8f3ae 100644 --- a/doc/dumpcap.pod +++ b/doc/dumpcap.pod @@ -14,6 +14,7 @@ S<[ B<-D> ]> S<[ B<-f> E<lt>capture filterE<gt> ]> S<[ B<-h> ]> S<[ B<-i> E<lt>capture interfaceE<gt>|- ]> +S<[ B<-I> E<lt>l|sE<gt> ]> S<[ B<-L> ]> S<[ B<-p> ]> S<[ B<-s> E<lt>capture snaplenE<gt> ]> @@ -155,6 +156,14 @@ standard libpcap format. Note: the Win32 version of B<Dumpcap> doesn't support capturing from pipes or stdin! +=item -I + +If run with the B<l> argument, print a verbose, machine-readable interface +list, similar to the B<-D> flag. + +If run with the B<s> argument, print statistics for each interface every +second until the program terminates. + =item -L List the data link types supported by the interface and exit. The reported @@ -115,6 +115,7 @@ print_usage(gboolean print_ver) { fprintf(output, " -y <link type> link layer type (def: first appropriate)\n"); fprintf(output, " -D print list of interfaces and exit\n"); fprintf(output, " -L print list of link-layer types of iface and exit\n"); + fprintf(output, " -I [l|s] print a detailed interface list (l) or interface statistics (s).\n"); fprintf(output, "\n"); fprintf(output, "Stop conditions:\n"); fprintf(output, " -c <packet count> stop after n packets (def: infinite)\n"); @@ -161,7 +162,10 @@ cmdarg_err(const char *fmt, ...) va_list ap; if(capture_child) { - /* XXX - convert to g_log */ + /* Print a bare error */ + va_start(ap, fmt); + vfprintf(stderr, fmt, ap); + va_end(ap); } else { va_start(ap, fmt); fprintf(stderr, "dumpcap: "); @@ -245,7 +249,7 @@ main(int argc, char *argv[]) gboolean list_link_layer_types = FALSE; int status; -#define OPTSTRING_INIT "a:b:c:Df:hi:Lps:vw:y:Z" +#define OPTSTRING_INIT "a:b:c:Df:hI:i:Lps:vw:y:Z" #ifdef _WIN32 #define OPTSTRING_WIN32 "B:" @@ -275,7 +279,7 @@ main(int argc, char *argv[]) /* the default_log_handler will use stdout, which makes trouble in */ /* capture child mode, as it uses stdout for it's sync_pipe */ /* so do the filtering in the console_log_handler and not here */ - log_flags = + log_flags = G_LOG_LEVEL_ERROR| G_LOG_LEVEL_CRITICAL| G_LOG_LEVEL_WARNING| @@ -297,7 +301,7 @@ main(int argc, char *argv[]) log_flags, console_log_handler, NULL /* user_data */); - /* Set the initial values in the capture_opts. This might be overwritten + /* Set the initial values in the capture_opts. This might be overwritten by the command line parameters. */ capture_opts_init(capture_opts, NULL); @@ -326,7 +330,7 @@ main(int argc, char *argv[]) /* Assemble the run-time version information string */ runtime_info_str = g_string_new("Running "); - get_runtime_version_info(runtime_info_str, NULL); + get_runtime_version_info(runtime_info_str, NULL); show_version(comp_info_str, runtime_info_str); g_string_free(comp_info_str, TRUE); g_string_free(runtime_info_str, TRUE); @@ -362,9 +366,15 @@ main(int argc, char *argv[]) /*** all non capture option specific ***/ case 'D': /* Print a list of capture devices and exit */ - status = capture_opts_list_interfaces(); + status = capture_opts_list_interfaces(FALSE); exit_main(status); break; + /* XXX - We might want to use 'D' for this. Do we use GNU + * getopt on every platform (which supports optional arguments)? */ + /* XXX - Implement interface stats */ + case 'I': + status = capture_opts_list_interfaces(TRUE); + exit_main(status); case 'L': /* Print list of link-layer types and exit */ list_link_layer_types = TRUE; break; @@ -473,7 +483,7 @@ console_log_handler(const char *log_domain, GLogLevelFlags log_level, /* create a "timestamp" */ time(&curr); - today = localtime(&curr); + today = localtime(&curr); switch(log_level & G_LOG_LEVEL_MASK) { case G_LOG_LEVEL_ERROR: @@ -558,7 +568,7 @@ report_cfilter_error(const char *cfilter, const char *errmsg) g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_DEBUG, "Capture filter error: %s", errmsg); pipe_write_block(1, SP_BAD_FILTER, errmsg); } else { - fprintf(stderr, + fprintf(stderr, "Invalid capture filter: \"%s\"!\n" "\n" "That string isn't a valid capture filter (%s).\n" @@ -571,9 +581,9 @@ void report_capture_error(const char *error_msg, const char *secondary_error_msg) { if(capture_child) { - g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_DEBUG, + g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_DEBUG, "Primary Error: %s", error_msg); - g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_DEBUG, + g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_DEBUG, "Secondary Error: %s", secondary_error_msg); sync_pipe_errmsg_to_parent(error_msg, secondary_error_msg); } else { diff --git a/gtk/capture_dlg.c b/gtk/capture_dlg.c index 4420dbeab2..54b95b07bd 100644 --- a/gtk/capture_dlg.c +++ b/gtk/capture_dlg.c @@ -236,7 +236,7 @@ set_link_type_list(GtkWidget *linktype_om, GtkWidget *entry) /* * Try to get the list of known interfaces. */ - if_list = get_interface_list(&err, NULL); + if_list = capture_interface_list(&err, NULL); if (if_list != NULL) { /* * We have the list - check it. @@ -627,7 +627,7 @@ capture_prep_cb(GtkWidget *w _U_, gpointer d _U_) } #endif - if_list = get_interface_list(&err, &err_str); + if_list = capture_interface_list(&err, &err_str); if (if_list == NULL && err == CANT_GET_INTERFACE_LIST) { simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, "%s", err_str); g_free(err_str); diff --git a/gtk/capture_if_dlg.c b/gtk/capture_if_dlg.c index 37eb732303..b2114b481c 100644 --- a/gtk/capture_if_dlg.c +++ b/gtk/capture_if_dlg.c @@ -397,7 +397,7 @@ combo_channel_new(void) gint if_list_comparator_alph (const void *first_arg, const void *second_arg){ const if_info_t *first = first_arg, *second = second_arg; - if (first != NULL && first->description != NULL && + if (first != NULL && first->description != NULL && second != NULL && second->description != NULL) { return g_strcasecmp(first->description, second->description); } else { @@ -458,7 +458,7 @@ capture_if_cb(GtkWidget *w _U_, gpointer d _U_) #endif /* LOAD THE INTERFACES */ - if_list = get_interface_list(&err, &err_str); + if_list = capture_interface_list(&err, &err_str); if_list = g_list_sort (if_list, if_list_comparator_alph); if (if_list == NULL && err == CANT_GET_INTERFACE_LIST) { simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, "%s", err_str); diff --git a/gtk/capture_prefs.c b/gtk/capture_prefs.c index f761b0174c..6033891d42 100644 --- a/gtk/capture_prefs.c +++ b/gtk/capture_prefs.c @@ -43,6 +43,7 @@ #include "capture_ui_utils.h" #include "main.h" #include "compat_macros.h" +#include "capture.h" #define DEVICE_KEY "device" #define PROM_MODE_KEY "prom_mode" @@ -108,7 +109,7 @@ capture_prefs_show(void) /* * XXX - what if we can't get the list? */ - if_list = get_interface_list(&err, NULL); + if_list = capture_interface_list(&err, NULL); combo_list = build_capture_combo_list(if_list, FALSE); free_interface_list(if_list); if (combo_list != NULL) { @@ -119,7 +120,7 @@ capture_prefs_show(void) gtk_entry_set_text(GTK_ENTRY(GTK_COMBO(if_cb)->entry), prefs.capture_device); gtk_table_attach_defaults(GTK_TABLE(main_tb), if_cb, 1, 2, row, row+1); - gtk_tooltips_set_tip(tooltips, GTK_COMBO(if_cb)->entry, + gtk_tooltips_set_tip(tooltips, GTK_COMBO(if_cb)->entry, "The default interface to be captured from.", NULL); gtk_widget_show(if_cb); OBJECT_SET_DATA(main_vb, DEVICE_KEY, if_cb); @@ -132,7 +133,7 @@ capture_prefs_show(void) gtk_widget_show(ifopts_lb); ifopts_bt = BUTTON_NEW_FROM_STOCK(WIRESHARK_STOCK_EDIT); - gtk_tooltips_set_tip(tooltips, ifopts_bt, + gtk_tooltips_set_tip(tooltips, ifopts_bt, "Open a dialog box to set various interface options.", NULL); SIGNAL_CONNECT(ifopts_bt, "clicked", ifopts_edit_cb, NULL); gtk_table_attach_defaults(GTK_TABLE(main_tb), ifopts_bt, 1, 2, row, row+1); @@ -142,7 +143,7 @@ capture_prefs_show(void) promisc_cb = create_preference_check_button(main_tb, row++, "Capture packets in promiscuous mode:", NULL, prefs.capture_prom_mode); - gtk_tooltips_set_tip(tooltips, promisc_cb, + gtk_tooltips_set_tip(tooltips, promisc_cb, "Usually a network card will only capture the traffic sent to its own network address. " "If you want to capture all traffic that the network card can \"see\", mark this option. " "See the FAQ for some more details of capturing packets from a switched network.", NULL); @@ -251,7 +252,7 @@ ifopts_edit_cb(GtkWidget *w, gpointer data _U_) int row = 0; GtkWidget *caller = gtk_widget_get_toplevel(w); - + /* Has an edit dialog box already been opened for that top-level widget? */ ifopts_edit_dlg = OBJECT_GET_DATA(caller, IFOPTS_DIALOG_PTR_KEY); @@ -260,7 +261,7 @@ ifopts_edit_cb(GtkWidget *w, gpointer data _U_) reactivate_window(ifopts_edit_dlg); return; } - + /* create a new dialog */ ifopts_edit_dlg = dlg_window_new("Wireshark: Preferences: Interface Options"); gtk_window_set_default_size(GTK_WINDOW(ifopts_edit_dlg), DEF_WIDTH, 300); @@ -269,18 +270,18 @@ ifopts_edit_cb(GtkWidget *w, gpointer data _U_) gtk_container_border_width(GTK_CONTAINER(main_vb), 5); gtk_container_add(GTK_CONTAINER(ifopts_edit_dlg), main_vb); gtk_widget_show(main_vb); - + /* create current options frame */ cur_opts_fr = gtk_frame_new("Interfaces"); gtk_container_add(GTK_CONTAINER(main_vb), cur_opts_fr); gtk_widget_show(cur_opts_fr); - + /* create a scrolled window to pack the current options CList widget into */ cur_scr_win = scrolled_window_new(NULL, NULL); gtk_container_border_width(GTK_CONTAINER(cur_scr_win), 3); gtk_container_add(GTK_CONTAINER(cur_opts_fr), cur_scr_win); gtk_widget_show(cur_scr_win); - + /* * Create current options CList. */ @@ -292,24 +293,24 @@ ifopts_edit_cb(GtkWidget *w, gpointer data _U_) gtk_container_add(GTK_CONTAINER(cur_scr_win), cur_clist); SIGNAL_CONNECT(cur_clist, "select_row", ifopts_edit_ifsel_cb, NULL); gtk_widget_show(cur_clist); - + /* add interface names to cell */ ifopts_if_clist_add(); gtk_clist_columns_autosize(GTK_CLIST(cur_clist)); - + /* initialize variable that saves currently selected row in "if_clist" */ ifrow = IFOPTS_IF_NOSEL; - + /* create edit options frame */ ed_opts_fr = gtk_frame_new("Properties"); gtk_box_pack_start(GTK_BOX(main_vb), ed_opts_fr, FALSE, FALSE, 0); gtk_widget_show(ed_opts_fr); - + main_hb = gtk_hbox_new(TRUE, 5); gtk_container_border_width(GTK_CONTAINER(main_hb), 3); gtk_container_add(GTK_CONTAINER(ed_opts_fr), main_hb); gtk_widget_show(main_hb); - + /* table to hold description text entry and hide button */ main_tb = gtk_table_new(IFOPTS_TABLE_ROWS, 4, FALSE); gtk_box_pack_start(GTK_BOX(main_hb), main_tb, TRUE, FALSE, 10); @@ -321,51 +322,51 @@ ifopts_edit_cb(GtkWidget *w, gpointer data _U_) gtk_table_attach_defaults(GTK_TABLE(main_tb), if_dev_lb, 0, 1, row, row+1); gtk_misc_set_alignment(GTK_MISC(if_dev_lb), 1.0, 0.5); gtk_widget_show(if_dev_lb); - + if_dev_lb = gtk_label_new(""); gtk_table_attach_defaults(GTK_TABLE(main_tb), if_dev_lb, 1, 2, row, row+1); gtk_misc_set_alignment(GTK_MISC(if_dev_lb), 0.0, 0.5); gtk_widget_show(if_dev_lb); row++; - + if_name_lb = gtk_label_new("Description:"); gtk_table_attach_defaults(GTK_TABLE(main_tb), if_name_lb, 0, 1, row, row+1); gtk_misc_set_alignment(GTK_MISC(if_name_lb), 1.0, 0.5); gtk_widget_show(if_name_lb); - + if_name_lb = gtk_label_new(""); gtk_table_attach_defaults(GTK_TABLE(main_tb), if_name_lb, 1, 2, row, row+1); gtk_misc_set_alignment(GTK_MISC(if_name_lb), 0.0, 0.5); gtk_widget_show(if_name_lb); row++; - + /* create interface description label and text entry */ if_descr_lb = gtk_label_new("Comment:"); gtk_table_attach_defaults(GTK_TABLE(main_tb), if_descr_lb, 0, 1, row, row+1); gtk_misc_set_alignment(GTK_MISC(if_descr_lb), 1.0, 0.5); gtk_widget_show(if_descr_lb); - + if_descr_te = gtk_entry_new(); - SIGNAL_CONNECT(if_descr_te, "changed", ifopts_edit_descr_changed_cb, + SIGNAL_CONNECT(if_descr_te, "changed", ifopts_edit_descr_changed_cb, cur_clist); gtk_entry_set_max_length(GTK_ENTRY(if_descr_te), IFOPTS_MAX_DESCR_LEN); gtk_table_attach_defaults(GTK_TABLE(main_tb), if_descr_te, 1, 2, row, row+1); gtk_widget_show(if_descr_te); row++; - + /* create hide interface label and button */ if_hide_lb = gtk_label_new("Hide interface?:"); gtk_table_attach_defaults(GTK_TABLE(main_tb), if_hide_lb, 0, 1, row, row+1); gtk_misc_set_alignment(GTK_MISC(if_hide_lb), 1.0, 0.5); gtk_widget_show(if_hide_lb); - + if_hide_cb = gtk_check_button_new(); - SIGNAL_CONNECT(if_hide_cb, "toggled", ifopts_edit_hide_changed_cb, + SIGNAL_CONNECT(if_hide_cb, "toggled", ifopts_edit_hide_changed_cb, cur_clist); gtk_table_attach_defaults(GTK_TABLE(main_tb), if_hide_cb, 1, 2, row, row+1); gtk_widget_show(if_hide_cb); row++; - + /* button row: OK and Cancel buttons */ bbox = dlg_button_row_new(GTK_STOCK_OK, GTK_STOCK_CANCEL, NULL); gtk_box_pack_start(GTK_BOX(main_vb), bbox, FALSE, FALSE, 0); @@ -392,7 +393,7 @@ ifopts_edit_cb(GtkWidget *w, gpointer data _U_) /* select the first row in if list, all option fields must exist for this */ gtk_clist_select_row(GTK_CLIST(cur_clist), 0, -1); - + gtk_widget_show(ifopts_edit_dlg); window_present(ifopts_edit_dlg); } @@ -406,11 +407,11 @@ ifopts_edit_ok_cb(GtkWidget *w _U_, gpointer parent_w) if (ifrow != IFOPTS_IF_NOSEL) { /* create/write new interfaces description string */ ifopts_write_new_descr(); - + /* create/write new "hidden" interfaces string */ ifopts_write_new_hide(); } - + /* Now nuke this window. */ gtk_grab_remove(GTK_WIDGET(parent_w)); window_destroy(GTK_WIDGET(parent_w)); @@ -443,31 +444,31 @@ ifopts_edit_ifsel_cb(GtkWidget *clist _U_, gpointer data _U_) { gchar *text; - + /* save currently selected row */ ifrow = row; - + /* get/display the interface device from current CList */ gtk_clist_get_text(GTK_CLIST(cur_clist), row, 0, &text); /* is needed, as gtk_entry_set_text() will change text again (bug in GTK?) */ text = strdup(text); gtk_label_set_text(GTK_LABEL(if_dev_lb), text); g_free(text); - + /* get/display the interface name from current CList */ gtk_clist_get_text(GTK_CLIST(cur_clist), row, 1, &text); /* is needed, as gtk_entry_set_text() will change text again (bug in GTK?) */ text = strdup(text); gtk_label_set_text(GTK_LABEL(if_name_lb), text); g_free(text); - + /* get/display the interface description from current CList */ gtk_clist_get_text(GTK_CLIST(cur_clist), row, 2, &text); /* is needed, as gtk_entry_set_text() will change text again (bug in GTK?) */ text = strdup(text); gtk_entry_set_text(GTK_ENTRY(if_descr_te), text); g_free(text); - + /* get/display the "hidden" button state from current CList */ gtk_clist_get_text(GTK_CLIST(cur_clist), row, 3, &text); if (strcmp("Yes", text) == 0) @@ -483,10 +484,10 @@ static void ifopts_edit_descr_changed_cb(GtkEditable *ed, gpointer udata) { gchar *text; - + if (ifrow == IFOPTS_IF_NOSEL) return; - + /* get current description text and set value in current CList */ text = gtk_editable_get_chars(GTK_EDITABLE(ed), 0, -1); /* replace any reserved formatting characters "()," with spaces */ @@ -503,7 +504,7 @@ ifopts_edit_hide_changed_cb(GtkToggleButton *tbt, gpointer udata) { if (ifrow == IFOPTS_IF_NOSEL) return; - + /* get "hidden" button state and set text in current CList */ if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(tbt)) == TRUE) gtk_clist_set_text(GTK_CLIST(udata), ifrow, 3, "Yes"); @@ -515,9 +516,9 @@ ifopts_edit_hide_changed_cb(GtkToggleButton *tbt, gpointer udata) * Add any saved options that apply to cells in current CList. * * NOTE: - * Interfaces that have been removed from the machine or disabled and - * no longer apply are ignored. Therefore, if the user subsequently - * selects "OK", the options for these interfaces are lost (they're + * Interfaces that have been removed from the machine or disabled and + * no longer apply are ignored. Therefore, if the user subsequently + * selects "OK", the options for these interfaces are lost (they're * lost permanently if "Save" is selected). */ static void @@ -529,12 +530,12 @@ ifopts_options_add(GtkCList *clist, if_info_t *if_info) gchar *desc; gchar *pr_descr; gchar *text[] = { NULL, NULL, NULL, NULL }; - + /* add interface descriptions and "hidden" flag */ if (prefs.capture_devices_descr != NULL) { /* create working copy of device descriptions */ pr_descr = g_strdup(prefs.capture_devices_descr); - + /* if we find a description for this interface */ if ((ifnm = strstr(pr_descr, if_info->name)) != NULL) { p = ifnm; @@ -580,7 +581,7 @@ ifopts_options_add(GtkCList *clist, if_info_t *if_info) text[2] = g_strdup(desc); /* add row to CList */ row = gtk_clist_append(GTK_CLIST(clist), text); - gtk_clist_set_selectable(GTK_CLIST(clist), row, + gtk_clist_set_selectable(GTK_CLIST(clist), row, FALSE); ifopts_options_free(text); break; @@ -614,13 +615,13 @@ ifopts_options_add(GtkCList *clist, if_info_t *if_info) } else text[3] = g_strdup("No"); - + /* add row to CList */ row = gtk_clist_append(GTK_CLIST(clist), text); gtk_clist_set_selectable(GTK_CLIST(clist), row, FALSE); ifopts_options_free(text); } - + g_free(pr_descr); } /* @@ -641,7 +642,7 @@ ifopts_options_add(GtkCList *clist, if_info_t *if_info) text[3] = g_strdup("Yes"); else text[3] = g_strdup("No"); - + /* add row to CList */ row = gtk_clist_append(GTK_CLIST(clist), text); gtk_clist_set_selectable(GTK_CLIST(clist), row, FALSE); @@ -662,7 +663,7 @@ ifopts_options_add(GtkCList *clist, if_info_t *if_info) text[2] = g_strdup(""); /* interface is not "hidden" */ text[3] = g_strdup("No"); - + /* add row to CList */ row = gtk_clist_append(GTK_CLIST(clist), text); gtk_clist_set_selectable(GTK_CLIST(clist), row, FALSE); @@ -674,7 +675,7 @@ static void ifopts_options_free(gchar *text[]) { gint i; - + for (i=0; i < IFOPTS_CLIST_COLS; i++) { if (text[i] != NULL) { g_free(text[i]); @@ -695,18 +696,18 @@ ifopts_if_clist_add(void) if_info_t *if_info; guint i; guint nitems; - - if_list = get_interface_list(&err, &err_str); + + if_list = capture_interface_list(&err, &err_str); if (if_list == NULL && err == CANT_GET_INTERFACE_LIST) { simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, "%s", err_str); g_free(err_str); return; } - + /* Seems we need to be at list head for g_list_length()? */ if_list = g_list_first(if_list); nitems = g_list_length(if_list); - + /* add OS description + interface name text to CList */ for (i=0; i < nitems; i++) { if_info = g_list_nth_data(if_list, i); @@ -717,7 +718,7 @@ ifopts_if_clist_add(void) /* fill current options CList with current preference values */ ifopts_options_add(GTK_CLIST(cur_clist), if_info); } - + free_interface_list(if_list); } @@ -734,10 +735,10 @@ ifopts_write_new_descr(void) gchar *desc; gchar *tmp_descr; gchar *new_descr; - + /* new preferences interfaces description string */ new_descr = g_malloc0(MAX_VAL_LEN); - + /* get description for each row (interface) */ for (i = 0; ;i++) { /* get description */ @@ -746,7 +747,7 @@ ifopts_write_new_descr(void) /* if no description, skip this interface */ if (strlen(desc) == 0) continue; - + /* get interface name */ gtk_clist_get_text(GTK_CLIST(cur_clist), i, 0, &ifnm); @@ -763,7 +764,7 @@ ifopts_write_new_descr(void) /* set first-in-list flag to false */ first_if = FALSE; } - + /* write new description string to preferences */ if (strlen(new_descr) > 0) { g_free(prefs.capture_devices_descr); @@ -790,10 +791,10 @@ ifopts_write_new_hide(void) gchar *hide; gchar *tmp_hide; gchar *new_hide; - + /* new preferences "hidden" interfaces string */ new_hide = g_malloc0(MAX_VAL_LEN); - + /* get "hidden" flag text for each row (interface) */ for (i = 0; ;i++) { /* get flag */ @@ -805,7 +806,7 @@ ifopts_write_new_hide(void) /* get interface name */ gtk_clist_get_text(GTK_CLIST(cur_clist), i, 0, &ifnm); - + /* * create/cat interface to new string */ @@ -819,7 +820,7 @@ ifopts_write_new_hide(void) /* set first-in-list flag to false */ first_if = FALSE; } - + /* write new "hidden" string to preferences */ if (strlen(new_hide) > 0) { g_free(prefs.capture_devices_hide); diff --git a/gtk/main.c b/gtk/main.c index beac1944d0..2853de6404 100644 --- a/gtk/main.c +++ b/gtk/main.c @@ -2568,7 +2568,7 @@ main(int argc, char *argv[]) /*** all non capture option specific ***/ case 'D': /* Print a list of capture devices and exit */ #ifdef HAVE_LIBPCAP - capture_opts_list_interfaces(); + capture_opts_list_interfaces(FALSE); exit(0); #else capture_option_specified = TRUE; @@ -740,7 +740,7 @@ main(int argc, char *argv[]) */ opterr = 0; optind_initial = optind; - + while ((opt = getopt(argc, argv, optstring)) != -1) { switch (opt) { case 'X': @@ -750,7 +750,7 @@ main(int argc, char *argv[]) break; } } - + optind = optind_initial; opterr = 1; @@ -948,7 +948,7 @@ main(int argc, char *argv[]) break; case 'D': /* Print a list of capture devices and exit */ #ifdef HAVE_LIBPCAP - status = capture_opts_list_interfaces(); + status = capture_opts_list_interfaces(FALSE); exit(status); #else capture_option_specified = TRUE; @@ -1146,7 +1146,7 @@ main(int argc, char *argv[]) "specified with \"-e\"."); exit(1); - } + } /* If no capture filter or read filter has been specified, and there are still command-line arguments, treat them as the tokens of a capture @@ -1269,7 +1269,7 @@ main(int argc, char *argv[]) "a capture isn't being done."); exit(1); } - + /* Note: TShark now allows the restriction of a _read_ file by packet count * and byte count as well as a write file. Other autostop options remain valid * only for a write file. @@ -1486,7 +1486,7 @@ main(int argc, char *argv[]) /* Process the packets in the file */ #ifdef HAVE_LIBPCAP - err = load_cap_file(&cfile, capture_opts.save_file, out_file_type, + err = load_cap_file(&cfile, capture_opts.save_file, out_file_type, capture_opts.has_autostop_packets ? capture_opts.autostop_packets : 0, capture_opts.has_autostop_filesize ? capture_opts.autostop_filesize : 0); #else @@ -2114,7 +2114,7 @@ report_counts_siginfo(int signum _U_) #endif /* HAVE_LIBPCAP */ static int -load_cap_file(capture_file *cf, char *save_file, int out_file_type, +load_cap_file(capture_file *cf, char *save_file, int out_file_type, int max_packet_count, gint64 max_byte_count) { gint linktype; @@ -2401,7 +2401,7 @@ process_packet(capture_file *cf, gint64 offset, const struct wtap_pkthdr *whdr, } if (passed) { - /* Keep the time of the current packet if the packet passed + /* Keep the time of the current packet if the packet passed the read filter so that the delta time since last displayed packet can be calculated */ prev_dis_ts = fdata.abs_ts; @@ -2809,7 +2809,7 @@ print_packet(capture_file *cf, epan_dissect_t *edt) case WRITE_FIELDS: proto_tree_write_fields(output_fields, edt, stdout); printf("\n"); - return !ferror(stdout); + return !ferror(stdout); } } else { /* Just fill in the columns. */ |