diff options
author | Jiří Klimeš <jklimes@redhat.com> | 2015-02-16 18:07:12 +0100 |
---|---|---|
committer | Jiří Klimeš <jklimes@redhat.com> | 2015-02-23 09:24:21 +0100 |
commit | 40e98f5d685bc41da32f65e6ee3b5ad1b46cca3f (patch) | |
tree | 49da035862627b4d6fac407a7a063fa9017bcea6 | |
parent | b4d52967829a213fcdc1e44bcf41275a9d32c674 (diff) | |
download | NetworkManager-40e98f5d685bc41da32f65e6ee3b5ad1b46cca3f.tar.gz |
nmcli: add --order option for 'nmcli connection show'
The option allows you to specify custom sorting order.
Default order (when no --order is provided) corresponds to -o "active:name:path"
Examples:
nmcli con show -o name
nmcli con show -o +name
- sort connections by name alphabetically
nmcli con show -o -name
- sort connections by name alphabetically in reverse order
mmcli con show -o active:name
- sort connections first by active status, then by name
mmcli con show -o -path
- sort connections by D-Bus path in reverse order
-rw-r--r-- | clients/cli/connections.c | 167 | ||||
-rw-r--r-- | man/nmcli.1.in | 21 |
2 files changed, 160 insertions, 28 deletions
diff --git a/clients/cli/connections.c b/clients/cli/connections.c index c6141b4ec8..bbe28d6f79 100644 --- a/clients/cli/connections.c +++ b/clients/cli/connections.c @@ -250,7 +250,8 @@ usage (void) { g_printerr (_("Usage: nmcli connection { COMMAND | help }\n\n" "COMMAND := { show | up | down | add | modify | edit | delete | reload | load }\n\n" - " show [--active] [[--show-secrets] [id | uuid | path | apath] <ID>] ...\n\n" + " show [--active] [--order <order spec>]\n" + " show [--active] [--show-secrets] [id | uuid | path | apath] <ID> ...\n\n" #if WITH_WIMAX " up [[id | uuid | path] <ID>] [ifname <ifname>] [ap <BSSID>] [nsp <name>] [passwd-file <file with passwords>]\n\n" #else @@ -271,12 +272,12 @@ usage_connection_show (void) { g_printerr (_("Usage: nmcli connection show { ARGUMENTS | help }\n" "\n" - "ARGUMENTS := [--active]\n" + "ARGUMENTS := [--active] [--order <order spec>]\n" "\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" + "profiles are shown. --order allows custom connection ordering (see manual page).\n" "\n" "ARGUMENTS := [--active] [--show-secrets] [id | uuid | path | apath] <ID> ...\n" "\n" @@ -1311,44 +1312,72 @@ split_required_fields_for_con_show (const char *input, } typedef enum { - NMC_SORT_ACTIVE, - NMC_SORT_NAME, - NMC_SORT_TYPE, - NMC_SORT_PATH, + NMC_SORT_ACTIVE = 1, + NMC_SORT_ACTIVE_INV = -1, + NMC_SORT_NAME = 2, + NMC_SORT_NAME_INV = -2, + NMC_SORT_TYPE = 3, + NMC_SORT_TYPE_INV = -3, + NMC_SORT_PATH = 4, + NMC_SORT_PATH_INV = -4, } NmcSortOrder; +typedef struct { + NmCli *nmc; + const GArray *order; +} NmcSortInfo; + static int compare_connections (gconstpointer a, gconstpointer b, gpointer user_data) { NMConnection *ca = *(NMConnection **)a; NMConnection *cb = *(NMConnection **)b; NMActiveConnection *aca, *acb; - NmCli *nmc = (NmCli *) user_data; - int cmp, i; + NmcSortInfo *info = (NmcSortInfo *) user_data; + GArray *default_order = NULL; + const GArray *order; + NmcSortOrder item; + int cmp = 0, i; const char *tmp1, *tmp2; unsigned long tmp1_int, tmp2_int; - NmcSortOrder default_order[] = { - NMC_SORT_ACTIVE, - NMC_SORT_NAME, - NMC_SORT_PATH, - }; - for (i = 0; i < G_N_ELEMENTS (default_order); i++) { - switch (default_order[i]) { + if (info->order ) + order = info->order; + else { + NmcSortOrder def[] = { NMC_SORT_ACTIVE, NMC_SORT_NAME, NMC_SORT_PATH }; + int num = G_N_ELEMENTS (def); + default_order = g_array_sized_new (FALSE, FALSE, sizeof (NmcSortOrder), num); + g_array_append_vals (default_order, def, num); + order = default_order; + } + + for (i = 0; i < order->len; i++) { + item = g_array_index (order, NmcSortOrder, i); + switch (item) { case NMC_SORT_ACTIVE: - aca = get_ac_for_connection (nm_client_get_active_connections (nmc->client), ca); - acb = get_ac_for_connection (nm_client_get_active_connections (nmc->client), cb); + case NMC_SORT_ACTIVE_INV: + aca = get_ac_for_connection (nm_client_get_active_connections (info->nmc->client), ca); + acb = get_ac_for_connection (nm_client_get_active_connections (info->nmc->client), cb); cmp = (aca && !acb) ? -1 : (!aca && acb) ? 1 : 0; + if (item == NMC_SORT_ACTIVE_INV) + cmp = -(cmp); break; case NMC_SORT_TYPE: + case NMC_SORT_TYPE_INV: cmp = g_strcmp0 (nm_connection_get_connection_type (ca), nm_connection_get_connection_type (cb)); + if (item == NMC_SORT_TYPE_INV) + cmp = -(cmp); break; case NMC_SORT_NAME: + case NMC_SORT_NAME_INV: cmp = g_strcmp0 (nm_connection_get_id (ca), nm_connection_get_id (cb)); + if (item == NMC_SORT_NAME_INV) + cmp = -(cmp); break; case NMC_SORT_PATH: + case NMC_SORT_PATH_INV: tmp1 = nm_connection_get_path (ca); tmp2 = nm_connection_get_path (cb); tmp1 = tmp1 ? strrchr (tmp1, '/') : "0"; @@ -1356,27 +1385,36 @@ compare_connections (gconstpointer a, gconstpointer b, gpointer user_data) nmc_string_to_uint (tmp1 ? tmp1+1 : "0", FALSE, 0, 0, &tmp1_int); nmc_string_to_uint (tmp2 ? tmp2+1 : "0", FALSE, 0, 0, &tmp2_int); cmp = (int) tmp1_int - tmp2_int; + if (item == NMC_SORT_PATH_INV) + cmp = -(cmp); break; default: cmp = 0; break; } if (cmp != 0) - return cmp; + goto end; } - return 0; +end: + if (default_order) + g_array_unref (default_order); + return cmp; } static GPtrArray * -sort_connections (const GPtrArray *cons, NmCli *nmc) +sort_connections (const GPtrArray *cons, NmCli *nmc, const GArray *order) { GPtrArray *sorted; int i; + NmcSortInfo compare_info; + + compare_info.nmc = nmc; + compare_info.order = order; sorted = g_ptr_array_sized_new (cons->len); for (i = 0; cons && i < cons->len; i++) g_ptr_array_add (sorted, cons->pdata[i]); - g_ptr_array_sort_with_data (sorted, compare_connections, nmc); + g_ptr_array_sort_with_data (sorted, compare_connections, &compare_info); return sorted; } @@ -1436,7 +1474,7 @@ get_invisible_active_connections (NmCli *nmc) static NMCResultCode do_connections_show (NmCli *nmc, gboolean active_only, gboolean show_secrets, - int argc, char **argv) + const GArray *order, int argc, char **argv) { GError *err = NULL; char *profile_flds = NULL, *active_flds = NULL; @@ -1482,7 +1520,7 @@ do_connections_show (NmCli *nmc, gboolean active_only, gboolean show_secrets, g_ptr_array_free (invisibles, FALSE); /* Sort the connections and fill the output data */ - sorted_cons = sort_connections (nmc->connections, nmc); + sorted_cons = sort_connections (nmc->connections, nmc, order); for (i = 0; i < sorted_cons->len; i++) fill_output_connection (sorted_cons->pdata[i], nmc, active_only); g_ptr_array_free (sorted_cons, FALSE); @@ -9019,6 +9057,67 @@ nmcli_con_tab_completion (const char *text, int start, int end) return match_array; } +static GArray * +parse_preferred_connection_order (const char *order, GError **error) +{ + char **strv, **iter; + const char *str; + GArray *order_arr; + NmcSortOrder val; + gboolean inverse; + int i; + + strv = nmc_strsplit_set (order, ":", -1); + if (!strv || !*strv) { + g_set_error (error, NMCLI_ERROR, 0, + _("incorrect string '%s' of '--order' option"), order); + g_strfreev (strv); + return NULL; + } + + order_arr = g_array_sized_new (FALSE, FALSE, sizeof (NmcSortOrder), 4); + for (iter = strv; iter && *iter; iter++) { + str = *iter; + inverse = FALSE; + if (str[0] == '-') + inverse = TRUE; + if (str[0] == '+' || str[0] == '-') + str++; + + if (matches (str, "active") == 0) + val = inverse ? NMC_SORT_ACTIVE_INV : NMC_SORT_ACTIVE; + else if (matches (str, "name") == 0) + val = inverse ? NMC_SORT_NAME_INV : NMC_SORT_NAME; + else if (matches (str, "type") == 0) + val = inverse ? NMC_SORT_TYPE_INV : NMC_SORT_TYPE; + else if (matches (str, "path") == 0) + val = inverse ? NMC_SORT_PATH_INV : NMC_SORT_PATH; + else { + g_array_unref (order_arr); + order_arr = NULL; + g_set_error (error, NMCLI_ERROR, 0, + _("incorrect item '%s' in '--order' option"), *iter); + break; + } + /* Check duplicates*/ + for (i = 0; i < order_arr->len; i++) { + if (abs (g_array_index (order_arr, NmcSortOrder, i)) - abs (val) == 0) { + g_array_unref (order_arr); + order_arr = NULL; + g_set_error (error, NMCLI_ERROR, 0, + _("'%s' repeats in '--order' option"), str); + goto end; + } + } + + /* Value is ok and unique, add it to the array */ + g_array_append_val (order_arr, val); + } +end: + g_strfreev (strv); + return order_arr; +} + /* Entry point function for connections-related commands: 'nmcli connection' */ NMCResultCode do_connections (NmCli *nmc, int argc, char **argv) @@ -9061,16 +9160,17 @@ do_connections (NmCli *nmc, int argc, char **argv) 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, FALSE, FALSE, argc, argv); + nmc->return_value = do_connections_show (nmc, FALSE, FALSE, NULL, argc, argv); } else { if (matches (*argv, "show") == 0) { gboolean active = FALSE; gboolean show_secrets = FALSE; + GArray *order = NULL; int i; next_arg (&argc, &argv); /* check connection show options [--active] [--show-secrets] */ - for (i = 0; i < 2; i++) { + for (i = 0; i < 3; i++) { if (!active && nmc_arg_is_option (*argv, "active")) { active = TRUE; next_arg (&argc, &argv); @@ -9079,8 +9179,21 @@ do_connections (NmCli *nmc, int argc, char **argv) show_secrets = TRUE; next_arg (&argc, &argv); } + if (!order && nmc_arg_is_option (*argv, "order")) { + if (next_arg (&argc, &argv) != 0) { + g_set_error_literal (&error, NMCLI_ERROR, 0, + _("'--order' argument is missing")); + goto opt_error; + } + order = parse_preferred_connection_order (*argv, &error); + if (error) + goto opt_error; + next_arg (&argc, &argv); + } } - nmc->return_value = do_connections_show (nmc, active, show_secrets, argc, argv); + nmc->return_value = do_connections_show (nmc, active, show_secrets, order, argc, argv); + if (order) + g_array_unref (order); } else if (matches(*argv, "up") == 0) { nmc->return_value = do_connection_up (nmc, argc-1, argv+1); } else if (matches(*argv, "down") == 0) { diff --git a/man/nmcli.1.in b/man/nmcli.1.in index c9a69cb9bf..8ca2a3b2aa 100644 --- a/man/nmcli.1.in +++ b/man/nmcli.1.in @@ -289,12 +289,31 @@ active if a device is using that connection profile. Without a parameter, all profiles are listed. When --active option is specified, only the active profiles are shown. .TP -.B show [--active] [--show-secrets] [ id | uuid | path | apath ] <ID> ... +.B show [--active] [--order <order spec>] [--show-secrets] [ id | uuid | path | apath ] <ID> ... .br Show details for specified connections. By default, both static configuration and active connection data are displayed. When --active option is specified, only the active profiles are taken into account. When --show-secrets option is specified, secrets associated with the profile will be revealed too. +.sp +Ordering: +.br +The --order option can be used to get custom ordering of connections. The +connections can be ordered by active status, name, type or D-Bus path. If +connections are equal according to a sort order category, an additional +category can be specified. +The default sorting order is equivalent to "--order active:name:path". +.sp +<order spec> := category:category:... +.br +categogy := [+-]active | [+-]name | [+-]type | [+-]path +.br +\fI+\fP or no prefix means sorting in ascending order (alphabetically or in numbers). +.br +\fI-\fP means reverse (descending) order. +.br +The category names can be abbreviated (e.g. --order -a:na) +.sp \fIid\fP, \fIuuid\fP, \fIpath\fP and \fIapath\fP keywords can be used if \fI<ID>\fP is ambiguous. .RS |