This allows a flag to be set on loop devices so that when they are closed
for the last time, they'll self-destruct.

The kernel part has been submitted to lkml by David Woodhouse.

Signed-off-by: Bernardo Innocenti <[EMAIL PROTECTED]>
---
 mount/lomount.c |   33 ++++++++++++++++++++++++++++-----
 mount/lomount.h |    3 +++
 mount/loop.h    |    7 +++++++
 mount/mount.c   |   16 ++++++++++++----
 4 files changed, 50 insertions(+), 9 deletions(-)

diff --git a/mount/lomount.c b/mount/lomount.c
index 5bd8954..6aef652 100644
--- a/mount/lomount.c
+++ b/mount/lomount.c
@@ -369,7 +369,7 @@ digits_only(const char *s) {
 
 int
 set_loop(const char *device, const char *file, unsigned long long offset,
-        const char *encryption, int pfd, int *loopro) {
+        const char *encryption, int pfd, int *options) {
        struct loop_info64 loopinfo64;
        int fd, ffd, mode, i;
        char *pass;
@@ -385,20 +385,20 @@ set_loop(const char *device, const char *file, unsigned 
long long offset,
                }
        }
 
-       mode = (*loopro ? O_RDONLY : O_RDWR);
+       mode = (*options & SETLOOP_RDONLY) ? O_RDONLY : O_RDWR;
        if ((ffd = open(file, mode)) < 0) {
-               if (!*loopro && errno == EROFS)
+               if (!(*options & SETLOOP_RDONLY) && errno == EROFS)
                        ffd = open(file, mode = O_RDONLY);
                if (ffd < 0) {
                        perror(file);
                        return 1;
                }
+               *options |= SETLOOP_RDONLY;
        }
        if ((fd = open(device, mode)) < 0) {
                perror (device);
                return 1;
        }
-       *loopro = (mode == O_RDONLY);
 
        memset(&loopinfo64, 0, sizeof(loopinfo64));
 
@@ -467,6 +467,9 @@ set_loop(const char *device, const char *file, unsigned 
long long offset,
        }
        close (ffd);
 
+       if (*options & SETLOOP_AUTOCLEAR)
+               loopinfo64.lo_flags = LO_FLAGS_AUTOCLEAR;
+
        i = ioctl(fd, LOOP_SET_STATUS64, &loopinfo64);
        if (i) {
                struct loop_info loopinfo;
@@ -475,16 +478,30 @@ set_loop(const char *device, const char *file, unsigned 
long long offset,
                i = loop_info64_to_old(&loopinfo64, &loopinfo);
                if (i) {
                        errno = errsv;
+                       *options &= ~SETLOOP_AUTOCLEAR;
                        perror("ioctl: LOOP_SET_STATUS64");
                } else {
                        i = ioctl(fd, LOOP_SET_STATUS, &loopinfo);
                        if (i)
                                perror("ioctl: LOOP_SET_STATUS");
+                       else if (*options & SETLOOP_AUTOCLEAR)
+                       {
+                               i = ioctl(fd, LOOP_GET_STATUS, &loopinfo);
+                               if (i || !(loopinfo.lo_flags & 
LO_FLAGS_AUTOCLEAR))
+                                       *options &= ~SETLOOP_AUTOCLEAR;
+                       }
                }
                memset(&loopinfo, 0, sizeof(loopinfo));
        }
+       else if (*options & SETLOOP_AUTOCLEAR)
+       {
+               i = ioctl(fd, LOOP_GET_STATUS64, &loopinfo64);
+               if (i || !(loopinfo64.lo_flags & LO_FLAGS_AUTOCLEAR))
+                       *options &= ~SETLOOP_AUTOCLEAR;
+       }
        memset(&loopinfo64, 0, sizeof(loopinfo64));
 
+
        if (i) {
                ioctl (fd, LOOP_CLR_FD, 0);
                close (fd);
@@ -492,7 +509,13 @@ set_loop(const char *device, const char *file, unsigned 
long long offset,
                        free(filename);
                return 1;
        }
-       close (fd);
+
+       /*
+        * HACK: here we're leeking a file descriptor,
+        * but mount is a short-lived process anyway.
+        */
+       if (!(*options & SETLOOP_AUTOCLEAR))
+               close (fd);
 
        if (verbose > 1)
                printf(_("set_loop(%s,%s,%llu): success\n"),
diff --git a/mount/lomount.h b/mount/lomount.h
index 38b3a48..a5c1ae8 100644
--- a/mount/lomount.h
+++ b/mount/lomount.h
@@ -6,3 +6,6 @@ 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);
+
+#define SETLOOP_RDONLY     (1<<0)  /* Open loop read-only */
+#define SETLOOP_AUTOCLEAR  (1<<1)  /* Automatically detach loop on close 
(2.6.25?) */
diff --git a/mount/loop.h b/mount/loop.h
index 951a5d1..c745209 100644
--- a/mount/loop.h
+++ b/mount/loop.h
@@ -10,6 +10,13 @@
 #define LOOP_SET_STATUS64      0x4C04
 #define LOOP_GET_STATUS64      0x4C05
 
+/* Flags for loop_into{64,}->lo_flags */
+enum {
+       LO_FLAGS_READ_ONLY  = 1,
+       LO_FLAGS_USE_AOPS   = 2,
+       LO_FLAGS_AUTOCLEAR  = 4, /* New in 2.6.25? */
+};
+
 #define LO_NAME_SIZE   64
 #define LO_KEY_SIZE    32
 
diff --git a/mount/mount.c b/mount/mount.c
index 9d43e5f..6882afe 100644
--- a/mount/mount.c
+++ b/mount/mount.c
@@ -906,9 +906,12 @@ loop_check(const char **spec, const char **type, int 
*flags,
       if (verbose)
        printf(_("mount: skipping the setup of a loop device\n"));
     } else {
-      int loopro = (*flags & MS_RDONLY);
+      int loop_opts = SETLOOP_AUTOCLEAR; /* always attempt autoclear */
       int res;
 
+      if (*flags & MS_RDONLY)
+        loop_opts |= SETLOOP_RDONLY;
+
       offset = opt_offset ? strtoull(opt_offset, NULL, 0) : 0;
 
       if (is_mounted_same_loopfile(node, *loopfile, offset)) {
@@ -925,7 +928,7 @@ loop_check(const char **spec, const char **type, int *flags,
          printf(_("mount: going to use the loop device %s\n"), *loopdev);
 
        if ((res = set_loop(*loopdev, *loopfile, offset,
-                           opt_encryption, pfd, &loopro))) {
+                           opt_encryption, pfd, &loop_opts))) {
          if (res == 2) {
             /* loop dev has been grabbed by some other process,
                try again, if not given explicitly */
@@ -954,8 +957,13 @@ loop_check(const char **spec, const char **type, int 
*flags,
       if (verbose > 1)
        printf(_("mount: setup loop device successfully\n"));
       *spec = *loopdev;
-      if (loopro)
-       *flags |= MS_RDONLY;
+
+      if (loop_opts & SETLOOP_RDONLY)
+        *flags |= MS_RDONLY;
+
+      if (loop_opts & SETLOOP_AUTOCLEAR)
+        /* Prevent recording loop dev in mtab for cleanup on umount */
+        *loop = 0;
     }
   }
 
-- 
1.5.3.4.206.g58ba4

-
To unsubscribe from this list: send the line "unsubscribe util-linux-ng" in
the body of a message to [EMAIL PROTECTED]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to