xref: /illumos-gate/usr/src/cmd/hal/hald/device_store.c (revision 4f364e7c95ee7fd9d5bbeddc1940e92405bb0e72)
1 /***************************************************************************
2  * CVSID: $Id$
3  *
4  * device_store.c : HalDeviceStore 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 "device_store.h"
35 #include "hald_marshal.h"
36 #include "logger.h"
37 
38 static GObjectClass *parent_class;
39 
40 enum {
41 	STORE_CHANGED,
42 	DEVICE_PROPERTY_CHANGED,
43 	DEVICE_CAPABILITY_ADDED,
44 	LAST_SIGNAL
45 };
46 
47 static guint signals[LAST_SIGNAL] = { 0 };
48 
49 static void
50 hal_device_store_finalize (GObject *obj)
51 {
52 	HalDeviceStore *store = HAL_DEVICE_STORE (obj);
53 
54 	g_slist_foreach (store->devices, (GFunc) g_object_unref, NULL);
55 
56 	if (parent_class->finalize)
57 		parent_class->finalize (obj);
58 }
59 
60 static void
61 hal_device_store_class_init (HalDeviceStoreClass *klass)
62 {
63 	GObjectClass *obj_class = (GObjectClass *) klass;
64 
65 	parent_class = g_type_class_peek_parent (klass);
66 
67 	obj_class->finalize = hal_device_store_finalize;
68 
69 	signals[STORE_CHANGED] =
70 		g_signal_new ("store_changed",
71 			      G_TYPE_FROM_CLASS (klass),
72 			      G_SIGNAL_RUN_LAST,
73 			      G_STRUCT_OFFSET (HalDeviceStoreClass,
74 					       store_changed),
75 			      NULL, NULL,
76 			      hald_marshal_VOID__OBJECT_BOOL,
77 			      G_TYPE_NONE, 2,
78 			      G_TYPE_OBJECT,
79 			      G_TYPE_BOOLEAN);
80 
81 	signals[DEVICE_PROPERTY_CHANGED] =
82 		g_signal_new ("device_property_changed",
83 			      G_TYPE_FROM_CLASS (klass),
84 			      G_SIGNAL_RUN_LAST,
85 			      G_STRUCT_OFFSET (HalDeviceStoreClass,
86 					       device_property_changed),
87 			      NULL, NULL,
88 			      hald_marshal_VOID__OBJECT_STRING_BOOL_BOOL,
89 			      G_TYPE_NONE, 4,
90 			      G_TYPE_OBJECT,
91 			      G_TYPE_STRING,
92 			      G_TYPE_BOOLEAN,
93 			      G_TYPE_BOOLEAN);
94 
95 	signals[DEVICE_CAPABILITY_ADDED] =
96 		g_signal_new ("device_capability_added",
97 			      G_TYPE_FROM_CLASS (klass),
98 			      G_SIGNAL_RUN_LAST,
99 			      G_STRUCT_OFFSET (HalDeviceStoreClass,
100 					       device_capability_added),
101 			      NULL, NULL,
102 			      hald_marshal_VOID__OBJECT_STRING,
103 			      G_TYPE_NONE, 2,
104 			      G_TYPE_OBJECT,
105 			      G_TYPE_STRING);
106 }
107 
108 static void
109 hal_device_store_init (HalDeviceStore *device)
110 {
111 }
112 
113 GType
114 hal_device_store_get_type (void)
115 {
116 	static GType type = 0;
117 
118 	if (!type) {
119 		static GTypeInfo type_info = {
120 			sizeof (HalDeviceStoreClass),
121 			NULL, NULL,
122 			(GClassInitFunc) hal_device_store_class_init,
123 			NULL, NULL,
124 			sizeof (HalDeviceStore),
125 			0,
126 			(GInstanceInitFunc) hal_device_store_init
127 		};
128 
129 		type = g_type_register_static (G_TYPE_OBJECT,
130 					       "HalDeviceStore",
131 					       &type_info,
132 					       0);
133 	}
134 
135 	return type;
136 }
137 
138 HalDeviceStore *
139 hal_device_store_new (void)
140 {
141 	HalDeviceStore *store;
142 
143 	store = g_object_new (HAL_TYPE_DEVICE_STORE, NULL, NULL);
144 
145 	return store;
146 }
147 
148 static void
149 emit_device_property_changed (HalDevice *device,
150 			      const char *key,
151 			      gboolean added,
152 			      gboolean removed,
153 			      gpointer data)
154 {
155 	HalDeviceStore *store = HAL_DEVICE_STORE (data);
156 
157 	g_signal_emit (store, signals[DEVICE_PROPERTY_CHANGED], 0,
158 		       device, key, added, removed);
159 }
160 
161 static void
162 emit_device_capability_added (HalDevice *device,
163 			      const char *capability,
164 			      gpointer data)
165 {
166 	HalDeviceStore *store = HAL_DEVICE_STORE (data);
167 
168 	g_signal_emit (store, signals[DEVICE_CAPABILITY_ADDED], 0,
169 		       device, capability);
170 }
171 
172 void
173 hal_device_store_add (HalDeviceStore *store, HalDevice *device)
174 {
175 	const char buf[] = "/org/freedesktop/Hal/devices/";
176 
177 	if (strncmp(device->udi, buf, sizeof (buf) - 1) != 0) {
178 
179 		HAL_ERROR(("Can't add HalDevice with incorrect UDI. Valid "
180 			   "UDI must start with '/org/freedesktop/Hal/devices/'"));
181 		goto out;
182 	}
183 	store->devices = g_slist_prepend (store->devices,
184 					  g_object_ref (device));
185 
186 	g_signal_connect (device, "property_changed",
187 			  G_CALLBACK (emit_device_property_changed), store);
188 	g_signal_connect (device, "capability_added",
189 			  G_CALLBACK (emit_device_capability_added), store);
190 
191 	g_signal_emit (store, signals[STORE_CHANGED], 0, device, TRUE);
192 
193 out:
194 	;
195 }
196 
197 gboolean
198 hal_device_store_remove (HalDeviceStore *store, HalDevice *device)
199 {
200 	if (!g_slist_find (store->devices, device))
201 		return FALSE;
202 
203 	store->devices = g_slist_remove (store->devices, device);
204 
205 	g_signal_handlers_disconnect_by_func (device,
206 					      (gpointer)emit_device_property_changed,
207 					      store);
208 	g_signal_handlers_disconnect_by_func (device,
209 					      (gpointer)emit_device_capability_added,
210 					      store);
211 
212 	g_signal_emit (store, signals[STORE_CHANGED], 0, device, FALSE);
213 
214 	g_object_unref (device);
215 
216 	return TRUE;
217 }
218 
219 HalDevice *
220 hal_device_store_find (HalDeviceStore *store, const char *udi)
221 {
222 	GSList *iter;
223 
224 	for (iter = store->devices; iter != NULL; iter = iter->next) {
225 		HalDevice *d = iter->data;
226 
227 		if (strcmp (hal_device_get_udi (d), udi) == 0)
228 			return d;
229 	}
230 
231 	return NULL;
232 }
233 
234 void
235 hal_device_store_foreach (HalDeviceStore *store,
236 			  HalDeviceStoreForeachFn callback,
237 			  gpointer user_data)
238 {
239 	GSList *iter;
240 
241 	g_return_if_fail (store != NULL);
242 	g_return_if_fail (callback != NULL);
243 
244 	for (iter = store->devices; iter != NULL; iter = iter->next) {
245 		HalDevice *d = HAL_DEVICE (iter->data);
246 		gboolean cont;
247 
248 		cont = callback (store, d, user_data);
249 
250 		if (cont == FALSE)
251 			return;
252 	}
253 }
254 
255 static gboolean
256 hal_device_store_print_foreach_fn (HalDeviceStore *store,
257 				   HalDevice *device,
258 				   gpointer user_data)
259 {
260 	fprintf (stderr, "----\n");
261 	hal_device_print (device);
262 	fprintf (stderr, "----\n");
263 	return TRUE;
264 }
265 
266 void
267 hal_device_store_print (HalDeviceStore *store)
268 {
269 	fprintf (stderr, "===============================================\n");
270         fprintf (stderr, "Dumping %d devices\n",
271 		 g_slist_length (store->devices));
272 	fprintf (stderr, "===============================================\n");
273 	hal_device_store_foreach (store,
274 				  hal_device_store_print_foreach_fn,
275 				  NULL);
276 	fprintf (stderr, "===============================================\n");
277 }
278 
279 HalDevice *
280 hal_device_store_match_key_value_string (HalDeviceStore *store,
281 					 const char *key,
282 					 const char *value)
283 {
284 	GSList *iter;
285 
286 	g_return_val_if_fail (store != NULL, NULL);
287 	g_return_val_if_fail (key != NULL, NULL);
288 	g_return_val_if_fail (value != NULL, NULL);
289 
290 	for (iter = store->devices; iter != NULL; iter = iter->next) {
291 		HalDevice *d = HAL_DEVICE (iter->data);
292 		int type;
293 
294 		if (!hal_device_has_property (d, key))
295 			continue;
296 
297 		type = hal_device_property_get_type (d, key);
298 		if (type != HAL_PROPERTY_TYPE_STRING)
299 			continue;
300 
301 		if (strcmp (hal_device_property_get_string (d, key),
302 			    value) == 0)
303 			return d;
304 	}
305 
306 	return NULL;
307 }
308 
309 HalDevice *
310 hal_device_store_match_key_value_int (HalDeviceStore *store,
311 				      const char *key,
312 				      int value)
313 {
314 	GSList *iter;
315 
316 	g_return_val_if_fail (store != NULL, NULL);
317 	g_return_val_if_fail (key != NULL, NULL);
318 
319 	for (iter = store->devices; iter != NULL; iter = iter->next) {
320 		HalDevice *d = HAL_DEVICE (iter->data);
321 		int type;
322 
323 		if (!hal_device_has_property (d, key))
324 			continue;
325 
326 		type = hal_device_property_get_type (d, key);
327 		if (type != HAL_PROPERTY_TYPE_INT32)
328 			continue;
329 
330 		if (hal_device_property_get_int (d, key) == value)
331 			return d;
332 	}
333 
334 	return NULL;
335 }
336 
337 GSList *
338 hal_device_store_match_multiple_key_value_string (HalDeviceStore *store,
339 						  const char *key,
340 						  const char *value)
341 {
342 	GSList *iter;
343 	GSList *matches = NULL;
344 
345 	g_return_val_if_fail (store != NULL, NULL);
346 	g_return_val_if_fail (key != NULL, NULL);
347 	g_return_val_if_fail (value != NULL, NULL);
348 
349 	for (iter = store->devices; iter != NULL; iter = iter->next) {
350 		HalDevice *d = HAL_DEVICE (iter->data);
351 		int type;
352 
353 		if (!hal_device_has_property (d, key))
354 			continue;
355 
356 		type = hal_device_property_get_type (d, key);
357 		if (type != HAL_PROPERTY_TYPE_STRING)
358 			continue;
359 
360 		if (strcmp (hal_device_property_get_string (d, key),
361 			    value) == 0)
362 			matches = g_slist_prepend (matches, d);
363 	}
364 
365 	return matches;
366 }
367 
368 typedef struct {
369 	HalDeviceStore *store;
370 	char *key;
371 	char *value;
372 	HalDeviceStoreAsyncCallback callback;
373 	gpointer user_data;
374 
375 	guint prop_signal_id;
376 	guint store_signal_id;
377 	guint timeout_id;
378 } AsyncMatchInfo;
379 
380 static void
381 destroy_async_match_info (AsyncMatchInfo *info)
382 {
383 	g_object_unref (info->store);
384 
385 	g_free (info->key);
386 	g_free (info->value);
387 
388 	g_signal_handler_disconnect (info->store, info->prop_signal_id);
389 	g_signal_handler_disconnect (info->store, info->store_signal_id);
390 	g_source_remove (info->timeout_id);
391 
392 	g_free (info);
393 }
394 
395 static void
396 match_device_async (HalDeviceStore *store, HalDevice *device,
397 		    const char *key, gboolean removed, gboolean added,
398 		    gpointer user_data)
399 {
400 	AsyncMatchInfo *info = (AsyncMatchInfo *) user_data;
401 
402 	/* Only want to do it for added or changed properties */
403 	if (removed)
404 		return;
405 
406 	/* Keys have to match */
407 	if (strcmp (info->key, key) != 0)
408 		return;
409 
410 	/* Values have to match */
411 	if (strcmp (hal_device_property_get_string (device, key),
412 		    info->value) != 0)
413 		return;
414 
415 	info->callback (store, device, info->user_data);
416 
417 	destroy_async_match_info (info);
418 }
419 
420 static void
421 store_changed (HalDeviceStore *store, HalDevice *device,
422 	       gboolean added, gpointer user_data)
423 {
424 	AsyncMatchInfo *info = (AsyncMatchInfo *) user_data;
425 
426 	if (!added)
427 		return;
428 
429 	if (!hal_device_has_property (device, info->key))
430 		return;
431 
432 	if (strcmp (hal_device_property_get_string (device, info->key),
433 		    info->value) != 0)
434 		return;
435 
436 	info->callback (store, device, info->user_data);
437 
438 	destroy_async_match_info (info);
439 }
440 
441 static gboolean
442 match_device_async_timeout (gpointer user_data)
443 {
444 	AsyncMatchInfo *info = (AsyncMatchInfo *) user_data;
445 
446 	info->callback (info->store, NULL, info->user_data);
447 
448 	destroy_async_match_info (info);
449 
450 	return FALSE;
451 }
452 
453 void
454 hal_device_store_match_key_value_string_async (HalDeviceStore *store,
455 					       const char *key,
456 					       const char *value,
457 					       HalDeviceStoreAsyncCallback callback,
458 					       gpointer user_data,
459 					       int timeout)
460 {
461 	HalDevice *device;
462 	AsyncMatchInfo *info;
463 
464 	/* First check to see if it's already there */
465 	device = hal_device_store_match_key_value_string (store, key, value);
466 
467 	if (device != NULL || timeout == 0) {
468 		callback (store, device, user_data);
469 
470 		return;
471 	}
472 
473 	info = g_new0 (AsyncMatchInfo, 1);
474 
475 	info->store = g_object_ref (store);
476 	info->key = g_strdup (key);
477 	info->value = g_strdup (value);
478 	info->callback = callback;
479 	info->user_data = user_data;
480 
481 	info->prop_signal_id = g_signal_connect (store,
482 						 "device_property_changed",
483 						 G_CALLBACK (match_device_async),
484 						 info);
485 	info->store_signal_id = g_signal_connect (store,
486 						  "store_changed",
487 						  G_CALLBACK (store_changed),
488 						  info);
489 
490 	info->timeout_id = g_timeout_add (timeout,
491 					  match_device_async_timeout,
492 					  info);
493 }
494