dumpcap: Serialize machine readable interface caps as JSON
Serialize the machine readable version of the interface capability output as JSON, using an array to support multiple interfaces. When querying multiple interfaces, try all of them, exit with success (unless unexpected errors occur) and report any per-interface errors and exit codes inside the JSON rather than stopping after the first interface with error. Update capture_get_if_capabilities to process the JSON. It (and sync_if_capabilities_open) still only query a single interface at, but this will allow modification to handle multiple interfaces at once later. Related to #16191, #15082
This commit is contained in:
parent
212cfe132c
commit
0d93782443
|
@ -26,6 +26,7 @@
|
||||||
|
|
||||||
#include <capture/capture_ifinfo.h>
|
#include <capture/capture_ifinfo.h>
|
||||||
#include <wsutil/inet_addr.h>
|
#include <wsutil/inet_addr.h>
|
||||||
|
#include <wsutil/wsjson.h>
|
||||||
|
|
||||||
#ifdef HAVE_PCAP_REMOTE
|
#ifdef HAVE_PCAP_REMOTE
|
||||||
static GList *remote_interface_list = NULL;
|
static GList *remote_interface_list = NULL;
|
||||||
|
@ -199,8 +200,8 @@ capture_get_if_capabilities(const char *ifname, bool monitor_mode,
|
||||||
if_capabilities_t *caps;
|
if_capabilities_t *caps;
|
||||||
GList *linktype_list = NULL, *timestamp_list = NULL;
|
GList *linktype_list = NULL, *timestamp_list = NULL;
|
||||||
int err, i;
|
int err, i;
|
||||||
char *data, *primary_msg, *secondary_msg;
|
char *data, *primary_msg, *secondary_msg, *val_s;
|
||||||
char **raw_list;
|
jsmntok_t *tokens, *inf_tok, *array_tok, *cur_tok;
|
||||||
|
|
||||||
/* see if the interface is from extcap */
|
/* see if the interface is from extcap */
|
||||||
caps = extcap_get_if_dlts(ifname, err_primary_msg);
|
caps = extcap_get_if_dlts(ifname, err_primary_msg);
|
||||||
|
@ -228,23 +229,81 @@ capture_get_if_capabilities(const char *ifname, bool monitor_mode,
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Split our lines */
|
int num_tokens = json_parse(data, NULL, 0);
|
||||||
#ifdef _WIN32
|
if (num_tokens <= 0) {
|
||||||
raw_list = g_strsplit(data, "\r\n", 0);
|
ws_warning("Capture Interface Capabilities failed with invalid JSON.");
|
||||||
#else
|
g_free(data);
|
||||||
raw_list = g_strsplit(data, "\n", 0);
|
return NULL;
|
||||||
#endif
|
}
|
||||||
g_free(data);
|
|
||||||
|
|
||||||
/*
|
tokens = wmem_alloc_array(NULL, jsmntok_t, num_tokens);
|
||||||
* First line is 0 if monitor mode isn't supported, 1 if it is.
|
if (json_parse(data, tokens, num_tokens) <= 0) {
|
||||||
*/
|
|
||||||
if (raw_list[0] == NULL || *raw_list[0] == '\0') {
|
|
||||||
ws_info("Capture Interface Capabilities returned no information.");
|
ws_info("Capture Interface Capabilities returned no information.");
|
||||||
if (err_primary_msg) {
|
if (err_primary_msg) {
|
||||||
*err_primary_msg = g_strdup("Dumpcap returned no interface capability information");
|
*err_primary_msg = g_strdup("Dumpcap returned no interface capability information");
|
||||||
}
|
}
|
||||||
g_strfreev(raw_list);
|
wmem_free(NULL, tokens);
|
||||||
|
g_free(data);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
cur_tok = json_get_array_index(tokens, 0);
|
||||||
|
if (cur_tok == NULL) {
|
||||||
|
ws_warning("Capture Interface Capabilities failed with invalid JSON.");
|
||||||
|
wmem_free(NULL, tokens);
|
||||||
|
g_free(data);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
inf_tok = json_get_object(data, cur_tok, ifname);
|
||||||
|
if (inf_tok == NULL) {
|
||||||
|
ws_warning("Capture Interface Capabilities failed with invalid JSON.");
|
||||||
|
wmem_free(NULL, tokens);
|
||||||
|
g_free(data);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
double val_d;
|
||||||
|
if (!json_get_double(data, inf_tok, "status", &val_d)) {
|
||||||
|
ws_warning("Capture Interface Capabilities failed with invalid JSON.");
|
||||||
|
wmem_free(NULL, tokens);
|
||||||
|
g_free(data);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
err = (int)val_d;
|
||||||
|
if (err != 0) {
|
||||||
|
primary_msg = json_get_string(data, inf_tok, "primary_msg");
|
||||||
|
if (primary_msg) {
|
||||||
|
primary_msg = g_strdup(primary_msg);
|
||||||
|
}
|
||||||
|
secondary_msg = json_get_string(data, inf_tok, "secondary_msg");
|
||||||
|
if (secondary_msg) {
|
||||||
|
secondary_msg = g_strdup(secondary_msg);
|
||||||
|
}
|
||||||
|
ws_info("Capture Interface Capabilities failed. Error %d, %s",
|
||||||
|
err, primary_msg ? primary_msg : "no message");
|
||||||
|
if (err_primary_msg)
|
||||||
|
*err_primary_msg = primary_msg;
|
||||||
|
else
|
||||||
|
g_free(primary_msg);
|
||||||
|
if (err_secondary_msg)
|
||||||
|
*err_secondary_msg = secondary_msg;
|
||||||
|
else
|
||||||
|
g_free(secondary_msg);
|
||||||
|
wmem_free(NULL, tokens);
|
||||||
|
g_free(data);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool rfmon;
|
||||||
|
if (!json_get_boolean(data, inf_tok, "rfmon", &rfmon)) {
|
||||||
|
ws_message("Capture Interface Capabilities returned bad information.");
|
||||||
|
ws_message("Didn't return monitor-mode cap");
|
||||||
|
if (err_primary_msg) {
|
||||||
|
*err_primary_msg = ws_strdup_printf("Dumpcap didn't return monitor-mode capability");
|
||||||
|
}
|
||||||
|
wmem_free(NULL, tokens);
|
||||||
|
g_free(data);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -252,75 +311,67 @@ capture_get_if_capabilities(const char *ifname, bool monitor_mode,
|
||||||
* Allocate the interface capabilities structure.
|
* Allocate the interface capabilities structure.
|
||||||
*/
|
*/
|
||||||
caps = (if_capabilities_t *)g_malloc(sizeof *caps);
|
caps = (if_capabilities_t *)g_malloc(sizeof *caps);
|
||||||
switch (*raw_list[0]) {
|
caps->can_set_rfmon = rfmon;
|
||||||
|
|
||||||
case '0':
|
|
||||||
caps->can_set_rfmon = false;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case '1':
|
|
||||||
caps->can_set_rfmon = true;
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
ws_info("Capture Interface Capabilities returned bad information.");
|
|
||||||
if (err_primary_msg) {
|
|
||||||
*err_primary_msg = ws_strdup_printf("Dumpcap returned \"%s\" for monitor-mode capability",
|
|
||||||
raw_list[0]);
|
|
||||||
}
|
|
||||||
g_free(caps);
|
|
||||||
g_strfreev(raw_list);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The following are link-layer types.
|
* The following are link-layer types.
|
||||||
*/
|
*/
|
||||||
for (i = 1; raw_list[i] != NULL && *raw_list[i] != '\0'; i++) {
|
array_tok = json_get_array(data, inf_tok, "data_link_types");
|
||||||
data_link_info_t *data_link_info;
|
if (!array_tok) {
|
||||||
/* ...and what if the interface name has a tab in it, Mr. Clever Programmer? */
|
ws_message("Capture Interface Capabilities returned bad data_link information.");
|
||||||
char **lt_parts = g_strsplit(raw_list[i], "\t", 3);
|
if (err_primary_msg) {
|
||||||
if (lt_parts[0] == NULL || lt_parts[1] == NULL || lt_parts[2] == NULL) {
|
*err_primary_msg = ws_strdup_printf("Dumpcap didn't return data link types capability");
|
||||||
g_strfreev(lt_parts);
|
}
|
||||||
|
wmem_free(NULL, tokens);
|
||||||
|
g_free(data);
|
||||||
|
g_free(caps);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
for (i = 0; i < json_get_array_len(array_tok); i++) {
|
||||||
|
cur_tok = json_get_array_index(array_tok, i);
|
||||||
|
|
||||||
|
if (!json_get_double(data, cur_tok, "dlt", &val_d)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
data_link_info_t *data_link_info;
|
||||||
data_link_info = g_new(data_link_info_t,1);
|
data_link_info = g_new(data_link_info_t,1);
|
||||||
data_link_info->dlt = (int) strtol(lt_parts[0], NULL, 10);
|
|
||||||
data_link_info->name = g_strdup(lt_parts[1]);
|
|
||||||
if (strcmp(lt_parts[2], "(not supported)") != 0)
|
|
||||||
data_link_info->description = g_strdup(lt_parts[2]);
|
|
||||||
else
|
|
||||||
data_link_info->description = NULL;
|
|
||||||
g_strfreev(lt_parts);
|
|
||||||
|
|
||||||
|
data_link_info->dlt = (int)val_d;
|
||||||
|
val_s = json_get_string(data, cur_tok, "name");
|
||||||
|
data_link_info->name = val_s ? g_strdup(val_s) : NULL;
|
||||||
|
val_s = json_get_string(data, cur_tok, "description");
|
||||||
|
if (!val_s || strcmp(val_s, "(not supported)") == 0) {
|
||||||
|
data_link_info->description = NULL;
|
||||||
|
} else {
|
||||||
|
data_link_info->description = g_strdup(val_s);
|
||||||
|
}
|
||||||
linktype_list = g_list_append(linktype_list, data_link_info);
|
linktype_list = g_list_append(linktype_list, data_link_info);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (raw_list[i]) { /* Oh, timestamp types! */
|
array_tok = json_get_array(data, inf_tok, "timestamp_types");
|
||||||
for (i++; raw_list[i] != NULL && *raw_list[i] != '\0'; i++) {
|
if (array_tok) {
|
||||||
timestamp_info_t *timestamp_info;
|
for (i = 0; i < json_get_array_len(array_tok); i++) {
|
||||||
char **tt_parts = g_strsplit(raw_list[i], "\t", 2);
|
cur_tok = json_get_array_index(array_tok, i);
|
||||||
if (tt_parts[0] == NULL || tt_parts[1] == NULL) {
|
|
||||||
g_strfreev(tt_parts);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
timestamp_info_t *timestamp_info;
|
||||||
timestamp_info = g_new(timestamp_info_t,1);
|
timestamp_info = g_new(timestamp_info_t,1);
|
||||||
timestamp_info->name = g_strdup(tt_parts[0]);
|
val_s = json_get_string(data, cur_tok, "name");
|
||||||
timestamp_info->description = g_strdup(tt_parts[1]);
|
timestamp_info->name = val_s ? g_strdup(val_s) : NULL;
|
||||||
g_strfreev(tt_parts);
|
val_s = json_get_string(data, cur_tok, "description");
|
||||||
|
timestamp_info->description = val_s ? g_strdup(val_s) : NULL;
|
||||||
|
|
||||||
timestamp_list = g_list_append(timestamp_list, timestamp_info);
|
timestamp_list = g_list_append(timestamp_list, timestamp_info);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
g_strfreev(raw_list);
|
|
||||||
|
|
||||||
caps->data_link_types = linktype_list;
|
caps->data_link_types = linktype_list;
|
||||||
/* Might be NULL. Not all systems report timestamp types */
|
/* Might be NULL. Not all systems report timestamp types */
|
||||||
caps->timestamp_types = timestamp_list;
|
caps->timestamp_types = timestamp_list;
|
||||||
|
|
||||||
|
wmem_free(NULL, tokens);
|
||||||
|
g_free(data);
|
||||||
|
|
||||||
return caps;
|
return caps;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
141
dumpcap.c
141
dumpcap.c
|
@ -78,6 +78,7 @@
|
||||||
#include "wsutil/time_util.h"
|
#include "wsutil/time_util.h"
|
||||||
#include "wsutil/please_report_bug.h"
|
#include "wsutil/please_report_bug.h"
|
||||||
#include "wsutil/glib-compat.h"
|
#include "wsutil/glib-compat.h"
|
||||||
|
#include <wsutil/json_dumper.h>
|
||||||
#include <wsutil/ws_assert.h>
|
#include <wsutil/ws_assert.h>
|
||||||
|
|
||||||
#include "capture/ws80211_utils.h"
|
#include "capture/ws80211_utils.h"
|
||||||
|
@ -1089,21 +1090,17 @@ print_machine_readable_interfaces(GList *if_list)
|
||||||
* you MUST update capture_ifinfo.c:capture_get_if_capabilities() accordingly!
|
* you MUST update capture_ifinfo.c:capture_get_if_capabilities() accordingly!
|
||||||
*/
|
*/
|
||||||
static void
|
static void
|
||||||
print_machine_readable_if_capabilities(if_capabilities_t *caps, int queries)
|
print_machine_readable_if_capabilities(json_dumper *dumper, if_capabilities_t *caps, int queries)
|
||||||
{
|
{
|
||||||
GList *lt_entry, *ts_entry;
|
GList *lt_entry, *ts_entry;
|
||||||
const gchar *desc_str;
|
const gchar *desc_str;
|
||||||
|
|
||||||
if (capture_child) {
|
|
||||||
/* Let our parent know we succeeded. */
|
|
||||||
sync_pipe_write_string_msg(2, SP_SUCCESS, NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (queries & CAPS_QUERY_LINK_TYPES) {
|
if (queries & CAPS_QUERY_LINK_TYPES) {
|
||||||
if (caps->can_set_rfmon)
|
json_dumper_set_member_name(dumper, "rfmon");
|
||||||
printf("1\n");
|
// XXX: wsjson.h doesn't have a function to read booleans
|
||||||
else
|
json_dumper_value_anyf(dumper, "%s", caps->can_set_rfmon ? "true" : "false");
|
||||||
printf("0\n");
|
json_dumper_set_member_name(dumper, "data_link_types");
|
||||||
|
json_dumper_begin_array(dumper);
|
||||||
for (lt_entry = caps->data_link_types; lt_entry != NULL;
|
for (lt_entry = caps->data_link_types; lt_entry != NULL;
|
||||||
lt_entry = g_list_next(lt_entry)) {
|
lt_entry = g_list_next(lt_entry)) {
|
||||||
data_link_info_t *data_link_info = (data_link_info_t *)lt_entry->data;
|
data_link_info_t *data_link_info = (data_link_info_t *)lt_entry->data;
|
||||||
|
@ -1111,12 +1108,20 @@ print_machine_readable_if_capabilities(if_capabilities_t *caps, int queries)
|
||||||
desc_str = data_link_info->description;
|
desc_str = data_link_info->description;
|
||||||
else
|
else
|
||||||
desc_str = "(not supported)";
|
desc_str = "(not supported)";
|
||||||
printf("%d\t%s\t%s\n", data_link_info->dlt, data_link_info->name,
|
json_dumper_begin_object(dumper);
|
||||||
desc_str);
|
json_dumper_set_member_name(dumper, "dlt");
|
||||||
|
json_dumper_value_anyf(dumper, "%d", data_link_info->dlt);
|
||||||
|
json_dumper_set_member_name(dumper, "name");
|
||||||
|
json_dumper_value_string(dumper, data_link_info->name);
|
||||||
|
json_dumper_set_member_name(dumper, "description");
|
||||||
|
json_dumper_value_string(dumper, desc_str);
|
||||||
|
json_dumper_end_object(dumper);
|
||||||
}
|
}
|
||||||
|
json_dumper_end_array(dumper);
|
||||||
}
|
}
|
||||||
printf("\n");
|
|
||||||
if (queries & CAPS_QUERY_TIMESTAMP_TYPES) {
|
if (queries & CAPS_QUERY_TIMESTAMP_TYPES) {
|
||||||
|
json_dumper_set_member_name(dumper, "timestamp_types");
|
||||||
|
json_dumper_begin_array(dumper);
|
||||||
for (ts_entry = caps->timestamp_types; ts_entry != NULL;
|
for (ts_entry = caps->timestamp_types; ts_entry != NULL;
|
||||||
ts_entry = g_list_next(ts_entry)) {
|
ts_entry = g_list_next(ts_entry)) {
|
||||||
timestamp_info_t *timestamp = (timestamp_info_t *)ts_entry->data;
|
timestamp_info_t *timestamp = (timestamp_info_t *)ts_entry->data;
|
||||||
|
@ -1124,8 +1129,14 @@ print_machine_readable_if_capabilities(if_capabilities_t *caps, int queries)
|
||||||
desc_str = timestamp->description;
|
desc_str = timestamp->description;
|
||||||
else
|
else
|
||||||
desc_str = "(none)";
|
desc_str = "(none)";
|
||||||
printf("%s\t%s\n", timestamp->name, desc_str);
|
json_dumper_begin_object(dumper);
|
||||||
|
json_dumper_set_member_name(dumper, "name");
|
||||||
|
json_dumper_value_string(dumper, timestamp->name);
|
||||||
|
json_dumper_set_member_name(dumper, "description");
|
||||||
|
json_dumper_value_string(dumper, desc_str);
|
||||||
|
json_dumper_end_object(dumper);
|
||||||
}
|
}
|
||||||
|
json_dumper_end_array(dumper);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5870,43 +5881,89 @@ main(int argc, char *argv[])
|
||||||
gchar *open_status_str;
|
gchar *open_status_str;
|
||||||
guint ii;
|
guint ii;
|
||||||
|
|
||||||
for (ii = 0; ii < global_capture_opts.ifaces->len; ii++) {
|
if (machine_readable) {
|
||||||
interface_options *interface_opts;
|
status = 0;
|
||||||
|
json_dumper dumper = {
|
||||||
|
.output_file = stdout,
|
||||||
|
.flags = JSON_DUMPER_FLAGS_NO_DEBUG,
|
||||||
|
// Don't abort on failure
|
||||||
|
};
|
||||||
|
json_dumper_begin_array(&dumper);
|
||||||
|
for (ii = 0; ii < global_capture_opts.ifaces->len; ii++) {
|
||||||
|
interface_options *interface_opts;
|
||||||
|
|
||||||
interface_opts = &g_array_index(global_capture_opts.ifaces, interface_options, ii);
|
interface_opts = &g_array_index(global_capture_opts.ifaces, interface_options, ii);
|
||||||
|
|
||||||
caps = get_if_capabilities(interface_opts, &open_status, &open_status_str);
|
json_dumper_begin_object(&dumper);
|
||||||
if (caps == NULL) {
|
json_dumper_set_member_name(&dumper, interface_opts->name);
|
||||||
if (capture_child) {
|
|
||||||
char *error_msg = ws_strdup_printf("The capabilities of the capture device "
|
json_dumper_begin_object(&dumper);
|
||||||
"\"%s\" could not be obtained (%s)",
|
|
||||||
interface_opts->name, open_status_str);
|
open_status = CAP_DEVICE_OPEN_NO_ERR;
|
||||||
sync_pipe_write_errmsgs_to_parent(2, error_msg,
|
caps = get_if_capabilities(interface_opts, &open_status, &open_status_str);
|
||||||
get_pcap_failure_secondary_error_message(open_status, open_status_str));
|
json_dumper_set_member_name(&dumper, "status");
|
||||||
g_free(error_msg);
|
json_dumper_value_anyf(&dumper, "%i", open_status);
|
||||||
|
if (caps == NULL) {
|
||||||
|
json_dumper_set_member_name(&dumper, "primary_msg");
|
||||||
|
json_dumper_value_string(&dumper, open_status_str);
|
||||||
|
json_dumper_set_member_name(&dumper, "secondary_msg");
|
||||||
|
json_dumper_value_string(&dumper, get_pcap_failure_secondary_error_message(open_status, open_status_str));
|
||||||
|
g_free(open_status_str);
|
||||||
|
} else {
|
||||||
|
/* XXX: We need to change the format and adapt consumers */
|
||||||
|
print_machine_readable_if_capabilities(&dumper, caps, caps_queries);
|
||||||
|
free_if_capabilities(caps);
|
||||||
}
|
}
|
||||||
else {
|
json_dumper_end_object(&dumper);
|
||||||
cmdarg_err("The capabilities of the capture device "
|
json_dumper_end_object(&dumper);
|
||||||
"\"%s\" could not be obtained (%s).\n%s",
|
|
||||||
interface_opts->name, open_status_str,
|
|
||||||
get_pcap_failure_secondary_error_message(open_status, open_status_str));
|
|
||||||
}
|
|
||||||
g_free(open_status_str);
|
|
||||||
exit_main(2);
|
|
||||||
}
|
}
|
||||||
|
json_dumper_end_array(&dumper);
|
||||||
if (machine_readable) { /* tab-separated values to stdout */
|
if (json_dumper_finish(&dumper)) {
|
||||||
/* XXX: We need to change the format and adapt consumers */
|
|
||||||
print_machine_readable_if_capabilities(caps, caps_queries);
|
|
||||||
status = 0;
|
status = 0;
|
||||||
} else
|
if (capture_child) {
|
||||||
|
/* Let our parent know we succeeded. */
|
||||||
|
sync_pipe_write_string_msg(2, SP_SUCCESS, NULL);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
status = 2;
|
||||||
|
if (capture_child) {
|
||||||
|
sync_pipe_write_errmsgs_to_parent(2, "Unexpected JSON error", "");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for (ii = 0; ii < global_capture_opts.ifaces->len; ii++) {
|
||||||
|
interface_options *interface_opts;
|
||||||
|
|
||||||
|
interface_opts = &g_array_index(global_capture_opts.ifaces, interface_options, ii);
|
||||||
|
|
||||||
|
caps = get_if_capabilities(interface_opts, &open_status, &open_status_str);
|
||||||
|
if (caps == NULL) {
|
||||||
|
if (capture_child) {
|
||||||
|
char *error_msg = ws_strdup_printf("The capabilities of the capture device "
|
||||||
|
"\"%s\" could not be obtained (%s)",
|
||||||
|
interface_opts->name, open_status_str);
|
||||||
|
sync_pipe_write_errmsgs_to_parent(2, error_msg,
|
||||||
|
get_pcap_failure_secondary_error_message(open_status, open_status_str));
|
||||||
|
g_free(error_msg);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
cmdarg_err("The capabilities of the capture device "
|
||||||
|
"\"%s\" could not be obtained (%s).\n%s",
|
||||||
|
interface_opts->name, open_status_str,
|
||||||
|
get_pcap_failure_secondary_error_message(open_status, open_status_str));
|
||||||
|
}
|
||||||
|
g_free(open_status_str);
|
||||||
|
exit_main(2);
|
||||||
|
}
|
||||||
|
|
||||||
/* XXX: We might want to print also the interface name */
|
/* XXX: We might want to print also the interface name */
|
||||||
status = capture_opts_print_if_capabilities(caps,
|
status = capture_opts_print_if_capabilities(caps,
|
||||||
interface_opts,
|
interface_opts,
|
||||||
caps_queries);
|
caps_queries);
|
||||||
free_if_capabilities(caps);
|
free_if_capabilities(caps);
|
||||||
if (status != 0)
|
if (status != 0)
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
exit_main(status);
|
exit_main(status);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue