hotplug.c revision 3121:a0d9ec5b5403
1/***************************************************************************
2 *
3 * hotplug.c : HAL-internal hotplug events
4 *
5 * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
6 * Use is subject to license terms.
7 *
8 * Licensed under the Academic Free License version 2.1
9 *
10 **************************************************************************/
11
12#pragma ident	"%Z%%M%	%I%	%E% SMI"
13
14#ifdef HAVE_CONFIG_H
15#  include <config.h>
16#endif
17
18#include <stdio.h>
19#include <string.h>
20#include <errno.h>
21#include <sys/types.h>
22#include <sys/stat.h>
23#include <sys/un.h>
24#include <sys/utsname.h>
25#include <unistd.h>
26
27#include <glib.h>
28#include <dbus/dbus.h>
29#include <dbus/dbus-glib.h>
30
31#include "../osspec.h"
32#include "../logger.h"
33#include "../hald.h"
34#include "../device_info.h"
35
36#include "osspec_solaris.h"
37#include "hotplug.h"
38#include "devinfo.h"
39
40/** Queue of ordered hotplug events */
41GQueue *hotplug_event_queue;
42
43/** List of HotplugEvent objects we are currently processing */
44GSList *hotplug_events_in_progress = NULL;
45
46static void hotplug_event_begin (HotplugEvent *hotplug_event);
47
48void
49hotplug_event_end (void *end_token)
50{
51	HotplugEvent *hotplug_event = (HotplugEvent *) end_token;
52
53	hotplug_events_in_progress = g_slist_remove (hotplug_events_in_progress, hotplug_event);
54	g_free (hotplug_event);
55	hotplug_event_process_queue ();
56}
57
58static void
59hotplug_event_begin_devfs_add (HotplugEvent *hotplug_event, HalDevice *d)
60{
61	HalDevice *parent;
62	const gchar *parent_udi;
63	void (*begin_add_func) (HalDevice *, HalDevice *, DevinfoDevHandler *, void *);
64
65	if (d != NULL) {
66		/* XXX */
67		HAL_ERROR (("devpath %s already present in store, ignore event", hotplug_event->un.devfs.devfs_path));
68		hotplug_event_end ((void *) hotplug_event);
69		return;
70	}
71
72	/* find parent */
73	parent_udi = hal_device_property_get_string (hotplug_event->d, "info.parent");
74	if (parent_udi == NULL || strlen(parent_udi) == 0) {
75		parent = NULL;
76	} else {
77		parent = hal_device_store_match_key_value_string (hald_get_gdl (), "info.udi", parent_udi);
78	}
79	/* only root node is allowed to be orphan */
80	if (parent == NULL) {
81		if (strcmp(hotplug_event->un.devfs.devfs_path, "/") != 0) {
82			HAL_ERROR (("Parent is NULL devfs_path=%s parent_udi=%s", hotplug_event->un.devfs.devfs_path, parent_udi ? parent_udi : "<null>"));
83			hotplug_event_end ((void *) hotplug_event);
84			return;
85		}
86	}
87
88	/* children of ignored parent should be ignored */
89	if (parent != NULL && hal_device_property_get_bool (parent, "info.ignore")) {
90		HAL_INFO (("parent ignored %s", parent_udi));
91		hotplug_event_end ((void *) hotplug_event);
92		return;
93	}
94
95	/* custom or generic add function */
96	begin_add_func = hotplug_event->un.devfs.handler->hotplug_begin_add;
97	if (begin_add_func == NULL) {
98		begin_add_func = hotplug_event_begin_add_devinfo;
99	}
100	begin_add_func (hotplug_event->d,
101			 parent,
102			 hotplug_event->un.devfs.handler,
103			 (void *) hotplug_event);
104}
105
106static void
107hotplug_event_begin_devfs_remove (HotplugEvent *hotplug_event, HalDevice *d)
108{
109	if (d == NULL) {
110		HAL_ERROR (("devpath %s not present in store, ignore event", hotplug_event->un.devfs.devfs_path));
111		hotplug_event_end ((void *) hotplug_event);
112		return;
113	}
114	HAL_INFO (("hotplug_event_begin_devfs_remove %s", hal_device_get_udi (d)));
115
116	hotplug_event_begin_remove_devinfo(d,
117			 hotplug_event->un.devfs.devfs_path,
118			 (void *) hotplug_event);
119}
120
121static void
122hotplug_event_begin_devfs (HotplugEvent *hotplug_event)
123{
124	HalDevice *d;
125
126	HAL_INFO (("hotplug_event_begin_devfs: %s", hotplug_event->un.devfs.devfs_path));
127	d = hal_device_store_match_key_value_string (hald_get_gdl (),
128						"solaris.devfs_path",
129						hotplug_event->un.devfs.devfs_path);
130
131	if (hotplug_event->action == HOTPLUG_ACTION_ADD) {
132		hotplug_event_begin_devfs_add (hotplug_event, d);
133	} else if (hotplug_event->action == HOTPLUG_ACTION_REMOVE) {
134		hotplug_event_begin_devfs_remove (hotplug_event, d);
135	} else {
136		hotplug_event_end ((void *) hotplug_event);
137	}
138}
139
140static void
141hotplug_event_begin (HotplugEvent *hotplug_event)
142{
143	switch (hotplug_event->type) {
144
145	case HOTPLUG_EVENT_DEVFS:
146		hotplug_event_begin_devfs (hotplug_event);
147		break;
148
149	default:
150		HAL_ERROR (("Unknown hotplug event type %d", hotplug_event->type));
151		hotplug_event_end ((void *) hotplug_event);
152		break;
153	}
154}
155
156void
157hotplug_event_enqueue (HotplugEvent *hotplug_event, int front)
158{
159	if (hotplug_event_queue == NULL)
160		hotplug_event_queue = g_queue_new ();
161
162	if (front) {
163		g_queue_push_head (hotplug_event_queue, hotplug_event);
164	} else {
165		g_queue_push_tail (hotplug_event_queue, hotplug_event);
166	}
167}
168
169void
170hotplug_event_process_queue (void)
171{
172	HotplugEvent *hotplug_event;
173
174	if (hotplug_events_in_progress == NULL &&
175	    (hotplug_event_queue == NULL || g_queue_is_empty (hotplug_event_queue))) {
176		hotplug_queue_now_empty ();
177		goto out;
178	}
179
180	/* do not process events if some other event is in progress */
181	if (hotplug_events_in_progress != NULL && g_slist_length (hotplug_events_in_progress) > 0)
182		goto out;
183
184	hotplug_event = g_queue_pop_head (hotplug_event_queue);
185	if (hotplug_event == NULL)
186		goto out;
187
188	hotplug_events_in_progress = g_slist_append (hotplug_events_in_progress, hotplug_event);
189	hotplug_event_begin (hotplug_event);
190
191out:
192	;
193}
194