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