hal/hald device_info.c,1.32,1.33 hald_dbus.c,1.62,1.63

David Zeuthen david at kemper.freedesktop.org
Thu Jun 8 19:19:34 PDT 2006


Update of /cvs/hal/hal/hald
In directory kemper:/tmp/cvs-serv22208/hald

Modified Files:
	device_info.c hald_dbus.c 
Log Message:
2006-06-08  David Zeuthen  <davidz at redhat.com>

	Adds code so addons can claim interfaces and handle the methods on
	them in the addon daemon code. The example here is setting the LCD
	backlight on a Macbook Pro. Actual code for setting the backlight
	is based on code from Nicolas Boichat found on the mactel-linux
	mailing list.

	* hald/linux2/addons/addon-macbookpro-backlight.c: New file.

	* tools/hal-system-power-set-power-save: Bugfix so the right
	backend script is invoked.

	* libhal/libhal.h: Add prototype for libhal_device_claim_interface().

	* libhal/libhal.c (libhal_device_claim_interface): New function.

	* hald/linux2/addons/Makefile.am: Add rules for
	hald-addon-macbookpro-backlight. 

	* hald/hald_dbus.c (device_emit_condition): Only allow helpers,
	e.g.  only messages from direct connections.
	(device_claim_interface): New function to handle the
	ClaimInterface() method
	(do_introspect): Include introspection XML for ClaimInterface()
	and the introspection XML returned by ClaimInterface()
	invocations.
	(reply_from_fwd_message): New function
	(hald_dbus_filter_handle_methods): Handle ClaimInterface() and
	forward messages to the claimed interfaces on the appropriate
	objects.
	(local_server_message_handler): Forward signals from helpers onto
	the system message bus and DTRT when a helper disconnects.

	* hald/device_info.c (handle_spawn): New function. One can now do
	a <spawn udi="foo"> to spawn a child device. See the fdi file below
	for usage.
	(start, spawned_device_callouts_add_done, end):  Handle spawning
	device objects in response to <spawn>.

	* fdi/policy/10osvendor/10-laptop-panel-mgmt-policy.fdi: Add rules
	for matching the Macbook Pro in order to spawn a new device object
	with an addon for handing methods on the org.fd.H.D.LaptopPanel
	interface.

	* hal.conf.in: Allow some interfaces to also emit signals.

	* configure.in: Check for libpci so we can use it as an optional
	dependency. 



Index: device_info.c
===================================================================
RCS file: /cvs/hal/hal/hald/device_info.c,v
retrieving revision 1.32
retrieving revision 1.33
diff -u -d -r1.32 -r1.33
--- device_info.c	21 Jan 2006 06:36:51 -0000	1.32
+++ device_info.c	9 Jun 2006 02:19:32 -0000	1.33
@@ -41,6 +41,7 @@
 #include "logger.h"
 #include "device_info.h"
 #include "device_store.h"
+#include "util.h"
 
 /**
  * @defgroup DeviceInfo Device Info File Parsing
@@ -86,7 +87,10 @@
 	CURELEM_REMOVE = 6,
 
 	/** Processing a clear element */
-	CURELEM_CLEAR = 7
+	CURELEM_CLEAR = 7,
+
+	/** Processing a spawn element */
+	CURELEM_SPAWN = 8
 };
 
 /** What and how to merge */
@@ -100,7 +104,8 @@
 	MERGE_TYPE_COPY_PROPERTY = 6,
 	MERGE_TYPE_STRLIST       = 7,
 	MERGE_TYPE_REMOVE        = 8,
