xref: /illumos-gate/usr/src/cmd/hal/hald/solaris/sysevent.c (revision 0a44ef6d9afbfe052a7e975f55ea0d2954b62a82)
1 /***************************************************************************
2  *
3  * sysevent.c : Solaris sysevents
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 <unistd.h>
20 #include <stdlib.h>
21 #include <string.h>
22 #include <errno.h>
23 #include <fcntl.h>
24 #include <sys/dkio.h>
25 #include <sys/stat.h>
26 #include <libdevinfo.h>
27 #include <libsysevent.h>
28 #include <sys/sysevent/dev.h>
29 #include <glib.h>
30 
31 #include "../osspec.h"
32 #include "../logger.h"
33 #include "../hald.h"
34 #include "../hald_dbus.h"
35 #include "../device_info.h"
36 #include "../util.h"
37 #include "osspec_solaris.h"
38 #include "hotplug.h"
39 #include "devinfo.h"
40 #include "devinfo_storage.h"
41 #include "sysevent.h"
42 
43 #ifndef ESC_LOFI
44 #define ESC_LOFI "lofi"
45 #endif
46 
47 static void	sysevent_dev_handler(sysevent_t *);
48 static gboolean sysevent_iochannel_data(GIOChannel *, GIOCondition, gpointer);
49 static void	sysevent_dev_add(gchar *, gchar *);
50 static void	sysevent_dev_remove(gchar *, gchar *);
51 static void	sysevent_dev_branch(gchar *);
52 static void	sysevent_lofi_add(gchar *, gchar *);
53 static void	sysevent_lofi_remove(gchar *, gchar *);
54 
55 static sysevent_handle_t	*shp;
56 
57 static int sysevent_pipe_fds[2];
58 static GIOChannel *sysevent_iochannel;
59 static guint sysevent_source_id;
60 
61 gboolean
62 sysevent_init(void)
63 {
64 	GError *err = NULL;
65 	const char	*subcl[2];
66 
67         /*
68 	 * pipe used to serialize sysevents through the main loop
69  	 */
70         if (pipe (sysevent_pipe_fds) != 0) {
71                 HAL_INFO (("pipe() failed errno=%d", errno));
72 		return (FALSE);
73         }
74         sysevent_iochannel = g_io_channel_unix_new (sysevent_pipe_fds[0]);
75 	if (sysevent_iochannel == NULL) {
76                 HAL_INFO (("g_io_channel_unix_new failed"));
77 		return (FALSE);
78 	}
79 	g_io_channel_set_flags (sysevent_iochannel, G_IO_FLAG_NONBLOCK, &err);
80         sysevent_source_id = g_io_add_watch (
81                 sysevent_iochannel, G_IO_IN, sysevent_iochannel_data, NULL);
82 
83 	shp = sysevent_bind_handle(sysevent_dev_handler);
84 	if (shp == NULL) {
85 		HAL_INFO (("sysevent_bind_handle failed %d", errno));
86 		return (FALSE);
87 	}
88 
89 	subcl[0] = ESC_DISK;
90 	subcl[1] = ESC_LOFI;
91 	if (sysevent_subscribe_event(shp, EC_DEV_ADD, subcl, 2) != 0) {
92 		HAL_INFO (("subscribe(dev_add) failed %d", errno));
93 		sysevent_unbind_handle(shp);
94 		return (FALSE);
95 	}
96 	if (sysevent_subscribe_event(shp, EC_DEV_REMOVE, subcl, 2) != 0) {
97 		HAL_INFO (("subscribe(dev_remove) failed %d", errno));
98 		sysevent_unbind_handle(shp);
99 		return (FALSE);
100 	}
101 
102 	subcl[0] = ESC_DEV_BRANCH_REMOVE;
103 	if (sysevent_subscribe_event(shp, EC_DEV_BRANCH, subcl, 1) != 0) {
104 		HAL_INFO (("subscribe(dev_branch) failed %d", errno));
105 		sysevent_unbind_handle(shp);
106 		return (FALSE);
107 	}
108 
109 	return (B_TRUE);
110 }
111 
112 void
113 sysevent_fini(void)
114 {
115 	sysevent_unbind_handle(shp);
116 	shp = NULL;
117 }
118 
119 static void
120 sysevent_dev_handler(sysevent_t *ev)
121 {
122 	char		*class;
123 	char		*subclass;
124 	nvlist_t	*attr_list;
125 	char		*phys_path;
126 	char		*dev_name;
127 	char		s[1024];
128 	ssize_t		nwritten;
129 
130 	if ((class = sysevent_get_class_name(ev)) == NULL)
131 		return;
132 
133 	if ((subclass = sysevent_get_subclass_name(ev)) == NULL)
134 		return;
135 
136 	if (sysevent_get_attr_list(ev, &attr_list) != 0)
137 		return;
138 
139 	if (nvlist_lookup_string(attr_list, DEV_PHYS_PATH, &phys_path) != 0)
140 		goto out;
141 
142 	if (nvlist_lookup_string(attr_list, DEV_NAME, &dev_name) != 0)
143 		dev_name = "";
144 
145 	snprintf(s, sizeof (s), "%s %s %s %s\n",
146 		class, subclass, phys_path, dev_name);
147 	nwritten = write(sysevent_pipe_fds[1], s, strlen(s) + 1);
148 
149 	HAL_INFO (("sysevent_dev_handler: wrote %d bytes", nwritten));
150 
151 out:
152 	nvlist_free(attr_list);
153 }
154 
155 static gboolean
156 sysevent_iochannel_data (GIOChannel *source,
157                     GIOCondition condition,
158                     gpointer user_data)
159 {
160         GError *err = NULL;
161 	gchar *s = NULL;
162 	gsize len;
163 	int matches;
164 	gchar class[1024];
165 	gchar subclass[1024];
166 	gchar phys_path[1024];
167 	gchar dev_name[1024];
168 
169 	HAL_INFO (("sysevent_iochannel_data"));
170 
171 	while (g_io_channel_read_line (sysevent_iochannel, &s, &len, NULL,
172 					&err) == G_IO_STATUS_NORMAL) {
173 		if (len == 0) {
174 			break;
175 		}
176 
177 		class[0] = subclass[0] = phys_path[0] = dev_name[0] = '\0';
178 		matches = sscanf(s, "%s %s %s %s", class, subclass, phys_path, dev_name);
179 		g_free (s);
180 		s = NULL;
181 		if (matches < 3) {
182 			continue;
183 		}
184 		HAL_INFO (("sysevent: class=%s, sub=%s", class, subclass));
185 
186 		if (strcmp(class, EC_DEV_ADD) == 0) {
187 			if (strcmp(subclass, ESC_DISK) == 0) {
188 				sysevent_dev_add(phys_path, dev_name);
189 			} else if (strcmp(subclass, ESC_LOFI) == 0) {
190 				sysevent_lofi_add(phys_path, dev_name);
191 			}
192 		} else if (strcmp(class, EC_DEV_REMOVE) == 0) {
193 			if (strcmp(subclass, ESC_DISK) == 0) {
194 				sysevent_dev_remove(phys_path, dev_name);
195 			} else if (strcmp(subclass, ESC_LOFI) == 0) {
196 				sysevent_lofi_remove(phys_path, dev_name);
197 			}
198 		} else if (strcmp(class, EC_DEV_BRANCH) == 0) {
199 			sysevent_dev_branch(phys_path);
200 		}
201 	}
202 
203 	if (err) {
204 		g_error_free (err);
205 	}
206 
207 	return (TRUE);
208 }
209 
210 static void
211 sysevent_dev_add(gchar *devfs_path, gchar *name)
212 {
213 	gchar	*parent_devfs_path, *hotplug_devfs_path;
214 	HalDevice *parent;
215 
216 	HAL_INFO (("dev_add: %s %s", name, devfs_path));
217 
218         parent = hal_util_find_closest_ancestor (devfs_path, &parent_devfs_path, &hotplug_devfs_path);
219 	if (parent == NULL) {
220 		return;
221 	}
222 
223 	HAL_INFO (("dev_add: parent=%s", parent_devfs_path));
224 	HAL_INFO (("dev_add: real=%s", hotplug_devfs_path));
225 
226 	devinfo_add (parent, hotplug_devfs_path);
227 
228 	g_free (parent_devfs_path);
229 	g_free (hotplug_devfs_path);
230 
231 	hotplug_event_process_queue ();
232 }
233 
234 static void
235 sysevent_dev_remove(gchar *devfs_path, gchar *name)
236 {
237 	HAL_INFO (("dev_remove: %s %s", name, devfs_path));
238 
239 	devinfo_remove_branch (devfs_path, NULL);
240 	hotplug_event_process_queue ();
241 }
242 
243 static void
244 sysevent_dev_branch(gchar *devfs_path)
245 {
246 	HAL_INFO (("branch_remove: %s", devfs_path));
247 
248 	devinfo_remove_branch (devfs_path, NULL);
249 	hotplug_event_process_queue ();
250 }
251 
252 static void
253 sysevent_lofi_add(gchar *devfs_path, gchar *name)
254 {
255 	di_node_t node;
256 	const char *parent_udi;
257 	HalDevice *d, *parent;
258 
259 	HAL_INFO (("lofi_add: %s %s", name, devfs_path));
260 
261 	if ((d = hal_device_store_match_key_value_string (hald_get_gdl (),
262 	    "solaris.devfs_path", devfs_path)) == NULL) {
263 		HAL_INFO (("device not found in GDL %s", devfs_path));
264 		return;
265 	}
266 	parent_udi = hal_device_property_get_string (d, "info.parent");
267 	if ((parent_udi == NULL) || (strlen(parent_udi) == 0)) {
268 		HAL_INFO (("parent not found in GDL %s", parent_udi));
269 		return;
270 	}
271 	if ((parent = hal_device_store_match_key_value_string (hald_get_gdl (),
272 	    "info.udi", parent_udi)) == NULL) {
273 		HAL_INFO (("parent not found in GDL %s", parent_udi));
274 		return;
275 	}
276 
277 	if ((node = di_init (devfs_path, DINFOCPYALL)) == DI_NODE_NIL) {
278 		HAL_INFO (("device not found in devinfo %s", devfs_path));
279 		return;
280 	}
281 
282 	HAL_INFO (("device %s parent %s", hal_device_get_udi (d), parent_udi));
283 	devinfo_lofi_add_major (parent, node, devfs_path, NULL, TRUE, d);
284 
285 	di_fini (node);
286 
287 	hotplug_event_process_queue ();
288 }
289 
290 static void
291 sysevent_lofi_remove(gchar *parent_devfs_path, gchar *name)
292 {
293 	devinfo_lofi_remove_minor(parent_devfs_path, name);
294 	hotplug_event_process_queue ();
295 }
296