1 /*************************************************************************** 2 * 3 * hal-storage-eject.c : Eject method handler 4 * 5 * Copyright (C) 2006 David Zeuthen, <david@fubar.dk> 6 * 7 * This program is free software; you can redistribute it and/or modify 8 * it under the terms of the GNU General Public License as published by 9 * the Free Software Foundation; either version 2 of the License, or 10 * (at your option) any later version. 11 * 12 * This program is distributed in the hope that it will be useful, 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 * GNU General Public License for more details. 16 * 17 * You should have received a copy of the GNU General Public License 18 * along with this program; if not, write to the Free Software 19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 20 * 21 **************************************************************************/ 22 23 24 #ifdef HAVE_CONFIG_H 25 # include <config.h> 26 #endif 27 28 #include <stdio.h> 29 #include <stdlib.h> 30 #include <string.h> 31 #include <glib.h> 32 #include <glib/gstdio.h> 33 #include <sys/types.h> 34 #include <unistd.h> 35 36 #include <libhal.h> 37 #include <libhal-storage.h> 38 #ifdef HAVE_POLKIT 39 #include <libpolkit.h> 40 #endif 41 42 #include "hal-storage-shared.h" 43 44 /* possible values: "Volume", "Storage" */ 45 static char *devtype = "Volume"; 46 47 48 static void 49 usage (void) 50 { 51 fprintf (stderr, "This program should only be started by hald.\n"); 52 exit (1); 53 } 54 55 56 void static 57 unknown_eject_error (const char *detail) 58 { 59 fprintf (stderr, "org.freedesktop.Hal.Device.%s.UnknownFailure\n", devtype); 60 fprintf (stderr, "%s\n", detail); 61 exit (1); 62 } 63 64 65 static void 66 invalid_eject_option (const char *option, const char *uid) 67 { 68 fprintf (stderr, "org.freedesktop.Hal.Device.Volume.InvalidEjectOption\n"); 69 fprintf (stderr, "The option '%s' is not allowed for uid=%s\n", option, uid); 70 exit (1); 71 } 72 73 74 int 75 main (int argc, char *argv[]) 76 { 77 char *udi; 78 char *device; 79 const char *drive_udi; 80 LibHalDrive *drive; 81 LibHalVolume *volume; 82 DBusError error; 83 LibHalContext *hal_ctx = NULL; 84 DBusConnection *system_bus = NULL; 85 #ifdef HAVE_POLKIT 86 LibPolKitContext *pol_ctx = NULL; 87 #endif 88 char *invoked_by_uid; 89 char *invoked_by_syscon_name; 90 char **volume_udis; 91 int num_volumes; 92 int i; 93 char eject_options[1024]; 94 char **given_options; 95 const char *end; 96 97 device = getenv ("HAL_PROP_BLOCK_DEVICE"); 98 if (device == NULL) 99 usage (); 100 101 udi = getenv ("HAL_PROP_INFO_UDI"); 102 if (udi == NULL) 103 usage (); 104 105 invoked_by_uid = getenv ("HAL_METHOD_INVOKED_BY_UID"); 106 107 invoked_by_syscon_name = getenv ("HAL_METHOD_INVOKED_BY_SYSTEMBUS_CONNECTION_NAME"); 108 109 dbus_error_init (&error); 110 if ((hal_ctx = libhal_ctx_init_direct (&error)) == NULL) { 111 printf ("Cannot connect to hald\n"); 112 LIBHAL_FREE_DBUS_ERROR (&error); 113 usage (); 114 } 115 116 dbus_error_init (&error); 117 system_bus = dbus_bus_get (DBUS_BUS_SYSTEM, &error); 118 if (system_bus == NULL) { 119 printf ("Cannot connect to the system bus\n"); 120 LIBHAL_FREE_DBUS_ERROR (&error); 121 usage (); 122 } 123 #ifdef HAVE_POLKIT 124 pol_ctx = libpolkit_new_context (system_bus); 125 if (pol_ctx == NULL) { 126 printf ("Cannot get libpolkit context\n"); 127 unknown_eject_error ("Cannot get libpolkit context"); 128 } 129 #endif 130 131 /* read from stdin */ 132 if (strlen (fgets (eject_options, sizeof (eject_options), stdin)) > 0) 133 eject_options [strlen (eject_options) - 1] = '\0'; 134 /* validate that input from stdin is UTF-8 */ 135 if (!g_utf8_validate (eject_options, -1, &end)) 136 unknown_eject_error ("Error validating eject_options as UTF-8"); 137 #ifdef DEBUG 138 printf ("eject_options = '%s'\n", eject_options); 139 #endif 140 141 /* delete any trailing whitespace options from splitting the string */ 142 given_options = g_strsplit (eject_options, "\t", 0); 143 for (i = g_strv_length (given_options) - 1; i >= 0; --i) { 144 if (strlen (given_options[i]) > 0) 145 break; 146 given_options[i] = NULL; 147 } 148 149 /* check eject options */ 150 for (i = 0; given_options[i] != NULL; i++) { 151 char *given = given_options[i]; 152 153 /* none supported right now */ 154 155 invalid_eject_option (given, invoked_by_uid); 156 } 157 g_strfreev (given_options); 158 159 /* should be either volume or storage */ 160 if ((volume = libhal_volume_from_udi (hal_ctx, udi)) != NULL) { 161 drive_udi = libhal_volume_get_storage_device_udi (volume); 162 } else { 163 drive_udi = g_strdup (udi); 164 devtype = "Storage"; 165 } 166 if (drive_udi == NULL) { 167 unknown_eject_error ("Cannot get drive udi"); 168 } 169 if ((drive = libhal_drive_from_udi (hal_ctx, drive_udi)) == NULL) { 170 unknown_eject_error ("Cannot get drive from udi"); 171 } 172 173 /* first, unmount all volumes */ 174 volume_udis = libhal_drive_find_all_volumes (hal_ctx, drive, &num_volumes); 175 if (volume_udis == NULL) 176 unknown_eject_error ("Cannot get all enclosed volumes"); 177 for (i = 0; i < num_volumes; i++) { 178 char *volume_udi; 179 LibHalVolume *volume_to_unmount; 180 181 volume_udi = volume_udis[i]; 182 183 #ifdef DEBUG 184 printf ("processing drive's volume %s (%d of %d)\n", volume_udi, i + 1, num_volumes); 185 #endif 186 volume_to_unmount = libhal_volume_from_udi (hal_ctx, volume_udi); 187 if (volume_to_unmount == NULL) { 188 unknown_eject_error ("Cannot get volume object"); 189 } 190 191 if (libhal_volume_is_mounted (volume_to_unmount)) { 192 #ifdef DEBUG 193 printf (" unmounting\n"); 194 #endif 195 /* only lock around unmount call because hald's /proc/mounts handler 196 * will also want to lock the /media/.hal-mtab-lock file for peeking 197 */ 198 if (!lock_hal_mtab ()) { 199 unknown_eject_error ("Cannot obtain lock on /media/.hal-mtab"); 200 } 201 handle_unmount (hal_ctx, 202 #ifdef HAVE_POLKIT 203 pol_ctx, 204 #endif 205 volume_udi, volume_to_unmount, drive, 206 libhal_volume_get_device_file (volume_to_unmount), 207 invoked_by_uid, invoked_by_syscon_name, 208 FALSE, FALSE, system_bus); /* use neither lazy nor force */ 209 unlock_hal_mtab (); 210 } else { 211 #ifdef DEBUG 212 printf (" not mounted\n"); 213 #endif 214 } 215 216 libhal_volume_free (volume_to_unmount); 217 218 } 219 libhal_free_string_array (volume_udis); 220 221 /* now attempt the eject */ 222 handle_eject (hal_ctx, 223 #ifdef HAVE_POLKIT 224 pol_ctx, 225 #endif 226 libhal_drive_get_udi (drive), 227 drive, 228 libhal_drive_get_device_file (drive), 229 invoked_by_uid, 230 invoked_by_syscon_name, 231 FALSE, system_bus); 232 233 return 0; 234 } 235 236 237