-	MERGE_TYPE_CLEAR         = 9
+	MERGE_TYPE_CLEAR         = 9,
+	MERGE_TYPE_SPAWN         = 10
 };
 
 /** Parsing Context
@@ -748,6 +753,36 @@
 	return;
 }
 
+
+/** Called when the spawn element begins.
+ *
+ *  @param  pc                  Parsing context
+ *  @param  attr                Attribute key/value pairs
+ */
+static void
+handle_spawn (ParsingContext * pc, const char **attr)
+{
+	int num_attrib;
+
+	pc->merge_type = MERGE_TYPE_UNKNOWN;
+
+	for (num_attrib = 0; attr[num_attrib] != NULL; num_attrib++) {
+		;
+	}
+
+	if (num_attrib != 2)
+		return;
+
+	if (strcmp (attr[0], "udi") != 0)
+		return;
+
+	strncpy (pc->merge_key, attr[1], MAX_KEY_SIZE);
+
+	pc->merge_type = MERGE_TYPE_SPAWN;
+
+	return;
+}
+
 /** Called when the remove element begins.
  *
  *  @param  pc                  Parsing context
@@ -988,6 +1023,21 @@
 			parsing_abort (pc);
 		}
 		pc->curelem = CURELEM_DEVICE_INFO;
+	} else if (strcmp (el, "spawn") == 0) {
+		if (pc->curelem != CURELEM_MATCH) {
+			HAL_ERROR (("%s:%d:%d: Element <spawn> can only be "
+				    "inside <match>", 
+				    pc->file, 
+				    XML_GetCurrentLineNumber (pc->parser), 
+				    XML_GetCurrentColumnNumber (pc->parser)));
+			parsing_abort (pc);
+		}
+
+		pc->curelem = CURELEM_SPAWN;
+		if (pc->match_ok) {
+			handle_spawn (pc, attr);
+		} 
+
 	} else {
 		HAL_ERROR (("%s:%d:%d: Unknown element <%s>",
 			    pc->file,
@@ -1006,6 +1056,17 @@
 
 }
 
+static void 
+spawned_device_callouts_add_done (HalDevice *d, gpointer userdata1, gpointer userdata2)
+{
+	HAL_INFO (("Add callouts completed udi=%s", d->udi));
+
+	/* Move from temporary to global device store */
+	hal_device_store_remove (hald_get_tdl (), d);
+	hal_device_store_add (hald_get_gdl (), d);
+
+}
+
 /** Called by expat when an element ends.
  *
  *  @param  pc                  Parsing context
@@ -1201,6 +1262,31 @@
 				hal_device_property_remove (pc->device, pc->merge_key);
 			}
 		}
+	} else if (pc->merge_type == MERGE_TYPE_SPAWN) {
+		HalDevice *spawned;
+
+		spawned = hal_device_store_find (hald_get_gdl (), pc->merge_key);
+		if (spawned == NULL)
+			spawned = hal_device_store_find (hald_get_tdl (), pc->merge_key);
+
+		if (spawned == NULL) {
+			HAL_INFO (("Spawning new device object '%s' caused by <spawn> on udi '%s'", 
+				   pc->merge_key, pc->device->udi));
+
+			spawned = hal_device_new ();
+			hal_device_property_set_string (spawned, "info.bus", "unknown");
+			hal_device_property_set_string (spawned, "info.udi", pc->merge_key);
+			hal_device_property_set_string (spawned, "info.parent", pc->device->udi);
+			hal_device_set_udi (spawned, pc->merge_key);
+			
+			hal_device_store_add (hald_get_tdl (), spawned);
+			
+			di_search_and_merge (spawned, DEVICE_INFO_TYPE_INFORMATION);
+			di_search_and_merge (spawned, DEVICE_INFO_TYPE_POLICY);
+			
+			hal_util_callout_device_add (spawned, spawned_device_callouts_add_done, NULL, NULL);
+		}
+
 	} else if (pc->curelem == CURELEM_CLEAR && pc->match_ok) {
 		if (pc->merge_type == MERGE_TYPE_CLEAR) {
 			hal_device_property_strlist_clear (pc->device, pc->merge_key);
@@ -1208,7 +1294,6 @@
 	}
 
 
-
 	pc->cdata_buf_len = 0;
 	pc->depth--;
 

Index: hald_dbus.c
===================================================================
RCS file: /cvs/hal/hal/hald/hald_dbus.c,v
retrieving revision 1.62
retrieving revision 1.63
diff -u -d -r1.62 -r1.63
--- hald_dbus.c	6 Jun 2006 23:56:09 -0000	1.62
+++ hald_dbus.c	9 Jun 2006 02:19:32 -0000	1.63
@@ -2229,8 +2229,8 @@
 
 	udi = dbus_message_get_path (message);
 
-	if (!local_interface && !sender_has_privileges (connection, message)) {
-		raise_permission_denied (connection, message, "EmitCondition: not privileged");
+	if (!local_interface) {
+		raise_permission_denied (connection, message, "EmitCondition: only allowed for helpers");
 		return DBUS_HANDLER_RESULT_HANDLED;
 	}
 
@@ -2272,6 +2272,87 @@
 	return DBUS_HANDLER_RESULT_HANDLED;
 }
 
+typedef struct
+{
+	DBusConnection  *connection;
+	char            *interface_name;
+	char            *introspection_xml;
+	char            *udi;
+} HelperInterfaceHandler;
+
+static GSList *helper_interface_handlers = NULL;
+
+static DBusHandlerResult
+device_claim_interface (DBusConnection * connection, DBusMessage * message, dbus_bool_t local_interface)
+{
+	const char *udi;
+	HalDevice *device;
+	DBusMessageIter iter;
+	DBusMessage *reply;
+	DBusError error;
+	const char *interface_name;
+	const char *introspection_xml;
+	dbus_bool_t res;
+	
+	HAL_TRACE (("entering"));
+
+	udi = dbus_message_get_path (message);
+
+	if (!local_interface) {
+		raise_permission_denied (connection, message, "ClaimInterface: only allowed for helpers");
+		return DBUS_HANDLER_RESULT_HANDLED;
+	}
+
+	HAL_DEBUG (("udi=%s", udi));
+
+	dbus_error_init (&error);
+	if (!dbus_message_get_args (message, &error,
+				    DBUS_TYPE_STRING, &interface_name,
+				    DBUS_TYPE_STRING, &introspection_xml,
+				    DBUS_TYPE_INVALID)) {
+		raise_syntax (connection, message, "ClaimInterface");
+		return DBUS_HANDLER_RESULT_HANDLED;
+	}
+
+	device = hal_device_store_find (hald_get_gdl (), udi);
+	if (device == NULL)
+		device = hal_device_store_find (hald_get_tdl (), udi);
+
+	if (device == NULL) {
+		raise_no_such_device (connection, message, udi);
+		return DBUS_HANDLER_RESULT_HANDLED;
+	}
+
+	res = TRUE;
+
+	HAL_INFO (("Local connection 0x%x to handle interface '%s' on udi '%s'",
+		   connection,
+		   interface_name, 
+		   udi));
+
+	hal_device_property_strlist_add (device, "info.interfaces", interface_name);
+
+	HelperInterfaceHandler *hih = g_new0 (HelperInterfaceHandler, 1);
+	hih->connection = connection;
+	hih->interface_name = g_strdup (interface_name);
+	hih->introspection_xml = g_strdup (introspection_xml);
+	hih->udi = g_strdup (udi);
+	helper_interface_handlers = g_slist_append (helper_interface_handlers, hih);
+	
+
+	reply = dbus_message_new_method_return (message);
+	if (reply == NULL)
+		DIE (("No memory"));
+	dbus_message_iter_init_append (reply, &iter);
+	dbus_message_iter_append_basic (&iter, DBUS_TYPE_BOOLEAN, &res);
+
+	if (!dbus_connection_send (connection, reply, NULL))
+		DIE (("No memory"));
+
+	dbus_message_unref (reply);
+	return DBUS_HANDLER_RESULT_HANDLED;
+}
+
 
 /*
  * Create new device in tdl. Return temporary udi.
@@ -3054,6 +3135,12 @@
 				       "      <arg name=\"condition_name\" direction=\"in\" type=\"s\"/>\n"
 				       "      <arg name=\"condition_details\" direction=\"in\" type=\"s\"/>\n"
 				       "    </method>\n"
+
+				       "    <method name=\"ClaimInterface\">\n"
+				       "      <arg name=\"interface_name\" direction=\"in\" type=\"s\"/>\n"
+				       "      <arg name=\"introspection_xml\" direction=\"in\" type=\"s\"/>\n"
+				       "    </method>\n"
+
 				       "  </interface>\n");
 
 			GSList *interfaces;
@@ -3081,6 +3168,20 @@
 				method_names = hal_device_property_get_strlist (d, method_names_prop);
 				method_signatures = hal_device_property_get_strlist (d, method_signatures_prop);
 				method_argnames = hal_device_property_get_strlist (d, method_argnames_prop);
+
+				/* consult local list */
+				if (method_names == NULL) {
+					GSList *i;
+
+					for (i = helper_interface_handlers; i != NULL; i = g_slist_next (i)) {
+						HelperInterfaceHandler *hih = i->data;
+						if (strcmp (hih->udi, path) == 0) {
+							xml = g_string_append (xml, hih->introspection_xml);
+						}
+					}
+					
+				}
+
 				for (j = method_names, k = method_signatures, l = method_argnames;
 				     j != NULL && k != NULL && l != NULL;
 				     j = g_slist_next (j), k = g_slist_next (k), l = g_slist_next (l)) {
@@ -3103,25 +3204,32 @@
 						switch (sig[n]) {
 						case 'a':
 							if (n == strlen (sig) - 1) {
-								HAL_WARNING (("Broken signature for method %s on interface %s for object %s", name, ifname, path));
+								HAL_WARNING (("Broken signature for method %s "
+									      "on interface %s for object %s", 
+									      name, ifname, path));
 								continue;
 							}
 							g_string_append_printf (
-								xml, 
-								"      <arg name=\"%s\" direction=\"in\" type=\"a%c\"/>\n", args[m], sig[n + 1]);
+							  xml, 
+							  "      <arg name=\"%s\" direction=\"in\" type=\"a%c\"/>\n", 
+							  args[m], sig[n + 1]);
 							n++;
 							break;
 
 						default:
 							g_string_append_printf (
-								xml, 
-								"      <arg name=\"%s\" direction=\"in\" type=\"%c\"/>\n", args[m], sig[n]);
+							  xml, 
+							  "      <arg name=\"%s\" direction=\"in\" type=\"%c\"/>\n", 
+							  args[m], sig[n]);
 							break;
 						}
 					}
