1 /*************************************************************************** 2 * 3 * sysevent.c : Solaris sysevents 4 * 5 * Copyright 2007 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[3]; 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 subcl[2] = ESC_PRINTER; 92 if (sysevent_subscribe_event(shp, EC_DEV_ADD, subcl, 3) != 0) { 93 HAL_INFO (("subscribe(dev_add) failed %d", errno)); 94 sysevent_unbind_handle(shp); 95 return (FALSE); 96 } 97 if (sysevent_subscribe_event(shp, EC_DEV_REMOVE, subcl, 3) != 0) { 98 HAL_INFO (("subscribe(dev_remove) failed %d", errno)); 99 sysevent_unbind_handle(shp); 100 return (FALSE); 101 } 102 103 subcl[0] = ESC_DEV_BRANCH_REMOVE; 104 if (sysevent_subscribe_event(shp, EC_DEV_BRANCH, subcl, 1) != 0) { 105 HAL_INFO (("subscribe(dev_branch) failed %d", errno)); 106 sysevent_unbind_handle(shp); 107 return (FALSE); 108 } 109 110 return (B_TRUE); 111 } 112 113 void 114 sysevent_fini(void) 115 { 116 sysevent_unbind_handle(shp); 117 shp = NULL; 118 } 119 120 static void 121 sysevent_dev_handler(sysevent_t *ev) 122 { 123 char *class; 124 char *subclass; 125 nvlist_t *attr_list; 126 char *phys_path; 127 char *dev_name; 128 char s[1024]; 129 ssize_t nwritten; 130 131 if ((class = sysevent_get_class_name(ev)) == NULL) 132 return; 133 134 if ((subclass = sysevent_get_subclass_name(ev)) == NULL) 135 return; 136 137 if (sysevent_get_attr_list(ev, &attr_list) != 0) 138 return; 139 140 if (nvlist_lookup_string(attr_list, DEV_PHYS_PATH, &phys_path) != 0) 141 goto out; 142 143 if (nvlist_lookup_string(attr_list, DEV_NAME, &dev_name) != 0) 144 dev_name = ""; 145 146 snprintf(s, sizeof (s), "%s %s %s %s\n", 147 class, subclass, phys_path, dev_name); 148 nwritten = write(sysevent_pipe_fds[1], s, strlen(s) + 1); 149 150 HAL_INFO (("sysevent_dev_handler: wrote %d bytes", nwritten)); 151 152 out: 153 nvlist_free(attr_list); 154 } 155 156 static gboolean 157 sysevent_iochannel_data (GIOChannel *source, 158 GIOCondition condition, 159 gpointer user_data) 160 { 161 GError *err = NULL; 162 gchar *s = NULL; 163 gsize len; 164 int matches; 165 gchar class[1024]; 166 gchar subclass[1024]; 167 gchar phys_path[1024]; 168 gchar dev_name[1024]; 169 170 HAL_INFO (("sysevent_iochannel_data")); 171 172 while (g_io_channel_read_line (sysevent_iochannel, &s, &len, NULL, 173 &err) == G_IO_STATUS_NORMAL) { 174 if (len == 0) { 175 break; 176 } 177 178 class[0] = subclass[0] = phys_path[0] = dev_name[0] = '\0'; 179 matches = sscanf(s, "%s %s %s %s", class, subclass, phys_path, dev_name); 180 g_free (s); 181 s = NULL; 182 if (matches < 3) { 183 continue; 184 } 185 HAL_INFO (("sysevent: class=%s, sub=%s", class, subclass)); 186 187 if (strcmp(class, EC_DEV_ADD) == 0) { 188 if ((strcmp(subclass, ESC_DISK) == 0) || 189 (strcmp(subclass, ESC_PRINTER) == 0)) { 190 sysevent_dev_add(phys_path, dev_name); 191 } else if (strcmp(subclass, ESC_LOFI) == 0) { 192 sysevent_lofi_add(phys_path, dev_name); 193 } 194 } else if (strcmp(class, EC_DEV_REMOVE) == 0) { 195 if ((strcmp(subclass, ESC_DISK) == 0) || 196 (strcmp(subclass, ESC_PRINTER) == 0)) { 197 sysevent_dev_remove(phys_path, dev_name); 198 } else if (strcmp(subclass, ESC_LOFI) == 0) { 199 sysevent_lofi_remove(phys_path, dev_name); 200 } 201 } else if (strcmp(class, EC_DEV_BRANCH) == 0) { 202 sysevent_dev_branch(phys_path); 203 } 204 } 205 206 if (err) { 207 g_error_free (err); 208 } 209 210 return (TRUE); 211 } 212 213 static void 214 sysevent_dev_add(gchar *devfs_path, gchar *name) 215 { 216 gchar *parent_devfs_path, *hotplug_devfs_path; 217 HalDevice *parent; 218 219 HAL_INFO (("dev_add: %s %s", name, devfs_path)); 220 221 parent = hal_util_find_closest_ancestor (devfs_path, &parent_devfs_path, &hotplug_devfs_path); 222 if (parent == NULL) { 223 return; 224 } 225 226 HAL_INFO (("dev_add: parent=%s", parent_devfs_path)); 227 HAL_INFO (("dev_add: real=%s", hotplug_devfs_path)); 228 229 devinfo_add (parent, hotplug_devfs_path); 230 231 g_free (parent_devfs_path); 232 g_free (hotplug_devfs_path); 233 234 hotplug_event_process_queue (); 235 } 236 237 static void 238 sysevent_dev_remove(gchar *devfs_path, gchar *name) 239 { 240 HAL_INFO (("dev_remove: %s %s", name, devfs_path)); 241 242 devinfo_remove_branch (devfs_path, NULL); 243 hotplug_event_process_queue (); 244 } 245 246 static void 247 sysevent_dev_branch(gchar *devfs_path) 248 { 249 HAL_INFO (("branch_remove: %s", devfs_path)); 250 251 devinfo_remove_branch (devfs_path, NULL); 252 hotplug_event_process_queue (); 253 } 254 255 static void 256 sysevent_lofi_add(gchar *devfs_path, gchar *name) 257 { 258 di_node_t node; 259 const char *parent_udi; 260 HalDevice *d, *parent; 261 262 HAL_INFO (("lofi_add: %s %s", name, devfs_path)); 263 264 if ((d = hal_device_store_match_key_value_string (hald_get_gdl (), 265 "solaris.devfs_path", devfs_path)) == NULL) { 266 HAL_INFO (("device not found in GDL %s", devfs_path)); 267 return; 268 } 269 parent_udi = hal_device_property_get_string (d, "info.parent"); 270 if ((parent_udi == NULL) || (strlen(parent_udi) == 0)) { 271 HAL_INFO (("parent not found in GDL %s", parent_udi)); 272 return; 273 } 274 if ((parent = hal_device_store_match_key_value_string (hald_get_gdl (), 275 "info.udi", parent_udi)) == NULL) { 276 HAL_INFO (("parent not found in GDL %s", parent_udi)); 277 return; 278 } 279 280 if ((node = di_init (devfs_path, DINFOCPYALL)) == DI_NODE_NIL) { 281 HAL_INFO (("device not found in devinfo %s", devfs_path)); 282 return; 283 } 284 285 HAL_INFO (("device %s parent %s", hal_device_get_udi (d), parent_udi)); 286 devinfo_lofi_add_major (parent, node, devfs_path, NULL, TRUE, d); 287 288 di_fini (node); 289 290 hotplug_event_process_queue (); 291 } 292 293 static void 294 sysevent_lofi_remove(gchar *parent_devfs_path, gchar *name) 295 { 296 devinfo_lofi_remove_minor(parent_devfs_path, name); 297 hotplug_event_process_queue (); 298 } 299