xref: /illumos-gate/usr/src/cmd/hal/hald/solaris/hotplug.c (revision f5488aa822e08905cde61d596e965030a1dfffcd)
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 */
41 GQueue *hotplug_event_queue;
42 
43 /** List of HotplugEvent objects we are currently processing */
44 GSList *hotplug_events_in_progress = NULL;
45 
46 static void hotplug_event_begin (HotplugEvent *hotplug_event);
47 
48 void
49 hotplug_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 
58 static void
59 hotplug_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 
106 static void
107 hotplug_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 
121 static void
122 hotplug_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 
140 static void
141 hotplug_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 
156 void
157 hotplug_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 
169 void
170 hotplug_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 
191 out:
192 	;
193 }
194