-					xml = g_string_append (xml, 
-								"      <arg name=\"return_code\" direction=\"out\" type=\"i\"/>\n");
-					xml = g_string_append  (xml, "    </method>\n");
+					xml = g_string_append (
+						xml, 
+						"      <arg name=\"return_code\" direction=\"out\" type=\"i\"/>\n");
+					xml = g_string_append  (
+						xml, 
+						"    </method>\n");
 
 				}
 				
@@ -3156,11 +3264,43 @@
 	return DBUS_HANDLER_RESULT_HANDLED;
 }
 
+static void
+reply_from_fwd_message (DBusPendingCall *pending_call,
+			void            *user_data)
+{
+	DBusMessage *reply_from_addon;
+	DBusMessage *method_from_caller;
+	DBusMessage *reply;
+
+	/*HAL_INFO (("in reply_from_fwd_message : user_data = 0x%x", user_data));*/
+
+	method_from_caller = (DBusMessage *) user_data;
+	reply_from_addon = dbus_pending_call_steal_reply (pending_call);
+
+	reply = dbus_message_copy (reply_from_addon);
+	dbus_message_set_destination (reply, dbus_message_get_sender (method_from_caller));
+	dbus_message_set_reply_serial (reply, dbus_message_get_serial (method_from_caller));
+
+	if (dbus_connection != NULL)
+		dbus_connection_send (dbus_connection, reply, NULL);
+
+	dbus_message_unref (reply_from_addon);
+	dbus_message_unref (reply);
+}
 
 static DBusHandlerResult
 hald_dbus_filter_handle_methods (DBusConnection *connection, DBusMessage *message, 
 				 void *user_data, dbus_bool_t local_interface)
 {
+	/*
+	  HAL_INFO (("connection=0x%x obj_path=%s interface=%s method=%s local_interface=%d", 
+		   connection,
+		   dbus_message_get_path (message), 
+		   dbus_message_get_interface (message),
+		   dbus_message_get_member (message),
+		   local_interface));
+	*/
+
 	if (dbus_message_is_method_call (message,
 					 "org.freedesktop.Hal.Manager",
 					 "GetAllDevices") &&
@@ -3310,6 +3450,16 @@
 						"EmitCondition")) {
 		return device_emit_condition (connection, message, local_interface);
 	} else if (dbus_message_is_method_call (message,
+						"org.freedesktop.Hal.Device",
+						"ClaimInterface")) {
+		return device_claim_interface (connection, message, local_interface);
+#if 0
+	} else if (dbus_message_is_method_call (message,
+						"org.freedesktop.Hal.Device",
+						"ReleaseInterface")) {
+		return device_release_interface (connection, message, local_interface);
+#endif
+	} else if (dbus_message_is_method_call (message,
 						"org.freedesktop.DBus.Introspectable",
 						"Introspect")) {
 		return do_introspect (connection, message, local_interface);
@@ -3329,12 +3479,48 @@
 
 		d = NULL;
 
-		if (method != NULL) {
+		if (udi != NULL) {
 			d = hal_device_store_find (hald_get_gdl (), udi);
 			if (d == NULL)
 				d = hal_device_store_find (hald_get_tdl (), udi);
 		}
 
+		if (d != NULL && interface != NULL) {
+			GSList *i;
+
+			for (i = helper_interface_handlers; i != NULL; i = g_slist_next (i)) {
+				HelperInterfaceHandler *hih = i->data;
+				if (strcmp (hih->udi, udi) == 0 &&
+				    strcmp (hih->interface_name, interface) == 0) {
+					DBusPendingCall *pending_call;
+					DBusMessage *copy;
+
+					/*HAL_INFO (("forwarding method to connection 0x%x", hih->connection));*/
+
+					dbus_message_ref (message);
+
+					/* send a copy of the message */
+					copy = dbus_message_copy (message);
+					if (!dbus_connection_send_with_reply (hih->connection,
+									      copy,
+									      &pending_call,
+									      /*-1*/ 8000)) {
+						/* TODO: handle error */
+					} else {
+						/*HAL_INFO (("connection=%x message=%x", connection, message));*/
+						dbus_pending_call_set_notify (pending_call,
+									      reply_from_fwd_message,
+									      (void *) message,
+									      NULL);
+					}
+
+					dbus_message_unref (copy);
+
+					return DBUS_HANDLER_RESULT_HANDLED;
+				}
+			}
+		} 
+
 		if (d != NULL && interface != NULL && method != NULL && signature != NULL) {
 			GSList *interfaces;
 			GSList *i;
@@ -3397,11 +3583,6 @@
 hald_dbus_filter_function (DBusConnection * connection,
 			   DBusMessage * message, void *user_data)
 {
-	/*HAL_INFO (("obj_path=%s interface=%s method=%s", 
-		   dbus_message_get_path(message), 
-		   dbus_message_get_interface(message),
-		   dbus_message_get_member(message)));*/
-
 	if (dbus_message_is_signal (message, DBUS_INTERFACE_LOCAL, "Disconnected") &&
 	    strcmp (dbus_message_get_path (message), DBUS_PATH_LOCAL) == 0) {
 
@@ -3433,13 +3614,11 @@
 			      DBusMessage *message, 
 			      void *user_data)
 {
-/*
-	HAL_INFO (("local_server_message_handler: destination=%s obj_path=%s interface=%s method=%s", 
+	/*HAL_INFO (("local_server_message_handler: destination=%s obj_path=%s interface=%s method=%s", 
 		   dbus_message_get_destination (message), 
 		   dbus_message_get_path (message), 
 		   dbus_message_get_interface (message),
-		   dbus_message_get_member (message)));
-*/
+		   dbus_message_get_member (message)));*/
 
 	if (dbus_message_is_method_call (message, "org.freedesktop.DBus", "AddMatch")) {
 		DBusMessage *reply;
@@ -3454,12 +3633,41 @@
 		return DBUS_HANDLER_RESULT_HANDLED;
 	} else if (dbus_message_is_signal (message, DBUS_INTERFACE_LOCAL, "Disconnected") &&
 		   strcmp (dbus_message_get_path (message), DBUS_PATH_LOCAL) == 0) {
+		GSList *i;
+		GSList *j;
 		
 		HAL_INFO (("Client to local_server was disconnected"));
+
+		for (i = helper_interface_handlers; i != NULL; i = j) {
+			HelperInterfaceHandler *hih = i->data;
+
+			j = g_slist_next (i);
+
+			if (hih->connection == connection) {
+				g_free (hih->interface_name);
+				g_free (hih->introspection_xml);
+				g_free (hih->udi);
+				g_free (hih);
+				helper_interface_handlers = g_slist_remove (helper_interface_handlers, i);
+			}
+		}
+
 		dbus_connection_unref (connection);
 		return DBUS_HANDLER_RESULT_HANDLED;
-	} 
-	else return hald_dbus_filter_handle_methods (connection, message, user_data, TRUE);
+	} else if (dbus_message_get_type (message) == DBUS_MESSAGE_TYPE_SIGNAL) {
+		DBusMessage *copy;
+
+		/* it's a signal, just forward it onto the system message bus */
+		copy = dbus_message_copy (message);
+		if (dbus_connection != NULL) {
+			dbus_connection_send (dbus_connection, copy, NULL);
+		}
+		dbus_message_unref (copy);
+	} else {
+		return hald_dbus_filter_handle_methods (connection, message, user_data, TRUE);
+	}
+
+	return DBUS_HANDLER_RESULT_HANDLED;
 }
 
 static void




More information about the hal-commit mailing list