summaryrefslogtreecommitdiff
path: root/cli
diff options
context:
space:
mode:
authorJiří Klimeš <jklimes@redhat.com>2013-11-07 14:47:12 +0100
committerJiří Klimeš <jklimes@redhat.com>2014-01-23 13:45:46 +0100
commit26f8889286aa1a210fc0211f202224137b0acf36 (patch)
treeb058b1d43708f841e553da7421d85529c72d4f30 /cli
parent85272df6eb89682a3d13022281085b97527955e1 (diff)
cli: consolidate active and configured connections (rh #997999)
Handle connection profiles in a single 'show' command instead of 'show active' and 'show configured'. nmcli con show [--active] [[id|uuid|path|apath] <bla>] nmcli con show : display all connection profiles nmcli con show --active : only display active connection profiles (filters out inactive profiles) nmcli con show myeth : display details of "myeth" profile, and also active connection info (if the profile is active) nmcli -f profile con show myeth : only display "myeth"'s static configuration nmcli -f active con show myeth : only display active details of "myeth" nmcli -f connection.id,ipv4,general con show myeth : display "connection.id"a property "ipv4" setting and "GENERAL" group of active data https://bugzilla.redhat.com/show_bug.cgi?id=997999
Diffstat (limited to 'cli')
-rw-r--r--cli/src/connections.c779
-rw-r--r--cli/src/utils.c70
-rw-r--r--cli/src/utils.h4
3 files changed, 528 insertions, 325 deletions
diff --git a/cli/src/connections.c b/cli/src/connections.c
index c2b6721023..87c81f47d3 100644
--- a/cli/src/connections.c
+++ b/cli/src/connections.c
@@ -63,7 +63,7 @@
#define EDITOR_PROMPT_PROPERTY _("Property name? ")
#define EDITOR_PROMPT_CON_TYPE _("Enter connection type: ")
-/* Available fields for 'connection show configured' */
+/* Available fields for 'connection show' */
static NmcOutputField nmc_fields_con_show[] = {
{"NAME", N_("NAME"), 25}, /* 0 */
{"UUID", N_("UUID"), 38}, /* 1 */
@@ -73,10 +73,15 @@ static NmcOutputField nmc_fields_con_show[] = {
{"AUTOCONNECT", N_("AUTOCONNECT"), 13}, /* 5 */
{"READONLY", N_("READONLY"), 10}, /* 6 */
{"DBUS-PATH", N_("DBUS-PATH"), 42}, /* 7 */
+ {"ACTIVE", N_("ACTIVE"), 10}, /* 8 */
+ {"DEVICE", N_("DEVICE"), 10}, /* 9 */
+ {"STATE", N_("STATE"), 12}, /* 10 */
+ {"ACTIVE-PATH", N_("ACTIVE-PATH"), 51}, /* 11 */
{NULL, NULL, 0}
};
-#define NMC_FIELDS_CON_SHOW_ALL "NAME,UUID,TYPE,TIMESTAMP,TIMESTAMP-REAL,AUTOCONNECT,READONLY,DBUS-PATH"
-#define NMC_FIELDS_CON_SHOW_COMMON "NAME,UUID,TYPE,TIMESTAMP-REAL"
+#define NMC_FIELDS_CON_SHOW_ALL "NAME,UUID,TYPE,TIMESTAMP,TIMESTAMP-REAL,AUTOCONNECT,READONLY,DBUS-PATH,"\
+ "ACTIVE,DEVICE,STATE,ACTIVE-PATH"
+#define NMC_FIELDS_CON_SHOW_COMMON "NAME,UUID,TYPE,DEVICE"
/* Helper macro to define fields */
#define SETTING_FIELD(setting, props) { setting, N_(setting), 0, props, NULL, FALSE, FALSE, 0 }
@@ -108,7 +113,7 @@ extern NmcOutputField nmc_fields_setting_team[];
extern NmcOutputField nmc_fields_setting_team_port[];
extern NmcOutputField nmc_fields_setting_dcb[];
-/* Available settings for 'connection show configured <con>' */
+/* Available settings for 'connection show <con>' - profile part */
static NmcOutputField nmc_fields_settings_names[] = {
SETTING_FIELD (NM_SETTING_CONNECTION_SETTING_NAME, nmc_fields_setting_connection + 1), /* 0 */
SETTING_FIELD (NM_SETTING_WIRED_SETTING_NAME, nmc_fields_setting_wired + 1), /* 1 */
@@ -168,10 +173,10 @@ static NmcOutputField nmc_fields_settings_names[] = {
#define NMC_FIELDS_SETTINGS_NAMES_ALL NMC_FIELDS_SETTINGS_NAMES_ALL_X
#endif
-
-/* Available fields for 'connection show active' */
-static NmcOutputField nmc_fields_con_show_active[] = {
- {"GROUP", N_("GROUP"), 9}, /* 0 */ /* used only for 'GENERAL' group listing */
+/* Active connection data */
+/* Available fields for GENERAL group */
+static NmcOutputField nmc_fields_con_active_details_general[] = {
+ {"GROUP", N_("GROUP"), 9}, /* 0 */
{"NAME", N_("NAME"), 25}, /* 1 */
{"UUID", N_("UUID"), 38}, /* 2 */
{"DEVICES", N_("DEVICES"), 10}, /* 3 */
@@ -186,12 +191,8 @@ static NmcOutputField nmc_fields_con_show_active[] = {
{"MASTER-PATH", N_("MASTER-PATH"), 44}, /* 12 */
{NULL, NULL, 0}
};
-#define NMC_FIELDS_CON_ACTIVE_ALL "NAME,UUID,DEVICES,STATE,DEFAULT,DEFAULT6,VPN,ZONE,DBUS-PATH,CON-PATH,SPEC-OBJECT,MASTER-PATH"
-#define NMC_FIELDS_CON_ACTIVE_COMMON "NAME,UUID,DEVICES,DEFAULT,VPN,MASTER-PATH"
-
-
-/* GENERAL group is the same as nmc_fields_con_show_active */
-#define NMC_FIELDS_CON_ACTIVE_DETAILS_GENERAL_ALL "GROUP,"NMC_FIELDS_CON_ACTIVE_ALL
+#define NMC_FIELDS_CON_ACTIVE_DETAILS_GENERAL_ALL "GROUP,NAME,UUID,DEVICES,STATE,DEFAULT,DEFAULT6,"\
+ "VPN,ZONE,DBUS-PATH,CON-PATH,SPEC-OBJECT,MASTER-PATH"
/* IP group is handled by common.c */
@@ -214,18 +215,23 @@ extern NmcOutputField nmc_fields_ip6_config[];
extern NmcOutputField nmc_fields_dhcp4_config[];
extern NmcOutputField nmc_fields_dhcp6_config[];
-/* Available fields for 'connection show active <con>' */
+/* Available fields for 'connection show <con>' - active part */
static NmcOutputField nmc_fields_con_active_details_groups[] = {
- {"GENERAL", N_("GENERAL"), 0, nmc_fields_con_show_active + 1 }, /* 0 */
- {"IP4", N_("IP4"), 0, nmc_fields_ip4_config + 1 }, /* 1 */
- {"DHCP4", N_("DHCP4"), 0, nmc_fields_dhcp4_config + 1 }, /* 2 */
- {"IP6", N_("IP6"), 0, nmc_fields_ip6_config + 1 }, /* 3 */
- {"DHCP6", N_("DHCP6"), 0, nmc_fields_dhcp6_config + 1 }, /* 4 */
- {"VPN", N_("VPN"), 0, nmc_fields_con_active_details_vpn + 1}, /* 5 */
+ {"GENERAL", N_("GENERAL"), 0, nmc_fields_con_active_details_general + 1}, /* 0 */
+ {"IP4", N_("IP4"), 0, nmc_fields_ip4_config + 1 }, /* 1 */
+ {"DHCP4", N_("DHCP4"), 0, nmc_fields_dhcp4_config + 1 }, /* 2 */
+ {"IP6", N_("IP6"), 0, nmc_fields_ip6_config + 1 }, /* 3 */
+ {"DHCP6", N_("DHCP6"), 0, nmc_fields_dhcp6_config + 1 }, /* 4 */
+ {"VPN", N_("VPN"), 0, nmc_fields_con_active_details_vpn + 1 }, /* 5 */
{NULL, NULL, 0, NULL}
};
#define NMC_FIELDS_CON_ACTIVE_DETAILS_ALL "GENERAL,IP4,DHCP4,IP6,DHCP6,VPN"
+/* Pseudo group names for 'connection show <con>' */
+/* e.g.: nmcli -f profile con show my-eth0 */
+/* e.g.: nmcli -f active con show my-eth0 */
+#define CON_SHOW_DETAIL_GROUP_PROFILE "profile"
+#define CON_SHOW_DETAIL_GROUP_ACTIVE "active"
typedef struct {
NmCli *nmc;
@@ -254,8 +260,7 @@ usage (void)
fprintf (stderr,
_("Usage: nmcli connection { COMMAND | help }\n\n"
"COMMAND := { show | up | down | add | modify | edit | delete | reload | load }\n\n"
- " show configured [[id | uuid | path] <ID>]\n"
- " show active [[id | uuid | path | apath] <ID>]\n\n"
+ " show [--active] [[id | uuid | path | apath] <ID>] ...\n\n"
#if WITH_WIMAX
" up [[id | uuid | path] <ID>] [ifname <ifname>] [ap <BSSID>] [nsp <name>]\n\n"
#else
@@ -277,17 +282,20 @@ usage_connection_show (void)
fprintf (stderr,
_("Usage: nmcli connection show { ARGUMENTS | help }\n"
"\n"
- "ARGUMENTS := active [[id | uuid | path | apath] <ID>]\n"
+ "ARGUMENTS := [--active]\n"
"\n"
- "Show connections which are currently used by a device to connect to a network.\n"
- "Without a parameter, all active connections are listed. When <ID> is provided,\n"
- "the connection details are displayed instead.\n"
+ "List in-memory and on-disk connection profiles, some of which may also be\n"
+ "active if a device is using that connection profile. Without a parameter, all\n"
+ "profiles are listed. When --active option is specified, only the active\n"
+ "profiles are shown.\n"
"\n"
- "ARGUMENTS := configured [[id | uuid | path] <ID>]\n"
+ "ARGUMENTS := [--active] [id | uuid | path | apath] <ID> ...\n"
"\n"
- "Show in-memory and on-disk connections, some of which may also be active if\n"
- "a device is using that connection profile. Without a parameter, all profiles\n"
- "are listed. When <ID> is provided, the profile details are displayed instead.\n\n"));
+ "Show details for specified connections. By default, both static configuration\n"
+ "and active connection data are displayed. It is possible to filter the output\n"
+ "using global '--fields' option. Refer to the manual page for more information.\n"
+ "When --active option is specified, only the active profiles are taken into\n"
+ "account.\n"));
}
static void
@@ -491,8 +499,132 @@ quit (void)
g_main_loop_quit (loop); /* quit main loop */
}
+static const char *
+construct_header_name (const char *base, const char *spec)
+{
+ static char header_name[128];
+
+ if (spec == NULL)
+ return base;
+
+ g_strlcpy (header_name, base, sizeof (header_name));
+ g_strlcat (header_name, " (", sizeof (header_name));
+ g_strlcat (header_name, spec, sizeof (header_name));
+ g_strlcat (header_name, ")", sizeof (header_name));
+
+ return header_name;
+}
+
+static const char *
+active_connection_state_to_string (NMActiveConnectionState state)
+{
+ switch (state) {
+ case NM_ACTIVE_CONNECTION_STATE_ACTIVATING:
+ return _("activating");
+ case NM_ACTIVE_CONNECTION_STATE_ACTIVATED:
+ return _("activated");
+ case NM_ACTIVE_CONNECTION_STATE_DEACTIVATING:
+ return _("deactivating");
+ case NM_ACTIVE_CONNECTION_STATE_DEACTIVATED:
+ return _("deactivated");
+ case NM_ACTIVE_CONNECTION_STATE_UNKNOWN:
+ default:
+ return _("unknown");
+ }
+}
+
+static const char *
+vpn_connection_state_to_string (NMVPNConnectionState state)
+{
+ switch (state) {
+ case NM_VPN_CONNECTION_STATE_PREPARE:
+ return _("VPN connecting (prepare)");
+ case NM_VPN_CONNECTION_STATE_NEED_AUTH:
+ return _("VPN connecting (need authentication)");
+ case NM_VPN_CONNECTION_STATE_CONNECT:
+ return _("VPN connecting");
+ case NM_VPN_CONNECTION_STATE_IP_CONFIG_GET:
+ return _("VPN connecting (getting IP configuration)");
+ case NM_VPN_CONNECTION_STATE_ACTIVATED:
+ return _("VPN connected");
+ case NM_VPN_CONNECTION_STATE_FAILED:
+ return _("VPN connection failed");
+ case NM_VPN_CONNECTION_STATE_DISCONNECTED:
+ return _("VPN disconnected");
+ default:
+ return _("unknown");
+ }
+}
+
+/* Caller has to free the returned string */
+static char *
+get_ac_device_string (NMActiveConnection *active)
+{
+ GString *dev_str;
+ const GPtrArray *devices;
+ int i;
+
+ if (!active)
+ return NULL;
+
+ /* Get devices of the active connection */
+ dev_str = g_string_new (NULL);
+ devices = nm_active_connection_get_devices (active);
+ for (i = 0; devices && (i < devices->len); i++) {
+ NMDevice *device = g_ptr_array_index (devices, i);
+ const char *dev_iface = nm_device_get_iface (device);
+
+ if (dev_iface) {
+ g_string_append (dev_str, dev_iface);
+ g_string_append_c (dev_str, ',');
+ }
+ }
+ if (dev_str->len > 0)
+ g_string_truncate (dev_str, dev_str->len - 1); /* Cut off last ',' */
+
+ return g_string_free (dev_str, FALSE);
+}
+
+static NMActiveConnection *
+get_ac_for_connection (const GPtrArray *active_cons, NMConnection *connection)
+{
+ const char *con_path;
+ int i;
+ NMActiveConnection *ac = NULL;
+
+ /* Is the connection active? */
+ con_path = nm_connection_get_path (connection);
+ for (i = 0; active_cons && i < active_cons->len; i++) {
+ NMActiveConnection *candidate = g_ptr_array_index (active_cons, i);
+
+ if (!g_strcmp0 (nm_active_connection_get_connection (candidate), con_path)) {
+ ac = candidate;
+ break;
+ }
+ }
+ return ac;
+}
+
+static NMConnection *
+get_connection_for_active (const GSList *con_list, NMActiveConnection *active)
+{
+ const GSList *iter;
+ const char *path;
+
+ path = nm_active_connection_get_connection (active);
+ g_return_val_if_fail (path != NULL, NULL);
+
+ for (iter = con_list; iter; iter = g_slist_next (iter)) {
+ NMConnection *candidate = NM_CONNECTION (iter->data);
+
+ if (strcmp (nm_connection_get_path (candidate), path) == 0)
+ return candidate;
+ }
+ return NULL;
+}
+
static gboolean
-nmc_connection_detail (NMConnection *connection, NmCli *nmc)
+nmc_connection_profile_details (NMConnection *connection, NmCli *nmc)
{
GError *error = NULL;
GArray *print_settings_array;
@@ -501,6 +633,7 @@ nmc_connection_detail (NMConnection *connection, NmCli *nmc)
char *fields_str;
char *fields_all = NMC_FIELDS_SETTINGS_NAMES_ALL;
char *fields_common = NMC_FIELDS_SETTINGS_NAMES_ALL;
+ const char *base_hdr = _("Connection profile details");
gboolean was_output = FALSE;
if (!nmc->required_fields || strcasecmp (nmc->required_fields, "common") == 0)
@@ -512,7 +645,7 @@ nmc_connection_detail (NMConnection *connection, NmCli *nmc)
print_settings_array = parse_output_fields (fields_str, nmc_fields_settings_names, TRUE, &prop_array, &error);
if (error) {
- g_string_printf (nmc->return_text, _("Error: 'list configured': %s"), error->message);
+ g_string_printf (nmc->return_text, _("Error: 'connection show': %s"), error->message);
g_error_free (error);
nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
return FALSE;
@@ -520,7 +653,7 @@ nmc_connection_detail (NMConnection *connection, NmCli *nmc)
g_assert (print_settings_array);
/* Main header */
- nmc->print_fields.header_name = _("Connection details");
+ nmc->print_fields.header_name = (char *) construct_header_name (base_hdr, nm_connection_get_id (connection));
nmc->print_fields.indices = parse_output_fields (NMC_FIELDS_SETTINGS_NAMES_ALL,
nmc_fields_settings_names, FALSE, NULL, NULL);
@@ -556,45 +689,6 @@ nmc_connection_detail (NMConnection *connection, NmCli *nmc)
return TRUE;
}
-static void
-fill_output_connection (gpointer data, gpointer user_data)
-{
- NMConnection *connection = (NMConnection *) data;
- NmCli *nmc = (NmCli *) user_data;
- NMSettingConnection *s_con;
- guint64 timestamp;
- time_t timestamp_real;
- char *timestamp_str;
- char *timestamp_real_str;
- NmcOutputField *arr;
-
- s_con = nm_connection_get_setting_connection (connection);
- if (s_con) {
- /* Obtain field values */
- timestamp = nm_setting_connection_get_timestamp (s_con);
- timestamp_str = g_strdup_printf ("%" G_GUINT64_FORMAT, timestamp);
- if (timestamp) {
- timestamp_real = timestamp;
- timestamp_real_str = g_malloc0 (64);
- strftime (timestamp_real_str, 64, "%c", localtime (&timestamp_real));
- }
-
- arr = nmc_dup_fields_array (nmc_fields_con_show,
- sizeof (nmc_fields_con_show),
- 0);
- set_val_strc (arr, 0, nm_setting_connection_get_id (s_con));
- set_val_strc (arr, 1, nm_setting_connection_get_uuid (s_con));
- set_val_strc (arr, 2, nm_setting_connection_get_connection_type (s_con));
- set_val_str (arr, 3, timestamp_str);
- set_val_str (arr, 4, timestamp ? timestamp_real_str : g_strdup (_("never")));
- set_val_strc (arr, 5, nm_setting_connection_get_autoconnect (s_con) ? _("yes") : _("no"));
- set_val_strc (arr, 6, nm_setting_connection_get_read_only (s_con) ? _("yes") : _("no"));
- set_val_strc (arr, 7, nm_connection_get_path (connection));
-
- g_ptr_array_add (nmc->output_data, arr);
- }
-}
-
static NMConnection *
find_connection (GSList *list, const char *filter_type, const char *filter_val)
{
@@ -632,151 +726,101 @@ find_connection (GSList *list, const char *filter_type, const char *filter_val)
return NULL;
}
-static NMCResultCode
-do_connections_show (NmCli *nmc, int argc, char **argv)
+static NMActiveConnection *
+find_active_connection (const GPtrArray *active_cons, const GSList *cons,
+ const char *filter_type, const char *filter_val)
{
- GError *error1 = NULL;
- GError *error2 = NULL;
- char *fields_str;
- char *fields_all = NMC_FIELDS_CON_SHOW_ALL;
- char *fields_common = NMC_FIELDS_CON_SHOW_COMMON;
- gboolean printed = FALSE;
-
- nmc->should_wait = FALSE;
-
- if (!nmc->required_fields || strcasecmp (nmc->required_fields, "common") == 0)
- fields_str = fields_common;
- else if (!nmc->required_fields || strcasecmp (nmc->required_fields, "all") == 0)
- fields_str = fields_all;
- else
- fields_str = nmc->required_fields;
-
- if (argc == 0) {
- NmcOutputField *tmpl, *arr;
- size_t tmpl_len;
-
- tmpl = nmc_fields_con_show;
- tmpl_len = sizeof (nmc_fields_con_show);
- nmc->print_fields.indices = parse_output_fields (fields_str, tmpl, FALSE, NULL, &error1);
- if (error1)
- goto error;
- if (!nmc_terse_option_check (nmc->print_output, nmc->required_fields, &error2))
- goto error;
-
- /* Add headers */
- nmc->print_fields.header_name = _("List of configured connections");
- arr = nmc_dup_fields_array (tmpl, tmpl_len, NMC_OF_FLAG_MAIN_HEADER_ADD | NMC_OF_FLAG_FIELD_NAMES);
- g_ptr_array_add (nmc->output_data, arr);
-
- /* Add values */
- g_slist_foreach (nmc->system_connections, fill_output_connection, nmc);
- print_data (nmc); /* Print all data */
- } else {
- while (argc > 0) {
- NMConnection *con;
- const char *selector = NULL;
-
- if ( strcmp (*argv, "id") == 0
- || strcmp (*argv, "uuid") == 0
- || strcmp (*argv, "path") == 0) {
- selector = *argv;
- if (next_arg (&argc, &argv) != 0) {
- g_string_printf (nmc->return_text, _("Error: %s argument is missing."), *(argv-1));
- nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
- return nmc->return_value;
- }
- }
- if (!nmc->mode_specified)
- nmc->multiline_output = TRUE; /* multiline mode is default for 'show configured <con>' */
-
- con = find_connection (nmc->system_connections, selector, *argv);
- if (con) {
- if (printed)
- printf ("\n");
- printed = nmc_connection_detail (con, nmc);
- } else {
- g_string_printf (nmc->return_text, _("Error: %s - no such connection."), *argv);
- nmc->return_value = NMC_RESULT_ERROR_NOT_FOUND;
- return nmc->return_value;
- }
+ int i;
+ const char *path, *a_path, *path_num, *a_path_num;
+ const char *id;
+ const char *uuid;
+ NMConnection *con;
- argc--;
- argv++;
- }
- }
+ for (i = 0; active_cons && (i < active_cons->len); i++) {
+ NMActiveConnection *candidate = g_ptr_array_index (active_cons, i);
-error:
- if (error1) {
- g_string_printf (nmc->return_text, _("Error: 'show configured': %s"), error1->message);
- g_error_free (error1);
- nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
- }
- if (error2) {
- g_string_printf (nmc->return_text, _("Error: %s."), error2->message);
- nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
- g_error_free (error2);
- }
+ path = nm_active_connection_get_connection (candidate);
+ a_path = nm_object_get_path (NM_OBJECT (candidate));
+ uuid = nm_active_connection_get_uuid (candidate);
+ path_num = path ? strrchr (path, '/') + 1 : NULL;
+ a_path_num = a_path ? strrchr (a_path, '/') + 1 : NULL;
- return nmc->return_value;
-}
+ con = get_connection_for_active (cons, candidate);
+ id = nm_connection_get_id (con);
-static const char *
-active_connection_state_to_string (NMActiveConnectionState state)
-{
- switch (state) {
- case NM_ACTIVE_CONNECTION_STATE_ACTIVATING:
- return _("activating");
- case NM_ACTIVE_CONNECTION_STATE_ACTIVATED:
- return _("activated");
- case NM_ACTIVE_CONNECTION_STATE_DEACTIVATING:
- return _("deactivating");
- case NM_ACTIVE_CONNECTION_STATE_DEACTIVATED:
- return _("deactivated");
- case NM_ACTIVE_CONNECTION_STATE_UNKNOWN:
- default:
- return _("unknown");
+ /* When filter_type is NULL, compare connection ID (filter_val)
+ * against all types. Otherwise, only compare against the specific
+ * type. If 'path' or 'apath' filter types are specified, comparison
+ * against numeric index (in addition to the whole path) is allowed.
+ */
+ if ( ( (!filter_type || strcmp (filter_type, "id") == 0)
+ && strcmp (filter_val, id) == 0)
+ || ( (!filter_type || strcmp (filter_type, "uuid") == 0)
+ && strcmp (filter_val, uuid) == 0)
+ || ( (!filter_type || strcmp (filter_type, "path") == 0)
+ && (g_strcmp0 (filter_val, path) == 0 || (filter_type && g_strcmp0 (filter_val, path_num) == 0)))
+ || ( (!filter_type || strcmp (filter_type, "apath") == 0)
+ && (g_strcmp0 (filter_val, a_path) == 0 || (filter_type && g_strcmp0 (filter_val, a_path_num) == 0))))
+ return candidate;
}
+ return NULL;
}
-static const char *
-vpn_connection_state_to_string (NMVPNConnectionState state)
+static void
+fill_output_connection (gpointer data, gpointer user_data, gboolean active_only)
{
- switch (state) {
- case NM_VPN_CONNECTION_STATE_PREPARE:
- return _("VPN connecting (prepare)");
- case NM_VPN_CONNECTION_STATE_NEED_AUTH:
- return _("VPN connecting (need authentication)");
- case NM_VPN_CONNECTION_STATE_CONNECT:
- return _("VPN connecting");
- case NM_VPN_CONNECTION_STATE_IP_CONFIG_GET:
- return _("VPN connecting (getting IP configuration)");
- case NM_VPN_CONNECTION_STATE_ACTIVATED:
- return _("VPN connected");
- case NM_VPN_CONNECTION_STATE_FAILED:
- return _("VPN connection failed");
- case NM_VPN_CONNECTION_STATE_DISCONNECTED:
- return _("VPN disconnected");
- default:
- return _("unknown");
- }
-}
+ NMConnection *connection = (NMConnection *) data;
+ NmCli *nmc = (NmCli *) user_data;
+ NMSettingConnection *s_con;
+ guint64 timestamp;
+ time_t timestamp_real;
+ char *timestamp_str;
+ char *timestamp_real_str = "";
+ NmcOutputField *arr;
+ NMActiveConnection *ac = NULL;
+ const char *ac_path = NULL;
+ const char *ac_state = NULL;
+ char *ac_dev = NULL;
-static NMConnection *
-get_connection_for_active (const GSList *con_list, NMActiveConnection *active)
-{
- const GSList *iter;
- const char *path;
+ s_con = nm_connection_get_setting_connection (connection);
+ g_assert (s_con);
- path = nm_active_connection_get_connection (active);
- g_return_val_if_fail (path != NULL, NULL);
+ ac = get_ac_for_connection (nm_client_get_active_connections (nmc->client), connection);
+ if (active_only && !ac)
+ return;
- for (iter = con_list; iter; iter = g_slist_next (iter)) {
- NMConnection *candidate = NM_CONNECTION (iter->data);
+ if (ac) {
+ ac_path = nm_object_get_path (NM_OBJECT (ac));
+ ac_state = active_connection_state_to_string (nm_active_connection_get_state (ac));
+ ac_dev = get_ac_device_string (ac);
+ }
+
+ /* Obtain field values */
+ timestamp = nm_setting_connection_get_timestamp (s_con);
+ timestamp_str = g_strdup_printf ("%" G_GUINT64_FORMAT, timestamp);
+ if (timestamp) {
+ timestamp_real = timestamp;
+ timestamp_real_str = g_malloc0 (64);
+ strftime (timestamp_real_str, 64, "%c", localtime (&timestamp_real));
+ }
+
+ arr = nmc_dup_fields_array (nmc_fields_con_show,
+ sizeof (nmc_fields_con_show),
+ 0);
+ set_val_strc (arr, 0, nm_setting_connection_get_id (s_con));
+ set_val_strc (arr, 1, nm_setting_connection_get_uuid (s_con));
+ set_val_strc (arr, 2, nm_setting_connection_get_connection_type (s_con));
+ set_val_str (arr, 3, timestamp_str);
+ set_val_str (arr, 4, timestamp ? timestamp_real_str : g_strdup (_("never")));
+ set_val_strc (arr, 5, nm_setting_connection_get_autoconnect (s_con) ? _("yes") : _("no"));
+ set_val_strc (arr, 6, nm_setting_connection_get_read_only (s_con) ? _("yes") : _("no"));
+ set_val_strc (arr, 7, nm_connection_get_path (connection));
+ set_val_strc (arr, 8, ac ? _("yes") : _("no"));
+ set_val_str (arr, 9, ac_dev);
+ set_val_strc (arr, 10, ac_state);
+ set_val_strc (arr, 11, ac_path);
- if (strcmp (nm_connection_get_path (candidate), path) == 0)
- return candidate;
- }
- return NULL;
+ g_ptr_array_add (nmc->output_data, arr);
}
static void
@@ -815,8 +859,8 @@ fill_output_active_connection (NMActiveConnection *active,
if (dev_str->len > 0)
g_string_truncate (dev_str, dev_str->len - 1); /* Cut off last ',' */
- tmpl = nmc_fields_con_show_active;
- tmpl_len = sizeof (nmc_fields_con_show_active);
+ tmpl = nmc_fields_con_active_details_general;
+ tmpl_len = sizeof (nmc_fields_con_active_details_general);
if (!with_group) {
tmpl++;
tmpl_len -= sizeof (NmcOutputField);
@@ -860,46 +904,6 @@ fill_output_active_connection (NMActiveConnection *active,
g_string_free (dev_str, FALSE);
}
-static NMActiveConnection *
-find_active_connection (const GPtrArray *active_cons, const GSList *cons,
- const char *filter_type, const char *filter_val)
-{
- int i;
- const char *path, *a_path, *path_num, *a_path_num;
- const char *id;
- const char *uuid;
- NMConnection *con;
-
- for (i = 0; active_cons && (i < active_cons->len); i++) {
- NMActiveConnection *candidate = g_ptr_array_index (active_cons, i);
-
- path = nm_active_connection_get_connection (candidate);
- a_path = nm_object_get_path (NM_OBJECT (candidate));
- uuid = nm_active_connection_get_uuid (candidate);
- path_num = path ? strrchr (path, '/') + 1 : NULL;
- a_path_num = a_path ? strrchr (a_path, '/') + 1 : NULL;
-
- con = get_connection_for_active (cons, candidate);
- id = nm_connection_get_id (con);
-
- /* When filter_type is NULL, compare connection ID (filter_val)
- * against all types. Otherwise, only compare against the specific
- * type. If 'path' or 'apath' filter types are specified, comparison
- * against numeric index (in addition to the whole path) is allowed.
- */
- if ( ( (!filter_type || strcmp (filter_type, "id") == 0)
- && strcmp (filter_val, id) == 0)
- || ( (!filter_type || strcmp (filter_type, "uuid") == 0)
- && strcmp (filter_val, uuid) == 0)
- || ( (!filter_type || strcmp (filter_type, "path") == 0)
- && (g_strcmp0 (filter_val, path) == 0 || (filter_type && g_strcmp0 (filter_val, path_num) == 0)))
- || ( (!filter_type || strcmp (filter_type, "apath") == 0)
- && (g_strcmp0 (filter_val, a_path) == 0 || (filter_type && g_strcmp0 (filter_val, a_path_num) == 0))))
- return candidate;
- }
- return NULL;
-}
-
typedef struct {
char **array;
guint32 idx;
@@ -987,7 +991,7 @@ get_vpn_data_item (NMConnection *connection, enum VpnDataItem vpn_data_item)
/* FIXME end */
static gboolean
-nmc_active_connection_detail (NMActiveConnection *acon, NmCli *nmc)
+nmc_active_connection_details (NMActiveConnection *acon, NmCli *nmc)
{
GError *error = NULL;
GArray *print_groups;
@@ -998,6 +1002,7 @@ nmc_active_connection_detail (NMActiveConnection *acon, NmCli *nmc)
char *fields_common = NMC_FIELDS_CON_ACTIVE_DETAILS_ALL;
NmcOutputField *tmpl, *arr;
size_t tmpl_len;
+ const char *base_hdr = _("Activate connection details");
gboolean was_output = FALSE;
if (!nmc->required_fields || strcasecmp (nmc->required_fields, "common") == 0)
@@ -1009,7 +1014,7 @@ nmc_active_connection_detail (NMActiveConnection *acon, NmCli *nmc)
print_groups = parse_output_fields (fields_str, nmc_fields_con_active_details_groups, TRUE, &group_fields, &error);
if (error) {
- g_string_printf (nmc->return_text, _("Error: 'list active': %s"), error->message);
+ g_string_printf (nmc->return_text, _("Error: 'connection show': %s"), error->message);
g_error_free (error);
nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
return FALSE;
@@ -1017,7 +1022,7 @@ nmc_active_connection_detail (NMActiveConnection *acon, NmCli *nmc)
g_assert (print_groups);
/* Main header */
- nmc->print_fields.header_name = _("Active connection details");
+ nmc->print_fields.header_name = (char *) construct_header_name (base_hdr, nm_active_connection_get_uuid (acon));
nmc->print_fields.indices = parse_output_fields (NMC_FIELDS_CON_ACTIVE_DETAILS_ALL,
nmc_fields_con_active_details_groups, FALSE, NULL, NULL);
@@ -1040,8 +1045,8 @@ nmc_active_connection_detail (NMActiveConnection *acon, NmCli *nmc)
/* GENERAL */
if (strcasecmp (nmc_fields_con_active_details_groups[group_idx].name, nmc_fields_con_active_details_groups[0].name) == 0) {
/* Add field names */
- tmpl = nmc_fields_con_show_active;
- tmpl_len = sizeof (nmc_fields_con_show_active);
+ tmpl = nmc_fields_con_active_details_general;
+ tmpl_len = sizeof (nmc_fields_con_active_details_general);
nmc->print_fields.indices = parse_output_fields (group_fld ? group_fld : NMC_FIELDS_CON_ACTIVE_DETAILS_GENERAL_ALL,
tmpl, FALSE, NULL, NULL);
arr = nmc_dup_fields_array (tmpl, tmpl_len, NMC_OF_FLAG_FIELD_NAMES);
@@ -1158,33 +1163,144 @@ nmc_active_connection_detail (NMActiveConnection *acon, NmCli *nmc)
return TRUE;
}
+static gboolean
+split_required_fields_for_con_show (const char *input,
+ char **profile_flds,
+ char **active_flds,
+ GError **error)
+{
+ char **fields, **iter;
+ char *dot;
+ GString *str1, *str2;
+ gboolean found;
+ gboolean group_profile = FALSE;
+ gboolean group_active = FALSE;
+ gboolean success = TRUE;
+ gboolean is_all, is_common;
+ int i;
+
+ if (!input) {
+ *profile_flds = NULL;
+ *active_flds = NULL;
+ return TRUE;
+ }
+
+ str1 = g_string_new (NULL);
+ str2 = g_string_new (NULL);
+
+ /* Split supplied fields string */
+ fields = g_strsplit_set (input, ",", -1);
+ for (iter = fields; iter && *iter; iter++) {
+ g_strstrip (*iter);
+ dot = strchr (*iter, '.');
+ if (dot)
+ *dot = '\0';
+
+ is_all = !dot && strcasecmp (*iter, "all") == 0;
+ is_common = !dot && strcasecmp (*iter, "common") == 0;
+
+ found = FALSE;
+
+ for (i = 0; nmc_fields_settings_names[i].name; i++) {
+ if ( is_all || is_common
+ || !strcasecmp (*iter, nmc_fields_settings_names[i].name)) {
+ if (dot)
+ *dot = '.';
+ g_string_append (str1, *iter);
+ g_string_append_c (str1, ',');
+ found = TRUE;
+ break;
+ }
+ }
+ if (found)
+ continue;
+ for (i = 0; nmc_fields_con_active_details_groups[i].name; i++) {
+ if ( is_all || is_common
+ || !strcasecmp (*iter, nmc_fields_con_active_details_groups[i].name)) {
+ if (dot)
+ *dot = '.';
+ g_string_append (str2, *iter);
+ g_string_append_c (str2, ',');
+ found = TRUE;
+ break;
+ }
+ }
+ if (!found) {
+ if (dot)
+ *dot = '.';
+ if (!strcasecmp (*iter, CON_SHOW_DETAIL_GROUP_PROFILE))
+ group_profile = TRUE;
+ else if (!strcasecmp (*iter, CON_SHOW_DETAIL_GROUP_ACTIVE))
+ group_active = TRUE;
+ else {
+ char *allowed1 = nmc_get_allowed_fields (nmc_fields_settings_names, -1);
+ char *allowed2 = nmc_get_allowed_fields (nmc_fields_con_active_details_groups, -1);
+ g_set_error (error, NMCLI_ERROR, 0, _("invalid field '%s'; allowed fields: %s and %s, or %s,%s"),
+ *iter, allowed1, allowed2, CON_SHOW_DETAIL_GROUP_PROFILE, CON_SHOW_DETAIL_GROUP_ACTIVE);
+ g_free (allowed1);
+ g_free (allowed2);
+ success = FALSE;
+ break;
+ }
+ }
+ }
+ if (fields)
+ g_strfreev (fields);
+
+ /* Handle pseudo groups: profile, active */
+ if (success && group_profile) {
+ if (str1->len > 0) {
+ g_set_error (error, NMCLI_ERROR, 0, _("'%s' has to be alone'"),
+ CON_SHOW_DETAIL_GROUP_PROFILE);
+ success = FALSE;
+ } else
+ g_string_assign (str1, "all,");
+ }
+ if (success && group_active) {
+ if (str2->len > 0) {
+ g_set_error (error, NMCLI_ERROR, 0, _("'%s' has to be alone'"),
+ CON_SHOW_DETAIL_GROUP_ACTIVE);
+ success = FALSE;
+ } else
+ g_string_assign (str2, "all,");
+ }
+
+ if (success) {
+ if (str1->len > 0)
+ g_string_truncate (str1, str1->len - 1);
+ if (str2->len > 0)
+ g_string_truncate (str2, str2->len - 1);
+ *profile_flds = g_string_free (str1, str1->len == 0);
+ *active_flds = g_string_free (str2, str2->len == 0);
+ } else {
+ g_string_free (str1, TRUE);
+ g_string_free (str2, TRUE);
+ }
+ return success;
+}
+
static NMCResultCode
-do_connections_show_active (NmCli *nmc, int argc, char **argv)
+do_connections_show (NmCli *nmc, gboolean active_only, int argc, char **argv)
{
- const GPtrArray *active_cons;
- int i;
- GError *err1 = NULL;
- gboolean printed = FALSE;
- NmcOutputField *tmpl, *arr;
- size_t tmpl_len;
+ GError *err = NULL;
+ char *profile_flds = NULL, *active_flds = NULL;
nmc->should_wait = FALSE;
-
- /* Get active connections */
nmc->get_client (nmc);
if (!nm_client_get_manager_running (nmc->client)) {
g_string_printf (nmc->return_text, _("Error: NetworkManager is not running."));
nmc->return_value = NMC_RESULT_ERROR_NM_NOT_RUNNING;
- goto error;
+ goto finish;
}
- active_cons = nm_client_get_active_connections (nmc->client);
-
if (argc == 0) {
char *fields_str;
- char *fields_all = NMC_FIELDS_CON_ACTIVE_ALL;
- char *fields_common = NMC_FIELDS_CON_ACTIVE_COMMON;
+ char *fields_all = NMC_FIELDS_CON_SHOW_ALL;
+ char *fields_common = NMC_FIELDS_CON_SHOW_COMMON;
+ NmcOutputField *tmpl, *arr;
+ size_t tmpl_len;
+ GSList *iter;
if (!nmc->required_fields || strcasecmp (nmc->required_fields, "common") == 0)
fields_str = fields_common;
@@ -1193,65 +1309,121 @@ do_connections_show_active (NmCli *nmc, int argc, char **argv)
else
fields_str = nmc->required_fields;
- tmpl = nmc_fields_con_show_active + 1;
- tmpl_len = sizeof (nmc_fields_con_show_active) - sizeof (NmcOutputField);
- nmc->print_fields.indices = parse_output_fields (fields_str, tmpl, FALSE, NULL, &err1);
- if (err1)
- goto error;
+ tmpl = nmc_fields_con_show;
+ tmpl_len = sizeof (nmc_fields_con_show);
+ nmc->print_fields.indices = parse_output_fields (fields_str, tmpl, FALSE, NULL, &err);
+ if (err) {
+ goto finish;
+ }
+ if (!nmc_terse_option_check (nmc->print_output, nmc->required_fields, &err))
+ goto finish;
/* Add headers */
- nmc->print_fields.header_name = _("List of active connections");
+ nmc->print_fields.header_name = active_only ? _("NetworkManager active profiles") :
+ _("NetworkManager connection profiles");
arr = nmc_dup_fields_array (tmpl, tmpl_len, NMC_OF_FLAG_MAIN_HEADER_ADD | NMC_OF_FLAG_FIELD_NAMES);
g_ptr_array_add (nmc->output_data, arr);
/* Add values */
- for (i = 0; active_cons && i < active_cons->len; i++) {
- NMActiveConnection *ac = g_ptr_array_index (active_cons, i);
- fill_output_active_connection (ac, nmc, FALSE, 0);
+ for (iter = nmc->system_connections; iter; iter = g_slist_next (iter)) {
+ NMConnection *con = NM_CONNECTION (iter->data);
+ fill_output_connection (con, nmc, active_only);
}
print_data (nmc); /* Print all data */
} else {
+ gboolean new_line = FALSE;
+ gboolean without_fields = (nmc->required_fields == NULL);
+ const GPtrArray *active_cons = nm_client_get_active_connections (nmc->client);
+
+ /* multiline mode is default for 'connection show <ID>' */
+ if (!nmc->mode_specified)
+ nmc->multiline_output = TRUE;
+
+ /* Split required fields into the settings and active ones. */
+ if (!split_required_fields_for_con_show (nmc->required_fields, &profile_flds, &active_flds, &err))
+ goto finish;
+ g_free (nmc->required_fields);
+ nmc->required_fields = NULL;
+
while (argc > 0) {
- NMActiveConnection *acon;
+ NMConnection *con;
+ NMActiveConnection *acon = NULL;
const char *selector = NULL;
if ( strcmp (*argv, "id") == 0
|| strcmp (*argv, "uuid") == 0
|| strcmp (*argv, "path") == 0
|| strcmp (*argv, "apath") == 0) {
-
selector = *argv;
if (next_arg (&argc, &argv) != 0) {
g_string_printf (nmc->return_text, _("Error: %s argument is missing."), *(argv-1));
nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
- return nmc->return_value;
+ goto finish;
}
}
- if (!nmc->mode_specified)
- nmc->multiline_output = TRUE; /* multiline mode is default for 'show active <con>' */
- acon = find_active_connection (active_cons, nmc->system_connections, selector, *argv);
- if (acon) {
- if (printed)
+ /* Find connection by id, uuid, path or apath */
+ con = find_connection (nmc->system_connections, selector, *argv);
+ if (!con) {
+ acon = find_active_connection (active_cons, nmc->system_connections, selector, *argv);
+ if (acon)
+ con = get_connection_for_active (nmc->system_connections, acon);
+ }
+
+ /* Print connection details */
+ if (con) {
+ gboolean res;
+
+ /* Filter only active connections */
+ if (!acon)
+ acon = get_ac_for_connection (active_cons, con);
+ if (active_only && !acon) {
+ next_arg (&argc, &argv);
+ continue;
+ }
+
+ /* Show an empty line between connections */
+ if (new_line)
printf ("\n");
- printed = nmc_active_connection_detail (acon, nmc); /* separate connections by blank line */
+
+ /* Show profile configuration */
+ if (without_fields || profile_flds) {
+ nmc->required_fields = profile_flds;
+ res = nmc_connection_profile_details (con, nmc);
+ nmc->required_fields = NULL;
+ if (!res)
+ goto finish;
+ }
+
+ /* If the profile is active, print also active details */
+ if (without_fields || active_flds) {
+ if (acon) {
+ nmc->required_fields = active_flds;
+ res = nmc_active_connection_details (acon, nmc);
+ nmc->required_fields = NULL;
+ if (!res)
+ goto finish;
+ }
+ }
+ new_line = TRUE;
} else {
- g_string_printf (nmc->return_text, _("Error: '%s' is not an active connection."), *argv);
+ g_string_printf (nmc->return_text, _("Error: %s - no such connection profile."), *argv);
nmc->return_value = NMC_RESULT_ERROR_NOT_FOUND;
- return nmc->return_value;
+ goto finish;
}
- argc--;
- argv++;
+ next_arg (&argc, &argv);
}
}
-error:
- if (err1) {
- g_string_printf (nmc->return_text, _("Error: 'show active': %s"), err1->message);
- g_error_free (err1);
+finish:
+ if (err) {
+ g_string_printf (nmc->return_text, _("Error: %s."), err->message);
nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
+ g_error_free (err);
}
+ g_free (profile_flds);
+ g_free (active_flds);
return nmc->return_value;
}
@@ -5618,7 +5790,7 @@ editor_show_connection (NMConnection *connection, NmCli *nmc)
/* Remove any previous data */
nmc_empty_output_fields (nmc);
- nmc_connection_detail (connection, nmc);
+ nmc_connection_profile_details (connection, nmc);
}
static void
@@ -7889,35 +8061,30 @@ static NMCResultCode
parse_cmd (NmCli *nmc, int argc, char **argv)
{
GError *error = NULL;
- int arg_ret;
if (argc == 0) {
if (!nmc_terse_option_check (nmc->print_output, nmc->required_fields, &error))
goto opt_error;
- nmc->return_value = do_connections_show (nmc, argc, argv);
+ nmc->return_value = do_connections_show (nmc, FALSE, argc, argv);
} else {
if (nmc_arg_is_help (*argv)) {
usage ();
goto usage_exit;
}
else if (matches (*argv, "show") == 0) {
+ gboolean active = FALSE;
+
if (nmc_arg_is_help (*(argv+1))) {
usage_connection_show ();
goto usage_exit;
}
- arg_ret = next_arg (&argc, &argv);
- if (arg_ret != 0 || matches (*argv, "configured") == 0) {
+
+ next_arg (&argc, &argv);
+ if (nmc_arg_is_option (*argv, "active")) {
+ active = TRUE;
next_arg (&argc, &argv);
- nmc->return_value = do_connections_show (nmc, argc, argv);
- } else if (matches (*argv, "active") == 0) {
- if (!nmc_terse_option_check (nmc->print_output, nmc->required_fields, &error))
- goto opt_error;
- nmc->return_value = do_connections_show_active (nmc, argc-1, argv+1);
- } else {
- g_string_printf (nmc->return_text, _("Error: 'configured' or 'active' command is expected for 'connection show'."));
- nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
- nmc->should_wait = FALSE;
}
+ nmc->return_value = do_connections_show (nmc, active, argc, argv);
}
else if (matches(*argv, "up") == 0) {
if (nmc_arg_is_help (*(argv+1))) {
diff --git a/cli/src/utils.c b/cli/src/utils.c
index 4ea62530b9..f33a48e9a7 100644
--- a/cli/src/utils.c
+++ b/cli/src/utils.c
@@ -14,7 +14,7 @@
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
- * (C) Copyright 2010 - 2013 Red Hat, Inc.
+ * (C) Copyright 2010 - 2014 Red Hat, Inc.
*/
/* Generated configuration file */
@@ -72,6 +72,23 @@ nmc_arg_is_help (const char *arg)
return FALSE;
}
+gboolean
+nmc_arg_is_option (const char *str, const char *opt_name)
+{
+ const char *p;
+
+ if (!str || !*str)
+ return FALSE;
+
+ if (str[0] != '-')
+ return FALSE;
+
+ p = (str[1] == '-') ? str + 2 : str + 1;
+
+ return (*p ? (matches (p, opt_name) == 0) : FALSE);
+}
+
+
/*
* Helper function to parse command-line arguments.
* arg_arr: description of arguments to look for
@@ -699,27 +716,15 @@ parse_output_fields (const char *fields_str,
/* Field was not found - error case */
if (fields_array[i].name == NULL) {
- GString *allowed_fields = g_string_sized_new (256);
- int k;
-
/* Set GError */
- if (idx != -1 && fields_array[idx].group) {
- NmcOutputField *second_level = fields_array[idx].group;
- for (k = 0; second_level[k].name; k++)
- g_string_append_printf (allowed_fields, "%s.%s,",
- fields_array[idx].name, second_level[k].name);
- } else {
- for (k = 0; fields_array[k].name; k++)
- g_string_append_printf (allowed_fields, "%s,", fields_array[k].name);
- }
- g_string_truncate (allowed_fields, allowed_fields->len - 1);
-
if (!strcasecmp (*iter, "all") || !strcasecmp (*iter, "common"))
g_set_error (error, NMCLI_ERROR, 0, _("field '%s' has to be alone"), *iter);
- else
+ else {
+ char *allowed_fields = nmc_get_allowed_fields (fields_array, idx);
g_set_error (error, NMCLI_ERROR, 1, _("invalid field '%s'; allowed fields: %s"),
- *iter, allowed_fields->str);
- g_string_free (allowed_fields, TRUE);
+ *iter, allowed_fields);
+ g_free (allowed_fields);
+ }
/* Free arrays on error */
g_array_free (array, TRUE);
@@ -737,6 +742,35 @@ done:
return array;
}
+/**
+* nmc_get_allowed_fields:
+* @fields_array: array of fields
+* @group_idx: index to the array (for second-level array in 'group' member),
+* or -1
+*
+* Returns: string of allowed fields names.
+* Caller is responsible for freeing the array.
+*/
+char *
+nmc_get_allowed_fields (const NmcOutputField fields_array[], int group_idx)
+{
+ GString *allowed_fields = g_string_sized_new (256);
+ int i;
+
+ if (group_idx != -1 && fields_array[group_idx].group) {
+ NmcOutputField *second_level = fields_array[group_idx].group;
+ for (i = 0; second_level[i].name; i++)
+ g_string_append_printf (allowed_fields, "%s.%s,",
+ fields_array[group_idx].name, second_level[i].name);
+ } else {
+ for (i = 0; fields_array[i].name; i++)
+ g_string_append_printf (allowed_fields, "%s,", fields_array[i].name);
+ }
+ g_string_truncate (allowed_fields, allowed_fields->len - 1);
+
+ return g_string_free (allowed_fields, FALSE);
+}
+
gboolean
nmc_terse_option_check (NMCPrintOutput print_output, const char *fields, GError **error)
{
diff --git a/cli/src/utils.h b/cli/src/utils.h
index 2d3292bd36..e92952f331 100644
--- a/cli/src/utils.h
+++ b/cli/src/utils.h
@@ -14,7 +14,7 @@
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
- * (C) Copyright 2010 - 2013 Red Hat, Inc.
+ * (C) Copyright 2010 - 2014 Red Hat, Inc.
*/
#ifndef NMC_UTILS_H
@@ -38,6 +38,7 @@ typedef struct {
int matches (const char *cmd, const char *pattern);
int next_arg (int *argc, char ***argv);
gboolean nmc_arg_is_help (const char *arg);
+gboolean nmc_arg_is_option (const char *arg, const char *opt_name);
gboolean nmc_parse_args (nmc_arg_t *arg_arr, gboolean last, int *argc, char ***argv, GError **error);
char *ssid_to_hex (const char *str, gsize len);
gboolean nmc_string_to_int_base (const char *str,
@@ -85,6 +86,7 @@ GArray *parse_output_fields (const char *fields_str,
gboolean parse_groups,
GPtrArray **group_fields,
GError **error);
+char *nmc_get_allowed_fields (const NmcOutputField fields_array[], int group_idx);
gboolean nmc_terse_option_check (NMCPrintOutput print_output, const char *fields, GError **error);
NmcOutputField *nmc_dup_fields_array (NmcOutputField fields[], size_t size, guint32 flags);
void nmc_empty_output_fields (NmCli *nmc);