tray close

Artem Kachitchkine Artem.Kachitchkin at Sun.COM
Wed Aug 16 21:23:43 PDT 2006


Here's the preliminary patch. If it looks okay, I'll test some more and 
add documentation.

(diffs of hal-storage-eject.c look kinda weird, so I also attached the 
file itself)

thanks,
-Artem.
-------------- next part --------------
diff --git a/fdi/policy/10osvendor/20-storage-methods.fdi b/fdi/policy/10osvendor/20-storage-methods.fdi
index f67c7b0..9b3f3a5 100644
--- a/fdi/policy/10osvendor/20-storage-methods.fdi
+++ b/fdi/policy/10osvendor/20-storage-methods.fdi
@@ -184,5 +184,20 @@
       <append key="volume.unmount.valid_options" type="strlist">lazy</append>
 
     </match>
+
+    <match key="storage.requires_eject" bool="true">
+        <!-- storage Eject causes eject on each volume on this storage -->
+        <append key="info.interfaces" type="strlist">org.freedesktop.Hal.Device.Storage</append>
+        <append key="org.freedesktop.Hal.Device.Storage.method_names" type="strlist">Eject</append>
+        <append key="org.freedesktop.Hal.Device.Storage.method_signatures" type="strlist">as</append>
+	<append key="org.freedesktop.Hal.Device.Storage.method_argnames" type="strlist">extra_options</append>
+        <append key="org.freedesktop.Hal.Device.Storage.method_execpaths" type="strlist">hal-storage-eject</append>
+
+        <append key="info.interfaces" type="strlist">org.freedesktop.Hal.Device.Storage</append>
+        <append key="org.freedesktop.Hal.Device.Storage.method_names" type="strlist">CloseTray</append>
+        <append key="org.freedesktop.Hal.Device.Storage.method_signatures" type="strlist">as</append>
+	<append key="org.freedesktop.Hal.Device.Storage.method_argnames" type="strlist">extra_options</append>
+        <append key="org.freedesktop.Hal.Device.Storage.method_execpaths" type="strlist">hal-storage-closetray</append>
+    </match>
   </device>
 </deviceinfo>
diff --git a/tools/Makefile.am b/tools/Makefile.am
index bcfbf59..c595c7e 100644
--- a/tools/Makefile.am
+++ b/tools/Makefile.am
@@ -53,6 +53,7 @@ libexec_PROGRAMS =                      
 	hal-storage-mount	            \
 	hal-storage-unmount 	            \
 	hal-storage-eject	            \
+	hal-storage-closetray	            \
 	hal-storage-cleanup-mountpoint      \
 	hal-storage-cleanup-all-mountpoints \
 	hal-system-power-pmu
@@ -66,6 +67,9 @@ hal_storage_unmount_LDADD = @GLIB_LIBS@ 
 hal_storage_eject_SOURCES = hal-storage-eject.c hal-storage-shared.c hal-storage-shared.h
 hal_storage_eject_LDADD = @GLIB_LIBS@ @POLKIT_LIBS@ @DBUS_LIBS@ $(top_builddir)/libhal/libhal.la $(top_builddir)/libhal-storage/libhal-storage.la
 
+hal_storage_closetray_SOURCES = hal-storage-closetray.c hal-storage-shared.c hal-storage-shared.h
+hal_storage_closetray_LDADD = @GLIB_LIBS@ @POLKIT_LIBS@ @DBUS_LIBS@ $(top_builddir)/libhal/libhal.la $(top_builddir)/libhal-storage/libhal-storage.la
+
 hal_storage_cleanup_mountpoint_SOURCES = hal-storage-cleanup-mountpoint.c hal-storage-shared.c hal-storage-shared.h
 hal_storage_cleanup_mountpoint_LDADD = @GLIB_LIBS@ @POLKIT_LIBS@ @DBUS_LIBS@ $(top_builddir)/libhal/libhal.la $(top_builddir)/libhal-storage/libhal-storage.la
 
