1 /*************************************************************************** 2 * 3 * hotplug.c : HAL-internal hotplug events 4 * 5 * Copyright 2008 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 13 #ifdef HAVE_CONFIG_H 14 # include <config.h> 15 #endif 16 17 #include <stdio.h> 18 #include <string.h> 19 #include <errno.h> 20 #include <sys/types.h> 21 #include <sys/stat.h> 22 #include <sys/un.h> 23 #include <sys/utsname.h> 24 #include <unistd.h> 25 26 #include <glib.h> 27 #include <dbus/dbus.h> 28 #include <dbus/dbus-glib.h> 29 30 #include "../osspec.h" 31 #include "../logger.h" 32 #include "../hald.h" 33 #include "../device_info.h" 34 35 #include "osspec_solaris.h" 36 #include "hotplug.h" 37 #include "devinfo.h" 38 39 /** Queue of ordered hotplug events */ 40 GQueue *hotplug_event_queue; 41 42 /** List of HotplugEvent objects we are currently processing */ 43 GSList *hotplug_events_in_progress = NULL; 44 45 static void hotplug_event_begin (HotplugEvent *hotplug_event); 46 47 void 48 hotplug_event_end (void *end_token) 49 { 50 HotplugEvent *hotplug_event = (HotplugEvent *) end_token; 51 52 hotplug_events_in_progress = g_slist_remove (hotplug_events_in_progress, hotplug_event); 53 g_free (hotplug_event); 54 hotplug_event_process_queue (); 55 } 56 57 static void 58 hotplug_event_begin_devfs_add (HotplugEvent *hotplug_event, HalDevice *d) 59 { 60 HalDevice *parent; 61 const gchar *parent_udi; 62 void (*begin_add_func) (HalDevice *, HalDevice *, DevinfoDevHandler *, void *); 63 64 if (d != NULL) { 65 /* XXX */ 66 HAL_ERROR (("devpath %s already present in store, ignore event", hotplug_event->un.devfs.devfs_path)); 67 68 goto out; 69 } 70 71 /* find parent */ 72 parent_udi = hal_device_property_get_string (hotplug_event->d, "info.parent"); 73 if (parent_udi == NULL || strlen(parent_udi) == 0) { 74 parent = NULL; 75 } else { 76 parent = hal_device_store_match_key_value_string (hald_get_gdl (), "info.udi", parent_udi); 77 } 78 /* only root node is allowed to be orphan */ 79 if (parent == NULL) { 80 if (strcmp(hotplug_event->un.devfs.devfs_path, "/") != 0) { 81 HAL_ERROR (("Parent is NULL devfs_path=%s parent_udi=%s", hotplug_event->un.devfs.devfs_path, parent_udi ? parent_udi : "<null>")); 82 83 goto out; 84 } 85 } 86 87 /* children of ignored parent should be ignored */ 88 if (parent != NULL && hal_device_property_get_bool (parent, "info.ignore")) { 89 HAL_INFO (("parent ignored %s", parent_udi)); 90 91 goto out; 92 } 93 94 /* custom or generic add function */ 95 begin_add_func = hotplug_event->un.devfs.handler->hotplug_begin_add; 96 if (begin_add_func == NULL) { 97 begin_add_func = hotplug_event_begin_add_devinfo; 98 } 99 begin_add_func (hotplug_event->d, 100 parent, 101 hotplug_event->un.devfs.handler, 102 (void *) hotplug_event); 103 return; 104 105 out: 106 g_object_unref (hotplug_event->d); 107 hotplug_event_end ((void *) hotplug_event); 108 109 return; 110 } 111 112 static void 113 hotplug_event_begin_devfs_remove (HotplugEvent *hotplug_event, HalDevice *d) 114 { 115 if (d == NULL) { 116 HAL_ERROR (("devpath %s not present in store, ignore event", hotplug_event->un.devfs.devfs_path)); 117 hotplug_event_end ((void *) hotplug_event); 118 return; 119 } 120 HAL_INFO (("hotplug_event_begin_devfs_remove %s", hal_device_get_udi (d))); 121 122 hotplug_event_begin_remove_devinfo(d, 123 hotplug_event->un.devfs.devfs_path, 124 (void *) hotplug_event); 125 } 126 127 static void 128 hotplug_event_begin_devfs (HotplugEvent *hotplug_event) 129 { 130 HalDevice *d; 131 132 HAL_INFO (("hotplug_event_begin_devfs: %s", hotplug_event->un.devfs.devfs_path)); 133 d = hal_device_store_match_key_value_string (hald_get_gdl (), 134 "solaris.devfs_path", 135 hotplug_event->un.devfs.devfs_path); 136 137 if (hotplug_event->action == HOTPLUG_ACTION_ADD) { 138 hotplug_event_begin_devfs_add (hotplug_event, d); 139 } else if (hotplug_event->action == HOTPLUG_ACTION_REMOVE) { 140 hotplug_event_begin_devfs_remove (hotplug_event, d); 141 } else { 142 HAL_ERROR (("unsupported action %d", hotplug_event->action)); 143 g_object_unref (hotplug_event->d); 144 hotplug_event_end ((void *) hotplug_event); 145 } 146 } 147 148 static void 149 hotplug_event_begin (HotplugEvent *hotplug_event) 150 { 151 switch (hotplug_event->type) { 152 153 case HOTPLUG_EVENT_DEVFS: 154 hotplug_event_begin_devfs (hotplug_event); 155 break; 156 157 default: 158 HAL_ERROR (("Unknown hotplug event type %d", hotplug_event->type)); 159 g_object_unref (hotplug_event->d); 160 hotplug_event_end ((void *) hotplug_event); 161 break; 162 } 163 } 164 165 void 166 hotplug_event_enqueue (HotplugEvent *hotplug_event, int front) 167 { 168 if (hotplug_event_queue == NULL) 169 hotplug_event_queue = g_queue_new (); 170 171 if (front) { 172 g_queue_push_head (hotplug_event_queue, hotplug_event); 173 } else { 174 g_queue_push_tail (hotplug_event_queue, hotplug_event); 175 } 176 } 177 178 void 179 hotplug_event_process_queue (void) 180 { 181 HotplugEvent *hotplug_event; 182 183 if (hotplug_events_in_progress == NULL && 184 (hotplug_event_queue == NULL || g_queue_is_empty (hotplug_event_queue))) { 185 hotplug_queue_now_empty (); 186 goto out; 187 } 188 189 /* do not process events if some other event is in progress */ 190 if (hotplug_events_in_progress != NULL && g_slist_length (hotplug_events_in_progress) > 0) 191 goto out; 192 193 hotplug_event = g_queue_pop_head (hotplug_event_queue); 194 if (hotplug_event == NULL) 195 goto out; 196 197 hotplug_events_in_progress = g_slist_append (hotplug_events_in_progress, hotplug_event); 198 hotplug_event_begin (hotplug_event); 199 200 out: 201 ; 202 } 203