From: Karel Zak Date: Wed, 14 May 2008 14:38:47 +0000 (+0200) Subject: mount: remount doesn't care about loop= X-Git-Url: https://err.no/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=994c17b1b129cd3e71b8ad04fa2b531fffe8d786;p=util-linux mount: remount doesn't care about loop= The command # mount -oremount 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 Signed-off-by: Karel Zak --- diff --git a/mount/fstab.c b/mount/fstab.c index 108010f9..895fd2ce 100644 --- a/mount/fstab.c +++ b/mount/fstab.c @@ -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); diff --git a/mount/mount.8 b/mount/mount.8 index bb6b3f10..42d3e55e 100644 --- a/mount/mount.8 +++ b/mount/mount.8 @@ -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.