LCOV - code coverage report
Current view: top level - shutdown - umount.c (source / functions) Hit Total Coverage
Test: systemd_full.info Lines: 80 335 23.9 %
Date: 2019-08-23 13:36:53 Functions: 4 20 20.0 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 63 328 19.2 %

           Branch data     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                 :        132 : static void mount_point_free(MountPoint **head, MountPoint *m) {
      40         [ -  + ]:        132 :         assert(head);
      41         [ -  + ]:        132 :         assert(m);
      42                 :            : 
      43   [ -  +  +  +  :        132 :         LIST_REMOVE(mount_point, *head, m);
             -  +  -  + ]
      44                 :            : 
      45                 :        132 :         free(m->path);
      46                 :        132 :         free(m->remount_options);
      47                 :        132 :         free(m);
      48                 :        132 : }
      49                 :            : 
      50                 :         24 : void mount_points_list_free(MountPoint **head) {
      51         [ -  + ]:         24 :         assert(head);
      52                 :            : 
      53         [ +  + ]:        156 :         while (*head)
      54                 :        132 :                 mount_point_free(head, *head);
      55                 :         24 : }
      56                 :            : 
      57                 :         16 : int mount_points_list_get(const char *mountinfo, MountPoint **head) {
      58                 :         16 :         _cleanup_(mnt_free_tablep) struct libmnt_table *table = NULL;
      59                 :         16 :         _cleanup_(mnt_free_iterp) struct libmnt_iter *iter = NULL;
      60                 :            :         int r;
      61                 :            : 
      62         [ -  + ]:         16 :         assert(head);
      63                 :            : 
      64                 :         16 :         r = libmount_parse(mountinfo, NULL, &table, &iter);
      65         [ -  + ]:         16 :         if (r < 0)
      66         [ #  # ]:          0 :                 return log_error_errno(r, "Failed to parse %s: %m", mountinfo);
      67                 :            : 
      68                 :        352 :         for (;;) {
      69                 :            :                 struct libmnt_fs *fs;
      70                 :            :                 const char *path, *fstype;
      71   [ +  +  -  + ]:        368 :                 _cleanup_free_ char *options = NULL;
      72                 :        368 :                 unsigned long remount_flags = 0u;
      73   [ +  +  -  + ]:        368 :                 _cleanup_free_ char *remount_options = NULL;
      74                 :            :                 bool try_remount_ro;
      75   [ +  +  -  + ]:        368 :                 _cleanup_free_ MountPoint *m = NULL;
      76                 :            : 
      77                 :        368 :                 r = mnt_table_next_fs(table, iter, &fs);
      78         [ +  + ]:        368 :                 if (r == 1)
      79                 :         16 :                         break;
      80         [ -  + ]:        352 :                 if (r < 0)
      81         [ #  # ]:          0 :                         return log_error_errno(r, "Failed to get next entry from %s: %m", mountinfo);
      82                 :            : 
      83                 :        352 :                 path = mnt_fs_get_target(fs);
      84         [ -  + ]:        352 :                 if (!path)
      85                 :          0 :                         continue;
      86                 :            : 
      87                 :        352 :                 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         [ -  + ]:        352 :                 if (!strextend_with_separator(&options, ",",
      98                 :            :                                               mnt_fs_get_vfs_options(fs),
      99                 :            :                                               NULL))
     100                 :          0 :                         return log_oom();
     101         [ -  + ]:        352 :                 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   [ +  +  +  + ]:        528 :                 if (mount_point_is_api(path) ||
     114         [ +  + ]:        348 :                     mount_point_ignore(path) ||
     115                 :        172 :                     PATH_STARTSWITH_SET(path, "/dev", "/sys", "/proc"))
     116                 :        232 :                         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                 :        120 :                 try_remount_ro = detect_container() <= 0 &&
     129         [ +  - ]:        120 :                                  !fstype_is_network(fstype) &&
     130         [ +  + ]:        120 :                                  !fstype_is_api_vfs(fstype) &&
     131   [ +  -  +  - ]:        304 :                                  !fstype_is_ro(fstype) &&
     132         [ +  - ]:         64 :                                  !fstab_test_yes_no_option(options, "ro\0rw\0");
     133                 :            : 
     134         [ +  + ]:        120 :                 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                 :         64 :                         r = mnt_fs_get_propagation(fs, &remount_flags);
     141         [ -  + ]:         64 :                         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                 :         64 :                         r = mount_option_mangle(options, remount_flags, &remount_flags, &remount_options);
     147         [ -  + ]:         64 :                         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                 :         64 :                         remount_flags = (remount_flags|MS_REMOUNT|MS_RDONLY) & ~MS_BIND;
     155                 :            :                 }
     156                 :            : 
     157                 :        120 :                 m = new0(MountPoint, 1);
     158         [ -  + ]:        120 :                 if (!m)
     159                 :          0 :                         return log_oom();
     160                 :            : 
     161                 :        120 :                 m->path = strdup(path);
     162         [ -  + ]:        120 :                 if (!m->path)
     163                 :          0 :                         return log_oom();
     164                 :            : 
     165                 :        120 :                 m->remount_options = TAKE_PTR(remount_options);
     166                 :        120 :                 m->remount_flags = remount_flags;
     167                 :        120 :                 m->try_remount_ro = try_remount_ro;
     168                 :            : 
     169   [ -  +  +  + ]:        120 :                 LIST_PREPEND(mount_point, *head, TAKE_PTR(m));
     170                 :            :         }
     171                 :            : 
     172                 :         16 :         return 0;
     173                 :            : }
     174                 :            : 
     175                 :          8 : int swap_list_get(const char *swaps, MountPoint **head) {
     176                 :          8 :         _cleanup_(mnt_free_tablep) struct libmnt_table *t = NULL;
     177                 :          8 :         _cleanup_(mnt_free_iterp) struct libmnt_iter *i = NULL;
     178                 :            :         int r;
     179                 :            : 
     180         [ -  + ]:          8 :         assert(head);
     181                 :            : 
     182                 :          8 :         t = mnt_new_table();
     183                 :          8 :         i = mnt_new_iter(MNT_ITER_FORWARD);
     184   [ +  -  -  + ]:          8 :         if (!t || !i)
     185                 :          0 :                 return log_oom();
     186                 :            : 
     187                 :          8 :         r = mnt_table_parse_swaps(t, swaps);
     188         [ -  + ]:          8 :         if (r < 0)
     189         [ #  # ]:          0 :                 return log_error_errno(r, "Failed to parse %s: %m", swaps);
     190                 :            : 
     191                 :         12 :         for (;;) {
     192                 :            :                 struct libmnt_fs *fs;
     193   [ +  +  -  - ]:         20 :                 _cleanup_free_ MountPoint *swap = NULL;
     194                 :            :                 const char *source;
     195                 :            : 
     196                 :         20 :                 r = mnt_table_next_fs(t, i, &fs);
     197         [ +  + ]:         20 :                 if (r == 1)
     198                 :          8 :                         break;
     199         [ -  + ]:         12 :                 if (r < 0)
     200         [ #  # ]:          0 :                         return log_error_errno(r, "Failed to get next entry from %s: %m", swaps);
     201                 :            : 
     202                 :         12 :                 source = mnt_fs_get_source(fs);
     203         [ -  + ]:         12 :                 if (!source)
     204                 :          0 :                         continue;
     205                 :            : 
     206                 :         12 :                 swap = new0(MountPoint, 1);
     207         [ -  + ]:         12 :                 if (!swap)
     208                 :          0 :                         return -ENOMEM;
     209                 :            : 
     210                 :         12 :                 swap->path = strdup(source);
     211         [ -  + ]:         12 :                 if (!swap->path)
     212                 :          0 :                         return -ENOMEM;
     213                 :            : 
     214   [ -  +  +  + ]:         12 :                 LIST_PREPEND(mount_point, *head, TAKE_PTR(swap));
     215                 :            :         }
     216                 :            : 
     217                 :          8 :         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