12912Sartem /***************************************************************************
22912Sartem  *
32912Sartem  * hotplug.c : HAL-internal hotplug events
42912Sartem  *
52912Sartem  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
62912Sartem  * Use is subject to license terms.
72912Sartem  *
82912Sartem  * Licensed under the Academic Free License version 2.1
92912Sartem  *
102912Sartem  **************************************************************************/
112912Sartem 
122916Sartem #pragma ident	"%Z%%M%	%I%	%E% SMI"
132912Sartem 
142912Sartem #ifdef HAVE_CONFIG_H
152912Sartem #  include <config.h>
162912Sartem #endif
172912Sartem 
182912Sartem #include <stdio.h>
192912Sartem #include <string.h>
202912Sartem #include <errno.h>
212912Sartem #include <sys/types.h>
222912Sartem #include <sys/stat.h>
232912Sartem #include <sys/un.h>
242912Sartem #include <sys/utsname.h>
252912Sartem #include <unistd.h>
262912Sartem 
272912Sartem #include <glib.h>
282912Sartem #include <dbus/dbus.h>
292912Sartem #include <dbus/dbus-glib.h>
302912Sartem 
312912Sartem #include "../osspec.h"
322912Sartem #include "../logger.h"
332912Sartem #include "../hald.h"
342912Sartem #include "../device_info.h"
352912Sartem 
362912Sartem #include "osspec_solaris.h"
372912Sartem #include "hotplug.h"
382912Sartem #include "devinfo.h"
392912Sartem 
402912Sartem /** Queue of ordered hotplug events */
412912Sartem GQueue *hotplug_event_queue;
422912Sartem 
432912Sartem /** List of HotplugEvent objects we are currently processing */
442912Sartem GSList *hotplug_events_in_progress = NULL;
452912Sartem 
462912Sartem static void hotplug_event_begin (HotplugEvent *hotplug_event);
472912Sartem 
482912Sartem void
492912Sartem hotplug_event_end (void *end_token)
502912Sartem {
512912Sartem 	HotplugEvent *hotplug_event = (HotplugEvent *) end_token;
522912Sartem 
532912Sartem 	hotplug_events_in_progress = g_slist_remove (hotplug_events_in_progress, hotplug_event);
542912Sartem 	g_free (hotplug_event);
552912Sartem 	hotplug_event_process_queue ();
562912Sartem }
572912Sartem 
582912Sartem static void
592912Sartem hotplug_event_begin_devfs_add (HotplugEvent *hotplug_event, HalDevice *d)
602912Sartem {
612912Sartem 	HalDevice *parent;
622912Sartem 	const gchar *parent_udi;
632912Sartem 	void (*begin_add_func) (HalDevice *, HalDevice *, DevinfoDevHandler *, void *);
642912Sartem 
652912Sartem 	if (d != NULL) {
662912Sartem 		/* XXX */
672912Sartem 		HAL_ERROR (("devpath %s already present in store, ignore event", hotplug_event->un.devfs.devfs_path));
682912Sartem 		hotplug_event_end ((void *) hotplug_event);
692912Sartem 		return;
702912Sartem 	}
712912Sartem 
722912Sartem 	/* find parent */
732912Sartem 	parent_udi = hal_device_property_get_string (hotplug_event->d, "info.parent");
742912Sartem 	if (parent_udi == NULL || strlen(parent_udi) == 0) {
752912Sartem 		parent = NULL;
762912Sartem 	} else {
772912Sartem 		parent = hal_device_store_match_key_value_string (hald_get_gdl (), "info.udi", parent_udi);
782912Sartem 	}
792912Sartem 	/* only root node is allowed to be orphan */
802912Sartem 	if (parent == NULL) {
812912Sartem 		if (strcmp(hotplug_event->un.devfs.devfs_path, "/") != 0) {
822912Sartem 			HAL_ERROR (("Parent is NULL devfs_path=%s parent_udi=%s", hotplug_event->un.devfs.devfs_path, parent_udi ? parent_udi : "<null>"));
832912Sartem 			hotplug_event_end ((void *) hotplug_event);
842912Sartem 			return;
852912Sartem 		}
862912Sartem 	}
872912Sartem 
882912Sartem 	/* children of ignored parent should be ignored */
89*3121Sartem 	if (parent != NULL && hal_device_property_get_bool (parent, "info.ignore")) {
902912Sartem 		HAL_INFO (("parent ignored %s", parent_udi));
91*3121Sartem 		hotplug_event_end ((void *) hotplug_event);
92*3121Sartem 		return;
932912Sartem 	}
942912Sartem 
952912Sartem 	/* custom or generic add function */
962912Sartem 	begin_add_func = hotplug_event->un.devfs.handler->hotplug_begin_add;
972912Sartem 	if (begin_add_func == NULL) {
982912Sartem 		begin_add_func = hotplug_event_begin_add_devinfo;
992912Sartem 	}
1002912Sartem 	begin_add_func (hotplug_event->d,
1012912Sartem 			 parent,
1022912Sartem 			 hotplug_event->un.devfs.handler,
1032912Sartem 			 (void *) hotplug_event);
1042912Sartem }
1052912Sartem 
1062912Sartem static void
1072912Sartem hotplug_event_begin_devfs_remove (HotplugEvent *hotplug_event, HalDevice *d)
1082912Sartem {
1092912Sartem 	if (d == NULL) {
1102912Sartem 		HAL_ERROR (("devpath %s not present in store, ignore event", hotplug_event->un.devfs.devfs_path));
1112912Sartem 		hotplug_event_end ((void *) hotplug_event);
1122912Sartem 		return;
1132912Sartem 	}
114*3121Sartem 	HAL_INFO (("hotplug_event_begin_devfs_remove %s", hal_device_get_udi (d)));
1152912Sartem 
1162912Sartem 	hotplug_event_begin_remove_devinfo(d,
1172912Sartem 			 hotplug_event->un.devfs.devfs_path,
1182912Sartem 			 (void *) hotplug_event);
1192912Sartem }
1202912Sartem 
1212912Sartem static void
1222912Sartem hotplug_event_begin_devfs (HotplugEvent *hotplug_event)
1232912Sartem {
1242912Sartem 	HalDevice *d;
1252912Sartem 
1262912Sartem 	HAL_INFO (("hotplug_event_begin_devfs: %s", hotplug_event->un.devfs.devfs_path));
1272912Sartem 	d = hal_device_store_match_key_value_string (hald_get_gdl (),
1282912Sartem 						"solaris.devfs_path",
1292912Sartem 						hotplug_event->un.devfs.devfs_path);
1302912Sartem 
1312912Sartem 	if (hotplug_event->action == HOTPLUG_ACTION_ADD) {
1322912Sartem 		hotplug_event_begin_devfs_add (hotplug_event, d);
1332912Sartem 	} else if (hotplug_event->action == HOTPLUG_ACTION_REMOVE) {
1342912Sartem 		hotplug_event_begin_devfs_remove (hotplug_event, d);
1352912Sartem 	} else {
1362912Sartem 		hotplug_event_end ((void *) hotplug_event);
1372912Sartem 	}
1382912Sartem }
1392912Sartem 
1402912Sartem static void
1412912Sartem hotplug_event_begin (HotplugEvent *hotplug_event)
1422912Sartem {
1432912Sartem 	switch (hotplug_event->type) {
1442912Sartem 
1452912Sartem 	case HOTPLUG_EVENT_DEVFS:
1462912Sartem 		hotplug_event_begin_devfs (hotplug_event);
1472912Sartem 		break;
1482912Sartem 
1492912Sartem 	default:
1502912Sartem 		HAL_ERROR (("Unknown hotplug event type %d", hotplug_event->type));
1512912Sartem 		hotplug_event_end ((void *) hotplug_event);
1522912Sartem 		break;
1532912Sartem 	}
1542912Sartem }
1552912Sartem 
1562912Sartem void
1572912Sartem hotplug_event_enqueue (HotplugEvent *hotplug_event, int front)
1582912Sartem {
1592912Sartem 	if (hotplug_event_queue == NULL)
1602912Sartem 		hotplug_event_queue = g_queue_new ();
1612912Sartem 
1622912Sartem 	if (front) {
1632912Sartem 		g_queue_push_head (hotplug_event_queue, hotplug_event);
1642912Sartem 	} else {
1652912Sartem 		g_queue_push_tail (hotplug_event_queue, hotplug_event);
1662912Sartem 	}
1672912Sartem }
1682912Sartem 
1692912Sartem void
1702912Sartem hotplug_event_process_queue (void)
1712912Sartem {
1722912Sartem 	HotplugEvent *hotplug_event;
1732912Sartem 
1742912Sartem 	if (hotplug_events_in_progress == NULL &&
1752912Sartem 	    (hotplug_event_queue == NULL || g_queue_is_empty (hotplug_event_queue))) {
1762912Sartem 		hotplug_queue_now_empty ();
1772912Sartem 		goto out;
1782912Sartem 	}
1792912Sartem 
1802912Sartem 	/* do not process events if some other event is in progress */
1812912Sartem 	if (hotplug_events_in_progress != NULL && g_slist_length (hotplug_events_in_progress) > 0)
1822912Sartem 		goto out;
1832912Sartem 
1842912Sartem 	hotplug_event = g_queue_pop_head (hotplug_event_queue);
1852912Sartem 	if (hotplug_event == NULL)
1862912Sartem 		goto out;
1872912Sartem 
1882912Sartem 	hotplug_events_in_progress = g_slist_append (hotplug_events_in_progress, hotplug_event);
1892912Sartem 	hotplug_event_begin (hotplug_event);
1902912Sartem 
1912912Sartem out:
1922912Sartem 	;
1932912Sartem }
194