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