diff --git a/tools/hal-storage-closetray.c b/tools/hal-storage-closetray.c
new file mode 100644
index 0000000..368ca39
--- /dev/null
+++ b/tools/hal-storage-closetray.c
@@ -0,0 +1,177 @@
+/***************************************************************************
+ *
+ * hal-storage-mount.c : CloseTray method handler
+ *
+ * Copyright (C) 2006 David Zeuthen, <david at fubar.dk>
+ * Copyright (C) 2006 Sun Microsystems, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ **************************************************************************/
+
+
+#ifdef HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <glib.h>
+#include <glib/gstdio.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <libhal.h>
+#include <libhal-storage.h>
+#ifdef HAVE_POLKIT
+#include <libpolkit.h>
+#endif
+
+#include "hal-storage-shared.h"
+
+
+static void
+usage (void)
+{
+	fprintf (stderr, "This program should only be started by hald.\n");
+	exit (1);
+}
+
+
+void static
+unknown_closetray_error (const char *detail)
+{
+	fprintf (stderr, "org.freedesktop.Hal.Device.Storage.UnknownFailure\n");
+	fprintf (stderr, "%s\n", detail);
+	exit (1);
+}
+
+
+static void
+invalid_closetray_option (const char *option, const char *uid)
+{
+	fprintf (stderr, "org.freedesktop.Hal.Device.Storage.InvalidCloseTrayOption\n");
+	fprintf (stderr, "The option '%s' is not allowed for uid=%s\n", option, uid);
+	exit (1);
+}
+
+#ifdef __FreeBSD__
+#error Need FreeBSD specific changes here
+#endif
+
+
+int
+main (int argc, char *argv[])
+{
+	char *udi;
+	char *device;
+	LibHalDrive *drive;
+	DBusError error;
+	LibHalContext *hal_ctx = NULL;
+	DBusConnection *system_bus = NULL;
+#ifdef HAVE_POLKIT
+	LibPolKitContext *pol_ctx = NULL;
+#endif
+	char *invoked_by_uid;
+	char *invoked_by_syscon_name;
+	int i;
+	char closetray_options[1024];
+	char **given_options;
+	const char *end;
+
+	device = getenv ("HAL_PROP_BLOCK_DEVICE");
+	if (device == NULL)
+		usage ();
+
+	udi = getenv ("HAL_PROP_INFO_UDI");
+	if (udi == NULL)
+		usage ();
+
+	invoked_by_uid = getenv ("HAL_METHOD_INVOKED_BY_UID");
+
+	invoked_by_syscon_name = getenv ("HAL_METHOD_INVOKED_BY_SYSTEMBUS_CONNECTION_NAME");
+
+	dbus_error_init (&error);
+	if ((hal_ctx = libhal_ctx_init_direct (&error)) == NULL) {
+		printf ("Cannot connect to hald\n");
+		LIBHAL_FREE_DBUS_ERROR (&error);
+		usage ();
+	}
+
+	dbus_error_init (&error);
+	system_bus = dbus_bus_get (DBUS_BUS_SYSTEM, &error);
+	if (system_bus == NULL) {
+		printf ("Cannot connect to the system bus\n");
+		LIBHAL_FREE_DBUS_ERROR (&error);
+		usage ();
+	}
+#ifdef HAVE_POLKIT
+	pol_ctx = libpolkit_new_context (system_bus);
+	if (pol_ctx == NULL) {
+		printf ("Cannot get libpolkit context\n");
+		unknown_closetray_error ("Cannot get libpolkit context");
+	}
+#endif
+
+	/* read from stdin */
+	if (strlen (fgets (closetray_options, sizeof (closetray_options), stdin)) > 0)
+		closetray_options [strlen (closetray_options) - 1] = '\0';
+	/* validate that input from stdin is UTF-8 */
+	if (!g_utf8_validate (closetray_options, -1, &end))
+		unknown_closetray_error ("Error validating closetray_options as UTF-8");
+#ifdef DEBUG
+	printf ("closetray_options  = '%s'\n", closetray_options);
+#endif
+
+	/* delete any trailing whitespace options from splitting the string */
+	given_options = g_strsplit (closetray_options, "\t", 0);
+	for (i = g_strv_length (given_options) - 1; i >= 0; --i) {
+		if (strlen (given_options[i]) > 0)
+			break;
+		given_options[i] = NULL;
+	}
+
+	/* check options */
+	for (i = 0; given_options[i] != NULL; i++) {
+		char *given = given_options[i];
+
+		/* none supported right now */
+
+		invalid_closetray_option (given, invoked_by_uid);
+	}
+	g_strfreev (given_options);
+
+	/* should be storage */
+	if ((drive = libhal_drive_from_udi (hal_ctx, udi)) == NULL) {
+		unknown_closetray_error ("Cannot get drive");
+	}
+
+	/* use handle_eject() with the closetray option */
+	handle_eject (hal_ctx, 
+#ifdef HAVE_POLKIT
+		      pol_ctx, 
+#endif
+		      libhal_drive_get_udi (drive),
+		      drive,
+		      libhal_drive_get_device_file (drive),
+		      invoked_by_uid, 
+		      invoked_by_syscon_name,
+		      TRUE /* closetray option */);
+
+	return 0;
+}
+
+
diff --git a/tools/hal-storage-eject.c b/tools/hal-storage-eject.c
index 516d078..65248f3 100644
--- a/tools/hal-storage-eject.c
+++ b/tools/hal-storage-eject.c
@@ -1,7 +1,6 @@
 /***************************************************************************
- * CVSID: $Id: hal-storage-mount.c,v 1.7 2006/06/21 00:44:03 david Exp $
  *
- * hal-storage-mount.c : Mount wrapper
+ * hal-storage-eject.c : Eject method handler
  *
  * Copyright (C) 2006 David Zeuthen, <david at fubar.dk>
  *
@@ -42,6 +41,10 @@ #endif
 
 #include "hal-storage-shared.h"
 
+/* possible values: "Volume", "Storage" */
+static char *devtype = "Volume";
+
+
 static void
 usage (void)
 {
@@ -50,84 +53,21 @@ usage (void)
 }
 
 
