Home | History | Annotate | Download | only in solaris
      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