xref: /illumos-gate/usr/src/cmd/hal/hald/hald_dbus.c (revision d9e525a8)
1 /***************************************************************************
2  * CVSID: $Id$
3  *
4  * dbus.c : D-BUS interface of HAL daemon
5  *
6  * Copyright (C) 2003 David Zeuthen, <david@fubar.dk>
7  *
8  * Licensed under the Academic Free License version 2.1
9  *
10  * This program is free software; you can redistribute it and/or modify
11  * it under the terms of the GNU General Public License as published by
12  * the Free Software Foundation; either version 2 of the License, or
13  * (at your option) any later version.
14  *
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU General Public License for more details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with this program; if not, write to the Free Software
22  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
23  *
24  **************************************************************************/
25 
26 #ifdef HAVE_CONFIG_H
27 #  include <config.h>
28 #endif
29 
30 #include <stdlib.h>
31 #include <stdio.h>
32 #include <string.h>
33 #include <unistd.h>
34 #include <stdarg.h>
35 #include <stdint.h>
36 #include <sys/time.h>
37 
38 #include <dbus/dbus.h>
39 #include <dbus/dbus-glib-lowlevel.h>
40 
41 #include "hald.h"
42 #include "hald_dbus.h"
43 #include "device.h"
44 #include "device_store.h"
45 #include "device_info.h"
46 #include "logger.h"
47 #include "osspec.h"
48 #include "util.h"
49 #include "hald_runner.h"
50 
51 #define HALD_DBUS_ADDRESS "unix:tmpdir=" HALD_SOCKET_DIR
52 
53 static DBusConnection *dbus_connection = NULL;
54 
55 static void
56 raise_error (DBusConnection *connection,
57 	     DBusMessage *in_reply_to,
58 	     const char *error_name,
59 	     char *format, ...) __attribute__((format (printf, 4, 5)));
60 
61 /**
62  * @defgroup DaemonErrors Error conditions
63  * @ingroup HalDaemon
64  * @brief Various error messages the HAL daemon can raise
65  * @{
66  */
67 
68 /** Raise HAL error
69  *
70  *  @param  connection          D-Bus connection
71  *  @param  in_reply_to         message to report error on
72  *  @param  error_name          D-Bus error name
73  *  @param  format              printf-style format for error message
74  */
75 static void
raise_error(DBusConnection * connection,DBusMessage * in_reply_to,const char * error_name,char * format,...)76 raise_error (DBusConnection *connection,
77 	     DBusMessage *in_reply_to,
78 	     const char *error_name,
79 	     char *format, ...)
80 {
81 	char buf[512];
82 	DBusMessage *reply;
83 
84 	va_list args;
85 	va_start(args, format);
86 	vsnprintf(buf, sizeof buf, format, args);
87 	va_end(args);
88 
89 	HAL_WARNING ((buf));
90 	reply = dbus_message_new_error (in_reply_to, error_name, buf);
91 	if (reply == NULL)
92 		DIE (("No memory"));
93 	if (!dbus_connection_send (connection, reply, NULL))
94 		DIE (("No memory"));
95 	dbus_message_unref (reply);
96 }
97 
98 /** Raise the org.freedesktop.Hal.NoSuchDevice error
99  *
100  *  @param  connection          D-Bus connection
101  *  @param  in_reply_to         message to report error on
102  *  @param  udi                 Unique device id given
103  */
104 static void
raise_no_such_device(DBusConnection * connection,DBusMessage * in_reply_to,const char * udi)105 raise_no_such_device (DBusConnection *connection,
106 		      DBusMessage *in_reply_to, const char *udi)
107 {
108 	raise_error (
109 		connection, in_reply_to,
110 		"org.freedesktop.Hal.NoSuchDevice",
111 		"No device with id %s",
112 		udi
113 	);
114 }
115 
116 /** Raise the org.freedesktop.Hal.NoSuchProperty error
117  *
118  *  @param  connection          D-Bus connection
119  *  @param  in_reply_to         message to report error on
120  *  @param  device_id           Id of the device
121  *  @param  key                 Key of the property that didn't exist
122  */
123 static void
raise_no_such_property(DBusConnection * connection,DBusMessage * in_reply_to,const char * device_id,const char * key)124 raise_no_such_property (DBusConnection *connection,
125 			DBusMessage *in_reply_to,
126 			const char *device_id, const char *key)
127 {
128 	raise_error (
129 		connection, in_reply_to,
130 		"org.freedesktop.Hal.NoSuchProperty",
131 		"No property %s on device with id %s",
132 		key, device_id
133 	);
134 }
135 
136 /** Raise the org.freedesktop.Hal.TypeMismatch error
137  *
138  *  @param  connection          D-Bus connection
139  *  @param  in_reply_to         message to report error on
140  *  @param  device_id           Id of the device
141  *  @param  key                 Key of the property
142  */
143 static void
raise_property_type_error(DBusConnection * connection,DBusMessage * in_reply_to,const char * device_id,const char * key)144 raise_property_type_error (DBusConnection *connection,
145 			   DBusMessage *in_reply_to,
146 			   const char *device_id, const char *key)
147 {
148 	raise_error (
149 		connection, in_reply_to,
150 		"org.freedesktop.Hal.TypeMismatch",
151 		"Type mismatch setting property %s on device with id %s",
152 		key, device_id
153 	);
154 }
155 
156 /** Raise the org.freedesktop.Hal.SyntaxError error
157  *
158  *  @param  connection          D-Bus connection
159  *  @param  in_reply_to         message to report error on
160  *  @param  method_name         Name of the method that was invoked with
161  *                              the wrong signature
162  */
163 static void
raise_syntax(DBusConnection * connection,DBusMessage * in_reply_to,const char * method_name)164 raise_syntax (DBusConnection *connection,
165 	      DBusMessage *in_reply_to, const char *method_name)
166 {
167 	raise_error (
168 		connection, in_reply_to,
169 		"org.freedesktop.Hal.SyntaxError",
170 		"There is a syntax error in the invocation of the method %s",
171 		method_name
172 	);
173 }
174 
175 /** Raise the org.freedesktop.Hal.DeviceNotLocked error
176  *
177  *  @param  connection          D-Bus connection
178  *  @param  in_reply_to         message to report error on
179  *  @param  device              device which isn't locked
180  */
181 static void
raise_device_not_locked(DBusConnection * connection,DBusMessage * in_reply_to,HalDevice * device)182 raise_device_not_locked (DBusConnection *connection,
183 			 DBusMessage    *in_reply_to,
184 			 HalDevice      *device)
185 {
186 	raise_error (
187 		connection, in_reply_to,
188 		"org.freedesktop.Hal.DeviceNotLocked",
189 		"The device %s is not locked",
190 		 hal_device_get_udi (device)
191 	);
192 }
193 
194 /** Raise the org.freedesktop.Hal.DeviceAlreadyLocked error
195  *
196  *  @param  connection          D-Bus connection
197  *  @param  in_reply_to         message to report error on
198  *  @param  device              device which isn't locked
199  */
200 static void
raise_device_already_locked(DBusConnection * connection,DBusMessage * in_reply_to,HalDevice * device)201 raise_device_already_locked (DBusConnection *connection,
202 			     DBusMessage    *in_reply_to,
203 			     HalDevice      *device)
204 {
205 	DBusMessage *reply;
206 	const char *reason;
207 
208 	reason = hal_device_property_get_string (device, "info.locked.reason");
209 	HAL_WARNING (("Device %s is already locked: %s",
210 		      hal_device_get_udi (device), reason));
211 
212 
213 	reply = dbus_message_new_error (in_reply_to,
214 					"org.freedesktop.Hal.DeviceAlreadyLocked",
215 					reason);
216 
217 	if (reply == NULL || !dbus_connection_send (connection, reply, NULL))
218 		DIE (("No memory"));
219 
220 	dbus_message_unref (reply);
221 }
222 
223 /** Raise the org.freedesktop.Hal.BranchAlreadyClaimed error
224  *
225  *  @param  connection          D-Bus connection
226  *  @param  in_reply_to         message to report error on
227  *  @param  udi                 branch which isn't claimed
228  */
229 static void
raise_branch_already_claimed(DBusConnection * connection,DBusMessage * in_reply_to,HalDevice * device)230 raise_branch_already_claimed (DBusConnection *connection,
231 			     DBusMessage    *in_reply_to,
232 			     HalDevice      *device)
233 {
234 	DBusMessage *reply;
235 	const char *claim_service;
236 
237 	claim_service = hal_device_property_get_string (device, "info.claimed.service");
238 	HAL_WARNING (("Branch %s is already claimed by: %s",
239 		      hal_device_get_udi (device), claim_service));
240 
241 
242 	reply = dbus_message_new_error (in_reply_to,
243 					"org.freedesktop.Hal.BranchAlreadyClaimed",
244 					claim_service);
245 
246 	if (reply == NULL || !dbus_connection_send (connection, reply, NULL))
247 		DIE (("No memory"));
248 
249 	dbus_message_unref (reply);
250 }
251 
252 /** Raise the org.freedesktop.Hal.BranchNotClaimed error
253  *
254  *  @param  connection          D-Bus connection
255  *  @param  in_reply_to         message to report error on
256  *  @param  udi                 branch which isn't claimed
257  */
258 static void
raise_branch_not_claimed(DBusConnection * connection,DBusMessage * in_reply_to,HalDevice * device)259 raise_branch_not_claimed (DBusConnection *connection,
260 			     DBusMessage    *in_reply_to,
261 			     HalDevice      *device)
262 {
263 	raise_error (
264 		connection, in_reply_to,
265 		"org.freedesktop.Hal.BranchNotClaimed",
266 		"The branch %s is not claimed",
267 		 hal_device_get_udi (device)
268 	);
269 }
270 
271 /** Raise the org.freedesktop.Hal.PermissionDenied error
272  *
273  *  @param  connection          D-Bus connection
274  *  @param  in_reply_to         message to report error on
275  *  @param  message             what you're not allowed to do
276  */
277 static void
raise_permission_denied(DBusConnection * connection,DBusMessage * in_reply_to,const char * reason)278 raise_permission_denied (DBusConnection *connection,
279 			 DBusMessage    *in_reply_to,
280 			 const char     *reason)
281 {
282 	raise_error (
283 		connection, in_reply_to,
284 		"org.freedesktop.Hal.PermissionDenied",
285 		"Permission denied: %s",
286 		 reason
287 	);
288 }
289 
290 /** @} */
291 
292 /**
293  * @defgroup ManagerInterface D-BUS interface org.freedesktop.Hal.Manager
294  * @ingroup HalDaemon
295  * @brief D-BUS interface for querying device objects
296  *
297  * @{
298  */
299 
300 static gboolean
foreach_device_get_udi(HalDeviceStore * store,HalDevice * device,gpointer user_data)301 foreach_device_get_udi (HalDeviceStore *store, HalDevice *device,
302 			gpointer user_data)
303 {
304 	DBusMessageIter *iter = user_data;
305 	const char *udi;
306 
307 	udi = hal_device_get_udi (device);
308 	dbus_message_iter_append_basic (iter, DBUS_TYPE_STRING, &udi);
309 
310 	return TRUE;
311 }
312 
313 /** Get all devices.
314  *
315  *  <pre>
316  *  array{object_reference} Manager.GetAllDevices()
317  *  </pre>
318  *
319  *  @param  connection          D-BUS connection
320  *  @param  message             Message
321  *  @return                     What to do with the message
322  */
323 DBusHandlerResult
manager_get_all_devices(DBusConnection * connection,DBusMessage * message)324 manager_get_all_devices (DBusConnection * connection,
325 			 DBusMessage * message)
326 {
327 	DBusMessage *reply;
328 	DBusMessageIter iter;
329 	DBusMessageIter iter_array;
330 
331 	reply = dbus_message_new_method_return (message);
332 	if (reply == NULL)
333 		DIE (("No memory"));
334 
335 	dbus_message_iter_init_append (reply, &iter);
336 	dbus_message_iter_open_container (&iter,
337 					  DBUS_TYPE_ARRAY,
338 					  DBUS_TYPE_STRING_AS_STRING,
339 					  &iter_array);
340 
341 	hal_device_store_foreach (hald_get_gdl (),
342 				  foreach_device_get_udi,
343 				  &iter_array);
344 
345 	dbus_message_iter_close_container (&iter, &iter_array);
346 
347 	if (!dbus_connection_send (connection, reply, NULL))
348 		DIE (("No memory"));
349 
350 	dbus_message_unref (reply);
351 
352 	return DBUS_HANDLER_RESULT_HANDLED;
353 }
354 
355 typedef struct {
356 	const char *key;
357 	const char *value;
358 	DBusMessageIter *iter;
359 } DeviceMatchInfo;
360 
361 static gboolean
foreach_device_match_get_udi(HalDeviceStore * store,HalDevice * device,gpointer user_data)362 foreach_device_match_get_udi (HalDeviceStore *store, HalDevice *device,
363 			      gpointer user_data)
364 {
365 	DeviceMatchInfo *info = user_data;
366 	const char *dev_value;
367 
368 	if (hal_device_property_get_type (device,
369 					  info->key) != DBUS_TYPE_STRING)
370 		return TRUE;
371 
372 	dev_value = hal_device_property_get_string (device, info->key);
373 
374 	if (dev_value != NULL && strcmp (dev_value, info->value) == 0) {
375 		const char *udi;
376 		udi =  hal_device_get_udi (device);
377 		dbus_message_iter_append_basic  (info->iter,
378 						 DBUS_TYPE_STRING,
379 						 &udi);
380 	}
381 
382 	return TRUE;
383 }
384 
385 static gboolean
foreach_device_match_get_udi_tdl(HalDeviceStore * store,HalDevice * device,gpointer user_data)386 foreach_device_match_get_udi_tdl (HalDeviceStore *store, HalDevice *device,
387 				  gpointer user_data)
388 {
389 	DeviceMatchInfo *info = user_data;
390 	const char *dev_value;
391 
392 	/* skip devices in the TDL that hasn't got a real UDI yet */
393 	if (strncmp (device->udi, "/org/freedesktop/Hal/devices/temp",
394 		     sizeof ("/org/freedesktop/Hal/devices/temp")) == 0)
395 		return TRUE;
396 
397 	if (hal_device_property_get_type (device,
398 					  info->key) != DBUS_TYPE_STRING)
399 		return TRUE;
400 
401 	dev_value = hal_device_property_get_string (device, info->key);
402 
403 	if (dev_value != NULL && strcmp (dev_value, info->value) == 0) {
404 		const char *udi;
405 		udi = hal_device_get_udi (device);
406 
407 		dbus_message_iter_append_basic (info->iter,
408 						DBUS_TYPE_STRING,
409 						&udi);
410 	}
411 
412 	return TRUE;
413 }
414 
415 /** Find devices in the GDL where a single string property matches a given
416  *  value. Also returns devices in the TDL that has a non-tmp UDI.
417  *
418  *  <pre>
419  *  array{object_reference} Manager.FindDeviceStringMatch(string key,
420  *                                                        string value)
421  *  </pre>
422  *
423  *  @param  connection          D-BUS connection
424  *  @param  message             Message
425  *  @return                     What to do with the message
426  */
427 DBusHandlerResult
manager_find_device_string_match(DBusConnection * connection,DBusMessage * message)428 manager_find_device_string_match (DBusConnection * connection,
429 				  DBusMessage * message)
430 {
431 	DBusMessage *reply;
432 	DBusMessageIter iter;
433 	DBusMessageIter iter_array;
434 	DBusError error;
435 	const char *key;
436 	const char *value;
437 	DeviceMatchInfo info;
438 
439 	HAL_TRACE (("entering"));
440 
441 	dbus_error_init (&error);
442 	if (!dbus_message_get_args (message, &error,
443 				    DBUS_TYPE_STRING, &key,
444 				    DBUS_TYPE_STRING, &value,
445 				    DBUS_TYPE_INVALID)) {
446 		raise_syntax (connection, message,
447 			      "Manager.FindDeviceStringMatch");
448 		return DBUS_HANDLER_RESULT_HANDLED;
449 	}
450 
451 	reply = dbus_message_new_method_return (message);
452 	if (reply == NULL)
453 		DIE (("No memory"));
454 
455 	dbus_message_iter_init_append (reply, &iter);
456 	dbus_message_iter_open_container (&iter,
457 					  DBUS_TYPE_ARRAY,
458 					  DBUS_TYPE_STRING_AS_STRING,
459 					  &iter_array);
460 
461 	info.key = key;
462 	info.value = value;
463 	info.iter = &iter_array;
464 
465 	hal_device_store_foreach (hald_get_gdl (),
466 				  foreach_device_match_get_udi,
467 				  &info);
468 
469 	/* Also returns devices in the TDL that has a non-tmp UDI */
470 	hal_device_store_foreach (hald_get_tdl (),
471 				  foreach_device_match_get_udi_tdl,
472 				  &info);
473 
474 	dbus_message_iter_close_container (&iter, &iter_array);
475 
476 	if (!dbus_connection_send (connection, reply, NULL))
477 		DIE (("No memory"));
478 
479 	dbus_message_unref (reply);
480 
481 	return DBUS_HANDLER_RESULT_HANDLED;
482 }
483 
484 typedef struct {
485 	const char *capability;
486 	DBusMessageIter *iter;
487 } DeviceCapabilityInfo;
488 
489 static gboolean
foreach_device_by_capability(HalDeviceStore * store,HalDevice * device,gpointer user_data)490 foreach_device_by_capability (HalDeviceStore *store, HalDevice *device, gpointer user_data)
491 {
492 	DeviceCapabilityInfo *info = (DeviceCapabilityInfo *) user_data;
493 
494 	if (hal_device_has_capability (device, info->capability)) {
495 		dbus_message_iter_append_basic (info->iter,
496 						DBUS_TYPE_STRING,
497 						&(device->udi));
498 	}
499 
500 	return TRUE;
501 }
502 
503 /** Find devices in the GDL with a given capability.
504  *
505  *  <pre>
506  *  array{object_reference} Manager.FindDeviceByCapability(string capability)
507  *  </pre>
508  *
509  *  @param  connection          D-BUS connection
510  *  @param  message             Message
511  *  @return                     What to do with the message
512  */
513 DBusHandlerResult
manager_find_device_by_capability(DBusConnection * connection,DBusMessage * message)514 manager_find_device_by_capability (DBusConnection * connection,
515 				   DBusMessage * message)
516 {
517 	DBusMessage *reply;
518 	DBusMessageIter iter;
519 	DBusMessageIter iter_array;
520 	DBusError error;
521 	const char *capability;
522 	DeviceCapabilityInfo info;
523 
524 	HAL_TRACE (("entering"));
525 
526 	dbus_error_init (&error);
527 	if (!dbus_message_get_args (message, &error,
528 				    DBUS_TYPE_STRING, &capability,
529 				    DBUS_TYPE_INVALID)) {
530 		raise_syntax (connection, message,
531 			      "Manager.FindDeviceByCapability");
532 		return DBUS_HANDLER_RESULT_HANDLED;
533 	}
534 
535 	reply = dbus_message_new_method_return (message);
536 	if (reply == NULL)
537 		DIE (("No memory"));
538 
539 	dbus_message_iter_init_append (reply, &iter);
540 	dbus_message_iter_open_container (&iter,
541 					  DBUS_TYPE_ARRAY,
542 					  DBUS_TYPE_STRING_AS_STRING,
543 					  &iter_array);
544 
545 	info.capability = capability;
546 	info.iter = &iter_array;
547 
548 	hal_device_store_foreach (hald_get_gdl (),
549 				  foreach_device_by_capability,
550 				  &info);
551 
552 	dbus_message_iter_close_container (&iter, &iter_array);
553 
554 	if (!dbus_connection_send (connection, reply, NULL))
555 		DIE (("No memory"));
556 
557 	dbus_message_unref (reply);
558 
559 	return DBUS_HANDLER_RESULT_HANDLED;
560 }
561 
562 
563 /** Determine if a device exists.
564  *
565  *  <pre>
566  *  bool Manager.DeviceExists(string udi)
567  *  </pre>
568  *
569  *  @param  connection          D-BUS connection
570  *  @param  message             Message
571  *  @return                     What to do with the message
572  */
573 DBusHandlerResult
manager_device_exists(DBusConnection * connection,DBusMessage * message)574 manager_device_exists (DBusConnection * connection, DBusMessage * message)
575 {
576 	DBusMessage *reply;
577 	DBusMessageIter iter;
578 	DBusError error;
579 	HalDevice *d;
580 	const char *udi;
581 	dbus_bool_t b;
582 
583 	dbus_error_init (&error);
584 	if (!dbus_message_get_args (message, &error,
585 				    DBUS_TYPE_STRING, &udi,
586 				    DBUS_TYPE_INVALID)) {
587 		raise_syntax (connection, message, "Manager.DeviceExists");
588 		return DBUS_HANDLER_RESULT_HANDLED;
589 	}
590 
591 	HAL_TRACE (("entering, udi=%s", udi));
592 
593 	d = hal_device_store_find (hald_get_gdl (), udi);
594 
595 	if (d == NULL)
596 		d = hal_device_store_find (hald_get_tdl (), udi);
597 
598 	reply = dbus_message_new_method_return (message);
599 	dbus_message_iter_init_append (reply, &iter);
600 	b = d != NULL;
601 	dbus_message_iter_append_basic (&iter, DBUS_TYPE_BOOLEAN, &b);
602 
603 	if (reply == NULL)
604 		DIE (("No memory"));
605 
606 	if (!dbus_connection_send (connection, reply, NULL))
607 		DIE (("No memory"));
608 
609 	dbus_message_unref (reply);
610 	return DBUS_HANDLER_RESULT_HANDLED;
611 }
612 
613 /** Send signal DeviceAdded(string udi) on the org.freedesktop.Hal.Manager
614  *  interface on the object /org/freedesktop/Hal/Manager.
615  *
616  *  @param  device              The HalDevice added
617  */
618 void
manager_send_signal_device_added(HalDevice * device)619 manager_send_signal_device_added (HalDevice *device)
620 {
621 	const char *udi = hal_device_get_udi (device);
622 	DBusMessage *message;
623 	DBusMessageIter iter;
624 
625 	if (dbus_connection == NULL)
626 		goto out;
627 
628 	HAL_TRACE (("entering, udi=%s", udi));
629 
630 	message = dbus_message_new_signal ("/org/freedesktop/Hal/Manager",
631 					   "org.freedesktop.Hal.Manager",
632 					   "DeviceAdded");
633 
634 	dbus_message_iter_init_append (message, &iter);
635 	dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &udi);
636 
637 	if (!dbus_connection_send (dbus_connection, message, NULL))
638 		DIE (("error broadcasting message"));
639 
640 	dbus_message_unref (message);
641 
642 out:
643 	;
644 }
645 
646 /** Send signal DeviceRemoved(string udi) on the org.freedesktop.Hal.Manager
647  *  interface on the object /org/freedesktop/Hal/Manager.
648  *
649  *  @param  device              The HalDevice removed
650  */
651 void
manager_send_signal_device_removed(HalDevice * device)652 manager_send_signal_device_removed (HalDevice *device)
653 {
654 	const char *udi = hal_device_get_udi (device);
655 	DBusMessage *message;
656 	DBusMessageIter iter;
657 
658 	if (dbus_connection == NULL)
659 		goto out;
660 
661 	HAL_TRACE (("entering, udi=%s", udi));
662 
663 	message = dbus_message_new_signal ("/org/freedesktop/Hal/Manager",
664 					   "org.freedesktop.Hal.Manager",
665 					   "DeviceRemoved");
666 
667 	dbus_message_iter_init_append (message, &iter);
668 	dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &udi);
669 
670 	if (!dbus_connection_send (dbus_connection, message, NULL))
671 		DIE (("error broadcasting message"));
672 
673 	dbus_message_unref (message);
674 out:
675 	;
676 }
677 
678 /** Send signal NewCapability(string udi, string capability) on the
679  *  org.freedesktop.Hal.Manager interface on the object
680  *  /org/freedesktop/Hal/Manager.
681  *
682  *  @param  udi                 Unique Device Id
683  *  @param  capability          Capability
684  */
685 void
manager_send_signal_new_capability(HalDevice * device,const char * capability)686 manager_send_signal_new_capability (HalDevice *device,
687 				    const char *capability)
688 {
689 	const char *udi = hal_device_get_udi (device);
690 	DBusMessage *message;
691 	DBusMessageIter iter;
692 
693 	if (dbus_connection == NULL)
694 		goto out;
695 
696 	HAL_TRACE (("entering, udi=%s, cap=%s", udi, capability));
697 
698 	message = dbus_message_new_signal ("/org/freedesktop/Hal/Manager",
699 					   "org.freedesktop.Hal.Manager",
700 					   "NewCapability");
701 
702 	dbus_message_iter_init_append (message, &iter);
703 	dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &udi);
704 	dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &capability);
705 
706 	if (!dbus_connection_send (dbus_connection, message, NULL))
707 		DIE (("error broadcasting message"));
708 
709 	dbus_message_unref (message);
710 out:
711 	;
712 }
713 
714 /** @} */
715 
716 /**
717  * @defgroup DeviceInterface D-BUS interface org.freedesktop.Hal.Device
718  * @ingroup HalDaemon
719  * @brief D-BUS interface for generic device operations
720  * @{
721  */
722 
723 static gboolean
foreach_property_append(HalDevice * device,HalProperty * p,gpointer user_data)724 foreach_property_append (HalDevice *device, HalProperty *p,
725 			 gpointer user_data)
726 {
727 	DBusMessageIter *iter;
728 	DBusMessageIter iter_dict_entry;
729 	const char *key;
730 	int type;
731 
732 	iter = (DBusMessageIter *)user_data;
733 
734 	dbus_message_iter_open_container (iter,
735 					  DBUS_TYPE_DICT_ENTRY,
736 					  NULL,
737 					  &iter_dict_entry);
738 
739 	key = hal_property_get_key (p);
740 	type = hal_property_get_type (p);
741 
742 	dbus_message_iter_append_basic (&iter_dict_entry, DBUS_TYPE_STRING, &key);
743 
744 	switch (type) {
745 	case HAL_PROPERTY_TYPE_STRING:
746 	{
747 		DBusMessageIter iter_var;
748 		const char *v;
749 
750 		v = hal_property_get_string (p);
751 
752 		dbus_message_iter_open_container (&iter_dict_entry,
753 						  DBUS_TYPE_VARIANT,
754 						  DBUS_TYPE_STRING_AS_STRING,
755 						  &iter_var);
756 
757 		dbus_message_iter_append_basic (&iter_var,
758 						DBUS_TYPE_STRING,
759 						&v);
760 
761 		dbus_message_iter_close_container (&iter_dict_entry,
762 						   &iter_var);
763 		break;
764 	}
765 	case HAL_PROPERTY_TYPE_INT32:
766 	{
767 		DBusMessageIter iter_var;
768 		dbus_int32_t v;
769 
770 		v = hal_property_get_int (p);
771 
772 		dbus_message_iter_open_container (&iter_dict_entry,
773 						  DBUS_TYPE_VARIANT,
774 						  DBUS_TYPE_INT32_AS_STRING,
775 						  &iter_var);
776 
777 		dbus_message_iter_append_basic (&iter_var,
778 						DBUS_TYPE_INT32,
779 						&v);
780 
781 		dbus_message_iter_close_container (&iter_dict_entry,
782 						   &iter_var);
783 		break;
784 	}
785 	case HAL_PROPERTY_TYPE_UINT64:
786 	{
787 		DBusMessageIter iter_var;
788 		dbus_uint64_t v;
789 
790 		v = hal_property_get_uint64 (p);
791 
792 		dbus_message_iter_open_container (&iter_dict_entry,
793 						  DBUS_TYPE_VARIANT,
794 						  DBUS_TYPE_UINT64_AS_STRING,
795 						  &iter_var);
796 
797 		dbus_message_iter_append_basic (&iter_var,
798 						DBUS_TYPE_UINT64,
799 						&v);
800 
801 		dbus_message_iter_close_container (&iter_dict_entry,
802 						   &iter_var);
803 		break;
804 	}
805 	case HAL_PROPERTY_TYPE_DOUBLE:
806 	{
807 		DBusMessageIter iter_var;
808 		double v;
809 
810 		v = hal_property_get_double (p);
811 
812 		dbus_message_iter_open_container (&iter_dict_entry,
813 						  DBUS_TYPE_VARIANT,
814 						  DBUS_TYPE_DOUBLE_AS_STRING,
815 						  &iter_var);
816 
817 		dbus_message_iter_append_basic (&iter_var,
818 						DBUS_TYPE_DOUBLE,
819 						&v);
820 
821 		dbus_message_iter_close_container (&iter_dict_entry,
822 						   &iter_var);
823 		break;
824 	}
825 	case HAL_PROPERTY_TYPE_BOOLEAN:
826 	{
827 		DBusMessageIter iter_var;
828 		dbus_bool_t v;
829 
830 		v = hal_property_get_bool (p);
831 
832 		dbus_message_iter_open_container (&iter_dict_entry,
833 						  DBUS_TYPE_VARIANT,
834 						  DBUS_TYPE_BOOLEAN_AS_STRING,
835 						  &iter_var);
836 
837 		dbus_message_iter_append_basic (&iter_var,
838 						DBUS_TYPE_BOOLEAN,
839 						&v);
840 
841 		dbus_message_iter_close_container (&iter_dict_entry,
842 						   &iter_var);
843 		break;
844 	}
845 	case HAL_PROPERTY_TYPE_STRLIST:
846 	{
847 		DBusMessageIter iter_var, iter_array;
848 		GSList *iter;
849 
850 		dbus_message_iter_open_container (&iter_dict_entry,
851 						  DBUS_TYPE_VARIANT,
852 						  DBUS_TYPE_ARRAY_AS_STRING
853 						  DBUS_TYPE_STRING_AS_STRING,
854 						  &iter_var);
855 
856 		dbus_message_iter_open_container (&iter_var,
857 						  DBUS_TYPE_ARRAY,
858 						  DBUS_TYPE_STRING_AS_STRING,
859 						  &iter_array);
860 
861 		for (iter = hal_property_get_strlist (p); iter != NULL; iter = iter->next) {
862 
863 			const char *v;
864 			v = (const char *) iter->data;
865 
866 			dbus_message_iter_append_basic (&iter_array,
867 							DBUS_TYPE_STRING,
868 							&v);
869 		}
870 
871 		dbus_message_iter_close_container (&iter_var,
872 						   &iter_array);
873 
874 		dbus_message_iter_close_container (&iter_dict_entry,
875 						   &iter_var);
876 		break;
877 	}
878 
879 	default:
880 		HAL_WARNING (("Unknown property type 0x%04x", type));
881 		break;
882 	}
883 
884 	dbus_message_iter_close_container (iter, &iter_dict_entry);
885 
886 
887 	return TRUE;
888 }
889 
890 
891 
892 /** Get all properties on a device.
893  *
894  *  <pre>
895  *  map{string, any} Device.GetAllProperties()
896  *
897  *    raises org.freedesktop.Hal.NoSuchDevice
898  *  </pre>
899  *
900  *  @param  connection          D-BUS connection
901  *  @param  message             Message
902  *  @return                     What to do with the message
903  */
904 DBusHandlerResult
device_get_all_properties(DBusConnection * connection,DBusMessage * message)905 device_get_all_properties (DBusConnection * connection,
906 			   DBusMessage * message)
907 {
908 	DBusMessage *reply;
909 	DBusMessageIter iter;
910 	DBusMessageIter iter_dict;
911 	HalDevice *d;
912 	const char *udi;
913 
914 	udi = dbus_message_get_path (message);
915 
916 	HAL_TRACE (("entering, udi=%s", udi));
917 
918 	d = hal_device_store_find (hald_get_gdl (), udi);
919 	if (d == NULL)
920 		d = hal_device_store_find (hald_get_tdl (), udi);
921 
922 	if (d == NULL) {
923 		raise_no_such_device (connection, message, udi);
924 		return DBUS_HANDLER_RESULT_HANDLED;
925 	}
926 
927 	reply = dbus_message_new_method_return (message);
928 	if (reply == NULL)
929 		DIE (("No memory"));
930 
931 	dbus_message_iter_init_append (reply, &iter);
932 
933 	dbus_message_iter_open_container (&iter,
934 					  DBUS_TYPE_ARRAY,
935 					  DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
936 					  DBUS_TYPE_STRING_AS_STRING
937 					  DBUS_TYPE_VARIANT_AS_STRING
938 					  DBUS_DICT_ENTRY_END_CHAR_AS_STRING,
939 					  &iter_dict);
940 
941 	hal_device_property_foreach (d,
942 				     foreach_property_append,
943 				     &iter_dict);
944 
945 	dbus_message_iter_close_container (&iter, &iter_dict);
946 
947 	if (!dbus_connection_send (connection, reply, NULL))
948 		DIE (("No memory"));
949 
950 	dbus_message_unref (reply);
951 
952 	return DBUS_HANDLER_RESULT_HANDLED;
953 }
954 
955 #ifdef sun
956 #include <sys/stat.h>
957 static dbus_bool_t
user_at_console(unsigned long uid)958 user_at_console(unsigned long uid)
959 {
960 	struct stat st;
961 
962 	return ((stat("/dev/vt/console_user", &st) == 0) && (st.st_uid == uid));
963 }
964 #endif /* sun */
965 
966 static dbus_bool_t
sender_has_privileges(DBusConnection * connection,DBusMessage * message)967 sender_has_privileges (DBusConnection *connection, DBusMessage *message)
968 {
969 	DBusError error;
970 	unsigned long user_uid;
971 	const char *user_base_svc;
972 	dbus_bool_t ret;
973 
974 	ret = FALSE;
975 
976 	user_base_svc = dbus_message_get_sender (message);
977 	if (user_base_svc == NULL) {
978 		HAL_WARNING (("Cannot determine base service of caller"));
979 		goto out;
980 	}
981 
982 	HAL_DEBUG (("base_svc = %s", user_base_svc));
983 
984 	dbus_error_init (&error);
985 	user_uid = dbus_bus_get_unix_user (connection, user_base_svc, &error);
986 	if (user_uid == (unsigned long) -1 || dbus_error_is_set (&error)) {
987 		HAL_WARNING (("Could not get uid for connection: %s %s", error.name, error.message));
988 		dbus_error_free (&error);
989 		goto out;
990 	}
991 
992 	HAL_INFO (("uid for caller is %ld", user_uid));
993 
994 	if (user_uid != 0 && user_uid != geteuid()) {
995 #ifdef sun
996 		if (dbus_message_is_method_call (message,
997 						"org.freedesktop.Hal.Device",
998 						"Rescan")) {
999 			if (user_at_console(user_uid)) {
1000 				ret = TRUE;
1001 				goto out;
1002 			}
1003 		}
1004 #endif
1005 		HAL_WARNING (("uid %d is not privileged", user_uid));
1006 		goto out;
1007 	}
1008 
1009 	ret = TRUE;
1010 
1011 out:
1012 	return ret;
1013 }
1014 
1015 
1016 /** Set multiple properties on a device in an atomic fashion.
1017  *
1018  *  <pre>
1019  *  Device.GetAllProperties(map{string, any} properties)
1020  *
1021  *    raises org.freedesktop.Hal.NoSuchDevice
1022  *  </pre>
1023  *
1024  *  @param  connection          D-BUS connection
1025  *  @param  message             Message
1026  *  @return                     What to do with the message
1027  */
1028 static DBusHandlerResult
device_set_multiple_properties(DBusConnection * connection,DBusMessage * message,dbus_bool_t local_interface)1029 device_set_multiple_properties (DBusConnection *connection, DBusMessage *message, dbus_bool_t local_interface)
1030 {
1031 	DBusMessage *reply;
1032 	DBusMessageIter iter;
1033 	DBusMessageIter dict_iter;
1034 	HalDevice *d;
1035 	const char *udi;
1036 
1037 	udi = dbus_message_get_path (message);
1038 
1039 	HAL_TRACE (("entering, udi=%s", udi));
1040 
1041 	d = hal_device_store_find (hald_get_gdl (), udi);
1042 	if (d == NULL)
1043 		d = hal_device_store_find (hald_get_tdl (), udi);
1044 
1045 	if (d == NULL) {
1046 		raise_no_such_device (connection, message, udi);
1047 		return DBUS_HANDLER_RESULT_HANDLED;
1048 	}
1049 
1050 	if (!local_interface && !sender_has_privileges (connection, message)) {
1051 		raise_permission_denied (connection, message, "SetProperty: not privileged");
1052 		return DBUS_HANDLER_RESULT_HANDLED;
1053 	}
1054 
1055 	dbus_message_iter_init (message, &iter);
1056 
1057 	if (dbus_message_iter_get_arg_type (&iter) != DBUS_TYPE_ARRAY  &&
1058 	    dbus_message_iter_get_element_type (&iter) != DBUS_TYPE_DICT_ENTRY) {
1059 		HAL_ERROR (("error, expecting an array of dict entries", __FILE__, __LINE__));
1060 		raise_syntax (connection, message, udi);
1061 		return DBUS_HANDLER_RESULT_HANDLED;
1062 	}
1063 
1064 	dbus_message_iter_recurse (&iter, &dict_iter);
1065 
1066 	/* update atomically */
1067 	device_property_atomic_update_begin ();
1068 
1069 	while (dbus_message_iter_get_arg_type (&dict_iter) == DBUS_TYPE_DICT_ENTRY)
1070 	{
1071 		DBusMessageIter dict_entry_iter, var_iter, array_iter;
1072 		const char *key;
1073 		int change_type;
1074 		dbus_bool_t rc __unused;
1075 
1076 		dbus_message_iter_recurse (&dict_iter, &dict_entry_iter);
1077 		dbus_message_iter_get_basic (&dict_entry_iter, &key);
1078 
1079 		dbus_message_iter_next (&dict_entry_iter);
1080 		dbus_message_iter_recurse (&dict_entry_iter, &var_iter);
1081 		change_type = dbus_message_iter_get_arg_type (&var_iter);
1082 
1083 		rc = FALSE;
1084 
1085 		switch (change_type) {
1086 		case DBUS_TYPE_ARRAY:
1087 			if (dbus_message_iter_get_element_type (&var_iter) != DBUS_TYPE_STRING) {
1088 				/* TODO: error */
1089 			}
1090 			dbus_message_iter_recurse (&var_iter, &array_iter);
1091 
1092 			hal_device_property_strlist_clear (d, key);
1093 
1094 			while (dbus_message_iter_get_arg_type (&array_iter) == DBUS_TYPE_STRING) {
1095 				const char *v;
1096 				dbus_message_iter_get_basic (&array_iter, &v);
1097 				HAL_INFO ((" strlist elem %s -> %s", key, v));
1098 				rc = hal_device_property_strlist_append (d, key, v);
1099 				dbus_message_iter_next (&array_iter);
1100 			}
1101 
1102 			break;
1103 		case DBUS_TYPE_STRING:
1104 		{
1105 			const char *v;
1106 			dbus_message_iter_get_basic (&var_iter, &v);
1107 			HAL_INFO (("%s -> %s", key, v));
1108 			rc = hal_device_property_set_string (d, key, v);
1109 			break;
1110 		}
1111 		case DBUS_TYPE_INT32:
1112 		{
1113 			dbus_int32_t v;
1114 			dbus_message_iter_get_basic (&var_iter, &v);
1115 			HAL_INFO (("%s -> %d", key, v));
1116 			rc = hal_device_property_set_int (d, key, v);
1117 			break;
1118 		}
1119 		case DBUS_TYPE_UINT64:
1120 		{
1121 			dbus_uint64_t v;
1122 			dbus_message_iter_get_basic (&var_iter, &v);
1123 			HAL_INFO (("%s -> %lld", key, v));
1124 			rc = hal_device_property_set_uint64 (d, key, v);
1125 			break;
1126 		}
1127 		case DBUS_TYPE_DOUBLE:
1128 		{
1129 			double v;
1130 			dbus_message_iter_get_basic (&var_iter, &v);
1131 			HAL_INFO (("%s -> %g", key, v));
1132 			rc = hal_device_property_set_double (d, key, v);
1133 			break;
1134 		}
1135 		case DBUS_TYPE_BOOLEAN:
1136 		{
1137 			gboolean v;
1138 			dbus_message_iter_get_basic (&var_iter, &v);
1139 			HAL_INFO (("%s -> %s", key, v ? "True" : "False"));
1140 			rc = hal_device_property_set_bool (d, key, v);
1141 			break;
1142 		}
1143 		default:
1144 			/* TODO: error */
1145 			break;
1146 		}
1147 
1148 		/* TODO: error out on rc==FALSE? */
1149 
1150 		dbus_message_iter_next (&dict_iter);
1151 	}
1152 
1153 	device_property_atomic_update_end ();
1154 
1155 
1156 	reply = dbus_message_new_method_return (message);
1157 	if (reply == NULL)
1158 		DIE (("No memory"));
1159 
1160 	if (!dbus_connection_send (connection, reply, NULL))
1161 		DIE (("No memory"));
1162 
1163 	dbus_message_unref (reply);
1164 	return DBUS_HANDLER_RESULT_HANDLED;
1165 }
1166 
1167 
1168 /** Get a property on a device.
1169  *
1170  *  <pre>
1171  *  any Device.GetProperty(string key)
1172  *  string Device.GetPropertyString(string key)
1173  *  int Device.GetPropertyInteger(string key)
1174  *  bool Device.GetPropertyBoolean(string key)
1175  *  double Device.GetPropertyDouble(string key)
1176  *
1177  *    raises org.freedesktop.Hal.NoSuchDevice,
1178  *           org.freedesktop.Hal.NoSuchProperty
1179  *  </pre>
1180  *
1181  *  @param  connection          D-BUS connection
1182  *  @param  message             Message
1183  *  @return                     What to do with the message
1184  */
1185 DBusHandlerResult
device_get_property(DBusConnection * connection,DBusMessage * message)1186 device_get_property (DBusConnection * connection, DBusMessage * message)
1187 {
1188 	DBusMessage *reply;
1189 	DBusMessageIter iter;
1190 	DBusError error;
1191 	HalDevice *d;
1192 	const char *udi;
1193 	char *key;
1194 	int type;
1195 	HalProperty *p;
1196 
1197 	udi = dbus_message_get_path (message);
1198 
1199 	HAL_TRACE (("entering, udi=%s", udi));
1200 
1201 	d = hal_device_store_find (hald_get_gdl (), udi);
1202 	if (d == NULL)
1203 		d = hal_device_store_find (hald_get_tdl (), udi);
1204 
1205 	if (d == NULL) {
1206 		raise_no_such_device (connection, message, udi);
1207 		return DBUS_HANDLER_RESULT_HANDLED;
1208 	}
1209 
1210 	dbus_error_init (&error);
1211 	if (!dbus_message_get_args (message, &error,
1212 				    DBUS_TYPE_STRING, &key,
1213 				    DBUS_TYPE_INVALID)) {
1214 		raise_syntax (connection, message, "GetProperty");
1215 		return DBUS_HANDLER_RESULT_HANDLED;
1216 	}
1217 
1218 	p = hal_device_property_find (d, key);
1219 	if (p == NULL) {
1220 		raise_no_such_property (connection, message, udi, key);
1221 		return DBUS_HANDLER_RESULT_HANDLED;
1222 	}
1223 
1224 	reply = dbus_message_new_method_return (message);
1225 	if (reply == NULL)
1226 		DIE (("No memory"));
1227 
1228 	dbus_message_iter_init_append (reply, &iter);
1229 
1230 	type = hal_property_get_type (p);
1231 	switch (type) {
1232 	case HAL_PROPERTY_TYPE_STRING:
1233 	{
1234 		const char *s;
1235 		s = hal_property_get_string (p);
1236 		dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &s);
1237 		break;
1238 	}
1239 	case HAL_PROPERTY_TYPE_INT32:
1240 	{
1241 		dbus_int32_t i;
1242 		i = hal_property_get_int (p);
1243 		dbus_message_iter_append_basic (&iter, DBUS_TYPE_INT32, &i);
1244 		break;
1245 	}
1246 	case HAL_PROPERTY_TYPE_UINT64:
1247 	{
1248 		dbus_uint64_t ul;
1249 		ul = hal_property_get_uint64 (p);
1250 		dbus_message_iter_append_basic (&iter, DBUS_TYPE_UINT64, &ul);
1251 		break;
1252 	}
1253 	case HAL_PROPERTY_TYPE_DOUBLE:
1254 	{
1255 		double d;
1256 		d = hal_property_get_double (p);
1257 		dbus_message_iter_append_basic (&iter, DBUS_TYPE_DOUBLE, &d);
1258 		break;
1259 	}
1260 	case HAL_PROPERTY_TYPE_BOOLEAN:
1261 	{
1262 		dbus_bool_t b;
1263 		b = hal_property_get_bool (p);
1264 		dbus_message_iter_append_basic (&iter, DBUS_TYPE_BOOLEAN, &b);
1265 		break;
1266 	}
1267 	case HAL_PROPERTY_TYPE_STRLIST:
1268 	{
1269 		GSList *l;
1270 		DBusMessageIter iter_array;
1271 
1272 		dbus_message_iter_open_container (&iter,
1273 						  DBUS_TYPE_ARRAY,
1274 						  DBUS_TYPE_STRING_AS_STRING,
1275 						  &iter_array);
1276 
1277 		for (l = hal_property_get_strlist (p); l != NULL; l = g_slist_next (l)) {
1278 			dbus_message_iter_append_basic (&iter_array, DBUS_TYPE_STRING, &(l->data));
1279 		}
1280 
1281 		dbus_message_iter_close_container (&iter, &iter_array);
1282 	}
1283 		break;
1284 
1285 	default:
1286 		HAL_WARNING (("Unknown property type %d", type));
1287 		break;
1288 	}
1289 
1290 	if (!dbus_connection_send (connection, reply, NULL))
1291 		DIE (("No memory"));
1292 
1293 	dbus_message_unref (reply);
1294 
1295 	return DBUS_HANDLER_RESULT_HANDLED;
1296 }
1297 
1298 
1299 /** Get the type of a property on a device.
1300  *
1301  *  <pre>
1302  *  int Device.GetPropertyType(string key)
1303  *
1304  *    raises org.freedesktop.Hal.NoSuchDevice,
1305  *           org.freedesktop.Hal.NoSuchProperty
1306  *  </pre>
1307  *
1308  *  @param  connection          D-BUS connection
1309  *  @param  message             Message
1310  *  @return                     What to do with the message
1311  */
1312 DBusHandlerResult
device_get_property_type(DBusConnection * connection,DBusMessage * message)1313 device_get_property_type (DBusConnection * connection,
1314 			  DBusMessage * message)
1315 {
1316 	DBusMessage *reply;
1317 	DBusMessageIter iter;
1318 	DBusError error;
1319 	HalDevice *d;
1320 	const char *udi;
1321 	char *key;
1322 	HalProperty *p;
1323 	dbus_int32_t i;
1324 
1325 	udi = dbus_message_get_path (message);
1326 
1327 	HAL_TRACE (("entering, udi=%s", udi));
1328 
1329 	d = hal_device_store_find (hald_get_gdl (), udi);
1330 	if (d == NULL)
1331 		d = hal_device_store_find (hald_get_tdl (), udi);
1332 
1333 	if (d == NULL) {
1334 		raise_no_such_device (connection, message, udi);
1335 		return DBUS_HANDLER_RESULT_HANDLED;
1336 	}
1337 
1338 	dbus_error_init (&error);
1339 	if (!dbus_message_get_args (message, &error,
1340 				    DBUS_TYPE_STRING, &key,
1341 				    DBUS_TYPE_INVALID)) {
1342 		raise_syntax (connection, message, "GetPropertyType");
1343 		return DBUS_HANDLER_RESULT_HANDLED;
1344 	}
1345 
1346 	p = hal_device_property_find (d, key);
1347 	if (p == NULL) {
1348 		raise_no_such_property (connection, message, udi, key);
1349 		return DBUS_HANDLER_RESULT_HANDLED;
1350 	}
1351 
1352 	reply = dbus_message_new_method_return (message);
1353 	if (reply == NULL)
1354 		DIE (("No memory"));
1355 
1356 	i = hal_property_get_type (p);
1357 	dbus_message_iter_init_append (reply, &iter);
1358 	dbus_message_iter_append_basic (&iter, DBUS_TYPE_INT32, &i);
1359 
1360 	if (!dbus_connection_send (connection, reply, NULL))
1361 		DIE (("No memory"));
1362 
1363 	dbus_message_unref (reply);
1364 
1365 	return DBUS_HANDLER_RESULT_HANDLED;
1366 }
1367 
1368 /** Set a property on a device.
1369  *
1370  *  <pre>
1371  *  void Device.SetProperty(string key, any value)
1372  *  void Device.SetPropertyString(string key, string value)
1373  *  void Device.SetPropertyInteger(string key, int value)
1374  *  void Device.SetPropertyBoolean(string key, bool value)
1375  *  void Device.SetPropertyDouble(string key, double value)
1376  *
1377  *    raises org.freedesktop.Hal.NoSuchDevice,
1378  *           org.freedesktop.Hal.NoSuchProperty
1379  *           org.freedesktop.Hal.TypeMismatch
1380  *  </pre>
1381  *
1382  *  @param  connection          D-BUS connection
1383  *  @param  message             Message
1384  *  @return                     What to do with the message
1385  */
1386 DBusHandlerResult
device_set_property(DBusConnection * connection,DBusMessage * message,dbus_bool_t local_interface)1387 device_set_property (DBusConnection * connection, DBusMessage * message, dbus_bool_t local_interface)
1388 {
1389 	const char *udi;
1390 	char *key;
1391 	int type;
1392 	dbus_bool_t rc;
1393 	HalDevice *device;
1394 	DBusMessageIter iter;
1395 	DBusMessage *reply;
1396 
1397 	HAL_TRACE (("entering"));
1398 
1399 	udi = dbus_message_get_path (message);
1400 
1401 	dbus_message_iter_init (message, &iter);
1402 	type = dbus_message_iter_get_arg_type (&iter);
1403 	if (type != DBUS_TYPE_STRING) {
1404 		raise_syntax (connection, message, "SetProperty");
1405 		return DBUS_HANDLER_RESULT_HANDLED;
1406 	}
1407 	dbus_message_iter_get_basic (&iter, &key);
1408 
1409 	if (!local_interface && !sender_has_privileges (connection, message)) {
1410 		raise_permission_denied (connection, message, "SetProperty: not privileged");
1411 		return DBUS_HANDLER_RESULT_HANDLED;
1412 	}
1413 
1414 	HAL_DEBUG (("udi=%s, key=%s", udi, key));
1415 
1416 	device = hal_device_store_find (hald_get_gdl (), udi);
1417 	if (device == NULL)
1418 		device = hal_device_store_find (hald_get_tdl (), udi);
1419 
1420 	if (device == NULL) {
1421 		raise_no_such_device (connection, message, udi);
1422 		return DBUS_HANDLER_RESULT_HANDLED;
1423 	}
1424 	dbus_message_iter_next (&iter);
1425 
1426 	/** @todo check permissions of the sender vs property to be modified */
1427 
1428 	type = dbus_message_iter_get_arg_type (&iter);
1429 	rc = FALSE;
1430 
1431 	switch (type) {
1432 	case DBUS_TYPE_STRING:
1433 	{
1434 		const char *v;
1435 		dbus_message_iter_get_basic (&iter, &v);
1436 		rc = hal_device_property_set_string (device, key, v);
1437 		break;
1438 	}
1439 	case DBUS_TYPE_INT32:
1440 	{
1441 		dbus_int32_t v;
1442 		dbus_message_iter_get_basic (&iter, &v);
1443 		rc = hal_device_property_set_int (device, key, v);
1444 		break;
1445 	}
1446 	case DBUS_TYPE_UINT64:
1447 	{
1448 		dbus_uint64_t v;
1449 		dbus_message_iter_get_basic (&iter, &v);
1450 		rc = hal_device_property_set_uint64 (device, key, v);
1451 		break;
1452 	}
1453 	case DBUS_TYPE_DOUBLE:
1454 	{
1455 		double v;
1456 		dbus_message_iter_get_basic (&iter, &v);
1457 		rc = hal_device_property_set_double (device, key, v);
1458 		break;
1459 	}
1460 	case DBUS_TYPE_BOOLEAN:
1461 	{
1462 		dbus_bool_t v;
1463 		dbus_message_iter_get_basic (&iter, &v);
1464 		rc = hal_device_property_set_bool (device, key, v);
1465 		break;
1466 	}
1467 	default:
1468 		HAL_WARNING (("Unsupported property type %d", type));
1469 		break;
1470 	}
1471 
1472 	if (!rc) {
1473 		raise_property_type_error (connection, message, udi, key);
1474 		return DBUS_HANDLER_RESULT_HANDLED;
1475 	}
1476 
1477 	reply = dbus_message_new_method_return (message);
1478 	if (reply == NULL)
1479 		DIE (("No memory"));
1480 
1481 	if (!dbus_connection_send (connection, reply, NULL))
1482 		DIE (("No memory"));
1483 
1484 	dbus_message_unref (reply);
1485 	return DBUS_HANDLER_RESULT_HANDLED;
1486 }
1487 
1488 /** This function is used to modify the Capabilities property. The reason
1489  *  for having a dedicated function is that the HAL daemon will broadcast
1490  *  a signal on the Manager interface to tell applications that the device
1491  *  have got a new capability.
1492  *
1493  *  This is useful as capabilities can be merged after the device is created.
1494  *  One example of this is networking cards under Linux 2.6; the net.ethernet
1495  *  capability is not merged when the device is initially found by looking in
1496  *  /sys/devices; it is merged when the /sys/classes tree is searched.
1497  *
1498  *  Note that the signal is emitted every time this method is invoked even
1499  *  though the capability already existed. This is useful in the above
1500  *  scenario when the PCI class says ethernet networking card but we yet
1501  *  don't have enough information to fill in the net.* and net.ethernet.*
1502  *  fields since this only happens when we visit the /sys/classes tree.
1503  *
1504  *  <pre>
1505  *  void Device.AddCapability(string capability)
1506  *
1507  *    raises org.freedesktop.Hal.NoSuchDevice,
1508  *    raises org.freedesktop.Hal.PermissionDenied,
1509  *  </pre>
1510  *
1511  *  @param  connection          D-BUS connection
1512  *  @param  message             Message
1513  *  @return                     What to do with the message
1514  */
1515 DBusHandlerResult
device_add_capability(DBusConnection * connection,DBusMessage * message,dbus_bool_t local_interface)1516 device_add_capability (DBusConnection * connection, DBusMessage * message, dbus_bool_t local_interface)
1517 {
1518 	const char *udi;
1519 	const char *capability;
1520 	HalDevice *d;
1521 	DBusMessage *reply;
1522 	DBusError error;
1523 
1524 	HAL_TRACE (("entering"));
1525 
1526 	if (!local_interface && !sender_has_privileges (connection, message)) {
1527 		raise_permission_denied (connection, message, "AddCapability: not privileged");
1528 		return DBUS_HANDLER_RESULT_HANDLED;
1529 	}
1530 
1531 	udi = dbus_message_get_path (message);
1532 
1533 	d = hal_device_store_find (hald_get_gdl (), udi);
1534 	if (d == NULL)
1535 		d = hal_device_store_find (hald_get_tdl (), udi);
1536 
1537 	if (d == NULL) {
1538 		raise_no_such_device (connection, message, udi);
1539 		return DBUS_HANDLER_RESULT_HANDLED;
1540 	}
1541 
1542 	dbus_error_init (&error);
1543 	if (!dbus_message_get_args (message, &error,
1544 				    DBUS_TYPE_STRING, &capability,
1545 				    DBUS_TYPE_INVALID)) {
1546 		raise_syntax (connection, message, "AddCapability");
1547 		return DBUS_HANDLER_RESULT_HANDLED;
1548 	}
1549 
1550 
1551 	hal_device_add_capability (d, capability);
1552 
1553 	reply = dbus_message_new_method_return (message);
1554 	if (reply == NULL)
1555 		DIE (("No memory"));
1556 
1557 	if (!dbus_connection_send (connection, reply, NULL))
1558 		DIE (("No memory"));
1559 
1560 	dbus_message_unref (reply);
1561 	return DBUS_HANDLER_RESULT_HANDLED;
1562 }
1563 
1564 
1565 /* TODO: docs */
1566 static DBusHandlerResult
device_string_list_append_prepend(DBusConnection * connection,DBusMessage * message,dbus_bool_t do_prepend)1567 device_string_list_append_prepend (DBusConnection * connection, DBusMessage * message, dbus_bool_t do_prepend)
1568 {
1569 	const char *udi;
1570 	const char *key;
1571 	const char *value;
1572 	HalDevice *d;
1573 	DBusMessage *reply;
1574 	DBusError error;
1575 	gboolean ret;
1576 
1577 	HAL_TRACE (("entering"));
1578 
1579 	udi = dbus_message_get_path (message);
1580 
1581 	d = hal_device_store_find (hald_get_gdl (), udi);
1582 	if (d == NULL)
1583 		d = hal_device_store_find (hald_get_tdl (), udi);
1584 
1585 	if (d == NULL) {
1586 		raise_no_such_device (connection, message, udi);
1587 		return DBUS_HANDLER_RESULT_HANDLED;
1588 	}
1589 
1590 	dbus_error_init (&error);
1591 	if (!dbus_message_get_args (message, &error,
1592 				    DBUS_TYPE_STRING, &key,
1593 				    DBUS_TYPE_STRING, &value,
1594 				    DBUS_TYPE_INVALID)) {
1595 		raise_syntax (connection, message, do_prepend ? "StringListPrepend" : "StringListAppend");
1596 		return DBUS_HANDLER_RESULT_HANDLED;
1597 	}
1598 
1599 	if (do_prepend)
1600 		ret = hal_device_property_strlist_prepend (d, key, value);
1601 	else
1602 		ret = hal_device_property_strlist_append (d, key, value);
1603 	if (!ret) {
1604 		raise_property_type_error (connection, message, udi, key);
1605 		return DBUS_HANDLER_RESULT_HANDLED;
1606 	}
1607 
1608 	reply = dbus_message_new_method_return (message);
1609 	if (reply == NULL)
1610 		DIE (("No memory"));
1611 
1612 	if (!dbus_connection_send (connection, reply, NULL))
1613 		DIE (("No memory"));
1614 
1615 	dbus_message_unref (reply);
1616 	return DBUS_HANDLER_RESULT_HANDLED;
1617 }
1618 
1619 /* TODO: docs */
1620 static DBusHandlerResult
device_string_list_remove(DBusConnection * connection,DBusMessage * message)1621 device_string_list_remove (DBusConnection * connection, DBusMessage * message)
1622 {
1623 	const char *udi;
1624 	const char *key;
1625 	const char *value;
1626 	HalDevice *d;
1627 	DBusMessage *reply;
1628 	DBusError error;
1629 	gboolean ret;
1630 
1631 	HAL_TRACE (("entering"));
1632 
1633 	udi = dbus_message_get_path (message);
1634 
1635 	d = hal_device_store_find (hald_get_gdl (), udi);
1636 	if (d == NULL)
1637 		d = hal_device_store_find (hald_get_tdl (), udi);
1638 
1639 	if (d == NULL) {
1640 		raise_no_such_device (connection, message, udi);
1641 		return DBUS_HANDLER_RESULT_HANDLED;
1642 	}
1643 
1644 	dbus_error_init (&error);
1645 	if (!dbus_message_get_args (message, &error,
1646 				    DBUS_TYPE_STRING, &key,
1647 				    DBUS_TYPE_STRING, &value,
1648 				    DBUS_TYPE_INVALID)) {
1649 		raise_syntax (connection, message, "StringListRemove");
1650 		return DBUS_HANDLER_RESULT_HANDLED;
1651 	}
1652 
1653 	ret = hal_device_property_strlist_remove (d, key, value);
1654 	if (!ret) {
1655 		raise_property_type_error (connection, message, udi, key);
1656 		return DBUS_HANDLER_RESULT_HANDLED;
1657 	}
1658 
1659 	reply = dbus_message_new_method_return (message);
1660 	if (reply == NULL)
1661 		DIE (("No memory"));
1662 
1663 	if (!dbus_connection_send (connection, reply, NULL))
1664 		DIE (("No memory"));
1665 
1666 	dbus_message_unref (reply);
1667 	return DBUS_HANDLER_RESULT_HANDLED;
1668 }
1669 
1670 
1671 
1672 /** Remove a property on a device.
1673  *
1674  *  <pre>
1675  *  void Device.RemoveProperty(string key)
1676  *
1677  *    raises org.freedesktop.Hal.NoSuchDevice,
1678  *           org.freedesktop.Hal.NoSuchProperty
1679  *           org.freedesktop.Hal.PermissionDenied
1680  *  </pre>
1681  *
1682  *  @param  connection          D-BUS connection
1683  *  @param  message             Message
1684  *  @return                     What to do with the message
1685  */
1686 DBusHandlerResult
device_remove_property(DBusConnection * connection,DBusMessage * message,dbus_bool_t local_interface)1687 device_remove_property (DBusConnection * connection, DBusMessage * message, dbus_bool_t local_interface)
1688 {
1689 	const char *udi;
1690 	char *key;
1691 	HalDevice *d;
1692 	DBusMessage *reply;
1693 	DBusError error;
1694 
1695 	HAL_TRACE (("entering"));
1696 
1697 	udi = dbus_message_get_path (message);
1698 
1699 	if (!local_interface && !sender_has_privileges (connection, message)) {
1700 		raise_permission_denied (connection, message, "RemoveProperty: not privileged");
1701 		return DBUS_HANDLER_RESULT_HANDLED;
1702 	}
1703 
1704 	d = hal_device_store_find (hald_get_gdl (), udi);
1705 	if (d == NULL)
1706 		d = hal_device_store_find (hald_get_tdl (), udi);
1707 
1708 	if (d == NULL) {
1709 		raise_no_such_device (connection, message, udi);
1710 		return DBUS_HANDLER_RESULT_HANDLED;
1711 	}
1712 
1713 	dbus_error_init (&error);
1714 	if (!dbus_message_get_args (message, &error,
1715 				    DBUS_TYPE_STRING, &key,
1716 				    DBUS_TYPE_INVALID)) {
1717 		raise_syntax (connection, message, "RemoveProperty");
1718 		return DBUS_HANDLER_RESULT_HANDLED;
1719 	}
1720 
1721 	if (!hal_device_property_remove (d, key)) {
1722 		raise_no_such_property (connection, message, udi, key);
1723 		return DBUS_HANDLER_RESULT_HANDLED;
1724 	}
1725 
1726 
1727 	reply = dbus_message_new_method_return (message);
1728 	if (reply == NULL)
1729 		DIE (("No memory"));
1730 
1731 	if (!dbus_connection_send (connection, reply, NULL))
1732 		DIE (("No memory"));
1733 
1734 	dbus_message_unref (reply);
1735 	return DBUS_HANDLER_RESULT_HANDLED;
1736 }
1737 
1738 
1739 /** Determine if a property exists
1740  *
1741  *  <pre>
1742  *  bool Device.PropertyExists(string key)
1743  *
1744  *    raises org.freedesktop.Hal.NoSuchDevice,
1745  *  </pre>
1746  *
1747  *  @param  connection          D-BUS connection
1748  *  @param  message             Message
1749  *  @return                     What to do with the message
1750  */
1751 DBusHandlerResult
device_property_exists(DBusConnection * connection,DBusMessage * message)1752 device_property_exists (DBusConnection * connection, DBusMessage * message)
1753 {
1754 	const char *udi;
1755 	char *key;
1756 	HalDevice *d;
1757 	DBusMessage *reply;
1758 	DBusError error;
1759 	DBusMessageIter iter;
1760 	dbus_bool_t b;
1761 
1762 	HAL_TRACE (("entering"));
1763 
1764 	udi = dbus_message_get_path (message);
1765 
1766 	d = hal_device_store_find (hald_get_gdl (), udi);
1767 	if (d == NULL)
1768 		d = hal_device_store_find (hald_get_tdl (), udi);
1769 
1770 	if (d == NULL) {
1771 		raise_no_such_device (connection, message, udi);
1772 		return DBUS_HANDLER_RESULT_HANDLED;
1773 	}
1774 
1775 	dbus_error_init (&error);
1776 	if (!dbus_message_get_args (message, &error,
1777 				    DBUS_TYPE_STRING, &key,
1778 				    DBUS_TYPE_INVALID)) {
1779 		raise_syntax (connection, message, "RemoveProperty");
1780 		return DBUS_HANDLER_RESULT_HANDLED;
1781 	}
1782 
1783 	reply = dbus_message_new_method_return (message);
1784 	if (reply == NULL)
1785 		DIE (("No memory"));
1786 
1787 	b =  hal_device_has_property (d, key);
1788 	dbus_message_iter_init_append (reply, &iter);
1789 	dbus_message_iter_append_basic (&iter, DBUS_TYPE_BOOLEAN, &b);
1790 
1791 	if (!dbus_connection_send (connection, reply, NULL))
1792 		DIE (("No memory"));
1793 
1794 	dbus_message_unref (reply);
1795 	return DBUS_HANDLER_RESULT_HANDLED;
1796 }
1797 
1798 
1799 /** Determine if a device has a capability
1800  *
1801  *  <pre>
1802  *  bool Device.QueryCapability(string capability_name)
1803  *
1804  *    raises org.freedesktop.Hal.NoSuchDevice,
1805  *  </pre>
1806  *
1807  *  @param  connection          D-BUS connection
1808  *  @param  message             Message
1809  *  @return                     What to do with the message
1810  */
1811 DBusHandlerResult
device_query_capability(DBusConnection * connection,DBusMessage * message)1812 device_query_capability (DBusConnection * connection,
1813 			 DBusMessage * message)
1814 {
1815 	dbus_bool_t rc;
1816 	const char *udi;
1817 	GSList *caps;
1818 	char *capability;
1819 	HalDevice *d;
1820 	DBusMessage *reply;
1821 	DBusError error;
1822 	DBusMessageIter iter;
1823 
1824 	HAL_TRACE (("entering"));
1825 
1826 	udi = dbus_message_get_path (message);
1827 
1828 	d = hal_device_store_find (hald_get_gdl (), udi);
1829 	if (d == NULL)
1830 		d = hal_device_store_find (hald_get_tdl (), udi);
1831 
1832 	if (d == NULL) {
1833 		raise_no_such_device (connection, message, udi);
1834 		return DBUS_HANDLER_RESULT_HANDLED;
1835 	}
1836 
1837 	dbus_error_init (&error);
1838 	if (!dbus_message_get_args (message, &error,
1839 				    DBUS_TYPE_STRING, &capability,
1840 				    DBUS_TYPE_INVALID)) {
1841 		raise_syntax (connection, message, "QueryCapability");
1842 		return DBUS_HANDLER_RESULT_HANDLED;
1843 	}
1844 
1845 	reply = dbus_message_new_method_return (message);
1846 	if (reply == NULL)
1847 		DIE (("No memory"));
1848 
1849 	rc = FALSE;
1850 	caps = hal_device_property_get_strlist (d, "info.capabilities");
1851 	if (caps != NULL) {
1852 		GSList *iter;
1853 
1854 		for (iter = caps; iter != NULL; iter=g_slist_next(iter)) {
1855 			if (strcmp (iter->data, capability) == 0) {
1856 				rc = TRUE;
1857 				break;
1858 			}
1859 		}
1860 	}
1861 
1862 	dbus_message_iter_init_append (reply, &iter);
1863 	dbus_message_iter_append_basic (&iter, DBUS_TYPE_BOOLEAN, &rc);
1864 
1865 	if (!dbus_connection_send (connection, reply, NULL))
1866 		DIE (("No memory"));
1867 
1868 	dbus_message_unref (reply);
1869 	return DBUS_HANDLER_RESULT_HANDLED;
1870 }
1871 
1872 static GHashTable *services_with_locks = NULL;
1873 
1874 /** Grab an advisory lock on a device.
1875  *
1876  *  <pre>
1877  *  bool Device.Lock(string reason)
1878  *
1879  *    raises org.freedesktop.Hal.NoSuchDevice,
1880  *           org.freedesktop.Hal.DeviceAlreadyLocked
1881  *  </pre>
1882  *
1883  *  @param  connection          D-BUS connection
1884  *  @param  message             Message
1885  *  @return                     What to do with the message
1886  */
1887 DBusHandlerResult
device_lock(DBusConnection * connection,DBusMessage * message)1888 device_lock (DBusConnection * connection,
1889 	     DBusMessage * message)
1890 {
1891 	const char *udi;
1892 	HalDevice *d;
1893 	DBusMessage *reply;
1894 	dbus_bool_t already_locked;
1895 	DBusError error;
1896 	char *reason;
1897 	const char *sender;
1898 
1899 	HAL_TRACE (("entering"));
1900 
1901 	udi = dbus_message_get_path (message);
1902 
1903 	d = hal_device_store_find (hald_get_gdl (), udi);
1904 	if (d == NULL)
1905 		d = hal_device_store_find (hald_get_tdl (), udi);
1906 
1907 	if (d == NULL) {
1908 		raise_no_such_device (connection, message, udi);
1909 		return DBUS_HANDLER_RESULT_HANDLED;
1910 	}
1911 
1912 	already_locked = hal_device_property_get_bool (d, "info.locked");
1913 
1914 	if (already_locked) {
1915 		raise_device_already_locked (connection, message, d);
1916 		return DBUS_HANDLER_RESULT_HANDLED;
1917 	}
1918 
1919 	dbus_error_init (&error);
1920 	if (!dbus_message_get_args (message, &error,
1921 				    DBUS_TYPE_STRING, &reason,
1922 				    DBUS_TYPE_INVALID)) {
1923 		raise_syntax (connection, message, "Lock");
1924 		return DBUS_HANDLER_RESULT_HANDLED;
1925 	}
1926 
1927 	reply = dbus_message_new_method_return (message);
1928 	if (reply == NULL)
1929 		DIE (("No memory"));
1930 
1931 	sender = dbus_message_get_sender (message);
1932 
1933 	hal_device_property_set_bool (d, "info.locked", TRUE);
1934 	hal_device_property_set_string (d, "info.locked.reason", reason);
1935 	hal_device_property_set_string (d, "info.locked.dbus_name",
1936 					sender);
1937 
1938 	if (services_with_locks == NULL) {
1939 		services_with_locks =
1940 			g_hash_table_new_full (g_str_hash,
1941 					       g_str_equal,
1942 					       g_free,
1943 					       g_object_unref);
1944 	}
1945 
1946 	g_hash_table_insert (services_with_locks, g_strdup (sender),
1947 			     g_object_ref (d));
1948 
1949 	if (!dbus_connection_send (connection, reply, NULL))
1950 		DIE (("No memory"));
1951 
1952 	dbus_message_unref (reply);
1953 	return DBUS_HANDLER_RESULT_HANDLED;
1954 }
1955 
1956 /** Release an advisory lock on a device.
1957  *
1958  *  <pre>
1959  *  bool Device.Unlock()
1960  *
1961  *    raises org.freedesktop.Hal.NoSuchDevice,
1962  *           org.freedesktop.Hal.DeviceNotLocked,
1963  *           org.freedesktop.Hal.PermissionDenied
1964  *  </pre>
1965  *
1966  *  @param  connection          D-BUS connection
1967  *  @param  message             Message
1968  *  @return                     What to do with the message
1969  */
1970 DBusHandlerResult
device_unlock(DBusConnection * connection,DBusMessage * message)1971 device_unlock (DBusConnection * connection,
1972 	       DBusMessage * message)
1973 {
1974 	dbus_bool_t rc;
1975 	const char *udi;
1976 	HalDevice *d;
1977 	DBusMessage *reply;
1978 	DBusError error;
1979 	const char *sender;
1980 
1981 	HAL_TRACE (("entering"));
1982 
1983 	udi = dbus_message_get_path (message);
1984 
1985 	d = hal_device_store_find (hald_get_gdl (), udi);
1986 	if (d == NULL)
1987 		d = hal_device_store_find (hald_get_tdl (), udi);
1988 
1989 	if (d == NULL) {
1990 		raise_no_such_device (connection, message, udi);
1991 		return DBUS_HANDLER_RESULT_HANDLED;
1992 	}
1993 
1994 	dbus_error_init (&error);
1995 	if (!dbus_message_get_args (message, &error,
1996 				    DBUS_TYPE_INVALID)) {
1997 		raise_syntax (connection, message, "Unlock");
1998 		return DBUS_HANDLER_RESULT_HANDLED;
1999 	}
2000 
2001 	reply = dbus_message_new_method_return (message);
2002 	if (reply == NULL)
2003 		DIE (("No memory"));
2004 
2005 	rc = hal_device_property_get_bool (d, "info.locked");
2006 
2007 	if (!rc) {
2008 		raise_device_not_locked (connection, message, d);
2009 		return DBUS_HANDLER_RESULT_HANDLED;
2010 	}
2011 
2012 	sender = dbus_message_get_sender (message);
2013 
2014 	if (strcmp (sender, hal_device_property_get_string (
2015 			    d, "info.locked.dbus_name")) != 0) {
2016 		char *reason;
2017 
2018 		reason = g_strdup_printf ("Service '%s' does not own the "
2019 					  "lock on %s", sender,
2020 					  hal_device_get_udi (d));
2021 
2022 		raise_permission_denied (connection, message, reason);
2023 
2024 		g_free (reason);
2025 
2026 		return DBUS_HANDLER_RESULT_HANDLED;
2027 	}
2028 
2029 	if (g_hash_table_lookup (services_with_locks, sender))
2030 		g_hash_table_remove (services_with_locks, sender);
2031 	else {
2032 		HAL_WARNING (("Service '%s' was not in the list of services "
2033 			      "with locks!", sender));
2034 	}
2035 
2036 	hal_device_property_remove (d, "info.locked");
2037 	hal_device_property_remove (d, "info.locked.reason");
2038 	hal_device_property_remove (d, "info.locked.dbus_name");
2039 
2040 	/* FIXME?  Pointless? */
2041 	if (!dbus_connection_send (connection, reply, NULL))
2042 		DIE (("No memory"));
2043 
2044 	dbus_message_unref (reply);
2045 	return DBUS_HANDLER_RESULT_HANDLED;
2046 }
2047 
2048 static GHashTable *services_with_claims = NULL;
2049 
2050 /** Claim a branch.
2051  *
2052  *  <pre>
2053  *  bool Manager.ClaimBranch(string udi, string claim_service)
2054  *  </pre>
2055  *
2056  *  @param  connection          D-BUS connection
2057  *  @param  message             Message
2058  *  @return                     What to do with the message
2059  */
2060 DBusHandlerResult
manager_claim_branch(DBusConnection * connection,DBusMessage * message)2061 manager_claim_branch (DBusConnection * connection, DBusMessage * message)
2062 {
2063 	DBusMessage *reply;
2064 	DBusMessageIter iter;
2065 	DBusError error;
2066 	HalDevice *d;
2067 	const char *udi;
2068 	const char *claim_service;
2069 	const char *sender;
2070 	dbus_bool_t already_claimed;
2071 	unsigned long uid;
2072 
2073 	dbus_error_init (&error);
2074 	if (!dbus_message_get_args (message, &error,
2075 				    DBUS_TYPE_STRING, &udi,
2076 				    DBUS_TYPE_STRING, &claim_service,
2077 				    DBUS_TYPE_INVALID)) {
2078 		raise_syntax (connection, message, "Manager.ClaimBranch");
2079 		return DBUS_HANDLER_RESULT_HANDLED;
2080 	}
2081 
2082 	HAL_TRACE (("entering, udi=%s", udi));
2083 
2084 	d = hal_device_store_find (hald_get_gdl (), udi);
2085 
2086 	if (d == NULL) {
2087 		raise_no_such_device (connection, message, udi);
2088 		return DBUS_HANDLER_RESULT_HANDLED;
2089 	}
2090 
2091 	already_claimed = hal_device_property_get_bool (d, "info.claimed");
2092 	if (already_claimed) {
2093 		raise_branch_already_claimed (connection, message, d);
2094 		return DBUS_HANDLER_RESULT_HANDLED;
2095 	}
2096 
2097 	reply = dbus_message_new_method_return (message);
2098 	if (reply == NULL)
2099 		DIE (("No memory"));
2100 
2101 	sender = dbus_message_get_sender (message);
2102 
2103 	dbus_error_init (&error);
2104 	uid = dbus_bus_get_unix_user (connection, sender, &error);
2105 	if (uid == (unsigned long) -1 || dbus_error_is_set (&error)) {
2106 		HAL_WARNING (("Could not get uid for connection: %s %s", error.name, error.message));
2107 		dbus_error_free (&error);
2108 		dbus_message_unref (reply);
2109 		raise_no_such_device (connection, message, udi);
2110 		return DBUS_HANDLER_RESULT_HANDLED;
2111 	}
2112 
2113 	hal_util_branch_claim (hald_get_gdl (), d, TRUE, claim_service, uid);
2114 	hal_device_property_set_string (d, "info.claimed.dbus_name", sender);
2115 
2116 	if (services_with_claims == NULL) {
2117 		services_with_claims =
2118 			g_hash_table_new_full (g_str_hash,
2119 					       g_str_equal,
2120 					       g_free,
2121 					       g_object_unref);
2122 	}
2123 
2124 	g_hash_table_insert (services_with_claims, g_strdup (sender),
2125 			     g_object_ref (d));
2126 
2127 	if (!dbus_connection_send (connection, reply, NULL))
2128 		DIE (("No memory"));
2129 
2130 	dbus_message_unref (reply);
2131 	return DBUS_HANDLER_RESULT_HANDLED;
2132 }
2133 
2134 /** Unclaim a branch.
2135  *
2136  *  <pre>
2137  *  bool Manager.UnclaimBranch(string udi)
2138  *  </pre>
2139  *
2140  *  @param  connection          D-BUS connection
2141  *  @param  message             Message
2142  *  @return                     What to do with the message
2143  */
2144 DBusHandlerResult
manager_unclaim_branch(DBusConnection * connection,DBusMessage * message)2145 manager_unclaim_branch (DBusConnection * connection, DBusMessage * message)
2146 {
2147 	DBusMessage *reply;
2148 	DBusMessageIter iter;
2149 	DBusError error;
2150 	HalDevice *d;
2151 	const char *udi;
2152 	const char *claim_service;
2153 	const char *sender;
2154 	dbus_bool_t already_claimed;
2155 
2156 	dbus_error_init (&error);
2157 	if (!dbus_message_get_args (message, &error,
2158 				    DBUS_TYPE_STRING, &udi,
2159 				    DBUS_TYPE_INVALID)) {
2160 		raise_syntax (connection, message, "Manager.UnclaimBranch");
2161 		return DBUS_HANDLER_RESULT_HANDLED;
2162 	}
2163 
2164 	HAL_TRACE (("entering, udi=%s", udi));
2165 
2166 	d = hal_device_store_find (hald_get_gdl (), udi);
2167 
2168 	if (d == NULL) {
2169 		raise_no_such_device (connection, message, udi);
2170 		return DBUS_HANDLER_RESULT_HANDLED;
2171 	}
2172 
2173 	already_claimed = hal_device_property_get_bool (d, "info.claimed");
2174 	if (!already_claimed) {
2175 		raise_branch_not_claimed (connection, message, d);
2176 		return DBUS_HANDLER_RESULT_HANDLED;
2177 	}
2178 
2179 	reply = dbus_message_new_method_return (message);
2180 	if (reply == NULL)
2181 		DIE (("No memory"));
2182 
2183 	if (strcmp (sender, hal_device_property_get_string (
2184 			    d, "info.claimed.dbus_name")) != 0) {
2185 		char *reason;
2186 
2187 		reason = g_strdup_printf ("Service '%s' does not own the "
2188 					  "claim on %s", sender,
2189 					  hal_device_get_udi (d));
2190 
2191 		raise_permission_denied (connection, message, reason);
2192 
2193 		g_free (reason);
2194 
2195 		return DBUS_HANDLER_RESULT_HANDLED;
2196 	}
2197 
2198 	if (g_hash_table_lookup (services_with_claims, sender))
2199 		g_hash_table_remove (services_with_claims, sender);
2200 	else {
2201 		HAL_WARNING (("Service '%s' was not in the list of services "
2202 			      "with claims!", sender));
2203 	}
2204 
2205 	hal_util_branch_claim (hald_get_gdl (), d, FALSE, NULL, 0);
2206 	hal_device_property_remove (d, "info.claimed.dbus_name");
2207 
2208 	if (!dbus_connection_send (connection, reply, NULL))
2209 		DIE (("No memory"));
2210 
2211 	dbus_message_unref (reply);
2212 	return DBUS_HANDLER_RESULT_HANDLED;
2213 }
2214 
2215 
2216 /** Counter for atomic updating */
2217 static int atomic_count = 0;
2218 
2219 /** Number of updates pending */
2220 static int num_pending_updates = 0;
2221 
2222 /** Structure for queing updates */
2223 typedef struct PendingUpdate_s {
2224 	char *udi;                    /**< udi of device */
2225 	char *key;                    /**< key of property; free when done */
2226 	dbus_bool_t removed;          /**< true iff property was removed */
2227 	dbus_bool_t added;            /**< true iff property was added */
2228 	struct PendingUpdate_s *next; /**< next update or #NULL */
2229 } PendingUpdate;
2230 
2231 static PendingUpdate *pending_updates_head = NULL;
2232 
2233 /** Begin an atomic update - this is useful for updating several properties
2234  *  in one go.
2235  *
2236  *  Note that an atomic update is recursive - use with caution!
2237  */
2238 void
device_property_atomic_update_begin(void)2239 device_property_atomic_update_begin (void)
2240 {
2241 	atomic_count++;
2242 }
2243 
2244 /** End an atomic update.
2245  *
2246  *  Note that an atomic update is recursive - use with caution!
2247  */
2248 void
device_property_atomic_update_end(void)2249 device_property_atomic_update_end (void)
2250 {
2251 	PendingUpdate *pu_iter = NULL;
2252 	PendingUpdate *pu_iter_next = NULL;
2253 	PendingUpdate *pu_iter2 = NULL;
2254 
2255 	--atomic_count;
2256 
2257 	if (atomic_count < 0) {
2258 		HAL_WARNING (("*** atomic_count = %d < 0 !!", atomic_count));
2259 		atomic_count = 0;
2260 	}
2261 
2262 	if (atomic_count == 0 && num_pending_updates > 0) {
2263 		DBusMessage *message;
2264 		DBusMessageIter iter;
2265 		DBusMessageIter iter_array;
2266 
2267 		for (pu_iter = pending_updates_head;
2268 		     pu_iter != NULL; pu_iter = pu_iter_next) {
2269 			int num_updates_this;
2270 
2271 			pu_iter_next = pu_iter->next;
2272 
2273 			/* see if we've already processed this */
2274 			if (pu_iter->udi == NULL)
2275 				goto already_processed;
2276 
2277 			/* count number of updates for this device */
2278 			num_updates_this = 0;
2279 			for (pu_iter2 = pu_iter; pu_iter2 != NULL; pu_iter2 = pu_iter2->next) {
2280 				if (strcmp (pu_iter2->udi, pu_iter->udi) == 0)
2281 					num_updates_this++;
2282 			}
2283 
2284 			/* prepare message */
2285 			message = dbus_message_new_signal (pu_iter->udi,
2286 							   "org.freedesktop.Hal.Device",
2287 							   "PropertyModified");
2288 			dbus_message_iter_init_append (message, &iter);
2289 			dbus_message_iter_append_basic (&iter, DBUS_TYPE_INT32,
2290 							&num_updates_this);
2291 
2292 			dbus_message_iter_open_container (&iter,
2293 							  DBUS_TYPE_ARRAY,
2294 							  DBUS_STRUCT_BEGIN_CHAR_AS_STRING
2295 							  DBUS_TYPE_STRING_AS_STRING
2296 							  DBUS_TYPE_BOOLEAN_AS_STRING
2297 							  DBUS_TYPE_BOOLEAN_AS_STRING
2298 							  DBUS_STRUCT_END_CHAR_AS_STRING,
2299 							  &iter_array);
2300 
2301 			for (pu_iter2 = pu_iter; pu_iter2 != NULL;
2302 			     pu_iter2 = pu_iter2->next) {
2303 				if (strcmp (pu_iter2->udi, pu_iter->udi) == 0) {
2304 					DBusMessageIter iter_struct;
2305 					dbus_message_iter_open_container (&iter_array,
2306 									  DBUS_TYPE_STRUCT,
2307 									  NULL,
2308 									  &iter_struct);
2309 					dbus_message_iter_append_basic
2310 					    (&iter_struct,
2311 					     DBUS_TYPE_STRING,
2312 					     &(pu_iter2->key));
2313 					dbus_message_iter_append_basic
2314 					    (&iter_struct,
2315 					     DBUS_TYPE_BOOLEAN,
2316 					     &(pu_iter2->removed));
2317 					dbus_message_iter_append_basic
2318 					    (&iter_struct,
2319 					     DBUS_TYPE_BOOLEAN,
2320 					     &(pu_iter2->added));
2321 
2322 					dbus_message_iter_close_container (&iter_array, &iter_struct);
2323 
2324 					/* signal this is already processed */
2325 					g_free (pu_iter2->key);
2326 					if (pu_iter2 != pu_iter) {
2327 						g_free (pu_iter2->udi);
2328 						pu_iter2->udi = NULL;
2329 					}
2330 				}
2331 			}
2332 
2333 			g_free (pu_iter->udi);
2334 			dbus_message_iter_close_container (&iter, &iter_array);
2335 
2336 			if (dbus_connection != NULL) {
2337 				if (!dbus_connection_send (dbus_connection, message, NULL))
2338 					DIE (("error broadcasting message"));
2339 			}
2340 
2341 			dbus_message_unref (message);
2342 
2343 		already_processed:
2344 			g_free (pu_iter);
2345 
2346 		} /* for all updates */
2347 
2348 		num_pending_updates = 0;
2349 		pending_updates_head = NULL;
2350 	}
2351 }
2352 
2353 
2354 
2355 void
device_send_signal_property_modified(HalDevice * device,const char * key,dbus_bool_t added,dbus_bool_t removed)2356 device_send_signal_property_modified (HalDevice *device, const char *key,
2357 				      dbus_bool_t added, dbus_bool_t removed)
2358 {
2359 	const char *udi = hal_device_get_udi (device);
2360 	DBusMessage *message;
2361 	DBusMessageIter iter;
2362 
2363 /*
2364     HAL_INFO(("Entering, udi=%s, key=%s, in_gdl=%s, removed=%s added=%s",
2365               device->udi, key,
2366               in_gdl ? "true" : "false",
2367               removed ? "true" : "false",
2368               added ? "true" : "false"));
2369 */
2370 
2371 	if (atomic_count > 0) {
2372 		PendingUpdate *pu;
2373 
2374 		pu = g_new0 (PendingUpdate, 1);
2375 		pu->udi = g_strdup (udi);
2376 		pu->key = g_strdup (key);
2377 		pu->removed = removed;
2378 		pu->added = added;
2379 		pu->next = pending_updates_head;
2380 
2381 		pending_updates_head = pu;
2382 		num_pending_updates++;
2383 	} else {
2384 		dbus_int32_t i;
2385 		DBusMessageIter iter_struct;
2386 		DBusMessageIter iter_array;
2387 
2388 		if (dbus_connection == NULL)
2389 			goto out;
2390 
2391 		message = dbus_message_new_signal (udi,
2392 						  "org.freedesktop.Hal.Device",
2393 						   "PropertyModified");
2394 
2395 		dbus_message_iter_init_append (message, &iter);
2396 		i = 1;
2397 		dbus_message_iter_append_basic (&iter, DBUS_TYPE_INT32, &i);
2398 
2399 		dbus_message_iter_open_container (&iter,
2400 						  DBUS_TYPE_ARRAY,
2401 						  DBUS_STRUCT_BEGIN_CHAR_AS_STRING
2402 						  DBUS_TYPE_STRING_AS_STRING
2403 						  DBUS_TYPE_BOOLEAN_AS_STRING
2404 						  DBUS_TYPE_BOOLEAN_AS_STRING
2405 						  DBUS_STRUCT_END_CHAR_AS_STRING,
2406 						  &iter_array);
2407 
2408 		dbus_message_iter_open_container (&iter_array,
2409 						  DBUS_TYPE_STRUCT,
2410 						  NULL,
2411 						  &iter_struct);
2412 
2413 		dbus_message_iter_append_basic (&iter_struct, DBUS_TYPE_STRING, &key);
2414 		dbus_message_iter_append_basic (&iter_struct, DBUS_TYPE_BOOLEAN, &removed);
2415 		dbus_message_iter_append_basic (&iter_struct, DBUS_TYPE_BOOLEAN, &added);
2416 
2417 		dbus_message_iter_close_container (&iter_array, &iter_struct);
2418 		dbus_message_iter_close_container (&iter, &iter_array);
2419 
2420 		if (!dbus_connection_send (dbus_connection, message, NULL))
2421 			DIE (("error broadcasting message"));
2422 
2423 		dbus_message_unref (message);
2424 	}
2425 out:
2426 	;
2427 }
2428 
2429 /** Emits a condition on a device; the device has to be in the GDL for
2430  *  this function to have effect.
2431  *
2432  *  Is intended for non-continuous events on the device like
2433  *  ProcesserOverheating, BlockDeviceGotDevice, e.g. conditions that
2434  *  are exceptional and may not be inferred by looking at properties
2435  *  (though some may).
2436  *
2437  *  This function accepts a number of parameters that are passed along
2438  *  in the D-BUS message. The recipient is supposed to extract the parameters
2439  *  himself, by looking at the HAL specification.
2440  *
2441  * @param  udi                  The UDI for this device
2442  * @param  condition_name       Name of condition
2443  * @param  first_arg_type       Type of the first argument
2444  * @param  ...                  value of first argument, list of additional
2445  *                              type-value pairs. Must be terminated with
2446  *                              DBUS_TYPE_INVALID
2447  */
2448 void
device_send_signal_condition(HalDevice * device,const char * condition_name,const char * condition_details)2449 device_send_signal_condition (HalDevice *device, const char *condition_name, const char *condition_details)
2450 {
2451 	const char *udi = hal_device_get_udi (device);
2452 	DBusMessage *message;
2453 	DBusMessageIter iter;
2454 
2455 	if (dbus_connection == NULL)
2456 		goto out;
2457 
2458 	message = dbus_message_new_signal (udi,
2459 					   "org.freedesktop.Hal.Device",
2460 					   "Condition");
2461 	dbus_message_iter_init_append (message, &iter);
2462 	dbus_message_iter_append_basic (&iter,
2463 					DBUS_TYPE_STRING,
2464 					&condition_name);
2465 	dbus_message_iter_append_basic (&iter,
2466 					DBUS_TYPE_STRING,
2467 					&condition_details);
2468 
2469 	if (!dbus_connection_send (dbus_connection, message, NULL))
2470 		DIE (("error broadcasting message"));
2471 
2472 	dbus_message_unref (message);
2473 out:
2474 	return;
2475 }
2476 
2477 
2478 
2479 static gboolean
reinit_dbus(gpointer user_data)2480 reinit_dbus (gpointer user_data)
2481 {
2482 	HAL_INFO (("entering!"));
2483 	if (hald_dbus_init ())
2484 		return FALSE;
2485 	else
2486 		return TRUE;
2487 }
2488 
2489 static void
service_deleted(DBusMessage * message)2490 service_deleted (DBusMessage *message)
2491 {
2492 	char *old_service_name;
2493 	char *new_service_name;
2494 	HalDevice *d;
2495 
2496 	if (!dbus_message_get_args (message, NULL,
2497 				    DBUS_TYPE_STRING, &old_service_name,
2498 				    DBUS_TYPE_STRING, &new_service_name,
2499 				    DBUS_TYPE_INVALID)) {
2500 		HAL_ERROR (("Invalid NameOwnerChanged signal from bus!"));
2501 		return;
2502 	}
2503 
2504 	if (services_with_locks != NULL) {
2505 		d = g_hash_table_lookup (services_with_locks, new_service_name);
2506 
2507 		if (d != NULL) {
2508 			hal_device_property_remove (d, "info.locked");
2509 			hal_device_property_remove (d, "info.locked.reason");
2510 			hal_device_property_remove (d, "info.locked.dbus_name");
2511 
2512 			g_hash_table_remove (services_with_locks, new_service_name);
2513 		}
2514 	}
2515 
2516 	if (services_with_claims != NULL) {
2517 		d = g_hash_table_lookup (services_with_claims, new_service_name);
2518 
2519 		if (d != NULL) {
2520 			hal_util_branch_claim (hald_get_gdl (), d, FALSE, NULL, 0);
2521 			hal_device_property_remove (d, "info.claimed.dbus_name");
2522 
2523 			g_hash_table_remove (services_with_claims, new_service_name);
2524 		}
2525 	}
2526 }
2527 
2528 static DBusHandlerResult
device_rescan(DBusConnection * connection,DBusMessage * message,dbus_bool_t local_interface)2529 device_rescan (DBusConnection * connection, DBusMessage * message, dbus_bool_t local_interface)
2530 {
2531 	const char *udi;
2532 	HalDevice *device;
2533 	DBusMessage *reply;
2534 	DBusMessageIter iter;
2535 	gboolean res;
2536 
2537 	HAL_INFO (("entering, local_interface=%d", local_interface));
2538 
2539 	udi = dbus_message_get_path (message);
2540 
2541 	if (!local_interface && !sender_has_privileges (connection, message)) {
2542 		raise_permission_denied (connection, message, "Rescan: not privileged");
2543 		return DBUS_HANDLER_RESULT_HANDLED;
2544 	}
2545 
2546 	HAL_DEBUG (("udi=%s", udi));
2547 
2548 	device = hal_device_store_find (hald_get_gdl (), udi);
2549 	if (device == NULL)
2550 		device = hal_device_store_find (hald_get_tdl (), udi);
2551 
2552 	if (device == NULL) {
2553 		raise_no_such_device (connection, message, udi);
2554 		return DBUS_HANDLER_RESULT_HANDLED;
2555 	}
2556 
2557 	res = osspec_device_rescan (device);
2558 
2559 	reply = dbus_message_new_method_return (message);
2560 	if (reply == NULL)
2561 		DIE (("No memory"));
2562 	dbus_message_iter_init_append (reply, &iter);
2563 	dbus_message_iter_append_basic (&iter, DBUS_TYPE_BOOLEAN, &res);
2564 
2565 	if (!dbus_connection_send (connection, reply, NULL))
2566 		DIE (("No memory"));
2567 
2568 	dbus_message_unref (reply);
2569 	return DBUS_HANDLER_RESULT_HANDLED;
2570 }
2571 
2572 static DBusHandlerResult
device_reprobe(DBusConnection * connection,DBusMessage * message,dbus_bool_t local_interface)2573 device_reprobe (DBusConnection * connection, DBusMessage * message, dbus_bool_t local_interface)
2574 {
2575 	const char *udi;
2576 	HalDevice *device;
2577 	DBusMessageIter iter;
2578 	DBusMessage *reply;
2579 	gboolean res;
2580 
2581 	HAL_TRACE (("entering"));
2582 
2583 	udi = dbus_message_get_path (message);
2584 
2585 	if (!local_interface && !sender_has_privileges (connection, message)) {
2586 		raise_permission_denied (connection, message, "Reprobe: not privileged");
2587 		return DBUS_HANDLER_RESULT_HANDLED;
2588 	}
2589 
2590 	HAL_DEBUG (("udi=%s", udi));
2591 
2592 	device = hal_device_store_find (hald_get_gdl (), udi);
2593 	if (device == NULL)
2594 		device = hal_device_store_find (hald_get_tdl (), udi);
2595 
2596 	if (device == NULL) {
2597 		raise_no_such_device (connection, message, udi);
2598 		return DBUS_HANDLER_RESULT_HANDLED;
2599 	}
2600 
2601 	res = osspec_device_reprobe (device);
2602 
2603 	reply = dbus_message_new_method_return (message);
2604 	if (reply == NULL)
2605 		DIE (("No memory"));
2606 	dbus_message_iter_init_append (reply, &iter);
2607 	dbus_message_iter_append_basic (&iter, DBUS_TYPE_BOOLEAN, &res);
2608 
2609 	if (!dbus_connection_send (connection, reply, NULL))
2610 		DIE (("No memory"));
2611 
2612 	dbus_message_unref (reply);
2613 	return DBUS_HANDLER_RESULT_HANDLED;
2614 }
2615 
2616 
2617 static DBusHandlerResult
device_emit_condition(DBusConnection * connection,DBusMessage * message,dbus_bool_t local_interface)2618 device_emit_condition (DBusConnection * connection, DBusMessage * message, dbus_bool_t local_interface)
2619 {
2620 	const char *udi;
2621 	HalDevice *device;
2622 	DBusMessageIter iter;
2623 	DBusMessage *reply;
2624 	DBusError error;
2625 	const char *condition_name;
2626 	const char *condition_details;
2627 	dbus_bool_t res;
2628 
2629 	HAL_TRACE (("entering"));
2630 
2631 	udi = dbus_message_get_path (message);
2632 
2633 	if (!local_interface) {
2634 		raise_permission_denied (connection, message, "EmitCondition: only allowed for helpers");
2635 		return DBUS_HANDLER_RESULT_HANDLED;
2636 	}
2637 
2638 	HAL_DEBUG (("udi=%s", udi));
2639 
2640 	dbus_error_init (&error);
2641 	if (!dbus_message_get_args (message, &error,
2642 				    DBUS_TYPE_STRING, &condition_name,
2643 				    DBUS_TYPE_STRING, &condition_details,
2644 				    DBUS_TYPE_INVALID)) {
2645 		raise_syntax (connection, message, "EmitCondition");
2646 		return DBUS_HANDLER_RESULT_HANDLED;
2647 	}
2648 
2649 
2650 	device = hal_device_store_find (hald_get_gdl (), udi);
2651 	if (device == NULL)
2652 		device = hal_device_store_find (hald_get_tdl (), udi);
2653 
2654 	if (device == NULL) {
2655 		raise_no_such_device (connection, message, udi);
2656 		return DBUS_HANDLER_RESULT_HANDLED;
2657 	}
2658 
2659 	device_send_signal_condition (device, condition_name, condition_details);
2660 
2661 	res = TRUE;
2662 
2663 	reply = dbus_message_new_method_return (message);
2664 	if (reply == NULL)
2665 		DIE (("No memory"));
2666 	dbus_message_iter_init_append (reply, &iter);
2667 	dbus_message_iter_append_basic (&iter, DBUS_TYPE_BOOLEAN, &res);
2668 
2669 	if (!dbus_connection_send (connection, reply, NULL))
2670 		DIE (("No memory"));
2671 
2672 	dbus_message_unref (reply);
2673 	return DBUS_HANDLER_RESULT_HANDLED;
2674 }
2675 
2676 typedef struct
2677 {
2678 	DBusConnection  *connection;
2679 	char            *interface_name;
2680 	char            *introspection_xml;
2681 	char            *udi;
2682 } HelperInterfaceHandler;
2683 
2684 static GSList *helper_interface_handlers = NULL;
2685 
2686 static DBusHandlerResult
device_claim_interface(DBusConnection * connection,DBusMessage * message,dbus_bool_t local_interface)2687 device_claim_interface (DBusConnection * connection, DBusMessage * message, dbus_bool_t local_interface)
2688 {
2689 	const char *udi;
2690 	HalDevice *device;
2691 	DBusMessageIter iter;
2692 	DBusMessage *reply;
2693 	DBusError error;
2694 	const char *interface_name;
2695 	const char *introspection_xml;
2696 	dbus_bool_t res;
2697 
2698 	HAL_TRACE (("entering"));
2699 
2700 	udi = dbus_message_get_path (message);
2701 
2702 	if (!local_interface) {
2703 		raise_permission_denied (connection, message, "ClaimInterface: only allowed for helpers");
2704 		return DBUS_HANDLER_RESULT_HANDLED;
2705 	}
2706 
2707 	HAL_DEBUG (("udi=%s", udi));
2708 
2709 	dbus_error_init (&error);
2710 	if (!dbus_message_get_args (message, &error,
2711 				    DBUS_TYPE_STRING, &interface_name,
2712 				    DBUS_TYPE_STRING, &introspection_xml,
2713 				    DBUS_TYPE_INVALID)) {
2714 		raise_syntax (connection, message, "ClaimInterface");
2715 		return DBUS_HANDLER_RESULT_HANDLED;
2716 	}
2717 
2718 	device = hal_device_store_find (hald_get_gdl (), udi);
2719 	if (device == NULL)
2720 		device = hal_device_store_find (hald_get_tdl (), udi);
2721 
2722 	if (device == NULL) {
2723 		raise_no_such_device (connection, message, udi);
2724 		return DBUS_HANDLER_RESULT_HANDLED;
2725 	}
2726 
2727 	res = TRUE;
2728 
2729 	HAL_INFO (("Local connection 0x%x to handle interface '%s' on udi '%s'",
2730 		   connection,
2731 		   interface_name,
2732 		   udi));
2733 
2734 	hal_device_property_strlist_add (device, "info.interfaces", interface_name);
2735 
2736 	HelperInterfaceHandler *hih = g_new0 (HelperInterfaceHandler, 1);
2737 	hih->connection = connection;
2738 	hih->interface_name = g_strdup (interface_name);
2739 	hih->introspection_xml = g_strdup (introspection_xml);
2740 	hih->udi = g_strdup (udi);
2741 	helper_interface_handlers = g_slist_append (helper_interface_handlers, hih);
2742 
2743 
2744 	reply = dbus_message_new_method_return (message);
2745 	if (reply == NULL)
2746 		DIE (("No memory"));
2747 	dbus_message_iter_init_append (reply, &iter);
2748 	dbus_message_iter_append_basic (&iter, DBUS_TYPE_BOOLEAN, &res);
2749 
2750 	if (!dbus_connection_send (connection, reply, NULL))
2751 		DIE (("No memory"));
2752 
2753 	dbus_message_unref (reply);
2754 	return DBUS_HANDLER_RESULT_HANDLED;
2755 }
2756 
2757 
2758 
2759 static DBusHandlerResult
addon_is_ready(DBusConnection * connection,DBusMessage * message,dbus_bool_t local_interface)2760 addon_is_ready (DBusConnection * connection, DBusMessage * message, dbus_bool_t local_interface)
2761 {
2762 	const char *udi;
2763 	HalDevice *device;
2764 	DBusMessageIter iter;
2765 	DBusMessage *reply;
2766 	DBusError error;
2767 	dbus_bool_t res;
2768 
2769 	HAL_TRACE (("entering"));
2770 
2771 	udi = dbus_message_get_path (message);
2772 
2773 	if (!local_interface) {
2774 		raise_permission_denied (connection, message, "AddonIsReady: only allowed for helpers");
2775 		return DBUS_HANDLER_RESULT_HANDLED;
2776 	}
2777 
2778 	HAL_DEBUG (("udi=%s", udi));
2779 
2780 	dbus_error_init (&error);
2781 	if (!dbus_message_get_args (message, &error,
2782 				    DBUS_TYPE_INVALID)) {
2783 		raise_syntax (connection, message, "AddonIsReady");
2784 		return DBUS_HANDLER_RESULT_HANDLED;
2785 	}
2786 
2787 	device = hal_device_store_find (hald_get_gdl (), udi);
2788 	if (device == NULL)
2789 		device = hal_device_store_find (hald_get_tdl (), udi);
2790 
2791 	if (device == NULL) {
2792 		raise_no_such_device (connection, message, udi);
2793 		return DBUS_HANDLER_RESULT_HANDLED;
2794 	}
2795 
2796 	if (hal_device_inc_num_ready_addons (device)) {
2797 		if (hal_device_are_all_addons_ready (device)) {
2798 			manager_send_signal_device_added (device);
2799 		}
2800 	}
2801 
2802 	res = TRUE;
2803 
2804 	HAL_INFO (("AddonIsReady on udi '%s'", udi));
2805 
2806 	reply = dbus_message_new_method_return (message);
2807 	if (reply == NULL)
2808 		DIE (("No memory"));
2809 	dbus_message_iter_init_append (reply, &iter);
2810 	dbus_message_iter_append_basic (&iter, DBUS_TYPE_BOOLEAN, &res);
2811 
2812 	if (!dbus_connection_send (connection, reply, NULL))
2813 		DIE (("No memory"));
2814 
2815 	dbus_message_unref (reply);
2816 	return DBUS_HANDLER_RESULT_HANDLED;
2817 }
2818 
2819 
2820 /*
2821  * Create new device in tdl. Return temporary udi.
2822  */
2823 DBusHandlerResult
manager_new_device(DBusConnection * connection,DBusMessage * message,dbus_bool_t local_interface)2824 manager_new_device (DBusConnection * connection, DBusMessage * message, dbus_bool_t local_interface)
2825 {
2826 	DBusMessage *reply;
2827 	DBusMessageIter iter;
2828 	DBusError error;
2829 	HalDevice *d;
2830 	gchar *udi;
2831 	int i;
2832 	struct timeval tv;
2833 
2834 	dbus_error_init (&error);
2835 
2836 	if (!local_interface && !sender_has_privileges (connection, message)) {
2837 		raise_permission_denied (connection, message, "NewDevice: not privileged");
2838 		return DBUS_HANDLER_RESULT_HANDLED;
2839 	}
2840 
2841 	reply = dbus_message_new_method_return (message);
2842 	if (reply == NULL)
2843 		DIE (("No memory"));
2844 
2845 	dbus_message_iter_init_append (reply, &iter);
2846 	d = hal_device_new ();
2847 
2848 	gettimeofday(&tv, NULL);
2849 	for (i = 0; i < 1000000 ; i++) {
2850 		udi = g_strdup_printf ("/org/freedesktop/Hal/devices/tmp%05x", ((unsigned) tv.tv_usec & 0xfffff)) + i;
2851 		if (!hal_device_store_find (hald_get_tdl (), udi)) break;
2852 		g_free (udi);
2853 		udi = NULL;
2854 	}
2855 
2856 	if (!udi) {
2857 		raise_error (connection, message, "org.freedesktop.Hal.NoSpace", "NewDevice: no space for device");
2858 		return DBUS_HANDLER_RESULT_HANDLED;
2859 	}
2860 
2861 	hal_device_set_udi (d, udi);
2862 	hal_device_property_set_string (d, "info.udi", udi);
2863 	hal_device_store_add (hald_get_tdl (), d);
2864 	dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &udi);
2865 	g_free (udi);
2866 
2867 	if (!dbus_connection_send (connection, reply, NULL))
2868 		DIE (("No memory"));
2869 
2870 	dbus_message_unref (reply);
2871 
2872 	return DBUS_HANDLER_RESULT_HANDLED;
2873 }
2874 
2875 
2876 /*
2877  * Callout helper.
2878  */
2879 static void
manager_remove_done(HalDevice * d,gpointer userdata1,gpointer userdata2)2880 manager_remove_done (HalDevice *d, gpointer userdata1, gpointer userdata2)
2881 {
2882 	HAL_INFO (("Remove callouts completed udi=%s", d->udi));
2883 
2884 	if (!hal_device_store_remove (hald_get_gdl (), d)) {
2885 		HAL_WARNING (("Error removing device"));
2886 	}
2887 }
2888 
2889 
2890 /*
2891  * Remove device. Looks in gdl and tdl.
2892  */
2893 DBusHandlerResult
manager_remove(DBusConnection * connection,DBusMessage * message,dbus_bool_t local_interface)2894 manager_remove (DBusConnection * connection, DBusMessage * message, dbus_bool_t local_interface)
2895 {
2896 	DBusMessage *reply;
2897 	DBusMessageIter iter;
2898 	DBusError error;
2899 	HalDevice *d;
2900 	char *udi;
2901 	int in_tdl = 0;
2902 
2903 	dbus_error_init (&error);
2904 
2905 	if (!local_interface && !sender_has_privileges (connection, message)) {
2906 		raise_permission_denied (connection, message, "Remove: not privileged");
2907 		return DBUS_HANDLER_RESULT_HANDLED;
2908 	}
2909 
2910 	if (!dbus_message_get_args (message, &error,
2911 				    DBUS_TYPE_STRING, &udi,
2912 				    DBUS_TYPE_INVALID)) {
2913 		raise_syntax (connection, message, "Remove");
2914 		return DBUS_HANDLER_RESULT_HANDLED;
2915 	}
2916 
2917 	reply = dbus_message_new_method_return (message);
2918 	if (reply == NULL)
2919 		DIE (("No memory"));
2920 
2921 	dbus_message_iter_init_append (reply, &iter);
2922 
2923 	d = hal_device_store_find (hald_get_gdl (), udi);
2924 	if (d == NULL) {
2925 		hal_device_store_find (hald_get_tdl (), udi);
2926 		in_tdl = 1;
2927 	}
2928 	if (d == NULL) {
2929 		raise_no_such_device (connection, message, udi);
2930 		return DBUS_HANDLER_RESULT_HANDLED;
2931 	}
2932 
2933 	/* FIXME:
2934 	 * run "info.callouts.remove" ?
2935 	 * delete in gdl ?
2936 	 * (auto) stop "info.addons" ?
2937 	 */
2938 
2939 	if (!in_tdl) {
2940 		hal_util_callout_device_remove (d, manager_remove_done, NULL, NULL);
2941 	}
2942 
2943 	hal_device_store_remove (in_tdl ? hald_get_tdl () : hald_get_gdl (), d);
2944 	g_object_unref (d);
2945 
2946 	if (!dbus_connection_send (connection, reply, NULL))
2947 		DIE (("No memory"));
2948 
2949 	dbus_message_unref (reply);
2950 
2951 	return DBUS_HANDLER_RESULT_HANDLED;
2952 }
2953 
2954 
2955 /*
2956  * Callout helper.
2957  */
2958 static void
manager_commit_done(HalDevice * d,gpointer userdata1,gpointer userdata2)2959 manager_commit_done (HalDevice *d, gpointer userdata1, gpointer userdata2)
2960 {
2961 	HAL_INFO (("Add callouts completed udi=%s", d->udi));
2962 }
2963 
2964 /*
2965  * Preprobing helper.
2966  */
2967 static void
manager_commit_preprobing_done(HalDevice * d,gpointer userdata1,gpointer userdata2)2968 manager_commit_preprobing_done (HalDevice *d, gpointer userdata1, gpointer userdata2)
2969 {
2970 	if (hal_device_property_get_bool (d, "info.ignore")) {
2971 		/* Leave the device here with info.ignore==TRUE so we won't pick up children
2972 		 * Also remove category and all capabilities
2973 		 */
2974 		hal_device_property_remove (d, "info.category");
2975 		hal_device_property_remove (d, "info.capabilities");
2976 		hal_device_property_set_string (d, "info.udi", "/org/freedesktop/Hal/devices/ignored-device");
2977 		hal_device_property_set_string (d, "info.product", "Ignored Device");
2978 
2979 		HAL_INFO (("Preprobing merged info.ignore==TRUE"));
2980 
2981 		return;
2982 	}
2983 
2984 	/* Merge properties from .fdi files */
2985 	di_search_and_merge (d, DEVICE_INFO_TYPE_INFORMATION);
2986 	di_search_and_merge (d, DEVICE_INFO_TYPE_POLICY);
2987 
2988 	hal_util_callout_device_add (d, manager_commit_done, NULL, NULL);
2989 }
2990 
2991 
2992 /*
2993  * Move device from tdl to gdl. Runs helpers and callouts.
2994  */
2995 DBusHandlerResult
manager_commit_to_gdl(DBusConnection * connection,DBusMessage * message,dbus_bool_t local_interface)2996 manager_commit_to_gdl (DBusConnection * connection, DBusMessage * message, dbus_bool_t local_interface)
2997 {
2998 	DBusMessage *reply;
2999 	DBusMessageIter iter;
3000 	DBusError error;
3001 	HalDevice *d;
3002 	char udi[256], *udi0, *tmp_udi;
3003 
3004 	dbus_error_init (&error);
3005 
3006 	if (!local_interface && !sender_has_privileges (connection, message)) {
3007 		raise_permission_denied (connection, message, "CommitToGdl: not privileged");
3008 		return DBUS_HANDLER_RESULT_HANDLED;
3009 	}
3010 
3011 	if (!dbus_message_get_args (message, &error,
3012 				    DBUS_TYPE_STRING, &tmp_udi,
3013 				    DBUS_TYPE_STRING, &udi0,
3014 				    DBUS_TYPE_INVALID)) {
3015 		raise_syntax (connection, message, "CommitToGdl");
3016 		return DBUS_HANDLER_RESULT_HANDLED;
3017 	}
3018 
3019 	reply = dbus_message_new_method_return (message);
3020 	if (reply == NULL)
3021 		DIE (("No memory"));
3022 
3023 	dbus_message_iter_init_append (reply, &iter);
3024 
3025 	/* look it up in tdl */
3026 
3027 	d = hal_device_store_find (hald_get_tdl (), tmp_udi);
3028 	if (d == NULL) {
3029 		raise_no_such_device (connection, message, tmp_udi);
3030 		return DBUS_HANDLER_RESULT_HANDLED;
3031 	}
3032 
3033 	/* sanity check & avoid races */
3034 	hal_util_compute_udi (hald_get_gdl (), udi, sizeof udi, "%s", udi0);
3035 
3036 	if (hal_device_store_find (hald_get_gdl (), udi)) {
3037 		/* loose it */
3038 		hal_device_store_remove (hald_get_tdl (), d);
3039 		g_object_unref (d);
3040 		raise_error (connection, message, "org.freedesktop.Hal.DeviceExists", "CommitToGdl: Device exists: %s", udi);
3041 		return DBUS_HANDLER_RESULT_HANDLED;
3042 	}
3043 
3044 	/* set new udi */
3045 	hal_device_property_remove (d, "info.udi");
3046 	hal_device_set_udi (d, udi);
3047 	hal_device_property_set_string (d, "info.udi", udi);
3048 
3049 	/* FIXME:
3050 	 * 'RequireEnable' property?
3051 	 * fdi "preprobe"?
3052 	 * run "info.callouts.preprobe"?
3053 	 * remove "info.ignore" devices?
3054 	 * fdi "information"?
3055 	 * fdi "policy"?
3056 	 * run "info.callouts.add"?
3057 	 * tdl -> gdl?
3058 	 * (auto) start "info.addons"?
3059 	 */
3060 
3061 	/* Process preprobe fdi files */
3062 	di_search_and_merge (d, DEVICE_INFO_TYPE_PREPROBE);
3063 	hal_util_callout_device_preprobe (d, manager_commit_preprobing_done, NULL, NULL);
3064 
3065 	/* move from tdl to gdl */
3066 	hal_device_store_remove (hald_get_tdl (), d);
3067 	hal_device_store_add (hald_get_gdl (), d);
3068 
3069 	if (!dbus_connection_send (connection, reply, NULL))
3070 		DIE (("No memory"));
3071 
3072 	dbus_message_unref (reply);
3073 
3074 	return DBUS_HANDLER_RESULT_HANDLED;
3075 }
3076 
3077 typedef struct {
3078 	char *udi;
3079 	char *execpath;
3080 	char **extra_env;
3081 	char *mstdin;
3082 	char *member;
3083 	char *interface;
3084 	DBusMessage *message;
3085 	DBusConnection *connection;
3086 } MethodInvocation;
3087 
3088 static void
3089 hald_exec_method_cb (HalDevice *d, guint32 exit_type,
3090 		     gint return_code, gchar **error,
3091 		     gpointer data1, gpointer data2);
3092 
3093 
3094 static void
hald_exec_method_free_mi(MethodInvocation * mi)3095 hald_exec_method_free_mi (MethodInvocation *mi)
3096 {
3097 	/* hald_runner_run_method() assumes ownership of mi->message.. so we don't free it here */
3098 	g_free (mi->udi);
3099 	g_free (mi->execpath);
3100 	g_strfreev (mi->extra_env);
3101 	g_free (mi->mstdin);
3102 	g_free (mi->member);
3103 	g_free (mi->interface);
3104 	g_free (mi);
3105 }
3106 
3107 /* returns FALSE if we don't actually invoke anything */
3108 static gboolean
hald_exec_method_do_invocation(MethodInvocation * mi)3109 hald_exec_method_do_invocation (MethodInvocation *mi)
3110 {
3111 	gboolean ret;
3112 	HalDevice *d;
3113 
3114 	ret = FALSE;
3115 
3116 	d = hal_device_store_find (hald_get_gdl (), mi->udi);
3117 	if (d == NULL)
3118 		d = hal_device_store_find (hald_get_tdl (), mi->udi);
3119 
3120 	if (d != NULL) {
3121 		/* no timeout */
3122 		hald_runner_run_method(d,
3123 				       mi->execpath,
3124 				       mi->extra_env,
3125 				       mi->mstdin,
3126 				       TRUE,
3127 				       0,
3128 				       hald_exec_method_cb,
3129 				       (gpointer) mi->message,
3130 				       (gpointer) mi->connection);
3131 
3132 		ret = TRUE;
3133 	} else {
3134 		HAL_WARNING (("In-queue method call on non-existant device"));
3135 
3136 		raise_no_such_device (mi->connection, mi->message, mi->udi);
3137 	}
3138 
3139 	return ret;
3140 }
3141 
3142 
3143 static GHashTable *udi_to_method_queue = NULL;
3144 
3145 
3146 gboolean
device_is_executing_method(HalDevice * d,const char * interface_name,const char * method_name)3147 device_is_executing_method (HalDevice *d, const char *interface_name, const char *method_name)
3148 {
3149 	gpointer origkey;
3150 	gboolean ret;
3151 	GList *queue;
3152 
3153 	ret = FALSE;
3154 
3155 	if (g_hash_table_lookup_extended (udi_to_method_queue, d->udi, &origkey, (gpointer) &queue)) {
3156 
3157 		if (queue != NULL) {
3158 			MethodInvocation *mi;
3159 			mi = (MethodInvocation *) queue->data;
3160 			if ((strcmp (mi->interface, interface_name) == 0) &&
3161 			    (strcmp (mi->member, method_name) == 0)) {
3162 				ret = TRUE;
3163 			}
3164 		}
3165 
3166 		ret = TRUE;
3167 	}
3168 	return ret;
3169 }
3170 
3171 static void
3172 hald_exec_method_process_queue (const char *udi);
3173 
3174 static void
hald_exec_method_enqueue(MethodInvocation * mi)3175 hald_exec_method_enqueue (MethodInvocation *mi)
3176 {
3177 	gpointer origkey;
3178 	GList *queue;
3179 
3180 	if (udi_to_method_queue == NULL) {
3181 		udi_to_method_queue = g_hash_table_new_full (g_str_hash,
3182 							     g_str_equal,
3183 							     g_free,
3184 							     NULL);
3185 	}
3186 
3187 	if (g_hash_table_lookup_extended (udi_to_method_queue, mi->udi, &origkey, (gpointer) &queue)) {
3188 		HAL_INFO (("enqueue"));
3189 		queue = g_list_append (queue, mi);
3190 		g_hash_table_replace (udi_to_method_queue, g_strdup (mi->udi), queue);
3191 	} else {
3192 		HAL_INFO (("no need to enqueue"));
3193 		queue = g_list_append (NULL, mi);
3194 		g_hash_table_insert (udi_to_method_queue, g_strdup (mi->udi), queue);
3195 
3196 		hald_exec_method_do_invocation (mi);
3197 	}
3198 }
3199 
3200 
3201 static void
hald_exec_method_process_queue(const char * udi)3202 hald_exec_method_process_queue (const char *udi)
3203 {
3204 	gpointer origkey;
3205 	GList *queue;
3206 	MethodInvocation *mi;
3207 
3208 	if (g_hash_table_lookup_extended (udi_to_method_queue, udi, &origkey, (gpointer) &queue)) {
3209 
3210 		/* clean the top of the list */
3211 		if (queue != NULL) {
3212 			mi = (MethodInvocation *) queue->data;
3213 			queue = g_list_delete_link (queue, queue);
3214 			if (queue == NULL) {
3215 				g_hash_table_remove (udi_to_method_queue, udi);
3216 				HAL_INFO (("No more methods in queue"));
3217 			}
3218 
3219 			/* if method was Volume.Unmount() then refresh mount state */
3220 			if (strcmp (mi->interface, "org.freedesktop.Hal.Device.Volume") == 0 &&
3221 			    strcmp (mi->member, "Unmount") == 0) {
3222 				HalDevice *d;
3223 
3224 				HAL_INFO (("Refreshing mount state for %s since Unmount() completed", mi->udi));
3225 
3226 				d = hal_device_store_find (hald_get_gdl (), mi->udi);
3227 				if (d == NULL) {
3228 					d = hal_device_store_find (hald_get_tdl (), mi->udi);
3229 				}
3230 
3231 				if (d != NULL) {
3232 					osspec_refresh_mount_state_for_block_device (d);
3233 				} else {
3234 					HAL_WARNING ((" Cannot find device object for %s", mi->udi));
3235 				}
3236 			}
3237 
3238 			hald_exec_method_free_mi (mi);
3239 		}
3240 
3241 		/* process the rest of the list */
3242 		if (queue != NULL) {
3243 			HAL_INFO (("Execing next method in queue"));
3244 			g_hash_table_replace (udi_to_method_queue, g_strdup (udi), queue);
3245 
3246 			mi = (MethodInvocation *) queue->data;
3247 			if (!hald_exec_method_do_invocation (mi)) {
3248 				/* the device went away before we got to it... */
3249 				hald_exec_method_process_queue (mi->udi);
3250 			}
3251 		}
3252 	}
3253 }
3254 
3255 static void
hald_exec_method_cb(HalDevice * d,guint32 exit_type,gint return_code,gchar ** error,gpointer data1,gpointer data2)3256 hald_exec_method_cb (HalDevice *d, guint32 exit_type,
3257 		     gint return_code, gchar **error,
3258 		     gpointer data1, gpointer data2)
3259 {
3260 	dbus_int32_t result;
3261 	DBusMessage *reply = NULL;
3262 	DBusMessage *message;
3263 	DBusMessageIter iter;
3264 	DBusConnection *conn;
3265 	gchar *exp_name = NULL;
3266 	gchar *exp_detail = NULL;
3267 	gboolean invalid_name = FALSE;
3268 
3269 	hald_exec_method_process_queue (d->udi);
3270 
3271 	message = (DBusMessage *) data1;
3272 	conn = (DBusConnection *) data2;
3273 
3274 	if (exit_type == HALD_RUN_SUCCESS && error != NULL &&
3275 	    error[0] != NULL && error[1] != NULL) {
3276 		exp_name = error[0];
3277 		if (error[0] != NULL) {
3278 			exp_detail = error[1];
3279 		}
3280 		HAL_INFO (("failed with '%s' '%s'", exp_name, exp_detail));
3281 	}
3282 
3283 	if (exit_type != HALD_RUN_SUCCESS) {
3284 		reply = dbus_message_new_error (message, "org.freedesktop.Hal.Device.UnknownError", "An unknown error occured");
3285 		if (conn != NULL) {
3286 			if (!dbus_connection_send (conn, reply, NULL))
3287 				DIE (("No memory"));
3288 		}
3289 		dbus_message_unref (reply);
3290 	} else if (exp_name != NULL && exp_detail != NULL) {
3291 		if (!is_valid_interface_name (exp_name)) {
3292 			/*
3293 			 * error name may be invalid,
3294 			 * if so we need a generic HAL error name;
3295 			 * otherwise, dbus will be messed up.
3296 			 */
3297 			invalid_name = TRUE;
3298 			exp_detail = g_strconcat (exp_name, " \n ", exp_detail, (void *)NULL);
3299 			exp_name = "org.freedesktop.Hal.Device.UnknownError";
3300 		}
3301 		reply = dbus_message_new_error (message, exp_name, exp_detail);
3302 		if (reply == NULL) {
3303 			/* error name may be invalid - assume caller fucked up and use a generic HAL error name */
3304 			reply = dbus_message_new_error (message, "org.freedesktop.Hal.Device.UnknownError", "An unknown error occured");
3305 			if (reply == NULL) {
3306 				DIE (("No memory"));
3307 			}
3308 		}
3309 		if (conn != NULL) {
3310 			if (!dbus_connection_send (conn, reply, NULL))
3311 				DIE (("No memory"));
3312 		}
3313 		dbus_message_unref (reply);
3314 
3315 	} else {
3316 		result = (dbus_int32_t) return_code;
3317 
3318 		reply = dbus_message_new_method_return (message);
3319 		if (reply == NULL)
3320 			DIE (("No memory"));
3321 
3322 		dbus_message_iter_init_append (reply, &iter);
3323 		dbus_message_iter_append_basic (&iter, DBUS_TYPE_INT32, &result);
3324 
3325 		if (conn != NULL) {
3326 			if (!dbus_connection_send (conn, reply, NULL))
3327 				DIE (("No memory"));
3328 		}
3329 
3330 		dbus_message_unref (reply);
3331 	}
3332 
3333 	if (invalid_name)
3334 		g_free (exp_detail);
3335 	dbus_message_unref (message);
3336 }
3337 
3338 static DBusHandlerResult
hald_exec_method(HalDevice * d,DBusConnection * connection,dbus_bool_t local_interface,DBusMessage * message,const char * execpath)3339 hald_exec_method (HalDevice *d, DBusConnection *connection, dbus_bool_t local_interface,
3340 		  DBusMessage *message, const char *execpath)
3341 {
3342 	int type;
3343 	GString *stdin_str;
3344 	DBusMessageIter iter;
3345 	char *extra_env[3];
3346 	char uid_export[128];
3347 	char sender_export[128];
3348 	MethodInvocation *mi;
3349 
3350 	/* add calling uid */
3351 	extra_env[0] = NULL;
3352 	extra_env[1] = NULL;
3353 	if (local_interface) {
3354 		extra_env[0] = "HAL_METHOD_INVOKED_BY_UID=0";
3355 		extra_env[1] = "HAL_METHOD_INVOKED_BY_SYSTEMBUS_CONNECTION_NAME=0";
3356 	} else {
3357 		const char *sender;
3358 
3359 		sender = dbus_message_get_sender (message);
3360 		if (sender != NULL) {
3361 			DBusError error;
3362 			unsigned long uid;
3363 
3364 			dbus_error_init (&error);
3365 			uid = dbus_bus_get_unix_user (connection, sender, &error);
3366 			if (!dbus_error_is_set (&error)) {
3367 				sprintf (uid_export, "HAL_METHOD_INVOKED_BY_UID=%lu", uid);
3368 				extra_env[0] = uid_export;
3369 			}
3370 			snprintf (sender_export, sizeof (sender_export),
3371 				  "HAL_METHOD_INVOKED_BY_SYSTEMBUS_CONNECTION_NAME=%s", sender);
3372 			extra_env[1] = sender_export;
3373 		}
3374 	}
3375 
3376 	if (extra_env[0] == NULL)
3377 		extra_env[0] = "HAL_METHOD_INVOKED_BY_UID=nobody";
3378 	if (extra_env[1] == NULL)
3379 		extra_env[1] = "HAL_METHOD_INVOKED_BY_SYSTEMBUS_CONNECTION_NAME=0";
3380 
3381 
3382 	extra_env[2] = NULL;
3383 
3384 	/* prepare stdin with parameters */
3385 	stdin_str = g_string_sized_new (256); /* default size for passing params; can grow */
3386 	dbus_message_iter_init (message, &iter);
3387 	while ((type = dbus_message_iter_get_arg_type (&iter)) != DBUS_TYPE_INVALID) {
3388 		switch (type) {
3389 		case DBUS_TYPE_BYTE:
3390 		{
3391 			unsigned char value;
3392 			dbus_message_iter_get_basic (&iter, &value);
3393 			g_string_append_printf (stdin_str, "%u", value);
3394 			break;
3395 		}
3396 		case DBUS_TYPE_INT16:
3397 		{
3398 			dbus_int16_t value;
3399 			dbus_message_iter_get_basic (&iter, &value);
3400 			g_string_append_printf (stdin_str, "%d", value);
3401 			break;
3402 		}
3403 		case DBUS_TYPE_UINT16:
3404 		{
3405 			dbus_uint16_t value;
3406 			dbus_message_iter_get_basic (&iter, &value);
3407 			g_string_append_printf (stdin_str, "%u", value);
3408 			break;
3409 		}
3410 		case DBUS_TYPE_INT32:
3411 		{
3412 			dbus_int32_t value;
3413 			dbus_message_iter_get_basic (&iter, &value);
3414 			g_string_append_printf (stdin_str, "%d", value);
3415 			break;
3416 		}
3417 		case DBUS_TYPE_UINT32:
3418 		{
3419 			dbus_uint32_t value;
3420 			dbus_message_iter_get_basic (&iter, &value);
3421 			g_string_append_printf (stdin_str, "%u", value);
3422 			break;
3423 		}
3424 		case DBUS_TYPE_INT64:
3425 		{
3426 			dbus_int64_t value;
3427 			dbus_message_iter_get_basic (&iter, &value);
3428 			g_string_append_printf (stdin_str, "%lld", (long long int) value);
3429 			break;
3430 		}
3431 		case DBUS_TYPE_UINT64:
3432 		{
3433 			dbus_uint64_t value;
3434 			dbus_message_iter_get_basic (&iter, &value);
3435 			g_string_append_printf (stdin_str, "%llu", (long long unsigned int) value);
3436 			break;
3437 		}
3438 		case DBUS_TYPE_DOUBLE:
3439 		{
3440 			double value;
3441 			dbus_message_iter_get_basic (&iter, &value);
3442 			g_string_append_printf (stdin_str, "%g", value);
3443 			break;
3444 		}
3445 		case DBUS_TYPE_BOOLEAN:
3446 		{
3447 			dbus_bool_t value;
3448 			dbus_message_iter_get_basic (&iter, &value);
3449 			g_string_append (stdin_str, value ? "true" : "false");
3450 			break;
3451 		}
3452 		case DBUS_TYPE_STRING:
3453 		{
3454 			char *value;
3455 			dbus_message_iter_get_basic (&iter, &value);
3456 			g_string_append (stdin_str, value);
3457 			break;
3458 		}
3459 
3460 		case DBUS_TYPE_ARRAY:
3461 		{
3462 			DBusMessageIter iter_strlist;
3463 			if (dbus_message_iter_get_element_type (&iter) != DBUS_TYPE_STRING)
3464 				goto error;
3465 
3466 			dbus_message_iter_recurse (&iter, &iter_strlist);
3467 			while (dbus_message_iter_get_arg_type (&iter_strlist) == DBUS_TYPE_STRING) {
3468 				const char *value;
3469 				dbus_message_iter_get_basic (&iter_strlist, &value);
3470 				g_string_append (stdin_str, value);
3471 				g_string_append (stdin_str, "\t");
3472 				dbus_message_iter_next(&iter_strlist);
3473 			}
3474 			break;
3475 		}
3476 
3477 		default:
3478 			goto error;
3479 		}
3480 
3481 		g_string_append_c (stdin_str, '\n');
3482 		dbus_message_iter_next (&iter);
3483 	}
3484 
3485 	mi = g_new0 (MethodInvocation, 1);
3486 	mi->udi = g_strdup (d->udi);
3487 	mi->execpath = g_strdup (execpath);
3488 	mi->extra_env = g_strdupv (extra_env);
3489 	mi->mstdin = g_strdup (stdin_str->str);
3490 	mi->message = message;
3491 	mi->connection = connection;
3492 	mi->member = g_strdup (dbus_message_get_member (message));
3493 	mi->interface = g_strdup (dbus_message_get_interface (message));
3494 	hald_exec_method_enqueue (mi);
3495 
3496 	dbus_message_ref (message);
3497 	g_string_free (stdin_str, TRUE);
3498 
3499 	return DBUS_HANDLER_RESULT_HANDLED;
3500 
3501 error:
3502 	g_string_free (stdin_str, TRUE);
3503 	return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
3504 }
3505 
3506 static gboolean
foreach_device_get_xml_node(HalDeviceStore * store,HalDevice * device,gpointer user_data)3507 foreach_device_get_xml_node (HalDeviceStore *store, HalDevice *device,
3508 			     gpointer user_data)
3509 {
3510 	GString *xml = user_data;
3511 	const char *udi, *name;
3512 
3513 	udi = hal_device_get_udi (device);
3514 	name = strrchr(udi, '/')+1;
3515 
3516 	xml = g_string_append(xml, "  <node name=\"");
3517 	xml = g_string_append(xml, name);
3518 	xml = g_string_append(xml, "\"/>\n");
3519 
3520 	return TRUE;
3521 }
3522 
3523 static DBusHandlerResult
do_introspect(DBusConnection * connection,DBusMessage * message,dbus_bool_t local_interface)3524 do_introspect (DBusConnection  *connection,
3525 	       DBusMessage     *message,
3526 	       dbus_bool_t      local_interface)
3527 {
3528 	const char *path;
3529 	DBusMessage *reply;
3530 	GString *xml;
3531 	char *xml_string;
3532 
3533 	HAL_TRACE (("entering do_introspect"));
3534 
3535 	path = dbus_message_get_path (message);
3536 
3537 	xml = g_string_new ("<!DOCTYPE node PUBLIC \"-//freedesktop//DTD D-BUS Object Introspection 1.0//EN\"\n"
3538 			    "\"http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd\">\n"
3539 			    "<node>\n"
3540 			    "  <interface name=\"org.freedesktop.DBus.Introspectable\">\n"
3541 			    "    <method name=\"Introspect\">\n"
3542 			    "      <arg name=\"data\" direction=\"out\" type=\"s\"/>\n"
3543 			    "    </method>\n"
3544 			    "  </interface>\n");
3545 
3546 	if (strcmp (path, "/") == 0) {
3547 
3548 		xml = g_string_append (xml,
3549 				       "  <node name=\"org\"/>\n");
3550 
3551 	} else if (strcmp (path, "/org") == 0) {
3552 
3553