diff options
Diffstat (limited to 'clients/cli/devices.c')
| -rw-r--r-- | clients/cli/devices.c | 1370 |
1 files changed, 756 insertions, 614 deletions
diff --git a/clients/cli/devices.c b/clients/cli/devices.c index 1e3d9e42..afa769f6 100644 --- a/clients/cli/devices.c +++ b/clients/cli/devices.c @@ -30,13 +30,14 @@ #include "utils.h" #include "common.h" #include "devices.h" +#include "connections.h" /* define some prompts */ #define PROMPT_INTERFACE _("Interface: ") #define PROMPT_INTERFACES _("Interface(s): ") /* Available fields for 'device status' */ -static NmcOutputField nmc_fields_dev_status[] = { +NmcOutputField nmc_fields_dev_status[] = { {"DEVICE", N_("DEVICE")}, /* 0 */ {"TYPE", N_("TYPE")}, /* 1 */ {"STATE", N_("STATE")}, /* 2 */ @@ -51,7 +52,7 @@ static NmcOutputField nmc_fields_dev_status[] = { /* Available fields for 'device show' - GENERAL part */ -static NmcOutputField nmc_fields_dev_show_general[] = { +NmcOutputField nmc_fields_dev_show_general[] = { {"NAME", N_("NAME")}, /* 0 */ {"DEVICE", N_("DEVICE")}, /* 1 */ {"TYPE", N_("TYPE")}, /* 2 */ @@ -85,7 +86,7 @@ static NmcOutputField nmc_fields_dev_show_general[] = { #define NMC_FIELDS_DEV_SHOW_GENERAL_COMMON "NAME,DEVICE,TYPE,VENDOR,PRODUCT,DRIVER,HWADDR,STATE" /* Available fields for 'device show' - CONNECTIONS part */ -static NmcOutputField nmc_fields_dev_show_connections[] = { +NmcOutputField nmc_fields_dev_show_connections[] = { {"NAME", N_("NAME")}, /* 0 */ {"AVAILABLE-CONNECTION-PATHS", N_("AVAILABLE-CONNECTION-PATHS")}, /* 1 */ {"AVAILABLE-CONNECTIONS", N_("AVAILABLE-CONNECTIONS")}, /* 2 */ @@ -95,7 +96,7 @@ static NmcOutputField nmc_fields_dev_show_connections[] = { #define NMC_FIELDS_DEV_SHOW_CONNECTIONS_COMMON "AVAILABLE-CONNECTION-PATHS,AVAILABLE-CONNECTIONS" /* Available fields for 'device show' - CAPABILITIES part */ -static NmcOutputField nmc_fields_dev_show_cap[] = { +NmcOutputField nmc_fields_dev_show_cap[] = { {"NAME", N_("NAME")}, /* 0 */ {"CARRIER-DETECT", N_("CARRIER-DETECT")}, /* 1 */ {"SPEED", N_("SPEED")}, /* 2 */ @@ -106,7 +107,7 @@ static NmcOutputField nmc_fields_dev_show_cap[] = { #define NMC_FIELDS_DEV_SHOW_CAP_COMMON "NAME,CARRIER-DETECT,SPEED,IS-SOFTWARE" /* Available fields for 'device show' - wired properties part */ -static NmcOutputField nmc_fields_dev_show_wired_prop[] = { +NmcOutputField nmc_fields_dev_show_wired_prop[] = { {"NAME", N_("NAME")}, /* 0 */ {"CARRIER", N_("CARRIER")}, /* 1 */ {"S390-SUBCHANNELS", N_("S390-SUBCHANNELS")}, /* 2 */ @@ -116,7 +117,7 @@ static NmcOutputField nmc_fields_dev_show_wired_prop[] = { #define NMC_FIELDS_DEV_SHOW_WIRED_PROP_COMMON "NAME,CARRIER,S390-SUBCHANNELS" /* Available fields for 'device show' - wireless properties part */ -static NmcOutputField nmc_fields_dev_show_wifi_prop[] = { +NmcOutputField nmc_fields_dev_show_wifi_prop[] = { {"NAME", N_("NAME")}, /* 0 */ {"WEP", N_("WEP")}, /* 1 */ {"WPA", N_("WPA")}, /* 2 */ @@ -133,7 +134,7 @@ static NmcOutputField nmc_fields_dev_show_wifi_prop[] = { #define NMC_FIELDS_DEV_SHOW_WIFI_PROP_COMMON "NAME,WEP,WPA,WPA2,TKIP,CCMP,AP,ADHOC" /* Available fields for 'device show' - wimax properties part */ -static NmcOutputField nmc_fields_dev_show_wimax_prop[] = { +NmcOutputField nmc_fields_dev_show_wimax_prop[] = { {"NAME", N_("NAME")}, /* 0 */ {"CTR-FREQ", N_("CTR-FREQ")}, /* 1 */ {"RSSI", N_("RSSI")}, /* 2 */ @@ -146,7 +147,7 @@ static NmcOutputField nmc_fields_dev_show_wimax_prop[] = { #define NMC_FIELDS_DEV_SHOW_WIMAX_PROP_COMMON "NAME,CTR-FREQ,RSSI,CINR,TX-POW,BSID" /* Available fields for 'device wifi list' */ -static NmcOutputField nmc_fields_dev_wifi_list[] = { +NmcOutputField nmc_fields_dev_wifi_list[] = { {"NAME", N_("NAME")}, /* 0 */ {"SSID", N_("SSID")}, /* 1 */ {"SSID-HEX", N_("SSID-HEX")}, /* 2 */ @@ -172,7 +173,7 @@ static NmcOutputField nmc_fields_dev_wifi_list[] = { #define NMC_FIELDS_DEV_WIFI_LIST_FOR_DEV_LIST "NAME,"NMC_FIELDS_DEV_WIFI_LIST_COMMON /* Available fields for 'device wimax list' */ -static NmcOutputField nmc_fields_dev_wimax_list[] = { +NmcOutputField nmc_fields_dev_wimax_list[] = { {"NAME", N_("NAME")}, /* 0 */ {"NSP", N_("NSP")}, /* 1 */ {"SIGNAL", N_("SIGNAL")}, /* 2 */ @@ -186,8 +187,8 @@ static NmcOutputField nmc_fields_dev_wimax_list[] = { #define NMC_FIELDS_DEV_WIMAX_LIST_COMMON "NSP,SIGNAL,TYPE,DEVICE,ACTIVE" #define NMC_FIELDS_DEV_WIMAX_LIST_FOR_DEV_LIST "NAME,"NMC_FIELDS_DEV_WIMAX_LIST_COMMON -/* Available fields for 'device show' - BOND, TEAM, BRIDGE part */ -static NmcOutputField nmc_fields_dev_show_master_prop[] = { +/* Available fields for 'device show' - BOND, BRIDGE part */ +NmcOutputField nmc_fields_dev_show_master_prop[] = { {"NAME", N_("NAME")}, /* 0 */ {"SLAVES", N_("SLAVES")}, /* 1 */ {NULL, NULL} @@ -195,8 +196,18 @@ static NmcOutputField nmc_fields_dev_show_master_prop[] = { #define NMC_FIELDS_DEV_SHOW_MASTER_PROP_ALL "NAME,SLAVES" #define NMC_FIELDS_DEV_SHOW_MASTER_PROP_COMMON "NAME,SLAVES" +/* Available fields for 'device show' - TEAM part */ +NmcOutputField nmc_fields_dev_show_team_prop[] = { + {"NAME", N_("NAME")}, /* 0 */ + {"SLAVES", N_("SLAVES")}, /* 1 */ + {"CONFIG", N_("CONFIG")}, /* 2 */ + {NULL, NULL} +}; +#define NMC_FIELDS_DEV_SHOW_TEAM_PROP_ALL "NAME,SLAVES,CONFIG" +#define NMC_FIELDS_DEV_SHOW_TEAM_PROP_COMMON "NAME,SLAVES,CONFIG" + /* Available fields for 'device show' - VLAN part */ -static NmcOutputField nmc_fields_dev_show_vlan_prop[] = { +NmcOutputField nmc_fields_dev_show_vlan_prop[] = { {"NAME", N_("NAME")}, /* 0 */ {"PARENT", N_("PARENT")}, /* 1 */ {"ID", N_("ID")}, /* 2 */ @@ -206,7 +217,7 @@ static NmcOutputField nmc_fields_dev_show_vlan_prop[] = { #define NMC_FIELDS_DEV_SHOW_VLAN_PROP_COMMON "NAME,PARENT,ID" /* Available fields for 'device show' - BLUETOOTH part */ -static NmcOutputField nmc_fields_dev_show_bluetooth[] = { +NmcOutputField nmc_fields_dev_show_bluetooth[] = { {"NAME", N_("NAME")}, /* 0 */ {"CAPABILITIES", N_("CAPABILITIES")}, /* 1 */ {NULL, NULL} @@ -221,7 +232,7 @@ extern NmcOutputField nmc_fields_dhcp4_config[]; extern NmcOutputField nmc_fields_dhcp6_config[]; /* Available sections for 'device show' */ -static NmcOutputField nmc_fields_dev_show_sections[] = { +NmcOutputField nmc_fields_dev_show_sections[] = { {"GENERAL", N_("GENERAL"), 0, nmc_fields_dev_show_general + 1 }, /* 0 */ {"CAPABILITIES", N_("CAPABILITIES"), 0, nmc_fields_dev_show_cap + 1 }, /* 1 */ {"WIFI-PROPERTIES", N_("WIFI-PROPERTIES"), 0, nmc_fields_dev_show_wifi_prop + 1 }, /* 2 */ @@ -234,7 +245,7 @@ static NmcOutputField nmc_fields_dev_show_sections[] = { {"IP6", N_("IP6"), 0, nmc_fields_ip6_config + 1 }, /* 9 */ {"DHCP6", N_("DHCP6"), 0, nmc_fields_dhcp6_config + 1 }, /* 10 */ {"BOND", N_("BOND"), 0, nmc_fields_dev_show_master_prop + 1 }, /* 11 */ - {"TEAM", N_("TEAM"), 0, nmc_fields_dev_show_master_prop + 1 }, /* 12 */ + {"TEAM", N_("TEAM"), 0, nmc_fields_dev_show_team_prop + 1 }, /* 12 */ {"BRIDGE", N_("BRIDGE"), 0, nmc_fields_dev_show_master_prop + 1 }, /* 13 */ {"VLAN", N_("VLAN"), 0, nmc_fields_dev_show_vlan_prop + 1 }, /* 14 */ {"BLUETOOTH", N_("BLUETOOTH"), 0, nmc_fields_dev_show_bluetooth + 1 }, /* 15 */ @@ -247,7 +258,7 @@ static NmcOutputField nmc_fields_dev_show_sections[] = { "GENERAL.CONNECTION,GENERAL.CON-PATH,WIRED-PROPERTIES,IP4,IP6" /* Available fields for 'device lldp' */ -static NmcOutputField nmc_fields_dev_lldp_list[] = { +NmcOutputField nmc_fields_dev_lldp_list[] = { {"NAME", N_("NAME")}, /* 0 */ {"DEVICE", N_("DEVICE")}, /* 1 */ {"CHASSIS-ID", N_("CHASSIS-ID")}, /* 2 */ @@ -281,12 +292,13 @@ static void usage (void) { g_printerr (_("Usage: nmcli device { COMMAND | help }\n\n" - "COMMAND := { status | show | connect | reapply | disconnect | delete | monitor | wifi | lldp }\n\n" + "COMMAND := { status | show | set | connect | reapply | modify | disconnect | delete | monitor | wifi | lldp }\n\n" " status\n\n" " show [<ifname>]\n\n" " set [ifname] <ifname> [autoconnect yes|no] [managed yes|no]\n\n" " connect <ifname>\n\n" " reapply <ifname>\n\n" + " modify <ifname> ([+|-]<setting>.<property> <value>)+\n\n" " disconnect <ifname> ...\n\n" " delete <ifname> ...\n\n" " monitor <ifname> ...\n\n" @@ -349,6 +361,26 @@ usage_device_reapply (void) } static void +usage_device_modify (void) +{ + g_printerr (_("Usage: nmcli device modify { ARGUMENTS | --help }\n" + "\n" + "ARGUMENTS := <ifname> ([+|-]<setting>.<property> <value>)+\n" + "\n" + "Modify one or more properties currently active on the device without modifying\n" + "the connection profile. The changes have immediate effect. For multi-valued\n" + "properties you can use optional '+' or '-' prefix to the property name.\n" + "The '+' sign allows appending items instead of overwriting the whole value.\n" + "The '-' sign allows removing selected items instead of the whole value.\n" + "\n" + "Examples:\n" + "nmcli dev mod em1 ipv4.method manual ipv4.addr \"192.168.1.2/24, 10.10.1.5/8\"\n" + "nmcli dev mod em1 +ipv4.dns 8.8.4.4\n" + "nmcli dev mod em1 -ipv4.dns 1\n" + "nmcli dev mod em1 -ipv6.addr \"abbe::cafe/56\"\n")); +} + +static void usage_device_disconnect (void) { g_printerr (_("Usage: nmcli device disconnect { ARGUMENTS | help }\n" @@ -489,8 +521,8 @@ compare_devices (const void *a, const void *b) nm_device_get_iface (db)); } -static NMDevice ** -get_devices_sorted (NMClient *client) +NMDevice ** +nmc_get_devices_sorted (NMClient *client) { const GPtrArray *devs; NMDevice **sorted; @@ -505,8 +537,33 @@ get_devices_sorted (NMClient *client) return sorted; } +static void +complete_device (NMDevice **devices, const char *prefix, gboolean wifi_only) +{ + int i; + + for (i = 0; devices[i]; i++) { + const char *iface = nm_device_get_iface (devices[i]); + + if (wifi_only && !NM_IS_DEVICE_WIFI (devices[i])) + continue; + + if (g_str_has_prefix (iface, prefix)) + g_print ("%s\n", iface); + } +} + +void +nmc_complete_device (NMClient *client, const char *prefix, gboolean wifi_only) +{ + gs_free NMDevice **devices = NULL; + + devices = nmc_get_devices_sorted (client); + complete_device (devices, prefix, wifi_only); +} + static GSList * -device_list (NmCli *nmc, int argc, char **argv) +get_device_list (NmCli *nmc, int argc, char **argv) { int arg_num = argc; char **arg_arr = NULL; @@ -530,8 +587,11 @@ device_list (NmCli *nmc, int argc, char **argv) } } - devices = get_devices_sorted (nmc->client); + devices = nmc_get_devices_sorted (nmc->client); while (arg_num > 0) { + if (arg_num == 1 && nmc->complete) + complete_device (devices, *arg_ptr, FALSE); + device = NULL; for (i = 0; devices[i]; i++) { if (!g_strcmp0 (nm_device_get_iface (devices[i]), *arg_ptr)) { @@ -546,7 +606,8 @@ device_list (NmCli *nmc, int argc, char **argv) else g_printerr (_("Warning: argument '%s' is duplicated.\n"), *arg_ptr); } else { - g_printerr (_("Error: Device '%s' not found.\n"), *arg_ptr); + if (!nmc->complete) + g_printerr (_("Error: Device '%s' not found.\n"), *arg_ptr); g_string_printf (nmc->return_text, _("Error: not all devices found.")); nmc->return_value = NMC_RESULT_ERROR_NOT_FOUND; } @@ -562,6 +623,45 @@ error: return queue; } +static NMDevice * +get_device (NmCli *nmc, int *argc, char ***argv, GError **error) +{ + gs_free NMDevice **devices = NULL; + gs_free char *ifname_ask = NULL; + const char *ifname = NULL; + int i; + + if (*argc == 0) { + if (nmc->ask) + ifname = ifname_ask = nmc_readline (PROMPT_INTERFACE); + + if (!ifname_ask) { + g_set_error_literal (error, NMCLI_ERROR, NMC_RESULT_ERROR_USER_INPUT, + _("No interface specified")); + return NULL; + } + } else { + ifname = **argv; + next_arg (argc, argv); + } + + devices = nmc_get_devices_sorted (nmc->client); + for (i = 0; devices[i]; i++) { + if (!g_strcmp0 (nm_device_get_iface (devices[i]), ifname)) + break; + } + + if (nmc->complete && !*argc) + complete_device (devices, ifname, FALSE); + + if (devices[i] == NULL) { + g_set_error (error, NMCLI_ERROR, NMC_RESULT_ERROR_NOT_FOUND, + _("Device '%s' not found"), ifname); + } + + return devices[i]; +} + static int compare_aps (gconstpointer a, gconstpointer b, gpointer user_data) { @@ -595,27 +695,22 @@ sort_access_points (const GPtrArray *aps) return sorted; } -typedef struct { - NmcTermColor color; - NmcTermFormat color_fmt; -} ColorInfo; - -static ColorInfo -wifi_signal_to_color (guint8 strength) +static void +wifi_signal_to_color (guint8 strength, NmcTermColor *color, NmcTermFormat *color_fmt) { - ColorInfo color_info = { NMC_TERM_COLOR_NORMAL, NMC_TERM_FORMAT_NORMAL }; + *color = NMC_TERM_COLOR_NORMAL; + *color_fmt = NMC_TERM_FORMAT_NORMAL; if (strength > 80) - color_info.color = NMC_TERM_COLOR_GREEN; + *color = NMC_TERM_COLOR_GREEN; else if (strength > 55) - color_info.color = NMC_TERM_COLOR_YELLOW; + *color = NMC_TERM_COLOR_YELLOW; else if (strength > 30) - color_info.color = NMC_TERM_COLOR_MAGENTA; + *color = NMC_TERM_COLOR_MAGENTA; else if (strength > 5) - color_info.color = NMC_TERM_COLOR_CYAN; + *color = NMC_TERM_COLOR_CYAN; else - color_info.color_fmt = NMC_TERM_FORMAT_DIM; - return color_info; + *color_fmt = NMC_TERM_FORMAT_DIM; } static char * @@ -687,7 +782,8 @@ fill_output_access_point (gpointer data, gpointer user_data) GString *security_str; char *ap_name; const char *sig_bars; - ColorInfo color_info; + NmcTermColor color; + NmcTermFormat color_fmt; if (info->active_bssid) { const char *current_bssid = nm_access_point_get_bssid (ap); @@ -774,9 +870,9 @@ fill_output_access_point (gpointer data, gpointer user_data) set_val_strc (arr, 16, nm_object_get_path (NM_OBJECT (ap))); /* Set colors */ - color_info = wifi_signal_to_color (strength); - set_val_color_all (arr, color_info.color); - set_val_color_fmt_all (arr, color_info.color_fmt); + wifi_signal_to_color (strength, &color, &color_fmt); + set_val_color_all (arr, color); + set_val_color_fmt_all (arr, color_fmt); if (active) arr[15].color = NMC_TERM_COLOR_GREEN; @@ -840,10 +936,10 @@ get_active_connection_id (NMDevice *device) } static gboolean -print_bond_team_bridge_info (NMDevice *device, - NmCli *nmc, - const char *group_prefix, - const char *one_field) +print_bond_bridge_info (NMDevice *device, + NmCli *nmc, + const char *group_prefix, + const char *one_field) { const GPtrArray *slaves = NULL; GString *slaves_str; @@ -853,10 +949,10 @@ print_bond_team_bridge_info (NMDevice *device, if (NM_IS_DEVICE_BOND (device)) slaves = nm_device_bond_get_slaves (NM_DEVICE_BOND (device)); - else if (NM_IS_DEVICE_TEAM (device)) - slaves = nm_device_team_get_slaves (NM_DEVICE_TEAM (device)); else if (NM_IS_DEVICE_BRIDGE (device)) slaves = nm_device_bridge_get_slaves (NM_DEVICE_BRIDGE (device)); + else + g_return_val_if_reached (FALSE); slaves_str = g_string_new (NULL); for (idx = 0; slaves && idx < slaves->len; idx++) { @@ -891,6 +987,76 @@ print_bond_team_bridge_info (NMDevice *device, return TRUE; } +static char * +sanitize_team_config (const char *config) +{ + char *ret; + int i; + + if (!config) + return NULL; + + ret = g_strdup (config); + + for (i = 0; i < strlen (ret); i++) { + if (ret[i] == '\n') + ret[i] = ' '; + } + + return ret; +} + +static gboolean +print_team_info (NMDevice *device, + NmCli *nmc, + const char *group_prefix, + const char *one_field) +{ + const GPtrArray *slaves = NULL; + GString *slaves_str; + int idx; + NmcOutputField *tmpl, *arr; + size_t tmpl_len; + + if (NM_IS_DEVICE_TEAM (device)) + slaves = nm_device_team_get_slaves (NM_DEVICE_TEAM (device)); + else + g_return_val_if_reached (FALSE); + + slaves_str = g_string_new (NULL); + for (idx = 0; slaves && idx < slaves->len; idx++) { + NMDevice *slave = g_ptr_array_index (slaves, idx); + const char *iface = nm_device_get_iface (slave); + + if (iface) { + g_string_append (slaves_str, iface); + g_string_append_c (slaves_str, ' '); + } + } + if (slaves_str->len > 0) + g_string_truncate (slaves_str, slaves_str->len-1); /* Chop off last space */ + + tmpl = nmc_fields_dev_show_team_prop; + tmpl_len = sizeof (nmc_fields_dev_show_team_prop); + nmc->print_fields.indices = parse_output_fields (one_field ? one_field : NMC_FIELDS_DEV_SHOW_TEAM_PROP_ALL, + tmpl, FALSE, NULL, NULL); + arr = nmc_dup_fields_array (tmpl, tmpl_len, NMC_OF_FLAG_FIELD_NAMES); + g_ptr_array_add (nmc->output_data, arr); + + arr = nmc_dup_fields_array (tmpl, tmpl_len, NMC_OF_FLAG_SECTION_PREFIX); + set_val_strc (arr, 0, group_prefix); /* TEAM */ + set_val_str (arr, 1, slaves_str->str); + set_val_str (arr, 2, sanitize_team_config (nm_device_team_get_config (NM_DEVICE_TEAM (device)))); + g_ptr_array_add (nmc->output_data, arr); + + print_data (nmc); /* Print all data */ + + g_string_free (slaves_str, FALSE); + nmc_empty_output_fields (nmc); + + return TRUE; +} + static gboolean show_device_info (NMDevice *device, NmCli *nmc) { @@ -1146,19 +1312,19 @@ show_device_info (NMDevice *device, NmCli *nmc) /* Bond specific information */ if (NM_IS_DEVICE_BOND (device)) { if (!strcasecmp (nmc_fields_dev_show_sections[section_idx].name, nmc_fields_dev_show_sections[11].name)) - was_output = print_bond_team_bridge_info (device, nmc, nmc_fields_dev_show_sections[11].name, section_fld); + was_output = print_bond_bridge_info (device, nmc, nmc_fields_dev_show_sections[11].name, section_fld); } /* Team specific information */ if (NM_IS_DEVICE_TEAM (device)) { if (!strcasecmp (nmc_fields_dev_show_sections[section_idx].name, nmc_fields_dev_show_sections[12].name)) - was_output = print_bond_team_bridge_info (device, nmc, nmc_fields_dev_show_sections[12].name, section_fld); + was_output = print_team_info (device, nmc, nmc_fields_dev_show_sections[12].name, section_fld); } /* Bridge specific information */ if (NM_IS_DEVICE_BRIDGE (device)) { if (!strcasecmp (nmc_fields_dev_show_sections[section_idx].name, nmc_fields_dev_show_sections[13].name)) - was_output = print_bond_team_bridge_info (device, nmc, nmc_fields_dev_show_sections[13].name, section_fld); + was_output = print_bond_bridge_info (device, nmc, nmc_fields_dev_show_sections[13].name, section_fld); } /* VLAN-specific information */ @@ -1264,20 +1430,20 @@ show_device_info (NMDevice *device, NmCli *nmc) return TRUE; } -static ColorInfo -device_state_to_color (NMDeviceState state) +void +nmc_device_state_to_color (NMDeviceState state, NmcTermColor *color, NmcTermFormat *color_fmt) { - ColorInfo color_info = { NMC_TERM_COLOR_NORMAL, NMC_TERM_FORMAT_NORMAL }; + *color = NMC_TERM_COLOR_NORMAL; + *color_fmt = NMC_TERM_FORMAT_NORMAL; if (state <= NM_DEVICE_STATE_UNAVAILABLE) - color_info.color_fmt= NMC_TERM_FORMAT_DIM; + *color_fmt= NMC_TERM_FORMAT_DIM; else if (state == NM_DEVICE_STATE_DISCONNECTED) - color_info.color = NMC_TERM_COLOR_RED; + *color = NMC_TERM_COLOR_RED; else if (state >= NM_DEVICE_STATE_PREPARE && state <= NM_DEVICE_STATE_SECONDARIES) - color_info.color = NMC_TERM_COLOR_YELLOW; + *color = NMC_TERM_COLOR_YELLOW; else if (state == NM_DEVICE_STATE_ACTIVATED) - color_info.color = NMC_TERM_COLOR_GREEN; - return color_info; + *color = NMC_TERM_COLOR_GREEN; } static void @@ -1285,7 +1451,8 @@ fill_output_device_status (NMDevice *device, NmCli *nmc) { NMActiveConnection *ac; NMDeviceState state; - ColorInfo color_info; + NmcTermColor color; + NmcTermFormat color_fmt; NmcOutputField *arr = nmc_dup_fields_array (nmc_fields_dev_status, sizeof (nmc_fields_dev_status), 0); @@ -1294,9 +1461,9 @@ fill_output_device_status (NMDevice *device, NmCli *nmc) ac = nm_device_get_active_connection (device); /* Show devices in color */ - color_info = device_state_to_color (state); - set_val_color_all (arr, color_info.color); - set_val_color_fmt_all (arr, color_info.color_fmt); + nmc_device_state_to_color (state, &color, &color_fmt); + set_val_color_all (arr, color); + set_val_color_fmt_all (arr, color_fmt); set_val_strc (arr, 0, nm_device_get_iface (device)); set_val_strc (arr, 1, nm_device_get_type_description (device)); @@ -1321,6 +1488,16 @@ do_devices_status (NmCli *nmc, int argc, char **argv) NmcOutputField *tmpl, *arr; size_t tmpl_len; + /* Nothing to complete */ + if (nmc->complete) + return nmc->return_value; + + if (!nmc_terse_option_check (nmc->print_output, nmc->required_fields, &error)) { + g_string_printf (nmc->return_text, _("Error: %s."), error->message); + g_error_free (error); + return NMC_RESULT_ERROR_USER_INPUT; + } + while (argc > 0) { g_printerr (_("Unknown parameter: %s\n"), *argv); argc--; @@ -1341,8 +1518,7 @@ do_devices_status (NmCli *nmc, int argc, char **argv) if (error) { g_string_printf (nmc->return_text, _("Error: 'device status': %s"), error->message); g_error_free (error); - nmc->return_value = NMC_RESULT_ERROR_USER_INPUT; - goto error; + return NMC_RESULT_ERROR_USER_INPUT; } /* Add headers */ @@ -1350,7 +1526,7 @@ do_devices_status (NmCli *nmc, int argc, char **argv) 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); - devices = get_devices_sorted (nmc->client); + devices = nmc_get_devices_sorted (nmc->client); for (i = 0; devices[i]; i++) fill_output_device_status (devices[i], nmc); @@ -1360,59 +1536,53 @@ do_devices_status (NmCli *nmc, int argc, char **argv) g_free (devices); return NMC_RESULT_SUCCESS; - -error: - return nmc->return_value; } static NMCResultCode -do_devices_show (NmCli *nmc, int argc, char **argv) +do_device_show (NmCli *nmc, int argc, char **argv) { - NMDevice **devices = NULL; - NMDevice *device = NULL; - const char *ifname = NULL; - int i; - gboolean ret; - - if (argc == 1) - ifname = *argv; - else if (argc > 1) { - g_string_printf (nmc->return_text, _("Error: invalid extra argument '%s'."), *(argv+1)); - nmc->return_value = NMC_RESULT_ERROR_USER_INPUT; - goto error; - } + gs_free_error GError *error = NULL; - devices = get_devices_sorted (nmc->client); + if (!nmc->mode_specified) + nmc->multiline_output = TRUE; /* multiline mode is default for 'device show' */ - if (ifname) { - /* Interface specified; show details only for the device */ - for (i = 0; devices[i]; i++) { - NMDevice *candidate = devices[i]; - const char *dev_iface = nm_device_get_iface (candidate); + if (argc) { + NMDevice *device; - if (!g_strcmp0 (dev_iface, ifname)) - device = candidate; - } + device = get_device (nmc, &argc, &argv, &error); if (!device) { - g_string_printf (nmc->return_text, _("Error: Device '%s' not found."), ifname); - nmc->return_value = NMC_RESULT_ERROR_NOT_FOUND; - goto error; + g_string_printf (nmc->return_text, _("Error: %s."), error->message); + return error->code; } + + if (argc) { + g_string_printf (nmc->return_text, _("Error: invalid extra argument '%s'."), *argv); + return NMC_RESULT_ERROR_USER_INPUT; + } + + if (nmc->complete) + return nmc->return_value; + show_device_info (device, nmc); } else { + NMDevice **devices = nmc_get_devices_sorted (nmc->client); + int i; + + /* nmc_do_cmd() should not call this with argc=0. */ + g_assert (!nmc->complete); + /* Show details for all devices */ for (i = 0; devices[i]; i++) { nmc_empty_output_fields (nmc); - ret = show_device_info (devices[i], nmc); - if (!ret) + if (!show_device_info (devices[i], nmc)) break; if (devices[i + 1]) g_print ("\n"); /* Empty line */ } + + g_free (devices); } -error: - g_free (devices); return nmc->return_value; } @@ -1657,57 +1827,27 @@ connect_device_cb (GObject *client, GAsyncResult *result, gpointer user_data) static NMCResultCode do_device_connect (NmCli *nmc, int argc, char **argv) { - NMDevice **devices; NMDevice *device = NULL; - const char *ifname = NULL; - char *ifname_ask = NULL; - int i; AddAndActivateInfo *info; + gs_free_error GError *error = NULL; /* Set default timeout for connect operation. */ if (nmc->timeout == -1) nmc->timeout = 90; - if (argc == 0) { - if (nmc->ask) - ifname = ifname_ask = nmc_readline (PROMPT_INTERFACE); - - if (!ifname_ask) { - g_string_printf (nmc->return_text, _("Error: No interface specified.")); - nmc->return_value = NMC_RESULT_ERROR_USER_INPUT; - goto error; - } - } else { - ifname = *argv; - } - - if (!ifname) { - g_string_printf (nmc->return_text, _("Error: No interface specified.")); - nmc->return_value = NMC_RESULT_ERROR_USER_INPUT; - goto error; + device = get_device (nmc, &argc, &argv, &error); + if (!device) { + g_string_printf (nmc->return_text, _("Error: %s."), error->message); + return error->code; } - if (next_arg (&argc, &argv) == 0) { + if (*argv) { g_string_printf (nmc->return_text, _("Error: extra argument not allowed: '%s'."), *argv); - nmc->return_value = NMC_RESULT_ERROR_USER_INPUT; - goto error; - } - - devices = get_devices_sorted (nmc->client); - for (i = 0; devices[i]; i++) { - NMDevice *candidate = devices[i]; - const char *dev_iface = nm_device_get_iface (candidate); - - if (!g_strcmp0 (dev_iface, ifname)) - device = candidate; + return NMC_RESULT_ERROR_USER_INPUT; } - g_free (devices); - if (!device) { - g_string_printf (nmc->return_text, _("Error: Device '%s' not found."), ifname); - nmc->return_value = NMC_RESULT_ERROR_NOT_FOUND; - goto error; - } + if (nmc->complete) + return nmc->return_value; /* * Use nowait_flag instead of should_wait, because exiting has to be postponed @@ -1740,9 +1880,6 @@ do_device_connect (NmCli *nmc, int argc, char **argv) if (nmc->print_output == NMC_PRINT_PRETTY) progress_id = g_timeout_add (120, progress_cb, device); -error: - g_free (ifname_ask); - return nmc->return_value; } @@ -1856,55 +1993,30 @@ reapply_device_cb (GObject *object, GAsyncResult *result, gpointer user_data) static NMCResultCode do_device_reapply (NmCli *nmc, int argc, char **argv) { - gs_free NMDevice **devices = NULL; - NMDevice *device = NULL; + NMDevice *device; DeviceCbInfo *info = NULL; - char **arg_ptr = argv; - int arg_num = argc; - int i; - gs_free char *device_name_free = NULL; - const char *device_name = NULL; + gs_free_error GError *error = NULL; /* Set default timeout for reapply operation. */ if (nmc->timeout == -1) nmc->timeout = 10; - if (argc == 0) { - if (nmc->ask) { - device_name_free = nmc_readline (PROMPT_INTERFACE); - device_name = device_name_free; - } - if (!device_name) { - g_string_printf (nmc->return_text, _("Error: No interface specified.")); - nmc->return_value = NMC_RESULT_ERROR_USER_INPUT; - return nmc->return_value; - } - } else if (argc == 1) { - device_name = arg_ptr[0]; - next_arg (&arg_num, &arg_ptr); - } else { - next_arg (&arg_num, &arg_ptr); - g_string_printf (nmc->return_text, _("Error: unsupported argument '%s'."), *arg_ptr); - nmc->return_value = NMC_RESULT_ERROR_USER_INPUT; - return nmc->return_value; + device = get_device (nmc, &argc, &argv, &error); + if (!device) { + g_string_printf (nmc->return_text, _("Error: %s."), error->message); + return error->code; } - devices = get_devices_sorted (nmc->client); - for (i = 0; devices[i]; i++) { - if (!g_strcmp0 (nm_device_get_iface (devices[i]), device_name)) { - device = devices[i]; - break; - } + if (argc) { + g_string_printf (nmc->return_text, _("Error: invalid extra argument '%s'."), *argv); + return NMC_RESULT_ERROR_USER_INPUT; } - if (!device) { - g_string_printf (nmc->return_text, _("Error: device '%s' not found."), device_name); - nmc->return_value = NMC_RESULT_ERROR_NOT_FOUND; + if (nmc->complete) return nmc->return_value; - } nmc->nowait_flag = (nmc->timeout == 0); - nmc->should_wait = TRUE; + nmc->should_wait++; info = g_slice_new0 (DeviceCbInfo); info->nmc = nmc; @@ -1916,6 +2028,108 @@ do_device_reapply (NmCli *nmc, int argc, char **argv) return nmc->return_value; } +typedef struct { + NmCli *nmc; + int argc; + char **argv; +} ModifyInfo; + +static void +modify_reapply_cb (GObject *object, GAsyncResult *result, gpointer user_data) +{ + NMDevice *device = NM_DEVICE (object); + ModifyInfo *info = user_data; + NmCli *nmc = info->nmc; + GError *error = NULL; + + if (!nm_device_reapply_finish (device, result, &error)) { + g_string_printf (nmc->return_text, _("Error: Reapplying connection to device '%s' (%s) failed: %s"), + nm_device_get_iface (device), + nm_object_get_path (NM_OBJECT (device)), + error->message); + g_error_free (error); + nmc->return_value = NMC_RESULT_ERROR_DEV_DISCONNECT; + } else { + if (nmc->print_output == NMC_PRINT_PRETTY) + nmc_terminal_erase_line (); + g_print (_("Connection successfully reapplied to device '%s'.\n"), + nm_device_get_iface (device)); + } + + g_slice_free (ModifyInfo, info); + quit (); +} + +static void +modify_get_applied_cb (GObject *object, + GAsyncResult *result, + gpointer user_data) +{ + NMDevice *device = NM_DEVICE (object); + ModifyInfo *info = user_data; + NmCli *nmc = info->nmc; + gs_free_error GError *error = NULL; + NMConnection *connection; + guint64 version_id; + + connection = nm_device_get_applied_connection_finish (device, + result, + &version_id, + &error); + if (!connection) { + g_string_printf (nmc->return_text, _("Error: Reading applied connection from device '%s' (%s) failed: %s"), + nm_device_get_iface (device), + nm_object_get_path (NM_OBJECT (device)), + error->message); + nmc->return_value = NMC_RESULT_ERROR_UNKNOWN; + g_slice_free (ModifyInfo, info); + quit (); + return; + } + + if (!nmc_read_connection_properties (info->nmc, connection, &info->argc, &info->argv, &error)) { + g_string_assign (nmc->return_text, error->message); + nmc->return_value = error->code; + g_slice_free (ModifyInfo, info); + quit (); + return; + } + + if (nmc->complete) + quit (); + else + nm_device_reapply_async (device, connection, version_id, 0, NULL, modify_reapply_cb, info); +} + +static NMCResultCode +do_device_modify (NmCli *nmc, int argc, char **argv) +{ + NMDevice *device = NULL; + ModifyInfo *info = NULL; + gs_free_error GError *error = NULL; + + device = get_device (nmc, &argc, &argv, &error); + if (!device) { + g_string_printf (nmc->return_text, _("Error: %s."), error->message); + return error->code; + } + + if (nmc->timeout == -1) + nmc->timeout = 10; + + nmc->nowait_flag = (nmc->timeout == 0); + nmc->should_wait++; + + info = g_slice_new0 (ModifyInfo); + info->nmc = nmc; + info->argc = argc; + info->argv = argv; + + nm_device_get_applied_connection_async (device, 0, NULL, modify_get_applied_cb, info); + + return nmc->return_value; +} + static void disconnect_device_cb (GObject *object, GAsyncResult *result, gpointer user_data) { @@ -1950,7 +2164,7 @@ disconnect_device_cb (GObject *object, GAsyncResult *result, gpointer user_data) } static NMCResultCode -do_device_disconnect (NmCli *nmc, int argc, char **argv) +do_devices_disconnect (NmCli *nmc, int argc, char **argv) { NMDevice *device; DeviceCbInfo *info = NULL; @@ -1960,9 +2174,11 @@ do_device_disconnect (NmCli *nmc, int argc, char **argv) if (nmc->timeout == -1) nmc->timeout = 10; - queue = device_list (nmc, argc, argv); + queue = get_device_list (nmc, argc, argv); if (!queue) - goto error; + return nmc->return_value; + if (nmc->complete) + goto out; queue = g_slist_reverse (queue); info = g_slice_new0 (DeviceCbInfo); @@ -1988,7 +2204,7 @@ do_device_disconnect (NmCli *nmc, int argc, char **argv) nm_device_disconnect_async (device, NULL, disconnect_device_cb, info); } -error: +out: g_slist_free (queue); return nmc->return_value; } @@ -2017,7 +2233,7 @@ delete_device_cb (GObject *object, GAsyncResult *result, gpointer user_data) } static NMCResultCode -do_device_delete (NmCli *nmc, int argc, char **argv) +do_devices_delete (NmCli *nmc, int argc, char **argv) { NMDevice *device; DeviceCbInfo *info = NULL; @@ -2027,9 +2243,11 @@ do_device_delete (NmCli *nmc, int argc, char **argv) if (nmc->timeout == -1) nmc->timeout = 10; - queue = device_list (nmc, argc, argv); + queue = get_device_list (nmc, argc, argv); if (!queue) - goto error; + return nmc->return_value; + if (nmc->complete) + goto out; queue = g_slist_reverse (queue); info = g_slice_new0 (DeviceCbInfo); @@ -2052,7 +2270,7 @@ do_device_delete (NmCli *nmc, int argc, char **argv) nm_device_delete_async (device, NULL, delete_device_cb, info); } -error: +out: g_slist_free (queue); return nmc->return_value; } @@ -2062,9 +2280,7 @@ do_device_set (NmCli *nmc, int argc, char **argv) { #define DEV_SET_AUTOCONNECT 0 #define DEV_SET_MANAGED 1 - NMDevice **devices; NMDevice *device = NULL; - const char *ifname = NULL; int i; struct { int idx; @@ -2073,63 +2289,42 @@ do_device_set (NmCli *nmc, int argc, char **argv) [DEV_SET_AUTOCONNECT] = { -1 }, [DEV_SET_MANAGED] = { -1 }, }; + gs_free_error GError *error = NULL; if (argc >= 1 && g_strcmp0 (*argv, "ifname") == 0) { argc--; argv++; } - if (argc == 0) { - g_string_printf (nmc->return_text, _("Error: No interface specified.")); - nmc->return_value = NMC_RESULT_ERROR_USER_INPUT; - goto error; - } else - ifname = *argv; - - if (!ifname) { - g_string_printf (nmc->return_text, _("Error: No interface specified.")); - nmc->return_value = NMC_RESULT_ERROR_USER_INPUT; - goto error; - } - - devices = get_devices_sorted (nmc->client); - for (i = 0; devices[i]; i++) { - NMDevice *candidate = devices[i]; - const char *dev_iface = nm_device_get_iface (candidate); - - if (!g_strcmp0 (dev_iface, ifname)) - device = candidate; - } - g_free (devices); - + device = get_device (nmc, &argc, &argv, &error); if (!device) { - g_string_printf (nmc->return_text, _("Error: Device '%s' not found."), ifname); - nmc->return_value = NMC_RESULT_ERROR_NOT_FOUND; - goto error; + g_string_printf (nmc->return_text, _("Error: %s."), error->message); + return error->code; } - if (argc == 1) { + if (!argc) { g_string_printf (nmc->return_text, _("Error: No property specified.")); - nmc->return_value = NMC_RESULT_ERROR_USER_INPUT; - goto error; + return NMC_RESULT_ERROR_USER_INPUT; } i = 0; - while (next_arg (&argc, &argv) == 0) { + do { gboolean flag; - gs_free_error GError *tmp_err = NULL; + + if (argc == 1 && nmc->complete) + nmc_complete_strings (*argv, "managed", "autoconnect", NULL); if (matches (*argv, "managed") == 0) { 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; - goto error; + return NMC_RESULT_ERROR_USER_INPUT; } - if (!nmc_string_to_bool (*argv, &flag, &tmp_err)) { + if (argc == 1 && nmc->complete) + nmc_complete_bool (*argv); + if (!nmc_string_to_bool (*argv, &flag, &error)) { g_string_printf (nmc->return_text, _("Error: 'managed': %s."), - tmp_err->message); - nmc->return_value = NMC_RESULT_ERROR_USER_INPUT; - goto error; + error->message); + return NMC_RESULT_ERROR_USER_INPUT; } values[DEV_SET_MANAGED].idx = ++i; values[DEV_SET_MANAGED].value = flag; @@ -2137,25 +2332,26 @@ do_device_set (NmCli *nmc, int argc, char **argv) else if (matches (*argv, "autoconnect") == 0) { 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; - goto error; + return NMC_RESULT_ERROR_USER_INPUT; } - if (!nmc_string_to_bool (*argv, &flag, &tmp_err)) { + if (argc == 1 && nmc->complete) + nmc_complete_bool (*argv); + if (!nmc_string_to_bool (*argv, &flag, &error)) { g_string_printf (nmc->return_text, _("Error: 'autoconnect': %s."), - tmp_err->message); - nmc->return_value = NMC_RESULT_ERROR_USER_INPUT; - goto error; + error->message); + return NMC_RESULT_ERROR_USER_INPUT; } values[DEV_SET_AUTOCONNECT].idx = ++i; values[DEV_SET_AUTOCONNECT].value = flag; } else { - usage_device_set (); g_string_printf (nmc->return_text, _("Error: property '%s' is not known."), *argv); - nmc->return_value = NMC_RESULT_ERROR_USER_INPUT; - goto error; + return NMC_RESULT_ERROR_USER_INPUT; } - } + } while (next_arg (&argc, &argv) == 0); + + if (nmc->complete) + return nmc->return_value; /* when multiple properties are specified, set them in the order as they * are specified on the command line. */ @@ -2170,8 +2366,6 @@ do_device_set (NmCli *nmc, int argc, char **argv) if (values[DEV_SET_MANAGED].idx >= 0) nm_device_set_managed (device, values[DEV_SET_MANAGED].value); -error: - quit (); return nmc->return_value; } @@ -2179,10 +2373,14 @@ static void device_state (NMDevice *device, GParamSpec *pspec, NmCli *nmc) { NMDeviceState state = nm_device_get_state (device); - ColorInfo color = device_state_to_color (state); - char *str = nmc_colorize (nmc, color.color, color.color_fmt, "%s: %s\n", - nm_device_get_iface (device), - nmc_device_state_to_string (state)); + NmcTermColor color; + NmcTermFormat color_fmt; + char *str; + + nmc_device_state_to_color (state, &color, &color_fmt); + str = nmc_colorize (nmc, color, color_fmt, "%s: %s\n", + nm_device_get_iface (device), + nmc_device_state_to_string (state)); g_print ("%s", str); g_free (str); @@ -2235,8 +2433,14 @@ device_removed (NMClient *client, NMDevice *device, NmCli *nmc) } static NMCResultCode -do_device_monitor (NmCli *nmc, int argc, char **argv) +do_devices_monitor (NmCli *nmc, int argc, char **argv) { + GSList *queue = get_device_list (nmc, argc, argv); + GSList *iter; + + if (nmc->complete) + return nmc->return_value; + if (argc == 0) { /* No devices specified. Monitor all. */ const GPtrArray *devices = nm_client_get_devices (nmc->client); @@ -2249,21 +2453,14 @@ do_device_monitor (NmCli *nmc, int argc, char **argv) nmc->should_wait++; g_signal_connect (nmc->client, NM_CLIENT_DEVICE_ADDED, G_CALLBACK (device_added), nmc); } else { - /* Monitor just the specified devices. */ - GSList *queue = device_list (nmc, argc, argv); - GSList *iter; - - if (!queue) - return nmc->return_value; - + /* Monitor the specified devices. */ for (iter = queue; iter; iter = g_slist_next (iter)) device_watch (nmc, NM_DEVICE (iter->data)); g_slist_free (queue); } g_signal_connect (nmc->client, NM_CLIENT_DEVICE_REMOVED, G_CALLBACK (device_removed), nmc); - - return NMC_RESULT_SUCCESS; + return nmc->return_value; } static void @@ -2299,6 +2496,118 @@ show_access_point_info (NMDevice *device, NmCli *nmc) g_free (info); } +/* + * Find a Wi-Fi device with 'iface' in 'devices' array. If 'iface' is NULL, + * the first Wi-Fi device is returned. 'idx' parameter is updated to the point + * where the function finished so that the function can be called repeatedly + * to get next matching device. + * Returns: found device or NULL + */ +static NMDevice * +find_wifi_device_by_iface (NMDevice **devices, const char *iface, int *idx) +{ + int i; + + for (i = idx ? *idx : 0; devices[i]; i++) { + const char *dev_iface = nm_device_get_iface (devices[i]); + + if (!NM_IS_DEVICE_WIFI (devices[i])) + continue; + + if (iface) { + /* If a iface was specified then use it. */ + if (g_strcmp0 (dev_iface, iface) == 0) + break; + } else { + /* Else return the first Wi-Fi device. */ + break; + } + } + + if (idx) + *idx = i + 1; + return devices[i]; +} + +/* + * Find AP on 'device' according to 'bssid' or 'ssid' parameter. + * Returns: found AP or NULL + */ +static NMAccessPoint * +find_ap_on_device (NMDevice *device, const char *bssid, const char *ssid, gboolean complete) +{ + const GPtrArray *aps; + NMAccessPoint *ap = NULL; + int i; + + g_return_val_if_fail (NM_IS_DEVICE_WIFI (device), NULL); + + aps = nm_device_wifi_get_access_points (NM_DEVICE_WIFI (device)); + for (i = 0; i < aps->len; i++) { + NMAccessPoint *candidate_ap = g_ptr_array_index (aps, i); + + if (bssid) { + /* Parameter is BSSID */ + const char *candidate_bssid = nm_access_point_get_bssid (candidate_ap); + + /* Compare BSSIDs */ + if (complete) { + if (g_str_has_prefix (candidate_bssid, bssid)) + g_print ("%s\n", candidate_bssid); + } else if (strcmp (bssid, candidate_bssid) == 0) { + ap = candidate_ap; + break; + } + } + + if (ssid) { + /* Parameter is SSID */ + GBytes *candidate_ssid; + char *ssid_tmp; + + candidate_ssid = nm_access_point_get_ssid (candidate_ap); + if (!candidate_ssid) + continue; + + ssid_tmp = nm_utils_ssid_to_utf8 (g_bytes_get_data (candidate_ssid, NULL), + g_bytes_get_size (candidate_ssid)); + + /* Compare SSIDs */ + if (complete) { + if (g_str_has_prefix (ssid_tmp, ssid)) + g_print ("%s\n", ssid_tmp); + } else if (strcmp (ssid, ssid_tmp) == 0) { + ap = candidate_ap; + g_free (ssid_tmp); + break; + } + g_free (ssid_tmp); + } + } + + return ap; +} + +static void +complete_aps (NMDevice **devices, const char *ifname, + const char *bssid_prefix, const char *ssid_prefix) +{ + int devices_idx = 0; + NMDevice *device; + + while ((device = find_wifi_device_by_iface (devices, ifname, &devices_idx))) + find_ap_on_device (device, bssid_prefix, ssid_prefix, TRUE); +} + +void +nmc_complete_bssid (NMClient *client, const char *ifname, const char *bssid_prefix) +{ + gs_free NMDevice **devices = NULL; + + devices = nmc_get_devices_sorted (client); + complete_aps (devices, ifname, bssid_prefix, NULL); +} + static NMCResultCode do_device_wifi_list (NmCli *nmc, int argc, char **argv) { @@ -2307,7 +2616,7 @@ do_device_wifi_list (NmCli *nmc, int argc, char **argv) NMAccessPoint *ap = NULL; const char *ifname = NULL; const char *bssid_user = NULL; - NMDevice **devices = NULL; + gs_free NMDevice **devices = NULL; const GPtrArray *aps; APInfo *info; int i, j; @@ -2318,23 +2627,29 @@ do_device_wifi_list (NmCli *nmc, int argc, char **argv) size_t tmpl_len; const char *base_hdr = _("Wi-Fi scan list"); + devices = nmc_get_devices_sorted (nmc->client); + while (argc > 0) { + if (argc == 1 && nmc->complete) + nmc_complete_strings (*argv, "ifname", "bssid", NULL); + if (strcmp (*argv, "ifname") == 0) { 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; - goto error; + return NMC_RESULT_ERROR_USER_INPUT; } ifname = *argv; + complete_device (devices, ifname, TRUE); } else if (strcmp (*argv, "bssid") == 0 || strcmp (*argv, "hwaddr") == 0) { /* hwaddr is deprecated and will be removed later */ 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; - goto error; + return NMC_RESULT_ERROR_USER_INPUT; } bssid_user = *argv; - } else { + if (argc == 1 && nmc->complete) + complete_aps (devices, NULL, bssid_user, NULL); + } else if (!nmc->complete) { g_printerr (_("Unknown parameter: %s\n"), *argv); } @@ -2356,28 +2671,18 @@ do_device_wifi_list (NmCli *nmc, int argc, char **argv) if (error) { g_string_printf (nmc->return_text, _("Error: 'device wifi': %s"), error->message); g_error_free (error); - nmc->return_value = NMC_RESULT_ERROR_USER_INPUT; - goto error; + return NMC_RESULT_ERROR_USER_INPUT; } - devices = get_devices_sorted (nmc->client); - if (ifname) { - /* Device specified - list only APs of this interface */ - for (i = 0; devices[i]; i++) { - NMDevice *candidate = devices[i]; - const char *dev_iface = nm_device_get_iface (candidate); + if (nmc->complete) + return nmc->return_value; - if (!g_strcmp0 (dev_iface, ifname)) { - device = candidate; - break; - } - } + if (ifname) { + device = find_wifi_device_by_iface (devices, ifname, NULL); if (!device) { g_string_printf (nmc->return_text, _("Error: Device '%s' not found."), ifname); - nmc->return_value = NMC_RESULT_ERROR_NOT_FOUND; - goto error; + return NMC_RESULT_ERROR_NOT_FOUND; } - /* Main header name */ nmc->print_fields.header_name = (char *) construct_header_name (base_hdr, ifname); @@ -2398,8 +2703,7 @@ do_device_wifi_list (NmCli *nmc, int argc, char **argv) if (!ap) { g_string_printf (nmc->return_text, _("Error: Access point with bssid '%s' not found."), bssid_user); - nmc->return_value = NMC_RESULT_ERROR_NOT_FOUND; - goto error; + return NMC_RESULT_ERROR_NOT_FOUND; } /* Add headers (field names) */ arr = nmc_dup_fields_array (tmpl, tmpl_len, NMC_OF_FLAG_MAIN_HEADER_ADD | NMC_OF_FLAG_FIELD_NAMES); @@ -2420,15 +2724,17 @@ do_device_wifi_list (NmCli *nmc, int argc, char **argv) show_access_point_info (device, nmc); } } else { - const char *err_msg; if ( nm_device_get_device_type (device) == NM_DEVICE_TYPE_GENERIC - && g_strcmp0 (nm_device_get_type_description (device), "wifi") == 0) - err_msg = _("Error: Device '%s' was not recognized as a Wi-Fi device, check NetworkManager Wi-Fi plugin."); - else - err_msg = _("Error: Device '%s' is not a Wi-Fi device."); - g_string_printf (nmc->return_text, err_msg, ifname); - nmc->return_value = NMC_RESULT_ERROR_UNKNOWN; - goto error; + && g_strcmp0 (nm_device_get_type_description (device), "wifi") == 0) { + g_string_printf (nmc->return_text, + _("Error: Device '%s' was not recognized as a Wi-Fi device, check NetworkManager Wi-Fi plugin."), + ifname); + } else { + g_string_printf (nmc->return_text, + _("Error: Device '%s' is not a Wi-Fi device."), + ifname); + } + return NMC_RESULT_ERROR_UNKNOWN; } } else { gboolean empty_line = FALSE; @@ -2479,8 +2785,7 @@ do_device_wifi_list (NmCli *nmc, int argc, char **argv) if (!ap) { g_string_printf (nmc->return_text, _("Error: Access point with bssid '%s' not found."), bssid_user); - nmc->return_value = NMC_RESULT_ERROR_NOT_FOUND; - goto error; + return NMC_RESULT_ERROR_NOT_FOUND; } } else { for (i = 0; devices[i]; i++) { @@ -2501,101 +2806,9 @@ do_device_wifi_list (NmCli *nmc, int argc, char **argv) } } -error: - g_free (devices); return nmc->return_value; } -/* - * Find a Wi-Fi device with 'iface' in 'devices' array. If 'iface' is NULL, - * the first Wi-Fi device is returned. 'idx' parameter is updated to the point - * where the function finished so that the function can be called repeatedly - * to get next matching device. - * Returns: found device or NULL - */ -static NMDevice * -find_wifi_device_by_iface (const GPtrArray *devices, const char *iface, int *idx) -{ - NMDevice *device = NULL; - int i; - - for (i = *idx; i < devices->len; i++) { - NMDevice *candidate = g_ptr_array_index (devices, i); - const char *dev_iface = nm_device_get_iface (candidate); - - if (!NM_IS_DEVICE_WIFI (candidate)) - continue; - - if (iface) { - /* If a iface was specified then use it. */ - if (g_strcmp0 (dev_iface, iface) == 0) { - device = candidate; - break; - } - } else { - /* Else return the first Wi-Fi device. */ - device = candidate; - break; - } - } - - *idx = i + 1; - return device; -} - -/* - * Find AP on 'device' according to 'bssid' or 'ssid' parameter. - * Returns: found AP or NULL - */ -static NMAccessPoint * -find_ap_on_device (NMDevice *device, GByteArray *bssid, const char *ssid) -{ - const GPtrArray *aps; - NMAccessPoint *ap = NULL; - int i; - - g_return_val_if_fail (NM_IS_DEVICE_WIFI (device), NULL); - g_return_val_if_fail ((bssid && !ssid) || (!bssid && ssid), NULL); - - aps = nm_device_wifi_get_access_points (NM_DEVICE_WIFI (device)); - for (i = 0; i < aps->len; i++) { - NMAccessPoint *candidate_ap = g_ptr_array_index (aps, i); - - if (ssid) { - /* Parameter is SSID */ - GBytes *candidate_ssid; - - candidate_ssid = nm_access_point_get_ssid (candidate_ap); - if (candidate_ssid) { - char *ssid_tmp = nm_utils_ssid_to_utf8 (g_bytes_get_data (candidate_ssid, NULL), - g_bytes_get_size (candidate_ssid)); - - /* Compare SSIDs */ - if (strcmp (ssid, ssid_tmp) == 0) { - ap = candidate_ap; - g_free (ssid_tmp); - break; - } - g_free (ssid_tmp); - } - } else if (bssid) { - /* Parameter is BSSID */ - const char *candidate_bssid = nm_access_point_get_bssid (candidate_ap); - char *bssid_up = nm_utils_hwaddr_ntoa (bssid->data, bssid->len); - - /* Compare BSSIDs */ - if (strcmp (bssid_up, candidate_bssid) == 0) { - ap = candidate_ap; - g_free (bssid_up); - break; - } - g_free (bssid_up); - } - } - - return ap; -} - static NMCResultCode do_device_wifi_connect_network (NmCli *nmc, int argc, char **argv) { @@ -2619,7 +2832,7 @@ do_device_wifi_connect_network (NmCli *nmc, int argc, char **argv) gboolean wep_passphrase = FALSE; GByteArray *bssid1_arr = NULL; GByteArray *bssid2_arr = NULL; - const GPtrArray *devices; + gs_free NMDevice **devices = NULL; int devices_idx; char *ssid_ask = NULL; char *passwd_ask = NULL; @@ -2628,14 +2841,22 @@ do_device_wifi_connect_network (NmCli *nmc, int argc, char **argv) if (nmc->timeout == -1) nmc->timeout = 90; + devices = nmc_get_devices_sorted (nmc->client); + /* Get the first compulsory argument (SSID or BSSID) */ if (argc > 0) { param_user = *argv; bssid1_arr = nm_utils_hwaddr_atoba (param_user, ETH_ALEN); + if (argc == 1 && nmc->complete) + complete_aps (devices, NULL, param_user, param_user); + argc--; argv++; } else { + /* nmc_do_cmd() should not call this with argc=0. */ + g_assert (!nmc->complete); + if (nmc->ask) { ssid_ask = nmc_readline (_("SSID or BSSID: ")); param_user = ssid_ask ? ssid_ask : ""; @@ -2644,46 +2865,56 @@ do_device_wifi_connect_network (NmCli *nmc, int argc, char **argv) if (!ssid_ask) { g_string_printf (nmc->return_text, _("Error: SSID or BSSID are missing.")); nmc->return_value = NMC_RESULT_ERROR_USER_INPUT; - goto error; + goto finish; } } /* Get the rest of the parameters */ while (argc > 0) { + if (argc == 1 && nmc->complete) { + nmc_complete_strings (*argv, "ifname", "bssid", "password", "wep-key-type", + "name", "private", "hidden", NULL); + } + if (strcmp (*argv, "ifname") == 0) { 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; - goto error; + goto finish; } ifname = *argv; + complete_device (devices, ifname, TRUE); } else if (strcmp (*argv, "bssid") == 0) { 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; - goto error; + goto finish; } bssid = *argv; + if (argc == 1 && nmc->complete) + complete_aps (devices, NULL, bssid, NULL); bssid2_arr = nm_utils_hwaddr_atoba (bssid, ETH_ALEN); if (!bssid2_arr) { g_string_printf (nmc->return_text, _("Error: bssid argument value '%s' is not a valid BSSID."), bssid); nmc->return_value = NMC_RESULT_ERROR_USER_INPUT; - goto error; + goto finish; } } else if (strcmp (*argv, "password") == 0) { 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; - goto error; + goto finish; } password = *argv; } else if (strcmp (*argv, "wep-key-type") == 0) { 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; - goto error; + goto finish; } + if (argc == 1 && nmc->complete) + nmc_complete_strings (*argv, "key", "phrase", NULL); if (strcmp (*argv, "key") == 0) wep_passphrase = FALSE; else if (strcmp (*argv, "phrase") == 0) @@ -2693,13 +2924,13 @@ do_device_wifi_connect_network (NmCli *nmc, int argc, char **argv) _("Error: wep-key-type argument value '%s' is invalid, use 'key' or 'phrase'."), *argv); nmc->return_value = NMC_RESULT_ERROR_USER_INPUT; - goto error; + goto finish; } } else if (strcmp (*argv, "name") == 0) { 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; - goto error; + goto finish; } con_name = *argv; } else if (strcmp (*argv, "private") == 0) { @@ -2707,28 +2938,32 @@ do_device_wifi_connect_network (NmCli *nmc, int argc, char **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; - goto error; + goto finish; } + if (argc == 1 && nmc->complete) + nmc_complete_bool (*argv); if (!nmc_string_to_bool (*argv, &private, &err_tmp)) { g_string_printf (nmc->return_text, _("Error: %s: %s."), *(argv-1), err_tmp->message); nmc->return_value = NMC_RESULT_ERROR_USER_INPUT; g_clear_error (&err_tmp); - goto error; + goto finish; } } else if (strcmp (*argv, "hidden") == 0) { GError *err_tmp = NULL; 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; - goto error; + goto finish; } + if (argc == 1 && nmc->complete) + nmc_complete_bool (*argv); if (!nmc_string_to_bool (*argv, &hidden, &err_tmp)) { g_string_printf (nmc->return_text, _("Error: %s: %s."), *(argv-1), err_tmp->message); nmc->return_value = NMC_RESULT_ERROR_USER_INPUT; g_clear_error (&err_tmp); - goto error; + goto finish; } - } else { + } else if (!nmc->complete) { g_printerr (_("Unknown parameter: %s\n"), *argv); } @@ -2736,21 +2971,22 @@ do_device_wifi_connect_network (NmCli *nmc, int argc, char **argv) argv++; } + if (nmc->complete) + goto finish; + /* Verify SSID/BSSID parameters */ if (bssid1_arr && bssid2_arr && memcmp (bssid1_arr->data, bssid2_arr->data, ETH_ALEN)) { g_string_printf (nmc->return_text, _("Error: BSSID to connect to (%s) differs from bssid argument (%s)."), param_user, bssid); nmc->return_value = NMC_RESULT_ERROR_USER_INPUT; - goto error; + goto finish; } if (!bssid1_arr && strlen (param_user) > 32) { g_string_printf (nmc->return_text, _("Error: Parameter '%s' is neither SSID nor BSSID."), param_user); nmc->return_value = NMC_RESULT_ERROR_USER_INPUT; - goto error; + goto finish; } - devices = nm_client_get_devices (nmc->client); - /* Find a device to activate the connection on */ devices_idx = 0; device = find_wifi_device_by_iface (devices, ifname, &devices_idx); @@ -2761,7 +2997,7 @@ do_device_wifi_connect_network (NmCli *nmc, int argc, char **argv) else g_string_printf (nmc->return_text, _("Error: No Wi-Fi device found.")); nmc->return_value = NMC_RESULT_ERROR_UNKNOWN; - goto error; + goto finish; } /* For hidden SSID first scan it so that NM learns about the AP */ @@ -2783,18 +3019,20 @@ do_device_wifi_connect_network (NmCli *nmc, int argc, char **argv) scan_err->message); g_clear_error (&scan_err); nmc->return_value = NMC_RESULT_ERROR_NOT_FOUND; - goto error; + goto finish; } } /* Find an AP to connect to */ - ap = find_ap_on_device (device, bssid1_arr, bssid1_arr ? NULL : param_user); + ap = find_ap_on_device (device, bssid1_arr ? param_user : NULL, + bssid1_arr ? NULL : param_user, FALSE); if (!ap && !ifname) { NMDevice *dev; /* AP not found, ifname was not specified, so try finding the AP on another device. */ while ((dev = find_wifi_device_by_iface (devices, NULL, &devices_idx)) != NULL) { - ap = find_ap_on_device (dev, bssid1_arr, bssid1_arr ? NULL : param_user); + ap = find_ap_on_device (dev, bssid1_arr ? param_user : NULL, + bssid1_arr ? NULL : param_user, FALSE); if (ap) { device = dev; break; @@ -2808,7 +3046,7 @@ do_device_wifi_connect_network (NmCli *nmc, int argc, char **argv) else g_string_printf (nmc->return_text, _("Error: No access point with BSSID '%s' found."), param_user); nmc->return_value = NMC_RESULT_ERROR_NOT_FOUND; - goto error; + goto finish; } /* If there are some connection data from user, create a connection and @@ -2911,7 +3149,7 @@ do_device_wifi_connect_network (NmCli *nmc, int argc, char **argv) add_and_activate_cb, info); -error: +finish: if (bssid1_arr) g_byte_array_free (bssid1_arr, TRUE); if (bssid2_arr) @@ -3064,8 +3302,7 @@ do_device_wifi_hotspot (NmCli *nmc, int argc, char **argv) const char *password = NULL; gboolean show_password = FALSE; NMDevice *device = NULL; - int devices_idx; - const GPtrArray *devices; + gs_free NMDevice **devices = NULL; NMDeviceWifiCapabilities caps; NMConnection *connection = NULL; NMSettingConnection *s_con; @@ -3079,58 +3316,61 @@ do_device_wifi_hotspot (NmCli *nmc, int argc, char **argv) if (nmc->timeout == -1) nmc->timeout = 60; + devices = nmc_get_devices_sorted (nmc->client); + while (argc > 0) { + if (argc == 1 && nmc->complete) { + nmc_complete_strings (*argv, "ifname", "con-name", "ssid", "band", + "channel", "password", NULL); + } + if (strcmp (*argv, "ifname") == 0) { 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; - goto error; + return NMC_RESULT_ERROR_USER_INPUT; } ifname = *argv; + if (argc == 1 && nmc->complete) + complete_device (devices, ifname, TRUE); } else if (strcmp (*argv, "con-name") == 0) { 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; - goto error; + return NMC_RESULT_ERROR_USER_INPUT; } con_name = *argv; } else if (strcmp (*argv, "ssid") == 0) { 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; - goto error; + return NMC_RESULT_ERROR_USER_INPUT; } ssid = *argv; if (strlen (ssid) > 32) { g_string_printf (nmc->return_text, _("Error: ssid is too long.")); - nmc->return_value = NMC_RESULT_ERROR_USER_INPUT; - goto error; + return NMC_RESULT_ERROR_USER_INPUT; } } else if (strcmp (*argv, "band") == 0) { 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; - goto error; + return NMC_RESULT_ERROR_USER_INPUT; } band = *argv; + if (argc == 1 && nmc->complete) + nmc_complete_strings (band, "a", "bg", NULL); if (strcmp (band, "a") && strcmp (band, "bg")) { g_string_printf (nmc->return_text, _("Error: band argument value '%s' is invalid; use 'a' or 'bg'."), band); - nmc->return_value = NMC_RESULT_ERROR_USER_INPUT; - goto error; + return NMC_RESULT_ERROR_USER_INPUT; } } else if (strcmp (*argv, "channel") == 0) { 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; - goto error; + return NMC_RESULT_ERROR_USER_INPUT; } channel = *argv; } else if (strcmp (*argv, "password") == 0) { 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; - goto error; + return NMC_RESULT_ERROR_USER_INPUT; } password = *argv; /* --show-password is deprecated in favour of global --show-secrets option */ @@ -3139,8 +3379,7 @@ do_device_wifi_hotspot (NmCli *nmc, int argc, char **argv) show_password = TRUE; } else { g_string_printf (nmc->return_text, _("Error: Unknown parameter %s."), *argv); - nmc->return_value = NMC_RESULT_ERROR_USER_INPUT; - goto error; + return NMC_RESULT_ERROR_USER_INPUT; } argc--; @@ -3148,6 +3387,9 @@ do_device_wifi_hotspot (NmCli *nmc, int argc, char **argv) } show_password = nmc->show_secrets || show_password; + if (nmc->complete) + return nmc->return_value; + /* Verify band and channel parameters */ if (!channel) { if (g_strcmp0 (band, "bg") == 0) @@ -3158,30 +3400,25 @@ do_device_wifi_hotspot (NmCli *nmc, int argc, char **argv) if (channel) { if (!band) { g_string_printf (nmc->return_text, _("Error: channel requires band too.")); - nmc->return_value = NMC_RESULT_ERROR_USER_INPUT; - goto error; + return NMC_RESULT_ERROR_USER_INPUT; } if ( !nmc_string_to_uint (channel, TRUE, 1, 5825, &channel_int) || !nm_utils_wifi_is_channel_valid (channel_int, band)) { g_string_printf (nmc->return_text, _("Error: channel '%s' not valid for band '%s'."), channel, band); - nmc->return_value = NMC_RESULT_ERROR_USER_INPUT; - goto error; + return NMC_RESULT_ERROR_USER_INPUT; } } /* Find Wi-Fi device. When no ifname is provided, the first Wi-Fi is used. */ - devices = nm_client_get_devices (nmc->client); - devices_idx = 0; - device = find_wifi_device_by_iface (devices, ifname, &devices_idx); + device = find_wifi_device_by_iface (devices, ifname, NULL); if (!device) { if (ifname) g_string_printf (nmc->return_text, _("Error: Device '%s' is not a Wi-Fi device."), ifname); else g_string_printf (nmc->return_text, _("Error: No Wi-Fi device found.")); - nmc->return_value = NMC_RESULT_ERROR_UNKNOWN; - goto error; + return NMC_RESULT_ERROR_UNKNOWN; } /* Check device supported mode */ @@ -3193,8 +3430,7 @@ do_device_wifi_hotspot (NmCli *nmc, int argc, char **argv) else { g_string_printf (nmc->return_text, _("Error: Device '%s' supports neither AP nor Ad-Hoc mode."), nm_device_get_iface (device)); - nmc->return_value = NMC_RESULT_ERROR_UNKNOWN; - goto error; + return NMC_RESULT_ERROR_UNKNOWN; } /* Create a connection with appropriate parameters */ @@ -3227,9 +3463,8 @@ do_device_wifi_hotspot (NmCli *nmc, int argc, char **argv) if (!set_wireless_security_for_hotspot (s_wsec, wifi_mode, caps, password, show_password, &error)) { g_object_unref (connection); g_string_printf (nmc->return_text, _("Error: Invalid 'password': %s."), error->message); - nmc->return_value = NMC_RESULT_ERROR_UNKNOWN; g_clear_error (&error); - goto error; + return NMC_RESULT_ERROR_UNKNOWN; } s_ip4 = (NMSettingIPConfig *) nm_setting_ip4_config_new (); @@ -3242,7 +3477,7 @@ do_device_wifi_hotspot (NmCli *nmc, int argc, char **argv) /* Activate the connection now */ nmc->nowait_flag = (nmc->timeout == 0); - nmc->should_wait = TRUE; + nmc->should_wait++; info = g_malloc0 (sizeof (AddAndActivateInfo)); info->nmc = nmc; @@ -3257,7 +3492,6 @@ do_device_wifi_hotspot (NmCli *nmc, int argc, char **argv) add_and_activate_cb, info); -error: return nmc->return_value; } @@ -3282,47 +3516,53 @@ do_device_wifi_rescan (NmCli *nmc, int argc, char **argv) NMDevice *device; const char *ifname = NULL; GPtrArray *ssids; - const GPtrArray *devices; - int devices_idx; + gs_free NMDevice **devices = NULL; GVariantBuilder builder, array_builder; GVariant *options; const char *ssid; int i; ssids = g_ptr_array_new (); + devices = nmc_get_devices_sorted (nmc->client); /* Get the parameters */ while (argc > 0) { + if (argc == 1 && nmc->complete) + nmc_complete_strings (*argv, "ifname", "ssid", NULL); + if (strcmp (*argv, "ifname") == 0) { if (ifname) { g_string_printf (nmc->return_text, _("Error: '%s' cannot repeat."), *(argv-1)); nmc->return_value = NMC_RESULT_ERROR_USER_INPUT; - goto error; + goto finish; } 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; - goto error; + goto finish; } ifname = *argv; + if (argc == 1 && nmc->complete) + complete_device (devices, ifname, TRUE); } else if (strcmp (*argv, "ssid") == 0) { 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; - goto error; + goto finish; } g_ptr_array_add (ssids, *argv); - } else + } else if (!nmc->complete) g_printerr (_("Unknown parameter: %s\n"), *argv); argc--; argv++; } + if (nmc->complete) + goto finish; + /* Find Wi-Fi device to scan on. When no ifname is provided, the first Wi-Fi is used. */ - devices = nm_client_get_devices (nmc->client); - devices_idx = 0; - device = find_wifi_device_by_iface (devices, ifname, &devices_idx); + device = find_wifi_device_by_iface (devices, ifname, NULL); if (!device) { if (ifname) @@ -3330,7 +3570,7 @@ do_device_wifi_rescan (NmCli *nmc, int argc, char **argv) else g_string_printf (nmc->return_text, _("Error: No Wi-Fi device found.")); nmc->return_value = NMC_RESULT_ERROR_UNKNOWN; - goto error; + goto finish; } @@ -3353,35 +3593,32 @@ do_device_wifi_rescan (NmCli *nmc, int argc, char **argv) nm_device_wifi_request_scan_async (NM_DEVICE_WIFI (device), NULL, request_rescan_cb, nmc); - g_ptr_array_free (ssids, FALSE); - return nmc->return_value; -error: nmc->should_wait++; +finish: g_ptr_array_free (ssids, FALSE); return nmc->return_value; } +static NMCCommand device_wifi_cmds[] = { + {"list", do_device_wifi_list, NULL }, + {"connect", do_device_wifi_connect_network, NULL }, + {"hotspot", do_device_wifi_hotspot, NULL }, + {"rescan", do_device_wifi_rescan, NULL }, + {NULL, do_device_wifi_list, NULL } +}; + static NMCResultCode do_device_wifi (NmCli *nmc, int argc, char **argv) { - if (argc == 0) - nmc->return_value = do_device_wifi_list (nmc, argc-1, argv+1); - else if (argc > 0) { - if (matches (*argv, "list") == 0) { - nmc->return_value = do_device_wifi_list (nmc, argc-1, argv+1); - } else if (matches (*argv, "connect") == 0) { - nmc->return_value = do_device_wifi_connect_network (nmc, argc-1, argv+1); - } else if (matches (*argv, "hotspot") == 0) { - nmc->return_value = do_device_wifi_hotspot (nmc, argc-1, argv+1); - } else if (matches (*argv, "rescan") == 0) { - nmc->return_value = do_device_wifi_rescan (nmc, argc-1, argv+1); - } else { - g_string_printf (nmc->return_text, _("Error: 'device wifi' command '%s' is not valid."), *argv); - nmc->return_value = NMC_RESULT_ERROR_USER_INPUT; - } + GError *error = NULL; + + if (!nmc_terse_option_check (nmc->print_output, nmc->required_fields, &error)) { + g_string_printf (nmc->return_text, _("Error: %s."), error->message); + g_error_free (error); + return NMC_RESULT_ERROR_USER_INPUT; } - return nmc->return_value; + return nmc_do_cmd (nmc, device_wifi_cmds, *argv, argc, argv); } static int @@ -3468,27 +3705,32 @@ show_device_lldp_list (NMDevice *device, NmCli *nmc, char *fields_str, int *coun return neighbors->len; } -static gboolean +static NMCResultCode do_device_lldp_list (NmCli *nmc, int argc, char **argv) { - NMDevice *device = NULL, **devices = NULL; - GError *error = NULL; - const char *ifname = NULL; + NMDevice *device = NULL; + gs_free_error GError *error = NULL; char *fields_str; - int i, counter = 0; + int counter = 0; while (argc > 0) { + if (argc == 1 && nmc->complete) + nmc_complete_strings (*argv, "ifname", NULL); + if (strcmp (*argv, "ifname") == 0) { 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; - goto error; + return NMC_RESULT_ERROR_USER_INPUT; + } + + device = get_device (nmc, &argc, &argv, &error); + if (!device) { + g_string_printf (nmc->return_text, _("Error: %s."), error->message); + return error->code; } - ifname = *argv; } else { g_string_printf (nmc->return_text, _("Error: invalid extra argument '%s'."), *argv); - nmc->return_value = NMC_RESULT_ERROR_USER_INPUT; - goto error; + return NMC_RESULT_ERROR_USER_INPUT; } argc--; @@ -3506,57 +3748,50 @@ do_device_lldp_list (NmCli *nmc, int argc, char **argv) if (error) { g_string_printf (nmc->return_text, _("Error: 'device lldp list': %s"), error->message); - g_error_free (error); - nmc->return_value = NMC_RESULT_ERROR_USER_INPUT; - return nmc->return_value; + return NMC_RESULT_ERROR_USER_INPUT; } - devices = get_devices_sorted (nmc->client); - - if (ifname) { - for (i = 0; devices[i]; i++) { - NMDevice *candidate = devices[i]; - const char *dev_iface = nm_device_get_iface (candidate); - - if (!g_strcmp0 (dev_iface, ifname)) { - device = candidate; - break; - } - } - - if (!device) { - g_string_printf (nmc->return_text, _("Error: Device '%s' not found."), ifname); - nmc->return_value = NMC_RESULT_ERROR_NOT_FOUND; - goto error; - } + if (nmc->complete) + return nmc->return_value; + if (device) { nmc_empty_output_fields (nmc); show_device_lldp_list (device, nmc, fields_str, &counter); } else { + NMDevice **devices = nmc_get_devices_sorted (nmc->client); + int i; + for (i = 0; devices[i]; i++) { nmc_empty_output_fields (nmc); show_device_lldp_list (devices[i], nmc, fields_str, &counter); } + + g_free (devices); } -error: - g_free (devices); return nmc->return_value; } +static NMCCommand device_lldp_cmds[] = { + {"list", do_device_lldp_list, NULL }, + {NULL, do_device_lldp_list, NULL } +}; + static NMCResultCode do_device_lldp (NmCli *nmc, int argc, char **argv) { - if (argc == 0) - nmc->return_value = do_device_lldp_list (nmc, argc, argv); - else if (matches (*argv, "list") == 0) - nmc->return_value = do_device_lldp_list (nmc, argc-1, argv+1); - else { - g_string_printf (nmc->return_text, _("Error: 'device lldp' command '%s' is not valid."), *argv); - nmc->return_value = NMC_RESULT_ERROR_USER_INPUT; + GError *error = NULL; + + if (!nmc_terse_option_check (nmc->print_output, nmc->required_fields, &error)) { + g_string_printf (nmc->return_text, _("Error: %s."), error->message); + g_error_free (error); + return NMC_RESULT_ERROR_USER_INPUT; } - return nmc->return_value; + if (!nmc->mode_specified) + nmc->multiline_output = TRUE; /* multiline mode is default for 'device lldp' */ + + return nmc_do_cmd (nmc, device_lldp_cmds, *argv, argc, argv); } static gboolean @@ -3628,11 +3863,24 @@ nmcli_device_tab_completion (const char *text, int start, int end) return match_array; } +static const NMCCommand device_cmds[] = { + {"status", do_devices_status, usage_device_status }, + {"show", do_device_show, usage_device_show }, + {"connect", do_device_connect, usage_device_connect }, + {"reapply", do_device_reapply, usage_device_reapply }, + {"disconnect", do_devices_disconnect, usage_device_disconnect }, + {"delete", do_devices_delete, usage_device_delete }, + {"set", do_device_set, usage_device_set }, + {"monitor", do_devices_monitor, usage_device_monitor }, + {"wifi", do_device_wifi, usage_device_wifi }, + {"lldp", do_device_lldp, usage_device_lldp }, + {"modify", do_device_modify, usage_device_modify }, + {NULL, do_devices_status, usage }, +}; + NMCResultCode do_devices (NmCli *nmc, int argc, char **argv) { - GError *error = NULL; - /* Register polkit agent */ nmc_start_polkit_agent_start_try (nmc); @@ -3644,120 +3892,14 @@ do_devices (NmCli *nmc, int argc, char **argv) /* Check whether NetworkManager is running */ if (!nm_client_get_nm_running (nmc->client)) { g_string_printf (nmc->return_text, _("Error: NetworkManager is not running.")); - nmc->return_value = NMC_RESULT_ERROR_NM_NOT_RUNNING; - return nmc->return_value; + return NMC_RESULT_ERROR_NM_NOT_RUNNING; } - if (argc == 0) { - if (!nmc_terse_option_check (nmc->print_output, nmc->required_fields, &error)) - goto opt_error; - nmc->return_value = do_devices_status (nmc, 0, NULL); - } - - if (argc > 0) { - if (nmc_arg_is_help (*argv)) { - usage (); - goto usage_exit; - } - else if (matches (*argv, "status") == 0) { - if (nmc_arg_is_help (*(argv+1))) { - usage_device_status (); - goto usage_exit; - } - if (!nmc_terse_option_check (nmc->print_output, nmc->required_fields, &error)) - goto opt_error; - nmc->return_value = do_devices_status (nmc, argc-1, argv+1); - } - else if (matches (*argv, "show") == 0) { - if (nmc_arg_is_help (*(argv+1))) { - usage_device_show (); - goto usage_exit; - } - if (!nmc->mode_specified) - nmc->multiline_output = TRUE; /* multiline mode is default for 'device show' */ - nmc->return_value = do_devices_show (nmc, argc-1, argv+1); - } - else if (matches (*argv, "connect") == 0) { - if (nmc_arg_is_help (*(argv+1))) { - usage_device_connect (); - goto usage_exit; - } - nmc->return_value = do_device_connect (nmc, argc-1, argv+1); - } - else if (matches (*argv, "reapply") == 0) { - if (nmc_arg_is_help (*(argv+1))) { - usage_device_reapply (); - goto usage_exit; - } - nmc->return_value = do_device_reapply (nmc, argc-1, argv+1); - } - else if (matches (*argv, "disconnect") == 0) { - if (nmc_arg_is_help (*(argv+1))) { - usage_device_disconnect (); - goto usage_exit; - } - nmc->return_value = do_device_disconnect (nmc, argc-1, argv+1); - } - else if (matches (*argv, "delete") == 0) { - if (nmc_arg_is_help (*(argv+1))) { - usage_device_delete (); - goto usage_exit; - } - nmc->return_value = do_device_delete (nmc, argc-1, argv+1); - } - else if (matches (*argv, "set") == 0) { - if (nmc_arg_is_help (*(argv+1))) { - usage_device_set (); - goto usage_exit; - } - nmc->return_value = do_device_set (nmc, argc-1, argv+1); - } - else if (matches (*argv, "monitor") == 0) { - if (nmc_arg_is_help (*(argv+1))) { - usage_device_monitor (); - goto usage_exit; - } - nmc->return_value = do_device_monitor (nmc, argc-1, argv+1); - } - else if (matches (*argv, "wifi") == 0) { - if (nmc_arg_is_help (*(argv+1))) { - usage_device_wifi (); - goto usage_exit; - } - if (!nmc_terse_option_check (nmc->print_output, nmc->required_fields, &error)) - goto opt_error; - nmc->return_value = do_device_wifi (nmc, argc-1, argv+1); - } - else if (matches (*argv, "lldp") == 0) { - if (nmc_arg_is_help (*(argv+1))) { - usage_device_lldp (); - goto usage_exit; - } - if (!nmc_terse_option_check (nmc->print_output, nmc->required_fields, &error)) - goto opt_error; - if (!nmc->mode_specified) - nmc->multiline_output = TRUE; /* multiline mode is default for 'device lldp' */ - nmc->return_value = do_device_lldp (nmc, argc-1, argv+1); - } - else { - usage (); - g_string_printf (nmc->return_text, _("Error: 'dev' command '%s' is not valid."), *argv); - nmc->return_value = NMC_RESULT_ERROR_USER_INPUT; - } - } - -usage_exit: - return nmc->return_value; - -opt_error: - g_string_printf (nmc->return_text, _("Error: %s."), error->message); - nmc->return_value = NMC_RESULT_ERROR_USER_INPUT; - g_error_free (error); - return nmc->return_value; + return nmc_do_cmd (nmc, device_cmds, *argv, argc, argv); } void monitor_devices (NmCli *nmc) { - do_device_monitor (nmc, 0, NULL); + do_devices_monitor (nmc, 0, NULL); } |