cli: wait for all wifi scans to finish before displaying the result

Otherwise devices are displayed in a inconsistent order.

https://gitlab.freedesktop.org/NetworkManager/NetworkManager/issues/39
This commit is contained in:
Beniamino Galvani
2018-10-31 10:00:22 +01:00
parent 6651915e69
commit c0138cdb35

View File

@@ -2897,28 +2897,38 @@ wifi_print_aps (NMDeviceWifi *wifi,
typedef struct {
NmCli *nmc;
NMDeviceWifi *wifi;
const NMMetaAbstractInfo *const*tmpl;
NMDevice **devices;
const NMMetaAbstractInfo *const *tmpl;
const char *bssid_user;
GArray *out_indices;
} ScanInfo;
typedef struct {
ScanInfo *scan_info;
NMDeviceWifi *wifi;
gulong last_scan_id;
guint timeout_id;
GCancellable *scan_cancellable;
GArray *out_indices;
} WifiListData;
static void
wifi_list_finish (WifiListData *data)
{
NmCli *nmc = data->nmc;
ScanInfo *info = data->scan_info;
NmCli *nmc = info->nmc;
guint i;
wifi_print_aps (data->wifi, data->nmc, data->out_indices,
data->tmpl, data->bssid_user);
if (--nmc->should_wait == 0) {
if (--info->nmc->should_wait == 0) {
for (i = 0; info->devices[i]; i++) {
wifi_print_aps (NM_DEVICE_WIFI (info->devices[i]),
info->nmc,
info->out_indices,
info->tmpl,
info->bssid_user);
}
if (nmc->return_value == NMC_RESULT_ERROR_NOT_FOUND) {
g_string_printf (nmc->return_text, _("Error: Access point with bssid '%s' not found."),
data->bssid_user);
data->scan_info->bssid_user);
}
g_main_loop_quit (loop);
}
@@ -2926,9 +2936,15 @@ wifi_list_finish (WifiListData *data)
g_signal_handler_disconnect (data->wifi, data->last_scan_id);
nm_clear_g_source (&data->timeout_id);
nm_clear_g_cancellable (&data->scan_cancellable);
g_array_unref (data->out_indices);
g_object_unref (data->wifi);
g_slice_free (WifiListData, data);
if (info->nmc->should_wait == 0) {
for (i = 0; info->devices[i]; i++)
g_object_unref (info->devices[i]);
g_free (info->devices);
g_array_unref (info->out_indices);
g_free (info);
}
}
static void
@@ -2972,49 +2988,6 @@ wifi_list_scan_timeout (gpointer user_data)
return G_SOURCE_REMOVE;
}
static void
wifi_list_aps (NMDeviceWifi *wifi,
NmCli *nmc,
GArray *out_indices,
const NMMetaAbstractInfo *const*tmpl,
const char *bssid_user,
gint64 rescan_cutoff)
{
gboolean needs_rescan;
WifiListData *data;
needs_rescan = rescan_cutoff < 0 || (rescan_cutoff > 0 && nm_device_wifi_get_last_scan (wifi) < rescan_cutoff);
/* FIXME: nmcli should either
* - don't request any new scan for any device and print the full AP list right
* away.
* - or, when requesting a scan on one or more devices, don't print the result
* before all requests complete.
*
* Otherwise:
* - the printed output is not self consistent. E.g. it will print the result
* on one device at a certain time, while printing the result for another
* device at a later point in time.
* - the order in which we print the AP list per-device, is unstable. */
if (needs_rescan) {
data = g_slice_new0 (WifiListData);
data->nmc = nmc;
data->wifi = g_object_ref (wifi);
data->tmpl = tmpl;
data->out_indices = g_array_ref (out_indices);;
data->bssid_user = bssid_user;
data->last_scan_id = g_signal_connect (wifi, "notify::" NM_DEVICE_WIFI_LAST_SCAN,
G_CALLBACK (wifi_last_scan_updated), data);
data->scan_cancellable = g_cancellable_new ();
data->timeout_id = g_timeout_add_seconds (15, wifi_list_scan_timeout, data);
nm_device_wifi_request_scan_async (wifi, data->scan_cancellable, wifi_list_rescan_cb, data);
nmc->should_wait++;
} else {
wifi_print_aps (wifi, nmc, out_indices, tmpl, bssid_user);
}
}
static void
complete_aps (NMDevice **devices, const char *ifname,
const char *bssid_prefix, const char *ssid_prefix)
@@ -3044,12 +3017,15 @@ do_device_wifi_list (NmCli *nmc, int argc, char **argv)
const char *bssid_user = NULL;
const char *rescan = NULL;
gs_free NMDevice **devices = NULL;
guint i;
const char *fields_str = NULL;
const NMMetaAbstractInfo *const*tmpl;
gs_unref_array GArray *out_indices = NULL;
int option;
guint64 rescan_cutoff;
NMDeviceWifi *wifi;
ScanInfo *scan_info = NULL;
WifiListData *data;
guint i, j;
devices = nmc_get_devices_sorted (nmc->client);
@@ -3137,7 +3113,8 @@ do_device_wifi_list (NmCli *nmc, int argc, char **argv)
}
if (NM_IS_DEVICE_WIFI (device)) {
wifi_list_aps (NM_DEVICE_WIFI (device), nmc, out_indices, tmpl, bssid_user, rescan_cutoff);
devices[0] = device;
devices[1] = NULL;
} else {
if ( nm_device_get_device_type (device) == NM_DEVICE_TYPE_GENERIC
&& g_strcmp0 (nm_device_get_type_description (device), "wifi") == 0) {
@@ -3151,13 +3128,52 @@ do_device_wifi_list (NmCli *nmc, int argc, char **argv)
}
return NMC_RESULT_ERROR_UNKNOWN;
}
} else {
for (i = 0; devices[i]; i++) {
NMDevice *dev = devices[i];
}
if (NM_IS_DEVICE_WIFI (dev)) {
wifi_list_aps (NM_DEVICE_WIFI (dev), nmc, out_indices, tmpl, bssid_user, rescan_cutoff);
}
/* Filter out non-wifi devices */
for (i = 0, j = 0; devices[i]; i++) {
if (NM_IS_DEVICE_WIFI (devices[i]))
devices[j++] = devices[i];
}
devices[j] = NULL;
/* Start a new scan for devices that need it */
for (i = 0; devices[i]; i++) {
wifi = (NMDeviceWifi *) devices[i];
g_object_ref (wifi);
if ( rescan_cutoff == 0
|| (rescan_cutoff > 0 && nm_device_wifi_get_last_scan (wifi) >= rescan_cutoff))
continue;
if (!scan_info) {
scan_info = g_new0 (ScanInfo, 1);
scan_info->out_indices = g_array_ref (out_indices);
scan_info->tmpl = tmpl;
scan_info->bssid_user = bssid_user;
scan_info->nmc = nmc;
}
nmc->should_wait++;
data = g_slice_new0 (WifiListData);
data->wifi = wifi;
data->scan_info = scan_info;
data->last_scan_id = g_signal_connect (wifi, "notify::" NM_DEVICE_WIFI_LAST_SCAN,
G_CALLBACK (wifi_last_scan_updated), data);
data->scan_cancellable = g_cancellable_new ();
data->timeout_id = g_timeout_add_seconds (15, wifi_list_scan_timeout, data);
nm_device_wifi_request_scan_async (wifi, data->scan_cancellable, wifi_list_rescan_cb, data);
}
if (scan_info) {
scan_info->devices = g_steal_pointer (&devices);
} else {
/* Print results right away if no scan is pending */
for (i = 0; devices[i]; i++) {
wifi_print_aps (NM_DEVICE_WIFI (devices[i]),
nmc, out_indices,
tmpl, bssid_user);
g_object_unref (devices[i]);
}
}