X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?p=elogind.git;a=blobdiff_plain;f=src%2Fumount.c;h=3d328e0da955ecf855564b1067e5310d6afe9f1a;hp=0081d979d9d0128fd99ffa179dcebffc943d6484;hb=f1d19aa412b34fe025dfd48a5c79d34fdd0f9528;hpb=9279749b84cc87c7830280b7895a48bed03c9429 diff --git a/src/umount.c b/src/umount.c index 0081d979d..3d328e0da 100644 --- a/src/umount.c +++ b/src/umount.c @@ -37,6 +37,7 @@ typedef struct MountPoint { char *path; dev_t devnum; + bool skip_ro; LIST_FIELDS (struct MountPoint, mount_point); } MountPoint; @@ -71,6 +72,8 @@ static int mount_points_list_get(MountPoint **head) { for (i = 1;; i++) { int k; MountPoint *m; + char *root; + bool skip_ro; path = p = NULL; @@ -78,7 +81,7 @@ static int mount_points_list_get(MountPoint **head) { "%*s " /* (1) mount id */ "%*s " /* (2) parent id */ "%*s " /* (3) major:minor */ - "%*s " /* (4) root */ + "%ms " /* (4) root */ "%ms " /* (5) mount point */ "%*s" /* (6) mount options */ "%*[^-]" /* (7) optional fields */ @@ -87,7 +90,8 @@ static int mount_points_list_get(MountPoint **head) { "%*s" /* (10) mount source */ "%*s" /* (11) mount options 2 */ "%*[^\n]", /* some rubbish at the end */ - &path)) != 1) { + &root, + &path)) != 2) { if (k == EOF) break; @@ -97,6 +101,11 @@ static int mount_points_list_get(MountPoint **head) { continue; } + /* If we encounter a bind mount, don't try to remount + * the source dir too early */ + skip_ro = !streq(root, "/"); + free(root); + p = cunescape(path); free(path); @@ -105,7 +114,7 @@ static int mount_points_list_get(MountPoint **head) { goto finish; } - if (mount_point_is_api(p)) { + if (mount_point_is_api(p) || mount_point_ignore(p)) { free(p); continue; } @@ -117,6 +126,7 @@ static int mount_points_list_get(MountPoint **head) { } m->path = p; + m->skip_ro = skip_ro; LIST_PREPEND(MountPoint, mount_point, *head, m); } @@ -355,7 +365,7 @@ static int delete_loopback(const char *device) { int fd, r; if ((fd = open(device, O_RDONLY|O_CLOEXEC)) < 0) - return -errno; + return errno == ENOENT ? 0 : -errno; r = ioctl(fd, LOOP_CLR_FD, 0); close_nointr_nofail(fd); @@ -428,6 +438,11 @@ static int mount_points_list_remount_read_only(MountPoint **head, bool *changed) LIST_FOREACH_SAFE(mount_point, m, n, *head) { + if (m->skip_ro) { + n_failed++; + continue; + } + /* Trying to remount read-only */ if (mount(NULL, m->path, NULL, MS_MGC_VAL|MS_REMOUNT|MS_RDONLY, NULL) == 0) { if (changed) @@ -466,12 +481,24 @@ static int swap_points_list_off(MountPoint **head, bool *changed) { static int loopback_points_list_detach(MountPoint **head, bool *changed) { MountPoint *m, *n; - int n_failed = 0; + int n_failed = 0, k; + struct stat root_st; assert(head); + k = lstat("/", &root_st); + LIST_FOREACH_SAFE(mount_point, m, n, *head) { int r; + struct stat loopback_st; + + if (k >= 0 && + major(root_st.st_dev) != 0 && + lstat(m->path, &loopback_st) >= 0 && + root_st.st_dev == loopback_st.st_rdev) { + n_failed ++; + continue; + } if ((r = delete_loopback(m->path)) >= 0) { @@ -490,13 +517,23 @@ static int loopback_points_list_detach(MountPoint **head, bool *changed) { static int dm_points_list_detach(MountPoint **head, bool *changed) { MountPoint *m, *n; - int n_failed = 0; + int n_failed = 0, k; + struct stat root_st; assert(head); + k = lstat("/", &root_st); + LIST_FOREACH_SAFE(mount_point, m, n, *head) { int r; + if (k >= 0 && + major(root_st.st_dev) != 0 && + root_st.st_dev == m->devnum) { + n_failed ++; + continue; + } + if ((r = delete_dm(m->devnum)) >= 0) { if (r > 0 && changed)