-static void
-invalid_eject_option (const char *option, const char *uid)
+void static
+unknown_eject_error (const char *detail)
 {
-	fprintf (stderr, "org.freedesktop.Hal.Device.Volume.InvalidEjectOption\n");
-	fprintf (stderr, "The option '%s' is not allowed for uid=%s\n", option, uid);
+	fprintf (stderr, "org.freedesktop.Hal.Device.%s.UnknownFailure\n", devtype);
+	fprintf (stderr, "%s\n", detail);
 	exit (1);
 }
 
-#ifdef __FreeBSD__
-#error Need FreeBSD specific changes here
-#endif
-
-#define EJECT "/usr/bin/eject"
 
 static void
-handle_eject (LibHalContext *hal_ctx, 
-#ifdef HAVE_POLKIT
-	      LibPolKitContext *pol_ctx, 
-#endif
-	      const char *udi,
-	      LibHalDrive *drive, const char *device, 
-	      const char *invoked_by_uid, const char *invoked_by_syscon_name)
+invalid_eject_option (const char *option, const char *uid)
 {
-	GError *err = NULL;
-	char *sout = NULL;
-	char *serr = NULL;
-	int exit_status;
-	char *args[10];
-	int na;
-
-	/* TODO: should we require privileges here? */
-
-#ifdef DEBUG
-	printf ("device                           = %s\n", device);
-	printf ("invoked by uid                   = %s\n", invoked_by_uid);
-	printf ("invoked by system bus connection = %s\n", invoked_by_syscon_name);
-#endif
-
-	/* construct arguments to EJECT (e.g. /usr/bin/eject) */
-	na = 0;
-	args[na++] = EJECT;
-	args[na++] = (char *) device;
-	args[na++] = NULL;
-
-#ifdef DEBUG
-	printf ("will eject %s\n", device);
-#endif
-
-	/* invoke /bin/umount */
-	if (!g_spawn_sync ("/",
-			   args,
-			   NULL,
-			   0,
-			   NULL,
-			   NULL,
-			   &sout,
-			   &serr,
-			   &exit_status,
-			   &err)) {
-		printf ("Cannot execute %s\n", EJECT);
-		unknown_error ("Cannot spawn " EJECT);
-	}
-
-	/* check if eject was succesful */
-	if (exit_status != 0) {
-		printf ("%s error %d, stdout='%s', stderr='%s'\n", EJECT, exit_status, sout, serr);
-
-		unknown_error (serr);
-	}
-
-	/* eject was succesful... */
-
-#ifdef DEBUG
-	printf ("done ejecting\n");
-#endif
-
-	g_free (sout);
-	g_free (serr);
+	fprintf (stderr, "org.freedesktop.Hal.Device.Volume.InvalidEjectOption\n");
+	fprintf (stderr, "The option '%s' is not allowed for uid=%s\n", option, uid);
+	exit (1);
 }
 
 
