summary refs log tree commit diff
path: root/clients/cli/devices.c
diff options
context:
space:
mode:
authorMichael Biebl <biebl@debian.org>2019-02-26 19:01:41 +0100
committerMichael Biebl <biebl@debian.org>2019-02-26 19:01:41 +0100
commit964ae8cc391520440cf5aa13e2b9cc34850ea6c2 (patch)
tree50da9ecaee7fbb612ec18f9e24f7dec215bf7861 /clients/cli/devices.c
parent3626b425d1bc017fdc6f1ea0cfd329d1e1681641 (diff)
New upstream version 1.14.6 upstream/1.14.6
Diffstat (limited to 'clients/cli/devices.c')
-rw-r--r--clients/cli/devices.c155
1 files changed, 90 insertions, 65 deletions
diff --git a/clients/cli/devices.c b/clients/cli/devices.c
index 029ca671..5aaf4ef8 100644
--- a/clients/cli/devices.c
+++ b/clients/cli/devices.c
@@ -2094,6 +2094,7 @@ typedef struct {
 	GSList *queue;
 	guint timeout_id;
 	gboolean cmd_disconnect;
+	GCancellable *cancellable;
 } DeviceCbInfo;
 
 static void device_cb_info_finish (DeviceCbInfo *info, NMDevice *device);
@@ -2166,7 +2167,10 @@ device_cb_info_finish (DeviceCbInfo *info, NMDevice *device)
 
 	if (info->timeout_id)
 		g_source_remove (info->timeout_id);
+
 	g_signal_handlers_disconnect_by_func (info->nmc->client, device_removed_cb, info);
+	nm_clear_g_cancellable (&info->cancellable);
+
 	g_slice_free (DeviceCbInfo, info);
 	quit ();
 }
@@ -2343,11 +2347,14 @@ disconnect_device_cb (GObject *object, GAsyncResult *result, gpointer user_data)
 {
 	NMDevice *device = NM_DEVICE (object);
 	DeviceCbInfo *info = (DeviceCbInfo *) user_data;
-	NmCli *nmc = info->nmc;
+	NmCli *nmc;
 	NMDeviceState state;
 	GError *error = NULL;
 
 	if (!nm_device_disconnect_finish (device, result, &error)) {
+		if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
+			return;
+		nmc = info->nmc;
 		g_string_printf (nmc->return_text, _("Error: not all devices disconnected."));
 		g_printerr (_("Error: Device '%s' (%s) disconnecting failed: %s\n"),
 		            nm_device_get_iface (device),
@@ -2357,6 +2364,7 @@ disconnect_device_cb (GObject *object, GAsyncResult *result, gpointer user_data)
 		nmc->return_value = NMC_RESULT_ERROR_DEV_DISCONNECT;
 		device_cb_info_finish (info, device);
 	} else {
+		nmc = info->nmc;
 		state = nm_device_get_state (device);
 		if (nmc->nowait_flag || state <= NM_DEVICE_STATE_DISCONNECTED) {
 			/* Don't want to wait or device already disconnected */
@@ -2393,6 +2401,7 @@ do_devices_disconnect (NmCli *nmc, int argc, char **argv)
 	info = g_slice_new0 (DeviceCbInfo);
 	info->nmc = nmc;
 	info->cmd_disconnect = TRUE;
+	info->cancellable = g_cancellable_new ();
 	if (nmc->timeout > 0)
 		info->timeout_id = g_timeout_add_seconds (nmc->timeout, device_op_timeout_cb, info);
 
@@ -2410,7 +2419,7 @@ do_devices_disconnect (NmCli *nmc, int argc, char **argv)
 		                  G_CALLBACK (disconnect_state_cb), info);
 
 		/* Now disconnect the device */
-		nm_device_disconnect_async (device, NULL, disconnect_device_cb, info);
+		nm_device_disconnect_async (device, info->cancellable, disconnect_device_cb, info);
 	}
 
 out:
@@ -2795,7 +2804,7 @@ show_access_point_info (NMDeviceWifi *wifi, NmCli *nmc, NmcOutputData *out)
 
 		aps = sort_access_points (nm_device_wifi_get_access_points (wifi));
 		g_ptr_array_foreach (aps, fill_output_access_point, &info);
-		g_ptr_array_free (aps, FALSE);
+		g_ptr_array_free (aps, TRUE);
 	}
 
 	print_data_prepare_width (out->output_data);
@@ -2870,28 +2879,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;
-
-	wifi_print_aps (data->wifi, data->nmc, data->out_indices,
-	                data->tmpl, data->bssid_user);
+	ScanInfo *info = data->scan_info;
+	NmCli *nmc = info->nmc;
+	guint i;
 
-	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);
 	}
@@ -2899,9 +2918,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
@@ -2946,49 +2971,6 @@ wifi_list_scan_timeout (gpointer user_data)
 }
 
 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)
 {
@@ -3017,12 +2999,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);
 
@@ -3110,7 +3095,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) {
@@ -3124,13 +3110,52 @@ do_device_wifi_list (NmCli *nmc, int argc, char **argv)
 			}
 			return NMC_RESULT_ERROR_UNKNOWN;
 		}
+	}
+
+	/* 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++) {
-			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);
-			}
+			wifi_print_aps (NM_DEVICE_WIFI (devices[i]),
+			                nmc, out_indices,
+			                tmpl, bssid_user);
+			g_object_unref (devices[i]);
 		}
 	}