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