@@ -136,6 +76,8 @@ main (int argc, char *argv[])
 {
 	char *udi;
 	char *device;
+	const char *drive_udi;
+	LibHalDrive *drive;
 	LibHalVolume *volume;
 	DBusError error;
 	LibHalContext *hal_ctx = NULL;
@@ -182,7 +124,7 @@ #ifdef HAVE_POLKIT
 	pol_ctx = libpolkit_new_context (system_bus);
 	if (pol_ctx == NULL) {
 		printf ("Cannot get libpolkit context\n");
-		unknown_error ("Cannot get libpolkit context");
+		unknown_eject_error ("Cannot get libpolkit context");
 	}
 #endif
 
@@ -191,7 +133,7 @@ #endif
 		eject_options [strlen (eject_options) - 1] = '\0';
 	/* validate that input from stdin is UTF-8 */
 	if (!g_utf8_validate (eject_options, -1, &end))
-		unknown_error ("Error validating eject_options as UTF-8");
+		unknown_eject_error ("Error validating eject_options as UTF-8");
 #ifdef DEBUG
 	printf ("eject_options  = '%s'\n", eject_options);
 #endif
@@ -214,109 +156,79 @@ #endif
 	}
 	g_strfreev (given_options);
 
-
-	volume = libhal_volume_from_udi (hal_ctx, udi);
-	if (volume == NULL) {
-		LibHalDrive *drive;
-
-#ifdef DEBUG
-		printf ("eject called on drive %s\n", udi);
-#endif
-
-		drive = libhal_drive_from_udi (hal_ctx, udi);
-		if (drive == NULL) {
-			usage ();
-		} else {
-
-			/* TODO: should try to unmount? */
-
-			/* attempt the eject */
-			handle_eject (hal_ctx, 
-#ifdef HAVE_POLKIT
-				      pol_ctx, 
-#endif
-				      libhal_drive_get_udi (drive),
-				      drive,
-				      libhal_drive_get_device_file (drive),
-				      invoked_by_uid, 
-				      invoked_by_syscon_name);
-		}
-
+	/* should be either volume or storage */
+	if ((volume = libhal_volume_from_udi (hal_ctx, udi)) != NULL) {
+		drive_udi = libhal_volume_get_storage_device_udi (volume);
 	} else {
-		const char *drive_udi;
-		LibHalDrive *drive;
+		drive_udi = g_strdup (udi);
+		devtype = "Storage";
+	}
+	if (drive_udi == NULL) {
+		unknown_eject_error ("Cannot get drive udi");
+	}
+	if ((drive = libhal_drive_from_udi (hal_ctx, drive_udi)) == NULL) {
+		unknown_eject_error ("Cannot get drive from udi");
+	}
 
-		/* first, unmount all volumes */
+	/* first, unmount all volumes */
+	volume_udis = libhal_drive_find_all_volumes (hal_ctx, drive, &num_volumes);
+	if (volume_udis == NULL)
+		unknown_eject_error ("Cannot get all enclosed volumes");
+	for (i = 0; i < num_volumes; i++) {
+		char *volume_udi;
+		LibHalVolume *volume_to_unmount;
 
-		drive_udi = libhal_volume_get_storage_device_udi (volume);
-		
-		if (drive_udi == NULL)
-			unknown_error ("Cannot get drive_udi from volume");
-		drive = libhal_drive_from_udi (hal_ctx, drive_udi);
-		if (drive == NULL)
-			unknown_error ("Cannot get drive from hal");
-
-
-		volume_udis = libhal_drive_find_all_volumes (hal_ctx, drive, &num_volumes);
-		if (volume_udis == NULL)
-			unknown_error ("Cannot get all enclosed volumes");
-		for (i = 0; i < num_volumes; i++) {
-			char *volume_udi;
-			LibHalVolume *volume_to_unmount;
-
-			volume_udi = volume_udis[i];
+		volume_udi = volume_udis[i];
 			
 #ifdef DEBUG
-			printf ("processing drive's volume %s (%d of %d)\n", volume_udi, i + 1, num_volumes);
+		printf ("processing drive's volume %s (%d of %d)\n", volume_udi, i + 1, num_volumes);
 #endif
-			volume_to_unmount = libhal_volume_from_udi (hal_ctx, volume_udi);
-			if (volume_to_unmount == NULL) {
-				unknown_error ("Cannot get volume object");
-			}
+		volume_to_unmount = libhal_volume_from_udi (hal_ctx, volume_udi);
+		if (volume_to_unmount == NULL) {
+			unknown_eject_error ("Cannot get volume object");
+		}
 
-			if (libhal_volume_is_mounted (volume_to_unmount)) {
+		if (libhal_volume_is_mounted (volume_to_unmount)) {
 #ifdef DEBUG
-				printf (" unmounting\n");
+			printf (" unmounting\n");
 #endif
-				/* only lock around unmount call because hald's /proc/mounts handler
-				 * will also want to lock the /media/.hal-mtab-lock file for peeking
-				 */
-				if (!lock_hal_mtab ()) {
-					unknown_error ("Cannot obtain lock on /media/.hal-mtab");
-				}
-				handle_unmount (hal_ctx, 
+			/* only lock around unmount call because hald's /proc/mounts handler
+			 * will also want to lock the /media/.hal-mtab-lock file for peeking
+			 */
+			if (!lock_hal_mtab ()) {
+				unknown_eject_error ("Cannot obtain lock on /media/.hal-mtab");
+			}
+			handle_unmount (hal_ctx, 
 #ifdef HAVE_POLKIT
-						pol_ctx, 
+					pol_ctx, 
 #endif
-						udi, volume_to_unmount, drive, 
-						libhal_volume_get_device_file (volume_to_unmount), 
-						invoked_by_uid, invoked_by_syscon_name,
-						FALSE, FALSE); /* use neither lazy nor force */
-				unlock_hal_mtab ();
-			} else {
+					udi, volume_to_unmount, drive, 
+					libhal_volume_get_device_file (volume_to_unmount), 
+					invoked_by_uid, invoked_by_syscon_name,
+					FALSE, FALSE); /* use neither lazy nor force */
+			unlock_hal_mtab ();
+		} else {
 #ifdef DEBUG
-				printf (" not mounted\n");
+			printf (" not mounted\n");
 #endif
-			}
-
-			libhal_volume_free (volume_to_unmount);
-
 		}
-		libhal_free_string_array (volume_udis);
 
-		/* now attempt the eject */
-		handle_eject (hal_ctx, 
-#ifdef HAVE_POLKIT
-			      pol_ctx, 
-#endif
-			      libhal_drive_get_udi (drive),
-			      drive,
-			      libhal_drive_get_device_file (drive),
-			      invoked_by_uid, 
-			      invoked_by_syscon_name);
+		libhal_volume_free (volume_to_unmount);
 
 	}
+	libhal_free_string_array (volume_udis);
 
+	/* now attempt the eject */
+	handle_eject (hal_ctx, 
+#ifdef HAVE_POLKIT
+		      pol_ctx, 
+#endif
+		      libhal_drive_get_udi (drive),
+		      drive,
+		      libhal_drive_get_device_file (drive),
+		      invoked_by_uid, 
+		      invoked_by_syscon_name,
+		      FALSE);
 
 	return 0;
 }
diff --git a/tools/hal-storage-shared.c b/tools/hal-storage-shared.c
index dced663..f8af3a9 100644
--- a/tools/hal-storage-shared.c
+++ b/tools/hal-storage-shared.c
@@ -468,6 +468,79 @@ #endif
 	g_free (mount_point_to_unmount);
 }
 
