xref: /onnv-gate/usr/src/cmd/hal/addons/storage/addon-storage.c (revision 10459:38bef17cedbb)
12912Sartem /***************************************************************************
22912Sartem  *
32912Sartem  * addon-storage.c : watch removable media state changes
42912Sartem  *
5*10459SArtem.Kachitchkin@Sun.COM  * Copyright 2009 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 
122912Sartem #ifdef HAVE_CONFIG_H
132912Sartem #  include <config.h>
142912Sartem #endif
152912Sartem 
162912Sartem #include <errno.h>
172912Sartem #include <string.h>
182912Sartem #include <strings.h>
192912Sartem #include <stdlib.h>
202912Sartem #include <stdio.h>
212912Sartem #include <sys/ioctl.h>
222912Sartem #include <sys/types.h>
232912Sartem #include <sys/stat.h>
242912Sartem #include <sys/types.h>
252912Sartem #include <sys/wait.h>
262912Sartem #include <fcntl.h>
272912Sartem #include <unistd.h>
282912Sartem #include <sys/mnttab.h>
292912Sartem #include <sys/dkio.h>
302912Sartem #include <priv.h>
31*10459SArtem.Kachitchkin@Sun.COM #include <libsysevent.h>
32*10459SArtem.Kachitchkin@Sun.COM #include <sys/sysevent/dev.h>
332912Sartem 
342912Sartem #include <libhal.h>
352912Sartem 
362912Sartem #include "../../hald/logger.h"
372912Sartem 
382912Sartem #define	SLEEP_PERIOD	5
392912Sartem 
40*10459SArtem.Kachitchkin@Sun.COM static char			*udi;
41*10459SArtem.Kachitchkin@Sun.COM static char			*devfs_path;
42*10459SArtem.Kachitchkin@Sun.COM LibHalContext			*ctx = NULL;
43*10459SArtem.Kachitchkin@Sun.COM static sysevent_handle_t	*shp = NULL;
44*10459SArtem.Kachitchkin@Sun.COM 
45*10459SArtem.Kachitchkin@Sun.COM static void	sysevent_dev_handler(sysevent_t *);
46*10459SArtem.Kachitchkin@Sun.COM 
472912Sartem static void
my_dbus_error_free(DBusError * error)482912Sartem my_dbus_error_free(DBusError *error)
492912Sartem {
502912Sartem 	if (dbus_error_is_set(error)) {
512912Sartem 		dbus_error_free(error);
522912Sartem 	}
532912Sartem }
542912Sartem 
552912Sartem static void
sysevent_init()56*10459SArtem.Kachitchkin@Sun.COM sysevent_init ()
57*10459SArtem.Kachitchkin@Sun.COM {
58*10459SArtem.Kachitchkin@Sun.COM 	const char	*subcl[1];
59*10459SArtem.Kachitchkin@Sun.COM 
60*10459SArtem.Kachitchkin@Sun.COM 	shp = sysevent_bind_handle (sysevent_dev_handler);
61*10459SArtem.Kachitchkin@Sun.COM 	if (shp == NULL) {
62*10459SArtem.Kachitchkin@Sun.COM 		HAL_DEBUG (("sysevent_bind_handle failed %d", errno));
63*10459SArtem.Kachitchkin@Sun.COM 		return;
64*10459SArtem.Kachitchkin@Sun.COM 	}
65*10459SArtem.Kachitchkin@Sun.COM 
66*10459SArtem.Kachitchkin@Sun.COM 	subcl[0] = ESC_DEV_EJECT_REQUEST;
67*10459SArtem.Kachitchkin@Sun.COM 	if (sysevent_subscribe_event (shp, EC_DEV_STATUS, subcl, 1) != 0) {
68*10459SArtem.Kachitchkin@Sun.COM 		HAL_INFO (("subscribe(dev_status) failed %d", errno));
69*10459SArtem.Kachitchkin@Sun.COM 		sysevent_unbind_handle (shp);
70*10459SArtem.Kachitchkin@Sun.COM 		return;
71*10459SArtem.Kachitchkin@Sun.COM 	}
72*10459SArtem.Kachitchkin@Sun.COM }
73*10459SArtem.Kachitchkin@Sun.COM 
74*10459SArtem.Kachitchkin@Sun.COM static void
sysevent_fini()75*10459SArtem.Kachitchkin@Sun.COM sysevent_fini ()
76*10459SArtem.Kachitchkin@Sun.COM {
77*10459SArtem.Kachitchkin@Sun.COM 	if (shp != NULL) {
78*10459SArtem.Kachitchkin@Sun.COM 		sysevent_unbind_handle (shp);
79*10459SArtem.Kachitchkin@Sun.COM 		shp = NULL;
80*10459SArtem.Kachitchkin@Sun.COM 	}
81*10459SArtem.Kachitchkin@Sun.COM }
82*10459SArtem.Kachitchkin@Sun.COM 
83*10459SArtem.Kachitchkin@Sun.COM static void
sysevent_dev_handler(sysevent_t * ev)84*10459SArtem.Kachitchkin@Sun.COM sysevent_dev_handler (sysevent_t *ev)
85*10459SArtem.Kachitchkin@Sun.COM {
86*10459SArtem.Kachitchkin@Sun.COM 	char		*class;
87*10459SArtem.Kachitchkin@Sun.COM 	char		*subclass;
88*10459SArtem.Kachitchkin@Sun.COM 	nvlist_t	*attr_list;
89*10459SArtem.Kachitchkin@Sun.COM 	char		*phys_path, *path;
90*10459SArtem.Kachitchkin@Sun.COM 	char		*p;
91*10459SArtem.Kachitchkin@Sun.COM 	int		len;
92*10459SArtem.Kachitchkin@Sun.COM 	DBusError	error;
93*10459SArtem.Kachitchkin@Sun.COM 
94*10459SArtem.Kachitchkin@Sun.COM 	if ((class = sysevent_get_class_name (ev)) == NULL)
95*10459SArtem.Kachitchkin@Sun.COM 		return;
96*10459SArtem.Kachitchkin@Sun.COM 
97*10459SArtem.Kachitchkin@Sun.COM 	if ((subclass = sysevent_get_subclass_name (ev)) == NULL)
98*10459SArtem.Kachitchkin@Sun.COM 		return;
99*10459SArtem.Kachitchkin@Sun.COM 
100*10459SArtem.Kachitchkin@Sun.COM 	if ((strcmp (class, EC_DEV_STATUS) != 0) ||
101*10459SArtem.Kachitchkin@Sun.COM 	    (strcmp (subclass, ESC_DEV_EJECT_REQUEST) != 0))
102*10459SArtem.Kachitchkin@Sun.COM 		return;
103*10459SArtem.Kachitchkin@Sun.COM 
104*10459SArtem.Kachitchkin@Sun.COM 	if (sysevent_get_attr_list (ev, &attr_list) != 0)
105*10459SArtem.Kachitchkin@Sun.COM 		return;
106*10459SArtem.Kachitchkin@Sun.COM 
107*10459SArtem.Kachitchkin@Sun.COM 	if (nvlist_lookup_string (attr_list, DEV_PHYS_PATH, &phys_path) != 0) {
108*10459SArtem.Kachitchkin@Sun.COM 		goto out;
109*10459SArtem.Kachitchkin@Sun.COM 	}
110*10459SArtem.Kachitchkin@Sun.COM 
111*10459SArtem.Kachitchkin@Sun.COM 	/* see if event belongs to our LUN (ignore slice and "/devices" ) */
112*10459SArtem.Kachitchkin@Sun.COM 	if (strncmp (phys_path, "/devices", sizeof ("/devices") - 1) == 0)
113*10459SArtem.Kachitchkin@Sun.COM 		path = phys_path + sizeof ("/devices") - 1;
114*10459SArtem.Kachitchkin@Sun.COM 	else
115*10459SArtem.Kachitchkin@Sun.COM 		path = phys_path;
116*10459SArtem.Kachitchkin@Sun.COM 
117*10459SArtem.Kachitchkin@Sun.COM 	if ((p = strrchr (path, ':')) == NULL)
118*10459SArtem.Kachitchkin@Sun.COM 		goto out;
119*10459SArtem.Kachitchkin@Sun.COM 	len = (uintptr_t)p - (uintptr_t)path;
120*10459SArtem.Kachitchkin@Sun.COM 	if (strncmp (path, devfs_path, len) != 0)
121*10459SArtem.Kachitchkin@Sun.COM 		goto out;
122*10459SArtem.Kachitchkin@Sun.COM 
123*10459SArtem.Kachitchkin@Sun.COM 	HAL_DEBUG (("sysevent_dev_handler %s %s", subclass, phys_path));
124*10459SArtem.Kachitchkin@Sun.COM 
125*10459SArtem.Kachitchkin@Sun.COM 	/* we got it, tell the world */
126*10459SArtem.Kachitchkin@Sun.COM 	dbus_error_init (&error);
127*10459SArtem.Kachitchkin@Sun.COM 	libhal_device_emit_condition (ctx, udi, "EjectPressed", "", &error);
128*10459SArtem.Kachitchkin@Sun.COM 	dbus_error_free (&error);
129*10459SArtem.Kachitchkin@Sun.COM 
130*10459SArtem.Kachitchkin@Sun.COM out:
131*10459SArtem.Kachitchkin@Sun.COM 	nvlist_free(attr_list);
132*10459SArtem.Kachitchkin@Sun.COM }
133*10459SArtem.Kachitchkin@Sun.COM 
134*10459SArtem.Kachitchkin@Sun.COM static void
force_unmount(LibHalContext * ctx,const char * udi)1352912Sartem force_unmount (LibHalContext *ctx, const char *udi)
1362912Sartem {
1372912Sartem 	DBusError error;
1382912Sartem 	DBusMessage *msg = NULL;
1392912Sartem 	DBusMessage *reply = NULL;
1402912Sartem 	char **options = NULL;
1412912Sartem 	unsigned int num_options = 0;
1422912Sartem 	DBusConnection *dbus_connection;
1432912Sartem 	char *device_file;
1442912Sartem 
1452912Sartem 	dbus_error_init (&error);
1462912Sartem 
1472912Sartem 	dbus_connection = libhal_ctx_get_dbus_connection (ctx);
1482912Sartem 
1492912Sartem 	msg = dbus_message_new_method_call ("org.freedesktop.Hal", udi,
1502912Sartem 					    "org.freedesktop.Hal.Device.Volume",
1512912Sartem 					    "Unmount");
1522912Sartem 	if (msg == NULL) {
1532912Sartem 		HAL_DEBUG (("Could not create dbus message for %s", udi));
1542912Sartem 		goto out;
1552912Sartem 	}
1562912Sartem 
1572912Sartem 
1582912Sartem 	options = calloc (1, sizeof (char *));
1592912Sartem 	if (options == NULL) {
1602912Sartem 		HAL_DEBUG (("Could not allocate options array"));
1612912Sartem 		goto out;
1622912Sartem 	}
1632912Sartem 
1642912Sartem 	device_file = libhal_device_get_property_string (ctx, udi, "block.device", &error);
1652912Sartem 	if (device_file != NULL) {
1662912Sartem 		libhal_free_string (device_file);
1672912Sartem 	}
1682912Sartem 	dbus_error_free (&error);
1692912Sartem 
1702912Sartem 	if (!dbus_message_append_args (msg,
1712912Sartem 				       DBUS_TYPE_ARRAY, DBUS_TYPE_STRING, &options, num_options,
1722912Sartem 				       DBUS_TYPE_INVALID)) {
1732912Sartem 		HAL_DEBUG (("Could not append args to dbus message for %s", udi));
1742912Sartem 		goto out;
1752912Sartem 	}
1762912Sartem 
1772912Sartem 	if (!(reply = dbus_connection_send_with_reply_and_block (dbus_connection, msg, -1, &error))) {
1782912Sartem 		HAL_DEBUG (("Unmount failed for %s: %s : %s\n", udi, error.name, error.message));
1792912Sartem 		goto out;
1802912Sartem 	}
1812912Sartem 
1822912Sartem 	if (dbus_error_is_set (&error)) {
1832912Sartem 		HAL_DEBUG (("Unmount failed for %s\n%s : %s\n", udi, error.name, error.message));
1842912Sartem 		goto out;
1852912Sartem 	}
1862912Sartem 
1872912Sartem 	HAL_DEBUG (("Succesfully unmounted udi '%s'", udi));
1882912Sartem 
1892912Sartem out:
1902912Sartem 	dbus_error_free (&error);
1912912Sartem 	if (options != NULL)
1922912Sartem 		free (options);
1932912Sartem 	if (msg != NULL)
1942912Sartem 		dbus_message_unref (msg);
1952912Sartem 	if (reply != NULL)
1962912Sartem 		dbus_message_unref (reply);
1972912Sartem }
1982912Sartem 
1992912Sartem static void
unmount_childs(LibHalContext * ctx,const char * udi)2002912Sartem unmount_childs (LibHalContext *ctx, const char *udi)
2012912Sartem {
2022912Sartem 	DBusError error;
2032912Sartem 	int num_volumes;
2042912Sartem 	char **volumes;
2052912Sartem 
2062912Sartem 	dbus_error_init (&error);
2072912Sartem 
2082912Sartem 	/* need to force unmount all partitions */
2092912Sartem 	if ((volumes = libhal_manager_find_device_string_match (
2102912Sartem 	     ctx, "block.storage_device", udi, &num_volumes, &error)) != NULL) {
2112912Sartem 		dbus_error_free (&error);
2122912Sartem 		int i;
2132912Sartem 
2142912Sartem 		for (i = 0; i < num_volumes; i++) {
2152912Sartem 			char *vol_udi;
2162912Sartem 
2172912Sartem 			vol_udi = volumes[i];
2182912Sartem 			if (libhal_device_get_property_bool (ctx, vol_udi, "block.is_volume", &error)) {
2192912Sartem 				dbus_error_free (&error);
2202912Sartem 				if (libhal_device_get_property_bool (ctx, vol_udi, "volume.is_mounted", &error)) {
2212912Sartem 					dbus_error_free (&error);
2222912Sartem 					HAL_DEBUG (("Forcing unmount of child '%s'", vol_udi));
2232912Sartem 					force_unmount (ctx, vol_udi);
2242912Sartem 				}
2252912Sartem 			}
2262912Sartem 		}
2272912Sartem 		libhal_free_string_array (volumes);
2282912Sartem 	}
2292912Sartem 	my_dbus_error_free (&error);
2302912Sartem }
2312912Sartem 
2322912Sartem /** Check if a filesystem on a special device file is mounted
2332912Sartem  *
2342912Sartem  *  @param  device_file         Special device file, e.g. /dev/cdrom
2352912Sartem  *  @return                     TRUE iff there is a filesystem system mounted
2362912Sartem  *                              on the special device file
2372912Sartem  */
2382912Sartem static dbus_bool_t
is_mounted(const char * device_file)2392912Sartem is_mounted (const char *device_file)
2402912Sartem {
2412912Sartem 	FILE *f;
2422912Sartem 	dbus_bool_t rc = FALSE;
2432912Sartem 	struct mnttab mp;
2442912Sartem 	struct mnttab mpref;
2452912Sartem 
2462912Sartem 	if ((f = fopen ("/etc/mnttab", "r")) == NULL)
2472912Sartem 		return rc;
2482912Sartem 
2492912Sartem 	bzero(&mp, sizeof (mp));
2502912Sartem 	bzero(&mpref, sizeof (mpref));
2512912Sartem 	mpref.mnt_special = (char *)device_file;
2522912Sartem 	if (getmntany(f, &mp, &mpref) == 0) {
2532912Sartem 		rc = TRUE;
2542912Sartem 	}
2552912Sartem 
2562912Sartem 	fclose (f);
2572912Sartem 	return rc;
2582912Sartem }
2592912Sartem 
2602912Sartem void
close_device(int * fd)2612912Sartem close_device (int *fd)
2622912Sartem {
2632912Sartem 	if (*fd > 0) {
2642912Sartem 		close (*fd);
2652912Sartem 		*fd = -1;
2662912Sartem 	}
2672912Sartem }
2682912Sartem 
2692912Sartem void
drop_privileges()2702912Sartem drop_privileges ()
2712912Sartem {
2722912Sartem 	priv_set_t *pPrivSet = NULL;
2732912Sartem 	priv_set_t *lPrivSet = NULL;
2742912Sartem 
2752912Sartem 	/*
2762912Sartem 	 * Start with the 'basic' privilege set and then remove any
2772912Sartem 	 * of the 'basic' privileges that will not be needed.
2782912Sartem 	 */
2792912Sartem 	if ((pPrivSet = priv_str_to_set("basic", ",", NULL)) == NULL) {
2802912Sartem 		return;
2812912Sartem 	}
2822912Sartem 
2832912Sartem 	/* Clear privileges we will not need from the 'basic' set */
2842912Sartem 	(void) priv_delset(pPrivSet, PRIV_FILE_LINK_ANY);
2852912Sartem 	(void) priv_delset(pPrivSet, PRIV_PROC_INFO);
2862912Sartem 	(void) priv_delset(pPrivSet, PRIV_PROC_SESSION);
2872912Sartem 
2882912Sartem 	/* to open logindevperm'd devices */
2892912Sartem 	(void) priv_addset(pPrivSet, PRIV_FILE_DAC_READ);
2902912Sartem 
291*10459SArtem.Kachitchkin@Sun.COM 	/* to receive sysevents */
292*10459SArtem.Kachitchkin@Sun.COM 	(void) priv_addset(pPrivSet, PRIV_SYS_CONFIG);
293*10459SArtem.Kachitchkin@Sun.COM 
2942912Sartem 	/* Set the permitted privilege set. */
2952912Sartem 	if (setppriv(PRIV_SET, PRIV_PERMITTED, pPrivSet) != 0) {
2962912Sartem 		return;
2972912Sartem 	}
2982912Sartem 
2992912Sartem 	/* Clear the limit set. */
3002912Sartem 	if ((lPrivSet = priv_allocset()) == NULL) {
3012912Sartem 		return;
3022912Sartem 	}
3032912Sartem 
3042912Sartem 	priv_emptyset(lPrivSet);
3052912Sartem 
3062912Sartem 	if (setppriv(PRIV_SET, PRIV_LIMIT, lPrivSet) != 0) {
3072912Sartem 		return;
3082912Sartem 	}
3092912Sartem 
3102912Sartem 	priv_freeset(lPrivSet);
3112912Sartem }
3122912Sartem 
3132912Sartem int
main(int argc,char * argv[])3142912Sartem main (int argc, char *argv[])
3152912Sartem {
3162912Sartem 	char *device_file, *raw_device_file;
3172912Sartem 	DBusError error;
3182912Sartem 	char *bus;
3192912Sartem 	char *drive_type;
3202912Sartem 	int state, last_state;
3212912Sartem 	char *support_media_changed_str;
3222912Sartem 	int support_media_changed;
3232912Sartem 	int fd = -1;
3242912Sartem 
3252912Sartem 	if ((udi = getenv ("UDI")) == NULL)
3262912Sartem 		goto out;
3272912Sartem 	if ((device_file = getenv ("HAL_PROP_BLOCK_DEVICE")) == NULL)
3282912Sartem 		goto out;
3292912Sartem 	if ((raw_device_file = getenv ("HAL_PROP_BLOCK_SOLARIS_RAW_DEVICE")) == NULL)
3302912Sartem 		goto out;
3312912Sartem 	if ((bus = getenv ("HAL_PROP_STORAGE_BUS")) == NULL)
3322912Sartem 		goto out;
3332912Sartem 	if ((drive_type = getenv ("HAL_PROP_STORAGE_DRIVE_TYPE")) == NULL)
3342912Sartem 		goto out;
335*10459SArtem.Kachitchkin@Sun.COM 	if ((devfs_path = getenv ("HAL_PROP_SOLARIS_DEVFS_PATH")) == NULL)
336*10459SArtem.Kachitchkin@Sun.COM 		goto out;
3372912Sartem 
3382912Sartem 	drop_privileges ();
3392912Sartem 
3402912Sartem 	setup_logger ();
3412912Sartem 
342*10459SArtem.Kachitchkin@Sun.COM 	sysevent_init ();
343*10459SArtem.Kachitchkin@Sun.COM 
3442912Sartem 	support_media_changed_str = getenv ("HAL_PROP_STORAGE_CDROM_SUPPORT_MEDIA_CHANGED");
3452912Sartem 	if (support_media_changed_str != NULL && strcmp (support_media_changed_str, "true") == 0)
3462912Sartem 		support_media_changed = TRUE;
3472912Sartem 	else
3482912Sartem 		support_media_changed = FALSE;
3492912Sartem 
3502912Sartem 	dbus_error_init (&error);
3512912Sartem 
3522912Sartem 	if ((ctx = libhal_ctx_init_direct (&error)) == NULL) {
3532912Sartem 		goto out;
3542912Sartem 	}
3552912Sartem 	my_dbus_error_free (&error);
3562912Sartem 
3572912Sartem 	if (!libhal_device_addon_is_ready (ctx, udi, &error)) {
3582912Sartem 		goto out;
3592912Sartem 	}
3602912Sartem 	my_dbus_error_free (&error);
3612912Sartem 
3622912Sartem 	printf ("Doing addon-storage for %s (bus %s) (drive_type %s) (udi %s)\n", device_file, bus, drive_type, udi);
3632912Sartem 
3642912Sartem 	last_state = state = DKIO_NONE;
3652912Sartem 
3662912Sartem 	/* Linux version of this addon attempts to re-open the device O_EXCL
3672912Sartem 	 * every 2 seconds, trying to figure out if some other app,
3682912Sartem 	 * like a cd burner, is using the device. Aside from questionable
3692912Sartem 	 * value of this (apps should use HAL's locked property or/and
3702912Sartem 	 * Solaris in_use facility), but also frequent opens/closes
3712912Sartem 	 * keeps media constantly spun up. All this needs more thought.
3722912Sartem 	 */
3732912Sartem 	for (;;) {
3742912Sartem 		if (is_mounted (device_file)) {
3752912Sartem 			close_device (&fd);
3762912Sartem 			sleep (SLEEP_PERIOD);
3772912Sartem 		} else if ((fd < 0) && ((fd = open (raw_device_file, O_RDONLY | O_NONBLOCK)) < 0)) {
3782912Sartem 			HAL_DEBUG (("open failed for %s: %s", raw_device_file, strerror (errno)));
3792912Sartem 			sleep (SLEEP_PERIOD);
3802912Sartem 		} else {
3812912Sartem 			/* Check if a disc is in the drive */
3822912Sartem 			/* XXX initial call always returns inserted
3832912Sartem 			 * causing unnecessary rescan - optimize?
3842912Sartem 			 */
3852912Sartem 			if (ioctl (fd, DKIOCSTATE, &state) == 0) {
3862912Sartem 				if (state == last_state) {
3872912Sartem 					HAL_DEBUG (("state has not changed %d %s", state, device_file));
3882912Sartem 					continue;
3892912Sartem 				} else {
3902912Sartem 					HAL_DEBUG (("new state %d %s", state, device_file));
3912912Sartem 				}
3922912Sartem 
3932912Sartem 				switch (state) {
3942912Sartem 				case DKIO_EJECTED:
3952912Sartem 					HAL_DEBUG (("Media removal detected on %s", device_file));
3962912Sartem 					last_state = state;
3972912Sartem 
3982912Sartem 					libhal_device_set_property_bool (ctx, udi, "storage.removable.media_available", FALSE, &error);
3992912Sartem 					my_dbus_error_free (&error);
4002912Sartem 
4012912Sartem 					/* attempt to unmount all childs */
4022912Sartem 					unmount_childs (ctx, udi);
4032912Sartem 
4042912Sartem 					/* could have a fs on the main block device; do a rescan to remove it */
4052912Sartem 					libhal_device_rescan (ctx, udi, &error);
4062912Sartem 					my_dbus_error_free (&error);
4072912Sartem 					break;
4082912Sartem 
4092912Sartem 				case DKIO_INSERTED:
4102912Sartem 					HAL_DEBUG (("Media insertion detected on %s", device_file));
4112912Sartem 					last_state = state;
4122912Sartem 
4132912Sartem 					libhal_device_set_property_bool (ctx, udi, "storage.removable.media_available", TRUE, &error);
4142912Sartem 					my_dbus_error_free (&error);
4152912Sartem 
4162912Sartem 					/* could have a fs on the main block device; do a rescan to add it */
4172912Sartem 					libhal_device_rescan (ctx, udi, &error);
4182912Sartem 					my_dbus_error_free (&error);
4192912Sartem 					break;
4202912Sartem 
4212912Sartem 				case DKIO_DEV_GONE:
4222912Sartem 					HAL_DEBUG (("Device gone detected on %s", device_file));
4232912Sartem 					last_state = state;
4242912Sartem 
4252912Sartem 					unmount_childs (ctx, udi);
4262912Sartem 					close_device (&fd);
4272912Sartem 					goto out;
4282912Sartem 
4292912Sartem 				case DKIO_NONE:
4302912Sartem 				default:
4312912Sartem 					break;
4322912Sartem 				}
4332912Sartem 			} else {
4342912Sartem 				HAL_DEBUG (("DKIOCSTATE failed: %s\n", strerror(errno)));
4352912Sartem 				sleep (SLEEP_PERIOD);
4362912Sartem 			}
4372912Sartem 		}
4382912Sartem 	}
4392912Sartem 
4402912Sartem out:
441*10459SArtem.Kachitchkin@Sun.COM 	sysevent_fini ();
4422912Sartem 	if (ctx != NULL) {
4432912Sartem 		my_dbus_error_free (&error);
4442912Sartem 		libhal_ctx_shutdown (ctx, &error);
4452912Sartem 		libhal_ctx_free (ctx);
4462912Sartem 	}
4472912Sartem 
4482912Sartem 	return 0;
4492912Sartem }
450