]> err.no Git - util-linux/commitdiff
mount: remount doesn't care about loop=
authorKarel Zak <kzak@redhat.com>
Wed, 14 May 2008 14:38:47 +0000 (16:38 +0200)
committerKarel Zak <kzak@redhat.com>
Mon, 19 May 2008 08:31:40 +0000 (10:31 +0200)
The command

   # mount -oremount <spec> <dir>

doesn't read fstab or mtab. This is expected behaviour. Unfortunately,
we have to care about the internal loop= option which is generated and
maintained by mount(8)/umount(8). The loop= option has to be persistent.

How to reproduce this bug:

 # mount -o loop       /home/images/vfat.img /mnt/img; grep vfat /etc/mtab; \
   mount -o remount,ro /home/images/vfat.img /mnt/img; grep vfat /etc/mtab;

 /home/images/vfat.img /mnt/img vfat rw,loop=/dev/loop0 0 0
 /home/images/vfat.img /mnt/img vfat ro 0 0

Reported-By: David Chinner <dgc@sgi.com>
Signed-off-by: Karel Zak <kzak@redhat.com>
mount/fstab.c
mount/mount.8

index 108010f9d76320629be9294495da736253b3d130..895fd2ce27448dc7a38dca480671365d0ca8b6b6 100644 (file)
@@ -669,6 +669,88 @@ lock_mtab (void) {
        }
 }
 
+static char *
+get_option(const char *optname, const char *src, size_t *len)
+{
+       char *opt, *end;
+       size_t sz;
+
+       if (!src)
+               return NULL;
+
+       opt = strstr(src, optname);
+       if (!opt)
+               return NULL;
+
+       end = strchr(opt, ',');
+       sz = end ? end - opt : strlen(opt);
+
+       if (len)
+               *len = sz;
+
+       if ((opt == src || *(opt - 1) == ',') &&
+           (*(opt + sz) == '\0' || *(opt + sz) == ','))
+               return opt;
+
+       return NULL;
+}
+
+static int
+cpy_option(const char *optname, char *dest, const char *src)
+{
+       char *opt;
+       size_t sz;
+
+       opt = get_option(optname, src, &sz);
+       if (!opt)
+               /* the option doesn't exist */
+               return 0;
+
+       if (get_option(optname, dest, NULL))
+               /* the options is already in dest */
+               return 0;
+
+       if (*dest) {
+               dest = dest + strlen(dest);
+               *dest++ = ',';          /* separator */
+       }
+       memcpy(dest, opt, sz);  /* copy option */
+       *(dest + sz) = '\0';    /* terminator */
+
+       return 1;
+}
+
+/* Generates (and allocates) new options for remount
+ *
+ * We cannot blindly replace the old options, otherwise we will lost some
+ * internally generated stuff (e.g loop=).
+ */
+static char *
+mk_remount_opts(const char *old, const char *instead)
+{
+       char *new;
+       size_t sz;
+
+       if (old == NULL && instead == NULL)
+               return NULL;
+       if (!old)
+               return xstrdup(instead);
+
+       /* max size of new options is:
+        * old + new + '\0' + separator (for each copied option)
+        */
+       sz = strlen(old) + (instead ? strlen(instead) : 0) + 2;
+       new = xmalloc(sz);
+       if (instead && *instead)
+               strncpy(new, instead, sz);
+       else
+               *new = '\0';
+
+       cpy_option("loop=", new, old);
+
+       return new;
+}
+
 /*
  * Update the mtab.
  *  Used by umount with null INSTEAD: remove the last DIR entry.
@@ -721,8 +803,10 @@ update_mtab (const char *dir, struct my_mntent *instead) {
                        }
                } else if (!strcmp(mc->m.mnt_dir, instead->mnt_dir)) {
                        /* A remount */
+                       char *opts = mk_remount_opts(mc->m.mnt_opts,
+                                       instead->mnt_opts);
                        my_free(mc->m.mnt_opts);
-                       mc->m.mnt_opts = xstrdup(instead->mnt_opts);
+                       mc->m.mnt_opts = opts;
                } else {
                        /* A move */
                        my_free(mc->m.mnt_dir);
index bb6b3f10bf48f3b81887c6272bff715cc7231ec5..42d3e55e3baf0e4bff0e6fd8b4905df63ee878a6 100644 (file)
@@ -679,6 +679,27 @@ This option implies the options
 Attempt to remount an already-mounted file system.  This is commonly
 used to change the mount flags for a file system, especially to make a
 readonly file system writeable. It does not change device or mount point.
+
+The remount functionality follows the standard way how the mount command works
+with options from fstab. It means the mount command doesn't read fstab (or
+mtab) only when a
+.IR device
+and
+.IR dir
+are fully specified.
+
+.BR "mount -o remount,rw /dev/foo /dir"
+
+After this call all old mount options are replaced and arbitrary stuff from
+fstab is ignored, except the loop= option which is internally generated and
+maintained by the mount command.
+
+.BR "mount -o remount,rw  /dir"
+
+After this call mount reads fstab (or mtab) and merges these options with
+options from command line (
+.B -o
+).
 .TP
 .B ro
 Mount the file system read-only.