+#define EJECT "/usr/bin/eject"
+
+void
+handle_eject (LibHalContext *hal_ctx, 
+#ifdef HAVE_POLKIT
+	      LibPolKitContext *pol_ctx, 
+#endif
+	      const char *udi,
+	      LibHalDrive *drive, const char *device, 
+	      const char *invoked_by_uid, const char *invoked_by_syscon_name,
+	      gboolean closetray)
+{
+	GError *err = NULL;
+	char *sout = NULL;
+	char *serr = NULL;
+	int exit_status;
+	char *args[10];
+	int na;
+
+	/* TODO: should we require privileges here? */
+
+#ifdef DEBUG
+	printf ("device                           = %s\n", device);
+	printf ("invoked by uid                   = %s\n", invoked_by_uid);
+	printf ("invoked by system bus connection = %s\n", invoked_by_syscon_name);
+#endif
+
+	/* construct arguments to EJECT (e.g. /usr/bin/eject) */
+	na = 0;
+	args[na++] = EJECT;
+	if (closetray) {
+		args[na++] = "-t";
+	}
+	args[na++] = (char *) device;
+	args[na++] = NULL;
+
+#ifdef DEBUG
+	printf ("will eject %s\n", device);
+#endif
+
+	/* invoke eject command */
+	if (!g_spawn_sync ("/",
+			   args,
+			   NULL,
+			   0,
+			   NULL,
+			   NULL,
+			   &sout,
+			   &serr,
+			   &exit_status,
+			   &err)) {
+		printf ("Cannot execute %s\n", EJECT);
+		unknown_error ("Cannot spawn " EJECT);
+	}
+
+	/* check if eject was succesful */
+	if (exit_status != 0) {
+		printf ("%s error %d, stdout='%s', stderr='%s'\n", EJECT, exit_status, sout, serr);
+
+		unknown_error (serr);
+	}
+
+	/* eject was succesful... */
+
+#ifdef DEBUG
+	printf ("done ejecting\n");
+#endif
+
+	g_free (sout);
+	g_free (serr);
+}
+
+
 static int lock_mtab_fd = -1;
 
 gboolean
