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