--- gnome-mount-0.4/src/gnome-mount.c 2006-02-24 00:14:23.000000000 -0500 +++ gnome-mount-0.4.new/src/gnome-mount.c 2006-06-18 19:40:03.000000000 -0400 @@ -238,7 +238,8 @@ /* #define MOUNT_ERROR_DIALOG_RESPONSE_INSTALL_DRIVER 10 see below */ static void -show_error_dialog_mount (LibHalVolume *volume, const char *error_name, const char *error_detail, +show_error_dialog_mount (LibHalVolume *volume, LibHalDrive *drive, + const char *error_name, const char *error_detail, const char *fstype_requested) { GtkWidget *w; @@ -266,7 +267,10 @@ 0, _("Cannot mount volume")); - volume_name = libhal_volume_get_label (volume); + if (volume != NULL) + volume_name = libhal_volume_get_label (volume); + else + volume_name = NULL; if (strcmp (error_name, "org.freedesktop.Hal.Device.Volume.PermissionDenied") == 0) { gtk_message_dialog_format_secondary_text ( @@ -289,8 +293,8 @@ volume_name != NULL ? _("The volume '%s' uses the %s file system which is not supported by your system.") : _("The volume uses the %s file system which is not supported by your system."), - volume_name != NULL ? volume_name : fstype_requested, - volume_name != NULL ? fstype_requested : ""); + volume_name != NULL ? volume_name : (fstype_requested != NULL ? fstype_requested : ""), + volume_name != NULL ? (fstype_requested != NULL ? fstype_requested : "") : ""); /* some day.. :-) gtk_dialog_add_buttons (GTK_DIALOG (w), @@ -463,9 +467,9 @@ notify_parent (FALSE); - show_error_dialog_mount (volume, error.name, error.message, + show_error_dialog_mount (volume, drive, error.name, error.message, (fstype != NULL && strlen (fstype) > 0) ? - fstype : libhal_volume_get_fstype (volume)); + fstype : (volume != NULL ? libhal_volume_get_fstype (volume) : NULL)); dbus_error_free (&error); goto out; @@ -573,6 +577,226 @@ return flags; } + +static gboolean +fstab_open (gpointer *handle) +{ +#ifdef __FreeBSD__ + return setfsent () == 1; +#else + *handle = fopen ("/etc/fstab", "r"); + return *handle != NULL; +#endif +} + +static char * +fstab_next (gpointer handle, char **mount_point) +{ +#ifdef __FreeBSD__ + struct fstab *fstab; + + fstab = getfsent (); + + /* TODO: fill out mount_point */ + if (mount_point != NULL && fstab != NULL) { + *mount_point = fstab->fs_file; + } + + return fstab ? fstab->fs_spec : NULL; +#else + struct mntent *mnt; + + mnt = getmntent (handle); + + if (mount_point != NULL && mnt != NULL) { + *mount_point = mnt->mnt_dir; + } + + return mnt ? mnt->mnt_fsname : NULL; +#endif +} + + +static void +fstab_close (gpointer handle) +{ +#ifdef __FreeBSD__ + endfsent (); +#else + fclose (handle); +#endif +} + + +/* borrowed from gtk/gtkfilesystemunix.c in GTK+ on 02/23/2006 */ +static void +canonicalize_filename (gchar *filename) +{ + gchar *p, *q; + gboolean last_was_slash = FALSE; + + p = filename; + q = filename; + + while (*p) + { + if (*p == G_DIR_SEPARATOR) + { + if (!last_was_slash) + *q++ = G_DIR_SEPARATOR; + + last_was_slash = TRUE; + } + else + { + if (last_was_slash && *p == '.') + { + if (*(p + 1) == G_DIR_SEPARATOR || + *(p + 1) == '\0') + { + if (*(p + 1) == '\0') + break; + + p += 1; + } + else if (*(p + 1) == '.' && + (*(p + 2) == G_DIR_SEPARATOR || + *(p + 2) == '\0')) + { + if (q > filename + 1) + { + q--; + while (q > filename + 1 && + *(q - 1) != G_DIR_SEPARATOR) + q--; + } + + if (*(p + 2) == '\0') + break; + + p += 2; + } + else + { + *q++ = *p; + last_was_slash = FALSE; + } + } + else + { + *q++ = *p; + last_was_slash = FALSE; + } + } + + p++; + } + + if (q > filename + 1 && *(q - 1) == G_DIR_SEPARATOR) + q--; + + *q = '\0'; +} + +static char * +resolve_symlink (const char *file) +{ + GError *error; + char *dir; + char *link; + char *f; + char *f1; + + f = g_strdup (file); + + while (g_file_test (f, G_FILE_TEST_IS_SYMLINK)) { + link = g_file_read_link (f, &error); + if (link == NULL) { + g_warning ("Cannot resolve symlink %s: %s", f, error->message); + g_error_free (error); + g_free (f); + f = NULL; + goto out; + } + + dir = g_path_get_dirname (f); + f1 = g_strdup_printf ("%s/%s", dir, link); + g_free (dir); + g_free (link); + g_free (f); + f = f1; + } + +out: + if (f != NULL) + canonicalize_filename (f); + return f; +} + +static gboolean +is_in_fstab (const char *device_file, const char *label, const char *uuid, char **mount_point) +{ + gboolean ret; + gpointer handle; + char *entry; + char *_mount_point; + + ret = FALSE; + + /* check if /etc/fstab mentions this device... (with symlinks etc) */ + if (!fstab_open (&handle)) { + handle = NULL; + goto out; + } + + while ((entry = fstab_next (handle, &_mount_point)) != NULL) { + char *resolved; + + if (label != NULL && g_str_has_prefix (entry, "LABEL=")) { + if (strcmp (entry + 6, label) == 0) { + ret = TRUE; + if (mount_point != NULL) + *mount_point = g_strdup (_mount_point); + goto out; + } + } + + if (uuid != NULL && g_str_has_prefix (entry, "UUID=")) { + if (strcmp (entry + 5, uuid) == 0) { + ret = TRUE; + if (mount_point != NULL) + *mount_point = g_strdup (_mount_point); + goto out; + } + } + + resolved = resolve_symlink (entry); + if (strcmp (device_file, resolved) == 0) { + ret = TRUE; + g_free (resolved); + if (mount_point != NULL) + *mount_point = g_strdup (_mount_point); + goto out; + } + + g_free (resolved); + } + +out: + if (handle != NULL) + fstab_close (handle); + + return ret; +} + +#ifdef __FreeBSD__ +#define MOUNT "/sbin/mount" +#define UMOUNT "/sbin/umount" +#else +#define MOUNT "/bin/mount" +#define UMOUNT "/bin/umount" +#endif + static gboolean volume_mount (const char *udi, LibHalVolume *volume, LibHalDrive *drive) { @@ -587,9 +811,89 @@ char *key; gboolean ret; const char *fstype; + const char *device_file; + const char *label; + const char *uuid; ret = FALSE; + g_debug ("Mounting %s", udi); + + /* check if it's in /etc/fstab */ + label = NULL; + uuid = NULL; + device_file = NULL; + if (volume != NULL) { + label = libhal_volume_get_label (volume); + uuid = libhal_volume_get_uuid (volume); + device_file = libhal_volume_get_device_file (volume); + } else if (drive != NULL) { + device_file = libhal_drive_get_device_file (drive); + } + if (device_file != NULL) { + char *mount_point = NULL; + + if (is_in_fstab (device_file, label, uuid, &mount_point)) { + GError *err = NULL; + char *sout = NULL; + char *serr = NULL; + int exit_status; + char *args[3] = {MOUNT, NULL, NULL}; + char **envp = {NULL}; + + g_print (_("Device %s is in /etc/fstab with mount point \"%s\"\n"), + device_file, mount_point); + args[1] = mount_point; + if (!g_spawn_sync ("/", + args, + envp, + 0, + NULL, + NULL, + &sout, + &serr, + &exit_status, + &err)) { + g_warning ("Cannot execute %s\n", MOUNT); + g_free (mount_point); + goto out; + } + + if (exit_status != 0) { + char errstr[] = "mount: unknown filesystem type"; + + g_warning ("%s said error %d, stdout='%s', stderr='%s'\n", + MOUNT, exit_status, sout, serr); + + if (strstr (serr, "unknown filesystem type") != NULL) { + show_error_dialog_mount (volume, drive, "org.freedesktop.Hal.Device.Volume.UnknownFilesystemType", serr, NULL); + } else if (strstr (serr, "already mounted") != NULL) { + show_error_dialog_mount (volume, drive, "org.freedesktop.Hal.Device.Volume.AlreadyMounted", serr, NULL); + } else if (strstr (serr, "only root") != NULL) { + show_error_dialog_mount (volume, drive, "org.freedesktop.Hal.Device.Volume.PermissionDenied", serr, NULL); + } else if (strstr (serr, "bad option") != NULL) { + show_error_dialog_mount (volume, drive, "org.freedesktop.Hal.Device.Volume.InvalidMountOption", serr, NULL); + } else { + show_error_dialog_mount (volume, drive, "org.freedesktop.Hal.Device.Volume.UnknownFailure", serr, NULL); + } + + g_free (mount_point); + goto out; + + } + + g_print (_("Mounted %s at \"%s\" (using /etc/fstab)\n"), device_file, mount_point); + + g_free (mount_point); + ret = TRUE; + goto out; + + } + g_free (mount_point); + } + + + if (volume != NULL) { fstype = libhal_volume_get_fstype (volume); } else { @@ -690,6 +994,7 @@ g_free (mount_point); +out: return ret; } @@ -697,15 +1002,89 @@ static gboolean volume_unmount (const char *udi, LibHalVolume *volume, LibHalDrive *drive) { - gboolean ret = FALSE; + gboolean ret; DBusMessage *msg = NULL; DBusMessage *reply = NULL; DBusError error; char **options = NULL; unsigned int num_options = 0; + const char *fstype; + const char *device_file; + const char *label; + const char *uuid; + + ret = FALSE; g_debug ("Unmounting %s", udi); + /* check if it's in /etc/fstab */ + label = NULL; + uuid = NULL; + device_file = NULL; + if (volume != NULL) { + label = libhal_volume_get_label (volume); + uuid = libhal_volume_get_uuid (volume); + device_file = libhal_volume_get_device_file (volume); + } else if (drive != NULL) { + device_file = libhal_drive_get_device_file (drive); + } + if (device_file != NULL) { + char *mount_point = NULL; + + if (is_in_fstab (device_file, label, uuid, &mount_point)) { + GError *err = NULL; + char *sout = NULL; + char *serr = NULL; + int exit_status; + char *args[3] = {UMOUNT, NULL, NULL}; + char **envp = {NULL}; + + g_print (_("Device %s is in /etc/fstab with mount point \"%s\"\n"), + device_file, mount_point); + args[1] = mount_point; + if (!g_spawn_sync ("/", + args, + envp, + 0, + NULL, + NULL, + &sout, + &serr, + &exit_status, + &err)) { + g_warning ("Cannot execute %s\n", UMOUNT); + g_free (mount_point); + goto out; + } + + if (exit_status != 0) { + g_warning ("%s said error %d, stdout='%s', stderr='%s'\n", + UMOUNT, exit_status, sout, serr); + g_free (mount_point); + + if (strstr (serr, "is busy") != NULL) { + show_error_dialog_unmount (udi, volume, drive, "org.freedesktop.Hal.Device.Volume.Busy", serr); + } else if (strstr (serr, "not mounted") != NULL) { + show_error_dialog_unmount (udi, volume, drive, "org.freedesktop.Hal.Device.Volume.NotMounted", serr); + } else if (strstr (serr, "only root") != NULL) { + show_error_dialog_unmount (udi, volume, drive, "org.freedesktop.Hal.Device.Volume.PermissionDenied", serr); + } else { + show_error_dialog_unmount (udi, volume, drive, "org.freedesktop.Hal.Device.Volume.UnknownFailure", serr); + } + + goto out; + } + + g_print (_("Unmounted %s (using /etc/fstab).\n"), device_file); + + g_free (mount_point); + ret = TRUE; + goto out; + + } + g_free (mount_point); + } + msg = dbus_message_new_method_call ("org.freedesktop.Hal", udi, "org.freedesktop.Hal.Device.Volume", "Unmount"); @@ -752,8 +1131,82 @@ DBusError error; char **options = NULL; unsigned int num_options = 0; + const char *fstype; + const char *device_file; + const char *label; + const char *uuid; + + ret = FALSE; g_debug ("Ejecting %s", udi); + + /* check if it's in /etc/fstab */ + label = NULL; + uuid = NULL; + device_file = NULL; + if (volume != NULL) { + label = libhal_volume_get_label (volume); + uuid = libhal_volume_get_uuid (volume); + device_file = libhal_volume_get_device_file (volume); + } else if (drive != NULL) { + device_file = libhal_drive_get_device_file (drive); + } + if (device_file != NULL) { + char *mount_point = NULL; + + if (is_in_fstab (device_file, label, uuid, &mount_point)) { + GError *err = NULL; + char *sout = NULL; + char *serr = NULL; + int exit_status; + char *args[3] = {"eject", NULL, NULL}; + char **envp = {NULL}; + + g_print (_("Device %s is in /etc/fstab with mount point \"%s\"\n"), + device_file, mount_point); + args[1] = mount_point; + if (!g_spawn_sync ("/", + args, + envp, + G_SPAWN_SEARCH_PATH, + NULL, + NULL, + &sout, + &serr, + &exit_status, + &err)) { + g_warning ("Cannot execute %s\n", "eject"); + g_free (mount_point); + goto out; + } + + if (exit_status != 0) { + g_warning ("%s said error %d, stdout='%s', stderr='%s'\n", + "eject", exit_status, sout, serr); + g_free (mount_point); + + if (strstr (serr, "is busy") != NULL) { + show_error_dialog_eject (udi, volume, drive, "org.freedesktop.Hal.Device.Volume.Busy", serr); + } else if (strstr (serr, "only root") != NULL) { + show_error_dialog_eject (udi, volume, drive, "org.freedesktop.Hal.Device.Volume.PermissionDenied", serr); + } else if (strstr (serr, "unable to open") != NULL) { + show_error_dialog_eject (udi, volume, drive, "org.freedesktop.Hal.Device.Volume.PermissionDenied", serr); + } else { + show_error_dialog_eject (udi, volume, drive, "org.freedesktop.Hal.Device.Volume.UnknownFailure", serr); + } + + goto out; + } + + g_print (_("Ejected %s (using /etc/fstab).\n"), device_file); + + g_free (mount_point); + ret = TRUE; + goto out; + + } + g_free (mount_point); + } msg = dbus_message_new_method_call ("org.freedesktop.Hal", udi, "org.freedesktop.Hal.Device.Volume", @@ -1255,112 +1708,6 @@ { } - -/* borrowed from gtk/gtkfilesystemunix.c in GTK+ on 02/23/2006 */ -static void -canonicalize_filename (gchar *filename) -{ - gchar *p, *q; - gboolean last_was_slash = FALSE; - - p = filename; - q = filename; - - while (*p) - { - if (*p == G_DIR_SEPARATOR) - { - if (!last_was_slash) - *q++ = G_DIR_SEPARATOR; - - last_was_slash = TRUE; - } - else - { - if (last_was_slash && *p == '.') - { - if (*(p + 1) == G_DIR_SEPARATOR || - *(p + 1) == '\0') - { - if (*(p + 1) == '\0') - break; - - p += 1; - } - else if (*(p + 1) == '.' && - (*(p + 2) == G_DIR_SEPARATOR || - *(p + 2) == '\0')) - { - if (q > filename + 1) - { - q--; - while (q > filename + 1 && - *(q - 1) != G_DIR_SEPARATOR) - q--; - } - - if (*(p + 2) == '\0') - break; - - p += 2; - } - else - { - *q++ = *p; - last_was_slash = FALSE; - } - } - else - { - *q++ = *p; - last_was_slash = FALSE; - } - } - - p++; - } - - if (q > filename + 1 && *(q - 1) == G_DIR_SEPARATOR) - q--; - - *q = '\0'; -} - -static char * -resolve_symlink (const char *file) -{ - GError *error; - char *dir; - char *link; - char *f; - char *f1; - - f = g_strdup (file); - - while (g_file_test (f, G_FILE_TEST_IS_SYMLINK)) { - link = g_file_read_link (f, &error); - if (link == NULL) { - g_warning ("Cannot resolve symlink %s: %s", f, error->message); - g_error_free (error); - g_free (f); - f = NULL; - goto out; - } - - dir = g_path_get_dirname (f); - f1 = g_strdup_printf ("%s/%s", dir, link); - g_free (dir); - g_free (link); - g_free (f); - f = f1; - } - -out: - if (f != NULL) - canonicalize_filename (f); - return f; -} - int main (int argc, char *argv[]) { @@ -1689,7 +2036,8 @@ goto out; - } else if (fsusage == LIBHAL_VOLUME_USAGE_MOUNTABLE_FILESYSTEM) { + } else if (fsusage == LIBHAL_VOLUME_USAGE_MOUNTABLE_FILESYSTEM || + fsusage == LIBHAL_VOLUME_USAGE_UNKNOWN) { if (volume_mount (udi, volume, drive)) rc = 0; } @@ -1700,7 +2048,7 @@ out: if (drive != NULL) - libhal_volume_free (volume); + libhal_drive_free (drive); if (volume != NULL) libhal_volume_free (volume);