]> git.ipfire.org Git - thirdparty/util-linux.git/commitdiff
umount: allow unmounting loopdev specified by associated file
authorPetr Uzel <petr.uzel@suse.cz>
Thu, 17 Feb 2011 11:52:43 +0000 (12:52 +0100)
committerKarel Zak <kzak@redhat.com>
Mon, 18 Apr 2011 12:32:39 +0000 (14:32 +0200)
Make it possible to unmount a filesystem on a loop device if it is
specified by associated backing file. It does not attempt to unmount
anything if there are more than one loop device associated with the
given file.

Umount looks for associated loopdevice(s) only if umount is called
with the regular file as an argument.

Before:
mount -o loop -t ext2 img mnt
umount -v img
> Could not find /home/puzel/upstream/util-linux/img in mtab
> umount: img: not mounted

After:
mount -o loop -t ext2 img mnt
umount -v img
> img is associated with /dev/loop0, trying to unmount it
> /dev/loop0 has been unmounted

[kzak@redhat.com: - fix memory leak in lomount.c]

Addresses: https://bugzilla.novell.com/show_bug.cgi?id=666161
Signed-off-by: Petr Uzel <petr.uzel@suse.cz>
Signed-off-by: Karel Zak <kzak@redhat.com>
mount/lomount.c
mount/lomount.h
mount/umount.c

index 4d23a615ed7f665c5288d14abf1adeee801aa6bb..1c37838f0b991c44e5f40171b0ced00a3fbb6b6d 100644 (file)
@@ -403,6 +403,51 @@ done:
        return -1;
 }
 
+/* Find loop device associated with given @filename. Used for unmounting loop
+ * device specified by associated backing file.
+ *
+ * returns: 1 no such device/error
+ *          2 more than one loop device associated with @filename
+ *          0 exactly one loop device associated with @filename
+ *            (@loopdev points to string containing full device name)
+ */
+int
+find_loopdev_by_backing_file(const char *filename, char **loopdev)
+{
+       struct looplist ll;
+       struct stat filestat;
+       int fd;
+       int devs_n = 0;         /* number of loop devices found */
+       char* devname = NULL;
+
+       if (stat(filename, &filestat) == -1) {
+               perror(filename);
+               return 1;
+       }
+
+       if (looplist_open(&ll, LLFLG_USEDONLY) == -1) {
+               error(_("%s: /dev directory does not exist."), progname);
+               return 1;
+       }
+
+       while((devs_n < 2) && (fd = looplist_next(&ll)) != -1) {
+               if (is_associated(fd, &filestat, 0, 0) == 1) {
+                       if (!devname)
+                               devname = xstrdup(ll.name);
+                       devs_n++;
+               }
+               close(fd);
+       }
+       looplist_close(&ll);
+
+       if (devs_n == 1) {
+               *loopdev = devname;
+               return 0;               /* exactly one loopdev */
+       }
+       free(devname);
+       return devs_n ? 2 : 1;          /* more loopdevs or error */
+}
+
 #ifdef MAIN
 
 static int
@@ -565,6 +610,7 @@ show_associated_loop_devices(char *filename, unsigned long long offset, int isof
        return 0;
 }
 
+
 #endif /* MAIN */
 
 /* check if the loopfile is already associated with the same given
@@ -946,6 +992,13 @@ find_unused_loop_device (void) {
        return 0;
 }
 
+int
+find_loopdev_by_backing_file(const char *filename, char **loopdev)
+{
+       mutter();
+       return 1;
+}
+
 #endif /* !LOOP_SET_FD */
 
 #ifdef MAIN
index de8b76bf4f13a824b73ce83090766f782bfe0b8a..4acc371858976394378c023d730dbc1d8c9a721e 100644 (file)
@@ -11,6 +11,7 @@ extern char * find_unused_loop_device(void);
 extern int loopfile_used_with(char *devname, const char *filename, unsigned long long offset);
 extern char *loopfile_used (const char *filename, unsigned long long offset);
 extern char *loopdev_get_loopfile(const char *device);
+extern int find_loopdev_by_backing_file(const char *filename, char **loopdev);
 
 
 #define SETLOOP_RDONLY     (1<<0)  /* Open loop read-only */
index 468fb60134ca0764ee2246bdad0da37b5e8790b3..8ef342a521189d9a14e2e8452cf60bb29610f2d7 100644 (file)
@@ -502,6 +502,7 @@ umount_file (char *arg) {
        const char *file, *options;
        int fstab_has_user, fstab_has_users, fstab_has_owner, fstab_has_group;
        int ok;
+       struct stat statbuf;
 
        if (!*arg) {            /* "" would be expanded to `pwd` */
                die(2, _("Cannot unmount \"\"\n"));
@@ -509,6 +510,27 @@ umount_file (char *arg) {
        }
 
        file = canonicalize(arg); /* mtab paths are canonicalized */
+
+       /* if file is a regular file, check if it is associated
+        * with some loop device
+        */
+       if (!stat(file, &statbuf) && S_ISREG(statbuf.st_mode)) {
+               char *loopdev = NULL;
+               switch (find_loopdev_by_backing_file(file, &loopdev)) {
+               case 0:
+                       if (verbose)
+                               printf(_("%s is associated with %s, trying to unmount it\n"),
+                                      arg, loopdev);
+                       file = loopdev;
+                       break;
+               case 2:
+                       if (verbose)
+                               printf(_("%s is associated with more than one loop device: not unmounting\n"),
+                                      arg);
+                       break;
+               }
+       }
+
        if (verbose > 1)
                printf(_("Trying to unmount %s\n"), file);