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 */ 40GQueue *hotplug_event_queue; 41 42/** List of HotplugEvent objects we are currently processing */ 43GSList *hotplug_events_in_progress = NULL; 44 45static void hotplug_event_begin (HotplugEvent *hotplug_event); 46 47void 48hotplug_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 57static void 58hotplug_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 105out: 106 g_object_unref (hotplug_event->d); 107 hotplug_event_end ((void *) hotplug_event); 108 109 return; 110} 111 112static void 113hotplug_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 127static void 128hotplug_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 148static void 149hotplug_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 165void 166hotplug_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 178void 179hotplug_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 200out: 201 ; 202} 203