Diff between 6600b2585b7672b8cbba6d7cf7ba7e1d70baf642 and ee0c0702f64095467c12d5eb6ba0e702a2ed9cd1

Changed Files

File Additions Deletions Status
src/adapter.c +45 -4 modified
src/adapter.h +3 -1 modified
src/hcid.h +2 -0 modified
src/main.c +18 -1 modified

Full Patch

diff --git a/src/adapter.c b/src/adapter.c
index 77d820f..c1cde18 100644
--- a/src/adapter.c
+++ b/src/adapter.c
@@ -89,6 +89,8 @@
 static DBusConnection *dbus_conn = NULL;
 
 static GList *adapter_list = NULL;
+static unsigned int adapter_remaining = 0;
+static bool powering_down = false;
 
 static GSList *adapters = NULL;
 static int default_adapter_id = -1;
@@ -484,10 +486,18 @@ static void settings_changed(struct btd_adapter *adapter, uint32_t settings)
 	        g_dbus_emit_property_changed(dbus_conn, adapter->path,
 					ADAPTER_INTERFACE, "Powered");
 
-		if (adapter->current_settings & MGMT_SETTING_POWERED)
+		if (adapter->current_settings & MGMT_SETTING_POWERED) {
 			adapter_start(adapter);
-		else
+		} else {
 			adapter_stop(adapter);
+
+			if (powering_down) {
+				adapter_remaining--;
+
+				if (!adapter_remaining)
+					btd_exit();
+			}
+		}
 	}
 
 	if (changed_mask & MGMT_SETTING_CONNECTABLE)
@@ -1620,6 +1630,12 @@ static void property_set_powered(const GDBusPropertyTable *property,
 {
 	struct btd_adapter *adapter = user_data;
 
+	if (powering_down) {
+		g_dbus_pending_property_error(id, ERROR_INTERFACE ".Failed",
+							"Powering down");
+		return;
+	}
+
 	property_set_mode(adapter, MGMT_SETTING_POWERED, iter, id);
 }
 
@@ -3575,8 +3591,6 @@ static void adapter_remove(struct btd_adapter *adapter)
 	btd_adapter_gatt_server_stop(adapter);
 
 	g_slist_free(adapter->pin_callbacks);
-
-	set_mode(adapter, MGMT_OP_SET_POWERED, 0x00);
 }
 
 const char *adapter_get_path(struct btd_adapter *adapter)
@@ -5107,6 +5121,9 @@ static int adapter_register(struct btd_adapter *adapter)
 {
 	struct agent *agent;
 
+	if (powering_down)
+		return -EBUSY;
+
 	adapter->path = g_strdup_printf("/org/bluez/hci%d", adapter->dev_id);
 
 	if (!g_dbus_register_interface(dbus_conn,
@@ -5777,3 +5794,27 @@ void adapter_cleanup(void)
 
 	dbus_conn = NULL;
 }
+
+void adapter_shutdown(void)
+{
+	GList *list;
+
+	DBG("");
+
+	powering_down = true;
+
+	for (list = g_list_first(adapter_list); list;
+						list = g_list_next(list)) {
+		struct btd_adapter *adapter = list->data;
+
+		if (!(adapter->current_settings & MGMT_SETTING_POWERED))
+			continue;
+
+		set_mode(adapter, MGMT_OP_SET_POWERED, 0x00);
+
+		adapter_remaining++;
+	}
+
+	if (!adapter_remaining)
+		btd_exit();
+}
diff --git a/src/adapter.h b/src/adapter.h
index ec08886..5c53b4a 100644
--- a/src/adapter.h
+++ b/src/adapter.h
@@ -76,8 +76,10 @@ struct smp_ltk_info {
 	uint8_t val[16];
 };
 
-void adapter_cleanup(void);
 int adapter_init(void);
+void adapter_cleanup(void);
+void adapter_shutdown(void);
+
 struct btd_adapter *adapter_find(const bdaddr_t *sba);
 struct btd_adapter *adapter_find_by_id(int id);
 struct btd_adapter *adapter_get_default(void);
diff --git a/src/hcid.h b/src/hcid.h
index 9accebb..ea67cc2 100644
--- a/src/hcid.h
+++ b/src/hcid.h
@@ -46,3 +46,5 @@ void plugin_cleanup(void);
 
 void rfkill_init(void);
 void rfkill_exit(void);
+
+void btd_exit(void);
diff --git a/src/main.c b/src/main.c
index 57f1fa9..bd1e9d9 100644
--- a/src/main.c
+++ b/src/main.c
@@ -61,6 +61,8 @@
 #define DEFAULT_PAIRABLE_TIMEOUT       0 /* disabled */
 #define DEFAULT_DISCOVERABLE_TIMEOUT 180 /* 3 minutes */
 
+#define SHUTDOWN_GRACE_SECONDS 10
+
 struct main_opts main_opts;
 
 static const char * const supported_options[] = {
@@ -287,6 +289,17 @@ static void init_defaults(void)
 
 static GMainLoop *event_loop;
 
+void btd_exit(void)
+{
+	g_main_loop_quit(event_loop);
+}
+
+static gboolean quit_eventloop(gpointer user_data)
+{
+	btd_exit();
+	return FALSE;
+}
+
 static gboolean signal_handler(GIOChannel *channel, GIOCondition cond,
 							gpointer user_data)
 {
@@ -309,7 +322,11 @@ static gboolean signal_handler(GIOChannel *channel, GIOCondition cond,
 	case SIGTERM:
 		if (__terminated == 0) {
 			info("Terminating");
-			g_main_loop_quit(event_loop);
+			g_timeout_add_seconds(SHUTDOWN_GRACE_SECONDS,
+							quit_eventloop, NULL);
+
+			sd_notify(0, "STATUS=Powering down");
+			adapter_shutdown();
 		}
 
 		__terminated = 1;