xref: /illumos-gate/usr/src/cmd/hal/hald/device.c (revision bd0f52d78d701efcad2c460df61b45677d041c35)
1 /***************************************************************************
2  * CVSID: $Id$
3  *
4  * device.c : HalDevice methods
5  *
6  * Copyright (C) 2003 David Zeuthen, <david@fubar.dk>
7  * Copyright (C) 2004 Novell, Inc.
8  *
9  * Licensed under the Academic Free License version 2.1
10  *
11  * This program is free software; you can redistribute it and/or modify
12  * it under the terms of the GNU General Public License as published by
13  * the Free Software Foundation; either version 2 of the License, or
14  * (at your option) any later version.
15  *
16  * This program is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19  * GNU General Public License for more details.
20  *
21  * You should have received a copy of the GNU General Public License
22  * along with this program; if not, write to the Free Software
23  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
24  *
25  **************************************************************************/
26 
27 #ifdef HAVE_CONFIG_H
28 #  include <config.h>
29 #endif
30 
31 #include <stdio.h>
32 #include <string.h>
33 
34 #include "hald.h"
35 #include "device.h"
36 #include "hald_marshal.h"
37 #include "logger.h"
38 #include "hald_runner.h"
39 
40 static GObjectClass *parent_class;
41 
42 enum {
43 	PROPERTY_CHANGED,
44 	CAPABILITY_ADDED,
45 	CALLOUTS_FINISHED,
46 	CANCELLED,
47 	LAST_SIGNAL
48 };
49 
50 static guint signals[LAST_SIGNAL] = { 0 };
51 
52 #ifdef HALD_MEMLEAK_DBG
53 int dbg_hal_device_object_delta = 0;
54 #endif
55 
56 static void
57 hal_device_finalize (GObject *obj)
58 {
59 	HalDevice *device = HAL_DEVICE (obj);
60 
61 	runner_device_finalized (device);
62 
63 #ifdef HALD_MEMLEAK_DBG
64 	dbg_hal_device_object_delta--;
65 	printf ("************* in finalize for udi=%s\n", device->udi);
66 #endif
67 
68 
69 	g_slist_foreach (device->properties, (GFunc) hal_property_free, NULL);
70 
71 	g_free (device->udi);
72 
73 	if (parent_class->finalize)
74 		parent_class->finalize (obj);
75 
76 }
77 
78 static void
79 hal_device_class_init (HalDeviceClass *klass)
80 {
81 	GObjectClass *obj_class = (GObjectClass *) klass;
82 
83 	parent_class = g_type_class_peek_parent (klass);
84 
85 	obj_class->finalize = hal_device_finalize;
86 
87 	signals[PROPERTY_CHANGED] =
88 		g_signal_new ("property_changed",
89 			      G_TYPE_FROM_CLASS (klass),
90 			      G_SIGNAL_RUN_LAST,
91 			      G_STRUCT_OFFSET (HalDeviceClass,
92 					       property_changed),
93 			      NULL, NULL,
94 			      hald_marshal_VOID__STRING_BOOL_BOOL,
95 			      G_TYPE_NONE, 3,
96 			      G_TYPE_STRING,
97 			      G_TYPE_BOOLEAN,
98 			      G_TYPE_BOOLEAN);
99 
100 	signals[CAPABILITY_ADDED] =
101 		g_signal_new ("capability_added",
102 			      G_TYPE_FROM_CLASS (klass),
103 			      G_SIGNAL_RUN_LAST,
104 			      G_STRUCT_OFFSET (HalDeviceClass,
105 					       capability_added),
106 			      NULL, NULL,
107 			      hald_marshal_VOID__STRING,
108 			      G_TYPE_NONE, 1,
109 			      G_TYPE_STRING);
110 
111 	signals[CALLOUTS_FINISHED] =
112 		g_signal_new ("callouts_finished",
113 			      G_TYPE_FROM_CLASS (klass),
114 			      G_SIGNAL_RUN_LAST,
115 			      G_STRUCT_OFFSET (HalDeviceClass,
116 					       callouts_finished),
117 			      NULL, NULL,
118 			      hald_marshal_VOID__VOID,
119 			      G_TYPE_NONE, 0);
120 
121 	signals[CANCELLED] =
122 		g_signal_new ("cancelled",
123 			      G_TYPE_FROM_CLASS (klass),
124 			      G_SIGNAL_RUN_LAST,
125 			      G_STRUCT_OFFSET (HalDeviceClass,
126 					       cancelled),
127 			      NULL, NULL,
128 			      hald_marshal_VOID__VOID,
129 			      G_TYPE_NONE, 0);
130 }
131 
132 static void
133 hal_device_init (HalDevice *device)
134 {
135 	static int temp_device_counter = 0;
136 
137 	device->udi = g_strdup_printf ("/org/freedesktop/Hal/devices/temp/%d",
138 				       temp_device_counter++);
139 	device->num_addons = 0;
140 	device->num_addons_ready = 0;
141 }
142 
143 GType
144 hal_device_get_type (void)
145 {
146 	static GType type = 0;
147 
148 	if (!type) {
149 		static GTypeInfo type_info = {
150 			sizeof (HalDeviceClass),
151 			NULL, NULL,
152 			(GClassInitFunc) hal_device_class_init,
153 			NULL, NULL,
154 			sizeof (HalDevice),
155 			0,
156 			(GInstanceInitFunc) hal_device_init,
157 			NULL
158 		};
159 
160 		type = g_type_register_static (G_TYPE_OBJECT,
161 					       "HalDevice",
162 					       &type_info,
163 					       0);
164 	}
165 
166 	return type;
167 }
168 
169 
170 HalDevice *
171 hal_device_new (void)
172 {
173 	HalDevice *device;
174 
175 	device = g_object_new (HAL_TYPE_DEVICE, NULL, NULL);
176 
177 #ifdef HALD_MEMLEAK_DBG
178 	dbg_hal_device_object_delta++;
179 #endif
180 	return device;
181 }
182 
183 /** Merge all properties from source where the key starts with
184  *  source_namespace and put them onto target replacing source_namespace
185  *  with target_namespace
186  *
187  *  @param  target              Device to put properties onto
188  *  @param  source              Device to retrieve properties from
189  *  @param  target_namespace    Replace source namespace with this namespace
190  *  @param  source_namespace    Source namespace that property keys must match
191  */
192 void
193 hal_device_merge_with_rewrite  (HalDevice    *target,
194 				HalDevice    *source,
195 				const char   *target_namespace,
196 				const char   *source_namespace)
197 {
198 	GSList *iter;
199 	size_t source_ns_len;
200 
201 	source_ns_len = strlen (source_namespace);
202 
203 	/* doesn't handle info.capabilities */
204 
205 	/* device_property_atomic_update_begin (); */
206 
207 	for (iter = source->properties; iter != NULL; iter = iter->next) {
208 		HalProperty *p = iter->data;
209 		int type;
210 		const char *key;
211 		int target_type;
212 		gchar *target_key;
213 
214 		key = hal_property_get_key (p);
215 
216 		/* only care about properties that match source namespace */
217 		if (strncmp(key, source_namespace, source_ns_len) != 0)
218 			continue;
219 
220 		target_key = g_strdup_printf("%s%s", target_namespace,
221 					     key+source_ns_len);
222 
223 		type = hal_property_get_type (p);
224 
225 		/* only remove target if it exists with a different type */
226 		target_type = hal_device_property_get_type (target, key);
227 		if (target_type != HAL_PROPERTY_TYPE_INVALID && target_type != type)
228 			hal_device_property_remove (target, key);
229 
230 		switch (type) {
231 
232 		case HAL_PROPERTY_TYPE_STRING:
233 			hal_device_property_set_string (
234 				target, target_key,
235 				hal_property_get_string (p));
236 			break;
237 
238 		case HAL_PROPERTY_TYPE_INT32:
239 			hal_device_property_set_int (
240 				target, target_key,
241 				hal_property_get_int (p));
242 			break;
243 
244 		case HAL_PROPERTY_TYPE_UINT64:
245 			hal_device_property_set_uint64 (
246 				target, target_key,
247 				hal_property_get_uint64 (p));
248 			break;
249 
250 		case HAL_PROPERTY_TYPE_BOOLEAN:
251 			hal_device_property_set_bool (
252 				target, target_key,
253 				hal_property_get_bool (p));
254 			break;
255 
256 		case HAL_PROPERTY_TYPE_DOUBLE:
257 			hal_device_property_set_double (
258 				target, target_key,
259 				hal_property_get_double (p));
260 			break;
261 
262 		default:
263 			HAL_WARNING (("Unknown property type %d", type));
264 			break;
265 		}
266 
267 		g_free (target_key);
268 	}
269 
270 	/* device_property_atomic_update_end (); */
271 
272 }
273 
274 void
275 hal_device_merge (HalDevice *target, HalDevice *source)
276 {
277 	GSList *iter;
278 	GSList *caps;
279 
280 	/* device_property_atomic_update_begin (); */
281 
282 	for (iter = source->properties; iter != NULL; iter = iter->next) {
283 		HalProperty *p = iter->data;
284 		int type;
285 		const char *key;
286 		int target_type;
287 
288 		key = hal_property_get_key (p);
289 		type = hal_property_get_type (p);
290 
291 		/* handle info.capabilities in a special way */
292 		if (strcmp (key, "info.capabilities") == 0)
293 			continue;
294 
295 		/* only remove target if it exists with a different type */
296 		target_type = hal_device_property_get_type (target, key);
297 		if (target_type != HAL_PROPERTY_TYPE_INVALID && target_type != type)
298 			hal_device_property_remove (target, key);
299 
300 		switch (type) {
301 
302 		case HAL_PROPERTY_TYPE_STRING:
303 			hal_device_property_set_string (
304 				target, key,
305 				hal_property_get_string (p));
306 			break;
307 
308 		case HAL_PROPERTY_TYPE_INT32:
309 			hal_device_property_set_int (
310 				target, key,
311 				hal_property_get_int (p));
312 			break;
313 
314 		case HAL_PROPERTY_TYPE_UINT64:
315 			hal_device_property_set_uint64 (
316 				target, key,
317 				hal_property_get_uint64 (p));
318 			break;
319 
320 		case HAL_PROPERTY_TYPE_BOOLEAN:
321 			hal_device_property_set_bool (
322 				target, key,
323 				hal_property_get_bool (p));
324 			break;
325 
326 		case HAL_PROPERTY_TYPE_DOUBLE:
327 			hal_device_property_set_double (
328 				target, key,
329 				hal_property_get_double (p));
330 			break;
331 
332 		default:
333 			HAL_WARNING (("Unknown property type %d", type));
334 			break;
335 		}
336 	}
337 
338 	/* device_property_atomic_update_end (); */
339 
340 	caps = hal_device_property_get_strlist (source, "info.capabilities");
341 	for (iter = caps; iter != NULL; iter = iter->next) {
342 		if (!hal_device_has_capability (target, iter->data))
343 			hal_device_add_capability (target, iter->data);
344 	}
345 }
346 
347 gboolean
348 hal_device_matches (HalDevice *device1, HalDevice *device2,
349 		    const char *namespace)
350 {
351 	int len;
352 	GSList *iter;
353 
354 	len = strlen (namespace);
355 
356 	for (iter = device1->properties; iter != NULL; iter = iter->next) {
357 		HalProperty *p;
358 		const char *key;
359 		int type;
360 
361 		p = (HalProperty *) iter->data;
362 		key = hal_property_get_key (p);
363 		type = hal_property_get_type (p);
364 
365 		if (strncmp (key, namespace, len) != 0)
366 			continue;
367 
368 		if (!hal_device_has_property (device2, key))
369 			return FALSE;
370 
371 		switch (type) {
372 
373 		case HAL_PROPERTY_TYPE_STRING:
374 			if (strcmp (hal_property_get_string (p),
375 				    hal_device_property_get_string (device2,
376 								    key)) != 0)
377 				return FALSE;
378 			break;
379 
380 		case HAL_PROPERTY_TYPE_INT32:
381 			if (hal_property_get_int (p) !=
382 			    hal_device_property_get_int (device2, key))
383 				return FALSE;
384 			break;
385 
386 		case HAL_PROPERTY_TYPE_UINT64:
387 			if (hal_property_get_uint64 (p) !=
388 				hal_device_property_get_uint64 (device2, key))
389 				return FALSE;
390 			break;
391 
392 		case HAL_PROPERTY_TYPE_BOOLEAN:
393 			if (hal_property_get_bool (p) !=
394 			    hal_device_property_get_bool (device2, key))
395 				return FALSE;
396 			break;
397 
398 		case HAL_PROPERTY_TYPE_DOUBLE:
399 			if (hal_property_get_double (p) !=
400 			    hal_device_property_get_double (device2, key))
401 				return FALSE;
402 			break;
403 
404 		default:
405 			HAL_WARNING (("Unknown property type %d", type));
406 			break;
407 		}
408 	}
409 
410 	return TRUE;
411 }
412 
413 const char *
414 hal_device_get_udi (HalDevice *device)
415 {
416 	return device->udi;
417 }
418 
419 void
420 hal_device_set_udi (HalDevice *device, const char *udi)
421 {
422 	if (device->udi != NULL)
423 		g_free (device->udi);
424 	device->udi = g_strdup (udi);
425 }
426 
427 void
428 hal_device_add_capability (HalDevice *device, const char *capability)
429 {
430 	if (hal_device_property_strlist_add (device, "info.capabilities", capability))
431 		g_signal_emit (device, signals[CAPABILITY_ADDED], 0, capability);
432 }
433 
434 gboolean
435 hal_device_has_capability (HalDevice *device, const char *capability)
436 {
437 	GSList *caps;
438 	GSList *iter;
439 	gboolean matched = FALSE;
440 
441 	caps = hal_device_property_get_strlist (device, "info.capabilities");
442 
443 	if (caps == NULL)
444 		return FALSE;
445 
446 	for (iter = caps; iter != NULL; iter = iter->next) {
447 		if (strcmp (iter->data, capability) == 0) {
448 			matched = TRUE;
449 			break;
450 		}
451 	}
452 
453 	return matched;
454 }
455 
456 gboolean
457 hal_device_has_property (HalDevice *device, const char *key)
458 {
459 	g_return_val_if_fail (device != NULL, FALSE);
460 	g_return_val_if_fail (key != NULL, FALSE);
461 
462 	return hal_device_property_find (device, key) != NULL;
463 }
464 
465 int
466 hal_device_num_properties (HalDevice *device)
467 {
468 	g_return_val_if_fail (device != NULL, -1);
469 
470 	return g_slist_length (device->properties);
471 }
472 
473 HalProperty *
474 hal_device_property_find (HalDevice *device, const char *key)
475 {
476 	GSList *iter;
477 
478 	g_return_val_if_fail (device != NULL, NULL);
479 	g_return_val_if_fail (key != NULL, NULL);
480 
481 	for (iter = device->properties; iter != NULL; iter = iter->next) {
482 		HalProperty *p = iter->data;
483 
484 		if (strcmp (hal_property_get_key (p), key) == 0)
485 			return p;
486 	}
487 
488 	return NULL;
489 }
490 
491 char *
492 hal_device_property_to_string (HalDevice *device, const char *key)
493 {
494 	HalProperty *prop;
495 
496 	prop = hal_device_property_find (device, key);
497 	if (!prop)
498 		return NULL;
499 
500 	return hal_property_to_string (prop);
501 }
502 
503 void
504 hal_device_property_foreach (HalDevice *device,
505 			     HalDevicePropertyForeachFn callback,
506 			     gpointer user_data)
507 {
508 	GSList *iter;
509 
510 	g_return_if_fail (device != NULL);
511 	g_return_if_fail (callback != NULL);
512 
513 	for (iter = device->properties; iter != NULL; iter = iter->next) {
514 		HalProperty *p = iter->data;
515 		gboolean cont;
516 
517 		cont = callback (device, p, user_data);
518 
519 		if (cont == FALSE)
520 			return;
521 	}
522 }
523 
524 int
525 hal_device_property_get_type (HalDevice *device, const char *key)
526 {
527 	HalProperty *prop;
528 
529 	g_return_val_if_fail (device != NULL, HAL_PROPERTY_TYPE_INVALID);
530 	g_return_val_if_fail (key != NULL, HAL_PROPERTY_TYPE_INVALID);
531 
532 	prop = hal_device_property_find (device, key);
533 
534 	if (prop != NULL)
535 		return hal_property_get_type (prop);
536 	else
537 		return HAL_PROPERTY_TYPE_INVALID;
538 }
539 
540 const char *
541 hal_device_property_get_string (HalDevice *device, const char *key)
542 {
543 	HalProperty *prop;
544 
545 	g_return_val_if_fail (device != NULL, NULL);
546 	g_return_val_if_fail (key != NULL, NULL);
547 
548 	prop = hal_device_property_find (device, key);
549 
550 	if (prop != NULL)
551 		return hal_property_get_string (prop);
552 	else
553 		return NULL;
554 }
555 
556 const char *
557 hal_device_property_get_as_string (HalDevice *device, const char *key, char *buf, size_t bufsize)
558 {
559 	HalProperty *prop;
560 
561 	g_return_val_if_fail (device != NULL, NULL);
562 	g_return_val_if_fail (key != NULL, NULL);
563 	g_return_val_if_fail (buf != NULL, NULL);
564 
565 	prop = hal_device_property_find (device, key);
566 
567 	if (prop != NULL) {
568 		switch (hal_property_get_type (prop)) {
569 		case HAL_PROPERTY_TYPE_STRING:
570 			strncpy (buf, hal_property_get_string (prop), bufsize);
571 			break;
572 		case HAL_PROPERTY_TYPE_INT32:
573 			snprintf (buf, bufsize, "%d", hal_property_get_int (prop));
574 			break;
575 		case HAL_PROPERTY_TYPE_UINT64:
576 			snprintf (buf, bufsize, "%llu", (long long unsigned int) hal_property_get_uint64 (prop));
577 			break;
578 		case HAL_PROPERTY_TYPE_DOUBLE:
579 			snprintf (buf, bufsize, "%f", hal_property_get_double (prop));
580 			break;
581 		case HAL_PROPERTY_TYPE_BOOLEAN:
582 			strncpy (buf, hal_property_get_bool (prop) ? "true" : "false", bufsize);
583 			break;
584 
585 		case HAL_PROPERTY_TYPE_STRLIST:
586 			/* print out as "\tval1\tval2\val3\t" */
587 		        {
588 				GSList *iter;
589 				guint i;
590 
591 				if (bufsize > 0)
592 					buf[0] = '\t';
593 				i = 1;
594 				for (iter = hal_property_get_strlist (prop);
595 				     iter != NULL && i < bufsize;
596 				     iter = g_slist_next (iter)) {
597 					guint len;
598 					const char *str;
599 
600 					str = (const char *) iter->data;
601 					len = strlen (str);
602 					strncpy (buf + i, str, bufsize - i);
603 					i += len;
604 
605 					if (i < bufsize) {
606 						buf[i] = '\t';
607 						i++;
608 					}
609 				}
610 			}
611 			break;
612 		}
613 		return buf;
614 	} else {
615 		buf[0] = '\0';
616 		return NULL;
617 	}
618 }
619 
620 dbus_int32_t
621 hal_device_property_get_int (HalDevice *device, const char *key)
622 {
623 	HalProperty *prop;
624 
625 	g_return_val_if_fail (device != NULL, -1);
626 	g_return_val_if_fail (key != NULL, -1);
627 
628 	prop = hal_device_property_find (device, key);
629 
630 	if (prop != NULL)
631 		return hal_property_get_int (prop);
632 	else
633 		return -1;
634 }
635 
636 dbus_uint64_t
637 hal_device_property_get_uint64 (HalDevice *device, const char *key)
638 {
639 	HalProperty *prop;
640 
641 	g_return_val_if_fail (device != NULL, -1);
642 	g_return_val_if_fail (key != NULL, -1);
643 
644 	prop = hal_device_property_find (device, key);
645 
646 	if (prop != NULL)
647 		return hal_property_get_uint64 (prop);
648 	else
649 		return -1;
650 }
651 
652 dbus_bool_t
653 hal_device_property_get_bool (HalDevice *device, const char *key)
654 {
655 	HalProperty *prop;
656 
657 	g_return_val_if_fail (device != NULL, FALSE);
658 	g_return_val_if_fail (key != NULL, FALSE);
659 
660 	prop = hal_device_property_find (device, key);
661 
662 	if (prop != NULL)
663 		return hal_property_get_bool (prop);
664 	else
665 		return FALSE;
666 }
667 
668 double
669 hal_device_property_get_double (HalDevice *device, const char *key)
670 {
671 	HalProperty *prop;
672 
673 	g_return_val_if_fail (device != NULL, -1.0);
674 	g_return_val_if_fail (key != NULL, -1.0);
675 
676 	prop = hal_device_property_find (device, key);
677 
678 	if (prop != NULL)
679 		return hal_property_get_double (prop);
680 	else
681 		return -1.0;
682 }
683 
684 gboolean
685 hal_device_property_set_string (HalDevice *device, const char *key,
686 				const char *value)
687 {
688 	HalProperty *prop;
689 
690 	/* check if property already exists */
691 	prop = hal_device_property_find (device, key);
692 
693 	if (prop != NULL) {
694 		if (hal_property_get_type (prop) != HAL_PROPERTY_TYPE_STRING)
695 			return FALSE;
696 
697 		/* don't bother setting the same value */
698 		if (value != NULL &&
699 		    strcmp (hal_property_get_string (prop), value) == 0)
700 			return TRUE;
701 
702 		hal_property_set_string (prop, value);
703 
704 		g_signal_emit (device, signals[PROPERTY_CHANGED], 0,
705 			       key, FALSE, FALSE);
706 
707 	} else {
708 
709 		prop = hal_property_new_string (key, value);
710 
711 		device->properties = g_slist_prepend (device->properties, prop);
712 
713 		g_signal_emit (device, signals[PROPERTY_CHANGED], 0,
714 			       key, FALSE, TRUE);
715 	}
716 
717 	return TRUE;
718 }
719 
720 gboolean
721 hal_device_property_set_int (HalDevice *device, const char *key,
722 			     dbus_int32_t value)
723 {
724 	HalProperty *prop;
725 
726 	/* check if property already exists */
727 	prop = hal_device_property_find (device, key);
728 
729 	if (prop != NULL) {
730 		if (hal_property_get_type (prop) != HAL_PROPERTY_TYPE_INT32)
731 			return FALSE;
732 
733 		/* don't bother setting the same value */
734 		if (hal_property_get_int (prop) == value)
735 			return TRUE;
736 
737 		hal_property_set_int (prop, value);
738 
739 		g_signal_emit (device, signals[PROPERTY_CHANGED], 0,
740 			       key, FALSE, FALSE);
741 
742 	} else {
743 		prop = hal_property_new_int (key, value);
744 
745 		device->properties = g_slist_prepend (device->properties, prop);
746 
747 		g_signal_emit (device, signals[PROPERTY_CHANGED], 0,
748 			       key, FALSE, TRUE);
749 	}
750 
751 	return TRUE;
752 }
753 
754 gboolean
755 hal_device_property_set_uint64 (HalDevice *device, const char *key,
756 			     dbus_uint64_t value)
757 {
758 	HalProperty *prop;
759 
760 	/* check if property already exists */
761 	prop = hal_device_property_find (device, key);
762 
763 	if (prop != NULL) {
764 		if (hal_property_get_type (prop) != HAL_PROPERTY_TYPE_UINT64)
765 			return FALSE;
766 
767 		/* don't bother setting the same value */
768 		if (hal_property_get_uint64 (prop) == value)
769 			return TRUE;
770 
771 		hal_property_set_uint64 (prop, value);
772 
773 		g_signal_emit (device, signals[PROPERTY_CHANGED], 0,
774 			       key, FALSE, FALSE);
775 
776 	} else {
777 		prop = hal_property_new_uint64 (key, value);
778 
779 		device->properties = g_slist_prepend (device->properties, prop);
780 
781 		g_signal_emit (device, signals[PROPERTY_CHANGED], 0,
782 			       key, FALSE, TRUE);
783 	}
784 
785 	return TRUE;
786 }
787 
788 gboolean
789 hal_device_property_set_bool (HalDevice *device, const char *key,
790 			     dbus_bool_t value)
791 {
792 	HalProperty *prop;
793 
794 	/* check if property already exists */
795 	prop = hal_device_property_find (device, key);
796 
797 	if (prop != NULL) {
798 		if (hal_property_get_type (prop) != HAL_PROPERTY_TYPE_BOOLEAN)
799 			return FALSE;
800 
801 		/* don't bother setting the same value */
802 		if (hal_property_get_bool (prop) == value)
803 			return TRUE;
804 
805 		hal_property_set_bool (prop, value);
806 
807 		g_signal_emit (device, signals[PROPERTY_CHANGED], 0,
808 			       key, FALSE, FALSE);
809 
810 	} else {
811 		prop = hal_property_new_bool (key, value);
812 
813 		device->properties = g_slist_prepend (device->properties, prop);
814 
815 		g_signal_emit (device, signals[PROPERTY_CHANGED], 0,
816 			       key, FALSE, TRUE);
817 	}
818 
819 	return TRUE;
820 }
821 
822 gboolean
823 hal_device_property_set_double (HalDevice *device, const char *key,
824 				double value)
825 {
826 	HalProperty *prop;
827 
828 	/* check if property already exists */
829 	prop = hal_device_property_find (device, key);
830 
831 	if (prop != NULL) {
832 		if (hal_property_get_type (prop) != HAL_PROPERTY_TYPE_DOUBLE)
833 			return FALSE;
834 
835 		/* don't bother setting the same value */
836 		if (hal_property_get_double (prop) == value)
837 			return TRUE;
838 
839 		hal_property_set_double (prop, value);
840 
841 		g_signal_emit (device, signals[PROPERTY_CHANGED], 0,
842 			       key, FALSE, FALSE);
843 
844 	} else {
845 		prop = hal_property_new_double (key, value);
846 
847 		device->properties = g_slist_prepend (device->properties, prop);
848 
849 		g_signal_emit (device, signals[PROPERTY_CHANGED], 0,
850 			       key, FALSE, TRUE);
851 	}
852 
853 	return TRUE;
854 }
855 
856 gboolean
857 hal_device_copy_property (HalDevice *from_device, const char *from, HalDevice *to_device, const char *to)
858 {
859 	gboolean rc;
860 
861 	rc = FALSE;
862 
863 	if (hal_device_has_property (from_device, from)) {
864 		switch (hal_device_property_get_type (from_device, from)) {
865 		case HAL_PROPERTY_TYPE_STRING:
866 			rc = hal_device_property_set_string (
867 				to_device, to, hal_device_property_get_string (from_device, from));
868 			break;
869 		case HAL_PROPERTY_TYPE_INT32:
870 			rc = hal_device_property_set_int (
871 				to_device, to, hal_device_property_get_int (from_device, from));
872 			break;
873 		case HAL_PROPERTY_TYPE_UINT64:
874 			rc = hal_device_property_set_uint64 (
875 				to_device, to, hal_device_property_get_uint64 (from_device, from));
876 			break;
877 		case HAL_PROPERTY_TYPE_BOOLEAN:
878 			rc = hal_device_property_set_bool (
879 				to_device, to, hal_device_property_get_bool (from_device, from));
880 			break;
881 		case HAL_PROPERTY_TYPE_DOUBLE:
882 			rc = hal_device_property_set_double (
883 				to_device, to, hal_device_property_get_double (from_device, from));
884 			break;
885 		}
886 	}
887 
888 	return rc;
889 }
890 
891 gboolean
892 hal_device_property_remove (HalDevice *device, const char *key)
893 {
894 	HalProperty *prop;
895 
896 	prop = hal_device_property_find (device, key);
897 
898 	if (prop == NULL)
899 		return FALSE;
900 
901 	device->properties = g_slist_remove (device->properties, prop);
902 
903 	hal_property_free (prop);
904 
905 	g_signal_emit (device, signals[PROPERTY_CHANGED], 0,
906 		       key, TRUE, FALSE);
907 
908 	return TRUE;
909 }
910 
911 gboolean
912 hal_device_property_set_attribute (HalDevice *device,
913 				   const char *key,
914 				   enum PropertyAttribute attr,
915 				   gboolean val)
916 {
917 	HalProperty *prop;
918 
919 	prop = hal_device_property_find (device, key);
920 
921 	if (prop == NULL)
922 		return FALSE;
923 
924 	return TRUE;
925 }
926 
927 void
928 hal_device_print (HalDevice *device)
929 {
930 	GSList *iter;
931 
932         fprintf (stderr, "device udi = %s\n", hal_device_get_udi (device));
933 
934 	for (iter = device->properties; iter != NULL; iter = iter->next) {
935 		HalProperty *p = iter->data;
936                 int type;
937                 const char *key;
938 
939                 key = hal_property_get_key (p);
940                 type = hal_property_get_type (p);
941 
942                 switch (type) {
943                 case HAL_PROPERTY_TYPE_STRING:
944                         fprintf (stderr, "  %s = '%s'  (string)\n", key,
945                                 hal_property_get_string (p));
946                         break;
947 
948                 case HAL_PROPERTY_TYPE_INT32:
949                         fprintf (stderr, "  %s = %d  0x%x  (int)\n", key,
950                                 hal_property_get_int (p),
951                                 hal_property_get_int (p));
952                         break;
953 
954                 case HAL_PROPERTY_TYPE_UINT64:
955                         fprintf (stderr, "  %s = %llu  0x%llx  (uint64)\n", key,
956                                 (long long unsigned int) hal_property_get_uint64 (p),
957                                 (long long unsigned int) hal_property_get_uint64 (p));
958                         break;
959 
960                 case HAL_PROPERTY_TYPE_DOUBLE:
961                         fprintf (stderr, "  %s = %g  (double)\n", key,
962                                 hal_property_get_double (p));
963                         break;
964 
965                 case HAL_PROPERTY_TYPE_BOOLEAN:
966                         fprintf (stderr, "  %s = %s  (bool)\n", key,
967                                 (hal_property_get_bool (p) ? "true" :
968                                  "false"));
969                         break;
970 
971                 default:
972                         HAL_WARNING (("Unknown property type %d", type));
973                         break;
974                 }
975         }
976         fprintf (stderr, "\n");
977 }
978 
979 
980 typedef struct {
981 	char *key;
982 	HalDevice *device;
983 	HalDeviceAsyncCallback callback;
984 	gpointer user_data;
985 
986 	guint prop_signal_id;
987 	guint timeout_id;
988 } AsyncMatchInfo;
989 
990 static void
991 destroy_async_match_info (AsyncMatchInfo *ai)
992 {
993 	g_free (ai->key);
994 	g_signal_handler_disconnect (ai->device, ai->prop_signal_id);
995 	g_source_remove (ai->timeout_id);
996 	g_object_unref (ai->device);
997 	g_free (ai);
998 }
999 
1000 static void
1001 prop_changed_cb (HalDevice *device, const char *key,
1002 		 gboolean removed, gboolean added, gpointer user_data)
1003 {
1004 	AsyncMatchInfo *ai = user_data;
1005 
1006 	if (strcmp (key, ai->key) != 0)
1007 		return;
1008 
1009 	/* the property is no longer there */
1010 	if (removed)
1011 		goto cleanup;
1012 
1013 
1014 	ai->callback (ai->device, ai->user_data, TRUE);
1015 
1016 cleanup:
1017 	destroy_async_match_info (ai);
1018 }
1019 
1020 
1021 static gboolean
1022 async_wait_timeout (gpointer user_data)
1023 {
1024 	AsyncMatchInfo *ai = (AsyncMatchInfo *) user_data;
1025 
1026 	ai->callback (ai->device, ai->user_data, FALSE);
1027 
1028 	destroy_async_match_info (ai);
1029 
1030 	return FALSE;
1031 }
1032 
1033 void
1034 hal_device_async_wait_property (HalDevice    *device,
1035 				const char   *key,
1036 				HalDeviceAsyncCallback callback,
1037 				gpointer     user_data,
1038 				int          timeout)
1039 {
1040 	HalProperty *prop;
1041 	AsyncMatchInfo *ai;
1042 
1043 	/* check if property already exists */
1044 	prop = hal_device_property_find (device, key);
1045 
1046 	if (prop != NULL || timeout==0) {
1047 		callback (device, user_data, prop != NULL);
1048 		return;
1049 	}
1050 
1051 	ai = g_new0 (AsyncMatchInfo, 1);
1052 
1053 	ai->device = g_object_ref (device);
1054 	ai->key = g_strdup (key);
1055 	ai->callback = callback;
1056 	ai->user_data = user_data;
1057 
1058 	ai->prop_signal_id = g_signal_connect (device, "property_changed",
1059 					       G_CALLBACK (prop_changed_cb),
1060 					       ai);
1061 
1062 	ai->timeout_id = g_timeout_add (timeout, async_wait_timeout, ai);
1063 }
1064 
1065 void
1066 hal_device_callouts_finished (HalDevice *device)
1067 {
1068 	g_signal_emit (device, signals[CALLOUTS_FINISHED], 0);
1069 }
1070 
1071 /** Used when giving up on a device, e.g. if no device file appeared
1072  */
1073 void
1074 hal_device_cancel (HalDevice *device)
1075 {
1076 	HAL_INFO (("udi=%s", device->udi));
1077 	g_signal_emit (device, signals[CANCELLED], 0);
1078 }
1079 
1080 
1081 
1082 
1083 GSList *
1084 hal_device_property_get_strlist (HalDevice    *device,
1085 				 const char   *key)
1086 {
1087 	HalProperty *prop;
1088 
1089 	g_return_val_if_fail (device != NULL, NULL);
1090 	g_return_val_if_fail (key != NULL, NULL);
1091 
1092 	prop = hal_device_property_find (device, key);
1093 
1094 	if (prop != NULL)
1095 		return hal_property_get_strlist (prop);
1096 	else
1097 		return NULL;
1098 }
1099 
1100 const char *
1101 hal_device_property_get_strlist_elem (HalDevice    *device,
1102 				      const char   *key,
1103 				      guint index)
1104 {
1105 	GSList *strlist;
1106 	GSList *i;
1107 
1108 	strlist = hal_device_property_get_strlist (device, key);
1109 	if (strlist == NULL)
1110 		return NULL;
1111 
1112 	i = g_slist_nth (strlist, index);
1113 	if (i == NULL)
1114 		return NULL;
1115 
1116 	return (const char *) i->data;
1117 }
1118 
1119 gboolean
1120 hal_device_property_strlist_append (HalDevice    *device,
1121 				    const char   *key,
1122 				    const char *value)
1123 {
1124 	HalProperty *prop;
1125 
1126 	/* check if property already exists */
1127 	prop = hal_device_property_find (device, key);
1128 
1129 	if (prop != NULL) {
1130 		if (hal_property_get_type (prop) != HAL_PROPERTY_TYPE_STRLIST)
1131 			return FALSE;
1132 
1133 		hal_property_strlist_append (prop, value);
1134 
1135 		g_signal_emit (device, signals[PROPERTY_CHANGED], 0,
1136 			       key, FALSE, FALSE);
1137 
1138 	} else {
1139 		prop = hal_property_new_strlist (key);
1140 		hal_property_strlist_append (prop, value);
1141 
1142 		device->properties = g_slist_prepend (device->properties, prop);
1143 
1144 		g_signal_emit (device, signals[PROPERTY_CHANGED], 0,
1145 			       key, FALSE, TRUE);
1146 	}
1147 
1148 	return TRUE;
1149 }
1150 
1151 gboolean
1152 hal_device_property_strlist_prepend (HalDevice    *device,
1153 				     const char   *key,
1154 				     const char *value)
1155 {
1156 	HalProperty *prop;
1157 
1158 	/* check if property already exists */
1159 	prop = hal_device_property_find (device, key);
1160 
1161 	if (prop != NULL) {
1162 		if (hal_property_get_type (prop) != HAL_PROPERTY_TYPE_STRLIST)
1163 			return FALSE;
1164 
1165 		hal_property_strlist_prepend (prop, value);
1166 
1167 		g_signal_emit (device, signals[PROPERTY_CHANGED], 0,
1168 			       key, FALSE, FALSE);
1169 
1170 	} else {
1171 		prop = hal_property_new_strlist (key);
1172 		hal_property_strlist_prepend (prop, value);
1173 
1174 		device->properties = g_slist_prepend (device->properties, prop);
1175 
1176 		g_signal_emit (device, signals[PROPERTY_CHANGED], 0,
1177 			       key, FALSE, TRUE);
1178 	}
1179 
1180 	return TRUE;
1181 }
1182 
1183 gboolean
1184 hal_device_property_strlist_remove_elem (HalDevice    *device,
1185 					 const char   *key,
1186 					 guint index)
1187 {
1188 	HalProperty *prop;
1189 
1190 	/* check if property already exists */
1191 	prop = hal_device_property_find (device, key);
1192 
1193 	if (prop == NULL)
1194 		return FALSE;
1195 
1196 	if (hal_property_get_type (prop) != HAL_PROPERTY_TYPE_STRLIST)
1197 		return FALSE;
1198 
1199 	if (hal_property_strlist_remove_elem (prop, index)) {
1200 		g_signal_emit (device, signals[PROPERTY_CHANGED], 0,
1201 			       key, FALSE, FALSE);
1202 		return TRUE;
1203 	}
1204 
1205 	return FALSE;
1206 }
1207 
1208 gboolean
1209 hal_device_property_strlist_clear (HalDevice    *device,
1210 				   const char   *key)
1211 {
1212 	HalProperty *prop;
1213 
1214 	/* check if property already exists */
1215 	prop = hal_device_property_find (device, key);
1216 
1217 	if (prop == NULL) {
1218 		prop = hal_property_new_strlist (key);
1219 
1220 		device->properties = g_slist_prepend (device->properties, prop);
1221 
1222 		g_signal_emit (device, signals[PROPERTY_CHANGED], 0,
1223 			       key, FALSE, TRUE);
1224 
1225 		return TRUE;
1226 	}
1227 
1228 	if (hal_property_get_type (prop) != HAL_PROPERTY_TYPE_STRLIST)
1229 		return FALSE;
1230 
1231 	if (hal_property_strlist_clear (prop)) {
1232 		g_signal_emit (device, signals[PROPERTY_CHANGED], 0,
1233 			       key, FALSE, FALSE);
1234 		return TRUE;
1235 	}
1236 
1237 	return FALSE;
1238 }
1239 
1240 
1241 gboolean
1242 hal_device_property_strlist_add (HalDevice *device,
1243 				 const char *key,
1244 				 const char *value)
1245 {
1246 	HalProperty *prop;
1247 	gboolean res;
1248 
1249 	res = FALSE;
1250 
1251 	/* check if property already exists */
1252 	prop = hal_device_property_find (device, key);
1253 
1254 	if (prop != NULL) {
1255 		if (hal_property_get_type (prop) != HAL_PROPERTY_TYPE_STRLIST)
1256 			goto out;
1257 
1258 		res = hal_property_strlist_add (prop, value);
1259 		if (res) {
1260 			g_signal_emit (device, signals[PROPERTY_CHANGED], 0,
1261 				       key, FALSE, FALSE);
1262 		}
1263 
1264 	} else {
1265 		prop = hal_property_new_strlist (key);
1266 		hal_property_strlist_prepend (prop, value);
1267 
1268 		device->properties = g_slist_prepend (device->properties, prop);
1269 
1270 		g_signal_emit (device, signals[PROPERTY_CHANGED], 0,
1271 			       key, FALSE, TRUE);
1272 
1273 		res = TRUE;
1274 	}
1275 
1276 out:
1277 	return res;
1278 }
1279 
1280 gboolean
1281 hal_device_property_strlist_remove (HalDevice *device,
1282 				    const char *key,
1283 				    const char *value)
1284 {
1285 	HalProperty *prop;
1286 
1287 	/* check if property already exists */
1288 	prop = hal_device_property_find (device, key);
1289 
1290 	if (prop == NULL)
1291 		return FALSE;
1292 
1293 	if (hal_property_get_type (prop) != HAL_PROPERTY_TYPE_STRLIST)
1294 		return FALSE;
1295 
1296 	if (hal_property_strlist_remove (prop, value)) {
1297 		g_signal_emit (device, signals[PROPERTY_CHANGED], 0,
1298 			       key, FALSE, FALSE);
1299 	}
1300 
1301 	return TRUE;
1302 }
1303 
1304 gboolean
1305 hal_device_property_strlist_is_empty (HalDevice    *device,
1306 				      const char   *key)
1307 {
1308 	GSList *strlist;
1309 
1310 	if ( hal_device_has_property (device, key)) {
1311 		strlist = hal_device_property_get_strlist (device, key);
1312 		if (strlist == NULL )
1313 			return TRUE;
1314 
1315 		if (g_slist_length (strlist) > 0)
1316 			return FALSE;
1317 		else
1318 			return TRUE;
1319 	}
1320 	return FALSE;
1321 }
1322 
1323 void
1324 hal_device_inc_num_addons (HalDevice *device)
1325 {
1326 	device->num_addons++;
1327 }
1328 
1329 gboolean
1330 hal_device_inc_num_ready_addons (HalDevice *device)
1331 {
1332 	if (hal_device_are_all_addons_ready (device)) {
1333 		HAL_ERROR (("In hal_device_inc_num_ready_addons for udi=%s but all addons are already ready!",
1334 			    device->udi));
1335 		return FALSE;
1336 	}
1337 
1338 	device->num_addons_ready++;
1339 	return TRUE;
1340 }
1341 
1342 gboolean
1343 hal_device_are_all_addons_ready (HalDevice *device)
1344 {
1345 	if (device->num_addons_ready == device->num_addons) {
1346 		return TRUE;
1347 	} else {
1348 		return FALSE;
1349 	}
1350 }
1351