diff --git a/tools/hal-storage-shared.h b/tools/hal-storage-shared.h
index f87d5d1..c1d7ebc 100644
--- a/tools/hal-storage-shared.h
+++ b/tools/hal-storage-shared.h
@@ -55,6 +55,14 @@ #endif
 		     const char *invoked_by_uid, const char *invoked_by_syscon_name,
 		     gboolean option_lazy, gboolean option_force);
 
+void handle_eject (LibHalContext *hal_ctx, 
+#ifdef HAVE_POLKIT
+		   LibPolKitContext *pol_ctx, 
+#endif
+		   const char *udi,
+		   LibHalDrive *drive, const char *device, 
+		   const char *invoked_by_uid, const char *invoked_by_syscon_name,
+		   gboolean closetray);
 
 #endif /* HAL_STORAGE_SHARED_H */
 
-------------- next part --------------
/***************************************************************************
 *
 * hal-storage-eject.c : Eject method handler
 *
 * Copyright (C) 2006 David Zeuthen, <david at fubar.dk>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 *
 **************************************************************************/


#ifdef HAVE_CONFIG_H
#  include <config.h>
#endif

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <glib.h>
#include <glib/gstdio.h>
#include <sys/types.h>
#include <unistd.h>

#include <libhal.h>
#include <libhal-storage.h>
#ifdef HAVE_POLKIT
#include <libpolkit.h>
#endif

#include "hal-storage-shared.h"

/* possible values: "Volume", "Storage" */
static char *devtype = "Volume";


static void
usage (void)
{
	fprintf (stderr, "This program should only be started by hald.\n");
	exit (1);
}


void static
unknown_eject_error (const char *detail)
{
	fprintf (stderr, "org.freedesktop.Hal.Device.%s.UnknownFailure\n", devtype);
	fprintf (stderr, "%s\n", detail);
	exit (1);
}


static void
invalid_eject_option (const char *option, const char *uid)
{
	fprintf (stderr, "org.freedesktop.Hal.Device.Volume.InvalidEjectOption\n");
	fprintf (stderr, "The option '%s' is not allowed for uid=%s\n", option, uid);
	exit (1);
}


