LCOV - code coverage report
Current view: top level - shutdown - umount.c (source / functions) Hit Total Coverage
Test: main_coverage.info Lines: 80 335 23.9 %
Date: 2019-08-22 15:41:25 Functions: 4 20 20.0 %

          Line data    Source code
       1             : /* SPDX-License-Identifier: LGPL-2.1+ */
       2             : /***
       3             :   Copyright © 2010 ProFUSION embedded systems
       4             : ***/
       5             : 
       6             : #include <errno.h>
       7             : #include <fcntl.h>
       8             : #include <linux/dm-ioctl.h>
       9             : #include <linux/loop.h>
      10             : #include <string.h>
      11             : #include <sys/mount.h>
      12             : #include <sys/swap.h>
      13             : #include <sys/stat.h>
      14             : #include <sys/types.h>
      15             : #include <unistd.h>
      16             : 
      17             : #include "sd-device.h"
      18             : 
      19             : #include "alloc-util.h"
      20             : #include "blockdev-util.h"
      21             : #include "def.h"
      22             : #include "device-util.h"
      23             : #include "escape.h"
      24             : #include "fd-util.h"
      25             : #include "fstab-util.h"
      26             : #include "libmount-util.h"
      27             : #include "mount-setup.h"
      28             : #include "mount-util.h"
      29             : #include "mountpoint-util.h"
      30             : #include "path-util.h"
      31             : #include "process-util.h"
      32             : #include "signal-util.h"
      33             : #include "string-util.h"
      34             : #include "strv.h"
      35             : #include "umount.h"
      36             : #include "util.h"
      37             : #include "virt.h"
      38             : 
      39          33 : static void mount_point_free(MountPoint **head, MountPoint *m) {
      40          33 :         assert(head);
      41          33 :         assert(m);
      42             : 
      43          33 :         LIST_REMOVE(mount_point, *head, m);
      44             : 
      45          33 :         free(m->path);
      46          33 :         free(m->remount_options);
      47          33 :         free(m);
      48          33 : }
      49             : 
      50           6 : void mount_points_list_free(MountPoint **head) {
      51           6 :         assert(head);
      52             : 
      53          39 :         while (*head)
      54          33 :                 mount_point_free(head, *head);
      55           6 : }
      56             : 
      57           4 : int mount_points_list_get(const char *mountinfo, MountPoint **head) {
      58           4 :         _cleanup_(mnt_free_tablep) struct libmnt_table *table = NULL;
      59           4 :         _cleanup_(mnt_free_iterp) struct libmnt_iter *iter = NULL;
      60             :         int r;
      61             : 
      62           4 :         assert(head);
      63             : 
      64           4 :         r = libmount_parse(mountinfo, NULL, &table, &iter);
      65           4 :         if (r < 0)
      66           0 :                 return log_error_errno(r, "Failed to parse %s: %m", mountinfo);
      67             : 
      68          88 :         for (;;) {
      69             :                 struct libmnt_fs *fs;
      70             :                 const char *path, *fstype;
      71          92 :                 _cleanup_free_ char *options = NULL;
      72          92 :                 unsigned long remount_flags = 0u;
      73          92 :                 _cleanup_free_ char *remount_options = NULL;
      74             :                 bool try_remount_ro;
      75          92 :                 _cleanup_free_ MountPoint *m = NULL;
      76             : 
      77          92 :                 r = mnt_table_next_fs(table, iter, &fs);
      78          92 :                 if (r == 1)
      79           4 :                         break;
      80          88 :                 if (r < 0)
      81           0 :                         return log_error_errno(r, "Failed to get next entry from %s: %m", mountinfo);
      82             : 
      83          88 :                 path = mnt_fs_get_target(fs);
      84          88 :                 if (!path)
      85           0 :                         continue;
      86             : 
      87          88 :                 fstype = mnt_fs_get_fstype(fs);
      88             : 
      89             :                 /* Combine the generic VFS options with the FS-specific
      90             :                  * options. Duplicates are not a problem here, because the only
      91             :                  * options that should come up twice are typically ro/rw, which
      92             :                  * are turned into MS_RDONLY or the inversion of it.
      93             :                  *
      94             :                  * Even if there are duplicates later in mount_option_mangle()
      95             :                  * they shouldn't hurt anyways as they override each other.
      96             :                  */
      97          88 :                 if (!strextend_with_separator(&options, ",",
      98             :                                               mnt_fs_get_vfs_options(fs),
      99             :                                               NULL))
     100           0 :                         return log_oom();
     101          88 :                 if (!strextend_with_separator(&options, ",",
     102             :                                               mnt_fs_get_fs_options(fs),
     103             :                                               NULL))
     104           0 :                         return log_oom();
     105             : 
     106             :                 /* Ignore mount points we can't unmount because they
     107             :                  * are API or because we are keeping them open (like
     108             :                  * /dev/console). Also, ignore all mounts below API
     109             :                  * file systems, since they are likely virtual too,
     110             :                  * and hence not worth spending time on. Also, in
     111             :                  * unprivileged containers we might lack the rights to
     112             :                  * unmount these things, hence don't bother. */
     113         132 :                 if (mount_point_is_api(path) ||
     114          87 :                     mount_point_ignore(path) ||
     115          43 :                     PATH_STARTSWITH_SET(path, "/dev", "/sys", "/proc"))
     116          58 :                         continue;
     117             : 
     118             :                 /* If we are in a container, don't attempt to
     119             :                  * read-only mount anything as that brings no real
     120             :                  * benefits, but might confuse the host, as we remount
     121             :                  * the superblock here, not the bind mount.
     122             :                  *
     123             :                  * If the filesystem is a network fs, also skip the
     124             :                  * remount. It brings no value (we cannot leave
     125             :                  * a "dirty fs") and could hang if the network is down.
     126             :                  * Note that umount2() is more careful and will not
     127             :                  * hang because of the network being down. */
     128          30 :                 try_remount_ro = detect_container() <= 0 &&
     129          30 :                                  !fstype_is_network(fstype) &&
     130          30 :                                  !fstype_is_api_vfs(fstype) &&
     131          76 :                                  !fstype_is_ro(fstype) &&
     132          16 :                                  !fstab_test_yes_no_option(options, "ro\0rw\0");
     133             : 
     134          30 :                 if (try_remount_ro) {
     135             :                         /* mount(2) states that mount flags and options need to be exactly the same
     136             :                          * as they were when the filesystem was mounted, except for the desired
     137             :                          * changes. So we reconstruct both here and adjust them for the later
     138             :                          * remount call too. */
     139             : 
     140          16 :                         r = mnt_fs_get_propagation(fs, &remount_flags);
     141          16 :                         if (r < 0) {
     142           0 :                                 log_warning_errno(r, "mnt_fs_get_propagation() failed for %s, ignoring: %m", path);
     143           0 :                                 continue;
     144             :                         }
     145             : 
     146          16 :                         r = mount_option_mangle(options, remount_flags, &remount_flags, &remount_options);
     147          16 :                         if (r < 0) {
     148           0 :                                 log_warning_errno(r, "mount_option_mangle failed for %s, ignoring: %m", path);
     149           0 :                                 continue;
     150             :                         }
     151             : 
     152             :                         /* MS_BIND is special. If it is provided it will only make the mount-point
     153             :                          * read-only. If left out, the super block itself is remounted, which we want. */
     154          16 :                         remount_flags = (remount_flags|MS_REMOUNT|MS_RDONLY) & ~MS_BIND;
     155             :                 }
     156             : 
     157          30 :                 m = new0(MountPoint, 1);
     158          30 :                 if (!m)
     159           0 :                         return log_oom();
     160             : 
     161          30 :                 m->path = strdup(path);
     162          30 :                 if (!m->path)
     163           0 :                         return log_oom();
     164             : 
     165          30 :                 m->remount_options = TAKE_PTR(remount_options);
     166          30 :                 m->remount_flags = remount_flags;
     167          30 :                 m->try_remount_ro = try_remount_ro;
     168             : 
     169          30 :                 LIST_PREPEND(mount_point, *head, TAKE_PTR(m));
     170             :         }
     171             : 
     172           4 :         return 0;
     173             : }
     174             : 
     175           2 : int swap_list_get(const char *swaps, MountPoint **head) {
     176           2 :         _cleanup_(mnt_free_tablep) struct libmnt_table *t = NULL;
     177           2 :         _cleanup_(mnt_free_iterp) struct libmnt_iter *i = NULL;
     178             :         int r;
     179             : 
     180           2 :         assert(head);
     181             : 
     182           2 :         t = mnt_new_table();
     183           2 :         i = mnt_new_iter(MNT_ITER_FORWARD);
     184           2 :         if (!t || !i)
     185           0 :                 return log_oom();
     186             : 
     187           2 :         r = mnt_table_parse_swaps(t, swaps);
     188           2 :         if (r < 0)
     189           0 :                 return log_error_errno(r, "Failed to parse %s: %m", swaps);
     190             : 
     191           3 :         for (;;) {
     192             :                 struct libmnt_fs *fs;
     193           5 :                 _cleanup_free_ MountPoint *swap = NULL;
     194             :                 const char *source;
     195             : 
     196           5 :                 r = mnt_table_next_fs(t, i, &fs);
     197           5 :                 if (r == 1)
     198           2 :                         break;
     199           3 :                 if (r < 0)
     200           0 :                         return log_error_errno(r, "Failed to get next entry from %s: %m", swaps);
     201             : 
     202           3 :                 source = mnt_fs_get_source(fs);
     203           3 :                 if (!source)
     204           0 :                         continue;
     205             : 
     206           3 :                 swap = new0(MountPoint, 1);
     207           3 :                 if (!swap)
     208           0 :                         return -ENOMEM;
     209             : 
     210           3 :                 swap->path = strdup(source);
     211           3 :                 if (!swap->path)
     212           0 :                         return -ENOMEM;
     213             : 
     214           3 :                 LIST_PREPEND(mount_point, *head, TAKE_PTR(swap));
     215             :         }
     216             : 
     217           2 :         return 0;
     218             : }
     219             : 
     220           0 : static int loopback_list_get(MountPoint **head) {
     221           0 :         _cleanup_(sd_device_enumerator_unrefp) sd_device_enumerator *e = NULL;
     222             :         sd_device *d;
     223             :         int r;
     224             : 
     225           0 :         assert(head);
     226             : 
     227           0 :         r = sd_device_enumerator_new(&e);
     228           0 :         if (r < 0)
     229           0 :                 return r;
     230             : 
     231           0 :         r = sd_device_enumerator_allow_uninitialized(e);
     232           0 :         if (r < 0)
     233           0 :                 return r;
     234             : 
     235           0 :         r = sd_device_enumerator_add_match_subsystem(e, "block", true);
     236           0 :         if (r < 0)
     237           0 :                 return r;
     238             : 
     239           0 :         r = sd_device_enumerator_add_match_sysname(e, "loop*");
     240           0 :         if (r < 0)
     241           0 :                 return r;
     242             : 
     243           0 :         r = sd_device_enumerator_add_match_sysattr(e, "loop/backing_file", NULL, true);
     244           0 :         if (r < 0)
     245           0 :                 return r;
     246             : 
     247           0 :         FOREACH_DEVICE(e, d) {
     248           0 :                 _cleanup_free_ char *p = NULL;
     249             :                 const char *dn;
     250             :                 MountPoint *lb;
     251             : 
     252           0 :                 if (sd_device_get_devname(d, &dn) < 0)
     253           0 :                         continue;
     254             : 
     255           0 :                 p = strdup(dn);
     256           0 :                 if (!p)
     257           0 :                         return -ENOMEM;
     258             : 
     259           0 :                 lb = new(MountPoint, 1);
     260           0 :                 if (!lb)
     261           0 :                         return -ENOMEM;
     262             : 
     263           0 :                 *lb = (MountPoint) {
     264           0 :                         .path = TAKE_PTR(p),
     265             :                 };
     266             : 
     267           0 :                 LIST_PREPEND(mount_point, *head, lb);
     268             :         }
     269             : 
     270           0 :         return 0;
     271             : }
     272             : 
     273           0 : static int dm_list_get(MountPoint **head) {
     274           0 :         _cleanup_(sd_device_enumerator_unrefp) sd_device_enumerator *e = NULL;
     275             :         sd_device *d;
     276             :         int r;
     277             : 
     278           0 :         assert(head);
     279             : 
     280           0 :         r = sd_device_enumerator_new(&e);
     281           0 :         if (r < 0)
     282           0 :                 return r;
     283             : 
     284           0 :         r = sd_device_enumerator_allow_uninitialized(e);
     285           0 :         if (r < 0)
     286           0 :                 return r;
     287             : 
     288           0 :         r = sd_device_enumerator_add_match_subsystem(e, "block", true);
     289           0 :         if (r < 0)
     290           0 :                 return r;
     291             : 
     292           0 :         r = sd_device_enumerator_add_match_sysname(e, "dm-*");
     293           0 :         if (r < 0)
     294           0 :                 return r;
     295             : 
     296           0 :         FOREACH_DEVICE(e, d) {
     297           0 :                 _cleanup_free_ char *p = NULL;
     298             :                 const char *dn;
     299             :                 MountPoint *m;
     300             :                 dev_t devnum;
     301             : 
     302           0 :                 if (sd_device_get_devnum(d, &devnum) < 0 ||
     303           0 :                     sd_device_get_devname(d, &dn) < 0)
     304           0 :                         continue;
     305             : 
     306           0 :                 p = strdup(dn);
     307           0 :                 if (!p)
     308           0 :                         return -ENOMEM;
     309             : 
     310           0 :                 m = new(MountPoint, 1);
     311           0 :                 if (!m)
     312           0 :                         return -ENOMEM;
     313             : 
     314           0 :                 *m = (MountPoint) {
     315           0 :                         .path = TAKE_PTR(p),
     316             :                         .devnum = devnum,
     317             :                 };
     318             : 
     319           0 :                 LIST_PREPEND(mount_point, *head, m);
     320             :         }
     321             : 
     322           0 :         return 0;
     323             : }
     324             : 
     325           0 : static int delete_loopback(const char *device) {
     326           0 :         _cleanup_close_ int fd = -1;
     327             :         int r;
     328             : 
     329           0 :         assert(device);
     330             : 
     331           0 :         fd = open(device, O_RDONLY|O_CLOEXEC);
     332           0 :         if (fd < 0)
     333           0 :                 return errno == ENOENT ? 0 : -errno;
     334             : 
     335           0 :         r = ioctl(fd, LOOP_CLR_FD, 0);
     336           0 :         if (r >= 0)
     337           0 :                 return 1;
     338             : 
     339             :         /* ENXIO: not bound, so no error */
     340           0 :         if (errno == ENXIO)
     341           0 :                 return 0;
     342             : 
     343           0 :         return -errno;
     344             : }
     345             : 
     346           0 : static int delete_dm(dev_t devnum) {
     347             : 
     348           0 :         struct dm_ioctl dm = {
     349             :                 .version = {
     350             :                         DM_VERSION_MAJOR,
     351             :                         DM_VERSION_MINOR,
     352             :                         DM_VERSION_PATCHLEVEL
     353             :                 },
     354             :                 .data_size = sizeof(dm),
     355             :                 .dev = devnum,
     356             :         };
     357             : 
     358           0 :         _cleanup_close_ int fd = -1;
     359             : 
     360           0 :         assert(major(devnum) != 0);
     361             : 
     362           0 :         fd = open("/dev/mapper/control", O_RDWR|O_CLOEXEC);
     363           0 :         if (fd < 0)
     364           0 :                 return -errno;
     365             : 
     366           0 :         if (ioctl(fd, DM_DEV_REMOVE, &dm) < 0)
     367           0 :                 return -errno;
     368             : 
     369           0 :         return 0;
     370             : }
     371             : 
     372           0 : static bool nonunmountable_path(const char *path) {
     373           0 :         return path_equal(path, "/")
     374             : #if ! HAVE_SPLIT_USR
     375           0 :                 || path_equal(path, "/usr")
     376             : #endif
     377           0 :                 || path_startswith(path, "/run/initramfs");
     378             : }
     379             : 
     380           0 : static int remount_with_timeout(MountPoint *m, int umount_log_level) {
     381             :         pid_t pid;
     382             :         int r;
     383             : 
     384           0 :         BLOCK_SIGNALS(SIGCHLD);
     385             : 
     386           0 :         assert(m);
     387             : 
     388             :         /* Due to the possibility of a remount operation hanging, we
     389             :          * fork a child process and set a timeout. If the timeout
     390             :          * lapses, the assumption is that that particular remount
     391             :          * failed. */
     392           0 :         r = safe_fork("(sd-remount)", FORK_RESET_SIGNALS|FORK_CLOSE_ALL_FDS|FORK_LOG|FORK_REOPEN_LOG, &pid);
     393           0 :         if (r < 0)
     394           0 :                 return r;
     395           0 :         if (r == 0) {
     396           0 :                 log_info("Remounting '%s' read-only in with options '%s'.", m->path, m->remount_options);
     397             : 
     398             :                 /* Start the mount operation here in the child */
     399           0 :                 r = mount(NULL, m->path, NULL, m->remount_flags, m->remount_options);
     400           0 :                 if (r < 0)
     401           0 :                         log_full_errno(umount_log_level, errno, "Failed to remount '%s' read-only: %m", m->path);
     402             : 
     403           0 :                 _exit(r < 0 ? EXIT_FAILURE : EXIT_SUCCESS);
     404             :         }
     405             : 
     406           0 :         r = wait_for_terminate_with_timeout(pid, DEFAULT_TIMEOUT_USEC);
     407           0 :         if (r == -ETIMEDOUT) {
     408           0 :                 log_error_errno(r, "Remounting '%s' timed out, issuing SIGKILL to PID " PID_FMT ".", m->path, pid);
     409           0 :                 (void) kill(pid, SIGKILL);
     410           0 :         } else if (r == -EPROTO)
     411           0 :                 log_debug_errno(r, "Remounting '%s' failed abnormally, child process " PID_FMT " aborted or exited non-zero.", m->path, pid);
     412           0 :         else if (r < 0)
     413           0 :                 log_error_errno(r, "Remounting '%s' failed unexpectedly, couldn't wait for child process " PID_FMT ": %m", m->path, pid);
     414             : 
     415           0 :         return r;
     416             : }
     417             : 
     418           0 : static int umount_with_timeout(MountPoint *m, int umount_log_level) {
     419             :         pid_t pid;
     420             :         int r;
     421             : 
     422           0 :         BLOCK_SIGNALS(SIGCHLD);
     423             : 
     424           0 :         assert(m);
     425             : 
     426             :         /* Due to the possibility of a umount operation hanging, we
     427             :          * fork a child process and set a timeout. If the timeout
     428             :          * lapses, the assumption is that that particular umount
     429             :          * failed. */
     430           0 :         r = safe_fork("(sd-umount)", FORK_RESET_SIGNALS|FORK_CLOSE_ALL_FDS|FORK_LOG|FORK_REOPEN_LOG, &pid);
     431           0 :         if (r < 0)
     432           0 :                 return r;
     433           0 :         if (r == 0) {
     434           0 :                 log_info("Unmounting '%s'.", m->path);
     435             : 
     436             :                 /* Start the mount operation here in the child Using MNT_FORCE
     437             :                  * causes some filesystems (e.g. FUSE and NFS and other network
     438             :                  * filesystems) to abort any pending requests and return -EIO
     439             :                  * rather than blocking indefinitely. If the filesysten is
     440             :                  * "busy", this may allow processes to die, thus making the
     441             :                  * filesystem less busy so the unmount might succeed (rather
     442             :                  * then return EBUSY).*/
     443           0 :                 r = umount2(m->path, MNT_FORCE);
     444           0 :                 if (r < 0)
     445           0 :                         log_full_errno(umount_log_level, errno, "Failed to unmount %s: %m", m->path);
     446             : 
     447           0 :                 _exit(r < 0 ? EXIT_FAILURE : EXIT_SUCCESS);
     448             :         }
     449             : 
     450           0 :         r = wait_for_terminate_with_timeout(pid, DEFAULT_TIMEOUT_USEC);
     451           0 :         if (r == -ETIMEDOUT) {
     452           0 :                 log_error_errno(r, "Unmounting '%s' timed out, issuing SIGKILL to PID " PID_FMT ".", m->path, pid);
     453           0 :                 (void) kill(pid, SIGKILL);
     454           0 :         } else if (r == -EPROTO)
     455           0 :                 log_debug_errno(r, "Unmounting '%s' failed abnormally, child process " PID_FMT " aborted or exited non-zero.", m->path, pid);
     456           0 :         else if (r < 0)
     457           0 :                 log_error_errno(r, "Unmounting '%s' failed unexpectedly, couldn't wait for child process " PID_FMT ": %m", m->path, pid);
     458             : 
     459           0 :         return r;
     460             : }
     461             : 
     462             : /* This includes remounting readonly, which changes the kernel mount options.
     463             :  * Therefore the list passed to this function is invalidated, and should not be reused. */
     464           0 : static int mount_points_list_umount(MountPoint **head, bool *changed, int umount_log_level) {
     465             :         MountPoint *m;
     466           0 :         int n_failed = 0;
     467             : 
     468           0 :         assert(head);
     469           0 :         assert(changed);
     470             : 
     471           0 :         LIST_FOREACH(mount_point, m, *head) {
     472           0 :                 if (m->try_remount_ro) {
     473             :                         /* We always try to remount directories
     474             :                          * read-only first, before we go on and umount
     475             :                          * them.
     476             :                          *
     477             :                          * Mount points can be stacked. If a mount
     478             :                          * point is stacked below / or /usr, we
     479             :                          * cannot umount or remount it directly,
     480             :                          * since there is no way to refer to the
     481             :                          * underlying mount. There's nothing we can do
     482             :                          * about it for the general case, but we can
     483             :                          * do something about it if it is aliased
     484             :                          * somewhere else via a bind mount. If we
     485             :                          * explicitly remount the super block of that
     486             :                          * alias read-only we hence should be
     487             :                          * relatively safe regarding keeping a dirty fs
     488             :                          * we cannot otherwise see.
     489             :                          *
     490             :                          * Since the remount can hang in the instance of
     491             :                          * remote filesystems, we remount asynchronously
     492             :                          * and skip the subsequent umount if it fails. */
     493           0 :                         if (remount_with_timeout(m, umount_log_level) < 0) {
     494             :                                 /* Remount failed, but try unmounting anyway,
     495             :                                  * unless this is a mount point we want to skip. */
     496           0 :                                 if (nonunmountable_path(m->path)) {
     497           0 :                                         n_failed++;
     498           0 :                                         continue;
     499             :                                 }
     500             :                         }
     501             :                 }
     502             : 
     503             :                 /* Skip / and /usr since we cannot unmount that
     504             :                  * anyway, since we are running from it. They have
     505             :                  * already been remounted ro. */
     506           0 :                 if (nonunmountable_path(m->path))
     507           0 :                         continue;
     508             : 
     509             :                 /* Trying to umount */
     510           0 :                 if (umount_with_timeout(m, umount_log_level) < 0)
     511           0 :                         n_failed++;
     512             :                 else
     513           0 :                         *changed = true;
     514             :         }
     515             : 
     516           0 :         return n_failed;
     517             : }
     518             : 
     519           0 : static int swap_points_list_off(MountPoint **head, bool *changed) {
     520             :         MountPoint *m, *n;
     521           0 :         int n_failed = 0;
     522             : 
     523           0 :         assert(head);
     524           0 :         assert(changed);
     525             : 
     526           0 :         LIST_FOREACH_SAFE(mount_point, m, n, *head) {
     527           0 :                 log_info("Deactivating swap %s.", m->path);
     528           0 :                 if (swapoff(m->path) == 0) {
     529           0 :                         *changed = true;
     530           0 :                         mount_point_free(head, m);
     531             :                 } else {
     532           0 :                         log_warning_errno(errno, "Could not deactivate swap %s: %m", m->path);
     533           0 :                         n_failed++;
     534             :                 }
     535             :         }
     536             : 
     537           0 :         return n_failed;
     538             : }
     539             : 
     540           0 : static int loopback_points_list_detach(MountPoint **head, bool *changed, int umount_log_level) {
     541             :         MountPoint *m, *n;
     542           0 :         int n_failed = 0, k;
     543             :         struct stat root_st;
     544             : 
     545           0 :         assert(head);
     546           0 :         assert(changed);
     547             : 
     548           0 :         k = lstat("/", &root_st);
     549             : 
     550           0 :         LIST_FOREACH_SAFE(mount_point, m, n, *head) {
     551             :                 int r;
     552             :                 struct stat loopback_st;
     553             : 
     554           0 :                 if (k >= 0 &&
     555           0 :                     major(root_st.st_dev) != 0 &&
     556           0 :                     lstat(m->path, &loopback_st) >= 0 &&
     557           0 :                     root_st.st_dev == loopback_st.st_rdev) {
     558           0 :                         n_failed++;
     559           0 :                         continue;
     560             :                 }
     561             : 
     562           0 :                 log_info("Detaching loopback %s.", m->path);
     563           0 :                 r = delete_loopback(m->path);
     564           0 :                 if (r >= 0) {
     565           0 :                         if (r > 0)
     566           0 :                                 *changed = true;
     567             : 
     568           0 :                         mount_point_free(head, m);
     569             :                 } else {
     570           0 :                         log_full_errno(umount_log_level, errno, "Could not detach loopback %s: %m", m->path);
     571           0 :                         n_failed++;
     572             :                 }
     573             :         }
     574             : 
     575           0 :         return n_failed;
     576             : }
     577             : 
     578           0 : static int dm_points_list_detach(MountPoint **head, bool *changed, int umount_log_level) {
     579             :         MountPoint *m, *n;
     580           0 :         int n_failed = 0, r;
     581             :         dev_t rootdev;
     582             : 
     583           0 :         assert(head);
     584           0 :         assert(changed);
     585             : 
     586           0 :         r = get_block_device("/", &rootdev);
     587           0 :         if (r <= 0)
     588           0 :                 rootdev = 0;
     589             : 
     590           0 :         LIST_FOREACH_SAFE(mount_point, m, n, *head) {
     591             : 
     592           0 :                 if (major(rootdev) != 0 && rootdev == m->devnum) {
     593           0 :                         n_failed ++;
     594           0 :                         continue;
     595             :                 }
     596             : 
     597           0 :                 log_info("Detaching DM %u:%u.", major(m->devnum), minor(m->devnum));
     598           0 :                 r = delete_dm(m->devnum);
     599           0 :                 if (r >= 0) {
     600           0 :                         *changed = true;
     601           0 :                         mount_point_free(head, m);
     602             :                 } else {
     603           0 :                         log_full_errno(umount_log_level, errno, "Could not detach DM %s: %m", m->path);
     604           0 :                         n_failed++;
     605             :                 }
     606             :         }
     607             : 
     608           0 :         return n_failed;
     609             : }
     610             : 
     611           0 : static int umount_all_once(bool *changed, int umount_log_level) {
     612             :         int r;
     613           0 :         _cleanup_(mount_points_list_free) LIST_HEAD(MountPoint, mp_list_head);
     614             : 
     615           0 :         assert(changed);
     616             : 
     617           0 :         LIST_HEAD_INIT(mp_list_head);
     618           0 :         r = mount_points_list_get(NULL, &mp_list_head);
     619           0 :         if (r < 0)
     620           0 :                 return r;
     621             : 
     622           0 :         return mount_points_list_umount(&mp_list_head, changed, umount_log_level);
     623             : }
     624             : 
     625           0 : int umount_all(bool *changed, int umount_log_level) {
     626             :         bool umount_changed;
     627             :         int r;
     628             : 
     629           0 :         assert(changed);
     630             : 
     631             :         /* Retry umount, until nothing can be umounted anymore. Mounts are
     632             :          * processed in order, newest first. The retries are needed when
     633             :          * an old mount has been moved, to a path inside a newer mount. */
     634             :         do {
     635           0 :                 umount_changed = false;
     636             : 
     637           0 :                 r = umount_all_once(&umount_changed, umount_log_level);
     638           0 :                 if (umount_changed)
     639           0 :                         *changed = true;
     640           0 :         } while (umount_changed);
     641             : 
     642           0 :         return r;
     643             : }
     644             : 
     645           0 : int swapoff_all(bool *changed) {
     646           0 :         _cleanup_(mount_points_list_free) LIST_HEAD(MountPoint, swap_list_head);
     647             :         int r;
     648             : 
     649           0 :         assert(changed);
     650             : 
     651           0 :         LIST_HEAD_INIT(swap_list_head);
     652             : 
     653           0 :         r = swap_list_get(NULL, &swap_list_head);
     654           0 :         if (r < 0)
     655           0 :                 return r;
     656             : 
     657           0 :         return swap_points_list_off(&swap_list_head, changed);
     658             : }
     659             : 
     660           0 : int loopback_detach_all(bool *changed, int umount_log_level) {
     661           0 :         _cleanup_(mount_points_list_free) LIST_HEAD(MountPoint, loopback_list_head);
     662             :         int r;
     663             : 
     664           0 :         assert(changed);
     665             : 
     666           0 :         LIST_HEAD_INIT(loopback_list_head);
     667             : 
     668           0 :         r = loopback_list_get(&loopback_list_head);
     669           0 :         if (r < 0)
     670           0 :                 return r;
     671             : 
     672           0 :         return loopback_points_list_detach(&loopback_list_head, changed, umount_log_level);
     673             : }
     674             : 
     675           0 : int dm_detach_all(bool *changed, int umount_log_level) {
     676           0 :         _cleanup_(mount_points_list_free) LIST_HEAD(MountPoint, dm_list_head);
     677             :         int r;
     678             : 
     679           0 :         assert(changed);
     680             : 
     681           0 :         LIST_HEAD_INIT(dm_list_head);
     682             : 
     683           0 :         r = dm_list_get(&dm_list_head);
     684           0 :         if (r < 0)
     685           0 :                 return r;
     686             : 
     687           0 :         return dm_points_list_detach(&dm_list_head, changed, umount_log_level);
     688             : }

Generated by: LCOV version 1.14