[RFC] Add persistent storage capability to HAL

Matthew Garrett mjg59 at srcf.ucam.org
Thu Aug 17 14:52:56 PDT 2006


The attached patch adds the ability to save devices (optionally 
recursively) and then reload them into HAL at a later stage. This is 
useful for Bluetooth, where it's impractical to rediscover devices when 
the device is no longer discoverable - instead, the device state should 
be stored and recreated when the HCI is connected. Somewhat draft code, 
but comments welcome.

-- 
Matthew Garrett | mjg59 at srcf.ucam.org
-------------- next part --------------
diff --git a/hald/linux2/probing/shared.h b/hald/linux2/probing/shared.h
index 3805b71..6202c35 100644
--- a/hald/linux2/probing/shared.h
+++ b/hald/linux2/probing/shared.h
@@ -171,4 +171,221 @@ out:
 #endif
 }
 
+void
+hal_save_device (const char *udi, gboolean recursive)
+{
+	LibHalPropertySet *properties;
+	LibHalPropertySetIterator iter;
+	DBusError error;
+	GKeyFile* keyfile;
+	const char *device = udi + 29; // Strip /org/freedesktop/Hal/devices/
+	const char *dirname = g_strdup_printf ("/var/lib/hal/persistent/%s",
+					       device);
+	const char *filename = g_strdup_printf ("%s/properties", dirname);
+	gsize length;
+	char *data;
+	
+	dbus_error_init (&error);
+	
+	g_mkdir_with_parents (dirname, 0644);
+	
+	properties = libhal_device_get_all_properties (ctx, udi, NULL);
+	
+	keyfile = g_key_file_new ();
+	
+	libhal_psi_init (&iter, properties);
+	
+	for (libhal_psi_init (&iter, properties); libhal_psi_has_more (&iter);
+	     libhal_psi_next (&iter)) {
+		char *type;
+		char *key;
+		
+		key = libhal_psi_get_key (&iter);
+		
+		switch (libhal_psi_get_type (&iter)) {
+		case LIBHAL_PROPERTY_TYPE_INVALID:
+			break;
+		case LIBHAL_PROPERTY_TYPE_INT32:
+		{
+			dbus_int32_t value = libhal_psi_get_int (&iter);
+			type = g_strdup_printf ("int32");
+			g_key_file_set_string (keyfile, key, "type", type);
+			g_key_file_set_integer (keyfile, key, "value", value);
+			break;
+		}
+		case LIBHAL_PROPERTY_TYPE_UINT64:
+		{
+			// FIXME - fails to deal with 64 bit values
+			dbus_uint64_t value = libhal_psi_get_uint64 (&iter);
+			type = g_strdup_printf ("uint64");
+			g_key_file_set_string (keyfile, key, "type", type);
+			g_key_file_set_integer (keyfile, key, "value", value);
+			break;
+		}
+		case LIBHAL_PROPERTY_TYPE_DOUBLE:
+		{
+			double value = libhal_psi_get_double (&iter);
+			type = g_strdup_printf ("double");
+			g_key_file_set_string (keyfile, key, "type", type);
+			g_key_file_set_double (keyfile, key, "value", value);
+			break;
+		}
+		case LIBHAL_PROPERTY_TYPE_BOOLEAN:
+		{
+			dbus_bool_t value = libhal_psi_get_bool (&iter);
+			type = g_strdup_printf ("bool");
+			g_key_file_set_string (keyfile, key, "type", type);
+			g_key_file_set_boolean (keyfile, key, "value", value);
+			break;
+		}
+		case LIBHAL_PROPERTY_TYPE_STRING:
+		{
+			char *value = libhal_psi_get_string (&iter);
+			type = g_strdup_printf ("string");
+			g_key_file_set_string (keyfile, key, "type", type);
+			g_key_file_set_string (keyfile, key, "value", value);
+			break;
+		}
+		case LIBHAL_PROPERTY_TYPE_STRLIST:
+		{
+			char **value = libhal_psi_get_strlist (&iter);
+			type = g_strdup_printf ("strlist");
+			g_key_file_set_string (keyfile, key, "type", type);
+			g_key_file_set_string_list (keyfile, key, "value", 
+						    value,
+						    libhal_string_array_length (value));
+			break;
+		}
+		}
+		
+		g_free (type);
+	}
+	
+	libhal_free_property_set (properties);
+	
+	/* This is a touch insane */
+	
+	data = g_key_file_to_data (keyfile, &length, NULL);
+	g_file_set_contents (filename, data, length, NULL);
+	g_free (data);
+	g_key_file_free (keyfile);
+	
+	if (recursive) {
+		int numchildren;
+		char **children;
+		
+		children = libhal_manager_find_device_string_match (ctx, "info.parent",
+								    udi, &numchildren,
+								    &error);
+		if (numchildren) {
+			int i;
+			for (i=0; i<numchildren; i++) {
+                                save_device (children[i], TRUE);
+			}
+		}
+	}
+}
+
+void 
+hal_load_device (const char *udi, gboolean recursive)
+{
+	int i;
+	gsize numkeys;
+	GDir *dir;
+	DBusError error;
+	gchar **keys;
+	GKeyFile* keyfile = g_key_file_new ();
+	const char *device = udi + 29; // Strip /org/freedesktop/Hal/devices/
+	const char *dirname = g_strdup_printf ("/var/lib/hal/persistent/%s",
+					       device);
+	const char *filename = g_strdup_printf ("%s/properties", dirname);
+	
+	g_key_file_load_from_file (keyfile, filename, G_KEY_FILE_NONE, NULL);
+	
+	keys = g_key_file_get_groups (keyfile, &numkeys);
+
+	dbus_error_init (&error);
+
+	if (!libhal_device_exists (ctx, udi, &error)) {
+		gchar *temp_udi = libhal_new_device (ctx, &error);
+		libhal_device_commit_to_gdl (ctx, temp_udi, udi, &error);
+		g_free (temp_udi);
+	}		
+	
+	for (i=0; i<numkeys; i++) {
+		gchar *type = g_key_file_get_string (keyfile, keys[i], "type",
+						     NULL);
+		if (strcmp (type, "int32") == 0) {
+			libhal_device_set_property_int (ctx, udi, keys[i], 
+							g_key_file_get_integer (keyfile,
+										keys[i],
+										"value",
+										NULL),
+							NULL);
+		}
+		else if (strcmp (type, "uint64") == 0) {
+			libhal_device_set_property_uint64 (ctx, udi, keys[i], 
+							   g_key_file_get_integer (keyfile,
+										   keys[i],
+										   "value",
+										   NULL),
+							   NULL);
+		}
+		else if (strcmp (type, "double") == 0) {
+			libhal_device_set_property_double (ctx, udi, keys[i], 
+						    g_key_file_get_double (keyfile,
+									   keys[i],
+									   "value",
+									   NULL),
+						    NULL);
+		}
+		else if (strcmp (type, "bool") == 0) {
+			libhal_device_set_property_bool (ctx, udi, keys[i], 
+						  g_key_file_get_boolean (keyfile,
+									  keys[i],
+									  "value",
+									  NULL),
+						  NULL);
+		}
+		else if (strcmp (type, "string") == 0) {
+			gchar *string = g_key_file_get_string (keyfile, keys[i], "value", NULL);
+			libhal_device_set_property_string (ctx, udi, keys[i], string,
+						    NULL);
+			g_free (string);
+		}
+		else if (strcmp (type, "strlist") == 0) {
+			gsize length;
+			int j=0;
+			gchar **values = g_key_file_get_string_list (keyfile, keys[i], "value", &length, NULL);
+
+			while (values[j]) {
+				libhal_device_property_strlist_append (ctx, udi, keys[i], values[j], NULL);
+				j++;
+			}
+		}
+	}
+
+	g_key_file_free (keyfile);
+	
+	if (!recursive)
+		return;
+
+	dir = g_dir_open (dirname, 0, NULL);
+	while ((filename = g_dir_read_name (dir))) {
+		gchar *new_dirname;
+		
+		new_dirname = g_build_filename (dirname, filename, NULL);
+
+		if (g_file_test (new_dirname, G_FILE_TEST_IS_DIR)) {
+			gchar *new_dev;
+			new_dev = g_strdup_printf ("%s/%s", udi, filename);
+			load_device (new_dev, TRUE);
+			g_free (new_dev);
+		}
+		g_free (new_dirname);
+	}
+	g_dir_close (dir);
+}
+
+
 #endif /* SHARED_H */


More information about the hal mailing list