int
main (int argc, char *argv[])
{
	char *udi;
	char *device;
	const char *drive_udi;
	LibHalDrive *drive;
	LibHalVolume *volume;
	DBusError error;
	LibHalContext *hal_ctx = NULL;
	DBusConnection *system_bus = NULL;
#ifdef HAVE_POLKIT
	LibPolKitContext *pol_ctx = NULL;
#endif
	char *invoked_by_uid;
	char *invoked_by_syscon_name;
	char **volume_udis;
	int num_volumes;
	int i;
	char eject_options[1024];
	char **given_options;
	const char *end;

	device = getenv ("HAL_PROP_BLOCK_DEVICE");
	if (device == NULL)
		usage ();

	udi = getenv ("HAL_PROP_INFO_UDI");
	if (udi == NULL)
		usage ();

	invoked_by_uid = getenv ("HAL_METHOD_INVOKED_BY_UID");

	invoked_by_syscon_name = getenv ("HAL_METHOD_INVOKED_BY_SYSTEMBUS_CONNECTION_NAME");

	dbus_error_init (&error);
	if ((hal_ctx = libhal_ctx_init_direct (&error)) == NULL) {
		printf ("Cannot connect to hald\n");
		LIBHAL_FREE_DBUS_ERROR (&error);
		usage ();
	}

	dbus_error_init (&error);
	system_bus = dbus_bus_get (DBUS_BUS_SYSTEM, &error);
	if (system_bus == NULL) {
		printf ("Cannot connect to the system bus\n");
		LIBHAL_FREE_DBUS_ERROR (&error);
		usage ();
	}
#ifdef HAVE_POLKIT
	pol_ctx = libpolkit_new_context (system_bus);
	if (pol_ctx == NULL) {
		printf ("Cannot get libpolkit context\n");
		unknown_eject_error ("Cannot get libpolkit context");
	}
#endif

	/* read from stdin */
	if (strlen (fgets (eject_options, sizeof (eject_options), stdin)) > 0)
		eject_options [strlen (eject_options) - 1] = '\0';
	/* validate that input from stdin is UTF-8 */
	if (!g_utf8_validate (eject_options, -1, &end))
		unknown_eject_error ("Error validating eject_options as UTF-8");
#ifdef DEBUG
	printf ("eject_options  = '%s'\n", eject_options);
#endif

	/* delete any trailing whitespace options from splitting the string */
	given_options = g_strsplit (eject_options, "\t", 0);
	for (i = g_strv_length (given_options) - 1; i >= 0; --i) {
		if (strlen (given_options[i]) > 0)
			break;
		given_options[i] = NULL;
	}

	/* check eject options */
	for (i = 0; given_options[i] != NULL; i++) {
		char *given = given_options[i];

		/* none supported right now */

		invalid_eject_option (given, invoked_by_uid);
	}
	g_strfreev (given_options);

	/* should be either volume or storage */
	if ((volume = libhal_volume_from_udi (hal_ctx, udi)) != NULL) {
		drive_udi = libhal_volume_get_storage_device_udi (volume);
	} else {
		drive_udi = g_strdup (udi);
		devtype = "Storage";
	}
	if (drive_udi == NULL) {
		unknown_eject_error ("Cannot get drive udi");
	}
	if ((drive = libhal_drive_from_udi (hal_ctx, drive_udi)) == NULL) {
		unknown_eject_error ("Cannot get drive from udi");
	}

	/* first, unmount all volumes */
	volume_udis = libhal_drive_find_all_volumes (hal_ctx, drive, &num_volumes);
	if (volume_udis == NULL)
		unknown_eject_error ("Cannot get all enclosed volumes");
	for (i = 0; i < num_volumes; i++) {
		char *volume_udi;
		LibHalVolume *volume_to_unmount;

		volume_udi = volume_udis[i];
			
#ifdef DEBUG
		printf ("processing drive's volume %s (%d of %d)\n", volume_udi, i + 1, num_volumes);
#endif
		volume_to_unmount = libhal_volume_from_udi (hal_ctx, volume_udi);
		if (volume_to_unmount == NULL) {
			unknown_eject_error ("Cannot get volume object");
		}

		if (libhal_volume_is_mounted (volume_to_unmount)) {
#ifdef DEBUG
			printf (" unmounting\n");
#endif
			/* only lock around unmount call because hald's /proc/mounts handler
			 * will also want to lock the /media/.hal-mtab-lock file for peeking
			 */
			if (!lock_hal_mtab ()) {
				unknown_eject_error ("Cannot obtain lock on /media/.hal-mtab");
			}
			handle_unmount (hal_ctx, 
#ifdef HAVE_POLKIT
					pol_ctx, 
#endif
					udi, volume_to_unmount, drive, 
					libhal_volume_get_device_file (volume_to_unmount), 
					invoked_by_uid, invoked_by_syscon_name,
					FALSE, FALSE); /* use neither lazy nor force */
			unlock_hal_mtab ();
		} else {
#ifdef DEBUG
			printf (" not mounted\n");
#endif
		}

		libhal_volume_free (volume_to_unmount);

	}
	libhal_free_string_array (volume_udis);

	/* now attempt the eject */
	handle_eject (hal_ctx, 
#ifdef HAVE_POLKIT
		      pol_ctx, 
#endif
		      libhal_drive_get_udi (drive),
		      drive,
		      libhal_drive_get_device_file (drive),
		      invoked_by_uid, 
		      invoked_by_syscon_name,
		      FALSE);

	return 0;
}




More information about the hal mailing list