]> git.ipfire.org Git - thirdparty/util-linux.git/commitdiff
libmount: fix and improve utab update on MS_MOVE
authorKarel Zak <kzak@redhat.com>
Wed, 4 May 2022 10:13:08 +0000 (12:13 +0200)
committerKarel Zak <kzak@redhat.com>
Wed, 4 May 2022 10:13:08 +0000 (12:13 +0200)
* avoid double '//'

* don't update /fooxxx when /foo update requested (make sure that
  startswith() returns path terminated by '/')

* canonicalize only once the new path -- all in utab/mtab is already
  canonicalized, so after MS_MOVE we need to care about the new path
  only

* use asprintf() rather than strcpy() and strcat(), don't compose a
  new path from prefix and subdir when replace entire path

Addresses: https://github.com/util-linux/util-linux/pull/1660
Signed-off-by: Karel Zak <kzak@redhat.com>
libmount/src/tab_update.c

index 51f2fae260ccdc665cd7f56a38246b678bc411cc..3a22e7188b94b6d44cdcffd0f736c1ff2ac8c40b 100644 (file)
@@ -767,33 +767,34 @@ static int update_modify_target(struct libmnt_update *upd, struct libmnt_lock *l
                const char *upd_target = mnt_fs_get_target(upd->fs);
                struct libmnt_iter itr;
                struct libmnt_fs *fs;
+               char *cn_target = mnt_resolve_path(upd_target, NULL);
+
+               if (!cn_target) {
+                       rc = -ENOMEM;
+                       goto done;
+               }
 
                mnt_reset_iter(&itr, MNT_ITER_BACKWARD);
-               while(mnt_table_next_fs(tb, &itr, &fs) == 0) {
-                       char *p, *e;
-                       size_t len;
+               while (mnt_table_next_fs(tb, &itr, &fs) == 0) {
+                       char *p;
+                       const char *e;
 
                        e = startswith(mnt_fs_get_target(fs), upd_source);
-                       if (!e)
+                       if (!e || (*e && *e != '/'))
                                continue;
+                       if (*e == '/')
+                               e++;            /* remove extra '/' */
 
-                       len = strlen(upd_target) + strlen(e) + 2;
-                       p = malloc(len);
-                       if (!p)
-                               rc = -ENOMEM;
-                       else {
-                               char *cn;
-
-                               strcpy(p, upd_target);
-                               strcat(p, "/");
-                               strcat(p, e);
-
-                               cn = mnt_resolve_path(p, NULL);
-                               rc = mnt_fs_set_target(fs, cn);
+                       /* no subdirectory, replace entire path */
+                       if (!*e)
+                               rc = mnt_fs_set_target(fs, cn_target);
 
-                               free(cn);
+                       /* update start of the path, keep subdirectory */
+                       else if (asprintf(&p, "%s/%s", cn_target, e) > 0) {
+                               rc = mnt_fs_set_target(fs, p);
                                free(p);
-                       }
+                       } else
+                               rc = -ENOMEM;
 
                        if (rc < 0)
                                break;
@@ -801,8 +802,10 @@ static int update_modify_target(struct libmnt_update *upd, struct libmnt_lock *l
 
                if (!rc)
                        rc = update_table(upd, tb);
+               free(cn_target);
        }
 
+done:
        if (lc)
                mnt_unlock_file(lc);