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