2020-11-09 05:23:58 +01:00
/* SPDX-License-Identifier: LGPL-2.1-or-later */
2010-10-07 14:43:57 +02:00
/***
2018-06-12 19:00:24 +02:00
Copyright © 2010 ProFUSION embedded systems
2010-10-07 14:43:57 +02:00
* * */
# include <errno.h>
# include <fcntl.h>
2019-04-10 12:55:53 +02:00
# include <linux/dm-ioctl.h>
2020-09-20 18:59:58 +02:00
# include <linux/major.h>
# include <linux/raid/md_u.h>
2015-10-23 18:52:53 +02:00
# include <linux/loop.h>
2010-10-07 14:43:57 +02:00
# include <sys/mount.h>
# include <sys/swap.h>
2019-03-27 11:32:41 +01:00
# include <sys/stat.h>
# include <sys/types.h>
# include <unistd.h>
2010-10-07 14:43:57 +02:00
2018-08-22 07:39:12 +02:00
# include "sd-device.h"
2015-11-17 06:52:45 +01:00
2015-10-27 03:01:06 +01:00
# include "alloc-util.h"
2017-12-22 15:22:59 +01:00
# include "blockdev-util.h"
2017-12-13 18:49:26 +01:00
# include "def.h"
2018-08-28 09:05:35 +02:00
# include "device-util.h"
2015-10-24 22:58:24 +02:00
# include "escape.h"
2015-10-25 13:14:12 +01:00
# include "fd-util.h"
2020-09-22 11:23:35 +02:00
# include "fs-util.h"
2015-10-26 15:13:28 +01:00
# include "fstab-util.h"
2019-04-04 12:54:19 +02:00
# include "libmount-util.h"
2010-10-07 14:43:57 +02:00
# include "mount-setup.h"
2017-12-22 15:22:59 +01:00
# include "mount-util.h"
2018-11-29 10:24:39 +01:00
# include "mountpoint-util.h"
2012-05-07 21:36:12 +02:00
# include "path-util.h"
2018-01-11 00:39:12 +01:00
# include "process-util.h"
2017-12-13 18:49:26 +01:00
# include "signal-util.h"
2015-10-24 22:58:24 +02:00
# include "string-util.h"
2018-11-23 16:51:53 +01:00
# include "strv.h"
2015-10-25 13:14:12 +01:00
# include "umount.h"
2010-10-07 14:43:57 +02:00
# include "util.h"
2012-08-24 22:50:16 +02:00
# include "virt.h"
2010-10-07 14:43:57 +02:00
2010-10-14 18:55:04 +02:00
static void mount_point_free ( MountPoint * * head , MountPoint * m ) {
assert ( head ) ;
assert ( m ) ;
2010-10-07 14:43:57 +02:00
2013-10-14 06:10:14 +02:00
LIST_REMOVE ( mount_point , * head , m ) ;
2010-10-14 18:55:04 +02:00
free ( m - > path ) ;
2018-03-08 18:37:21 +01:00
free ( m - > remount_options ) ;
2010-10-14 18:55:04 +02:00
free ( m ) ;
2010-10-07 14:43:57 +02:00
}
2018-03-14 11:03:36 +01:00
void mount_points_list_free ( MountPoint * * head ) {
2010-10-14 18:55:04 +02:00
assert ( head ) ;
while ( * head )
mount_point_free ( head , * head ) ;
2010-10-07 14:43:57 +02:00
}
2018-03-14 11:03:36 +01:00
int mount_points_list_get ( const char * mountinfo , MountPoint * * head ) {
2019-04-04 13:36:19 +02:00
_cleanup_ ( mnt_free_tablep ) struct libmnt_table * table = NULL ;
_cleanup_ ( mnt_free_iterp ) struct libmnt_iter * iter = NULL ;
2015-04-06 20:11:41 +02:00
int r ;
2010-10-07 14:43:57 +02:00
2010-10-14 18:55:04 +02:00
assert ( head ) ;
2019-04-05 14:43:06 +02:00
r = libmount_parse ( mountinfo , NULL , & table , & iter ) ;
2018-03-14 11:32:30 +01:00
if ( r < 0 )
2019-11-15 14:56:35 +01:00
return log_error_errno ( r , " Failed to parse %s: %m " , mountinfo ? : " /proc/self/mountinfo " ) ;
2018-03-14 11:32:30 +01:00
for ( ; ; ) {
struct libmnt_fs * fs ;
umount: Don't use options from fstab on remount
The fstab entry may contain comment/application-specific options, like
for example x-systemd.automount or x-initrd.mount.
With the recent switch to libmount, the mount options during remount are
now gathered via mnt_fs_get_options(), which returns the merged fstab
options with the effective options in mountinfo.
Unfortunately if one of these application-specific options are set in
fstab, the remount will fail with -EINVAL.
In systemd 238:
Remounting '/test-x-initrd-mount' read-only in with options
'errors=continue,user_xattr,acl'.
In systemd 239:
Remounting '/test-x-initrd-mount' read-only in with options
'errors=continue,user_xattr,acl,x-initrd.mount'.
Failed to remount '/test-x-initrd-mount' read-only: Invalid argument
So instead of using mnt_fs_get_options(), we're now using both
mnt_fs_get_fs_options() and mnt_fs_get_vfs_options() and merging the
results together so we don't get any non-relevant options from fstab.
Signed-off-by: aszlig <aszlig@nix.build>
2018-08-20 05:33:58 +02:00
const char * path , * fstype ;
_cleanup_free_ char * options = NULL ;
2018-03-14 11:32:30 +01:00
unsigned long remount_flags = 0u ;
_cleanup_free_ char * remount_options = NULL ;
bool try_remount_ro ;
2019-04-05 10:17:03 +02:00
_cleanup_free_ MountPoint * m = NULL ;
2010-10-07 14:43:57 +02:00
2019-04-04 13:36:19 +02:00
r = mnt_table_next_fs ( table , iter , & fs ) ;
2018-03-14 11:32:30 +01:00
if ( r = = 1 )
break ;
2015-04-06 20:11:41 +02:00
if ( r < 0 )
2019-11-15 14:56:35 +01:00
return log_error_errno ( r , " Failed to get next entry from %s: %m " , mountinfo ? : " /proc/self/mountinfo " ) ;
2018-03-14 11:32:30 +01:00
path = mnt_fs_get_target ( fs ) ;
if ( ! path )
continue ;
fstype = mnt_fs_get_fstype ( fs ) ;
2010-10-07 14:43:57 +02:00
umount: Don't use options from fstab on remount
The fstab entry may contain comment/application-specific options, like
for example x-systemd.automount or x-initrd.mount.
With the recent switch to libmount, the mount options during remount are
now gathered via mnt_fs_get_options(), which returns the merged fstab
options with the effective options in mountinfo.
Unfortunately if one of these application-specific options are set in
fstab, the remount will fail with -EINVAL.
In systemd 238:
Remounting '/test-x-initrd-mount' read-only in with options
'errors=continue,user_xattr,acl'.
In systemd 239:
Remounting '/test-x-initrd-mount' read-only in with options
'errors=continue,user_xattr,acl,x-initrd.mount'.
Failed to remount '/test-x-initrd-mount' read-only: Invalid argument
So instead of using mnt_fs_get_options(), we're now using both
mnt_fs_get_fs_options() and mnt_fs_get_vfs_options() and merging the
results together so we don't get any non-relevant options from fstab.
Signed-off-by: aszlig <aszlig@nix.build>
2018-08-20 05:33:58 +02:00
/* Combine the generic VFS options with the FS-specific
* options . Duplicates are not a problem here , because the only
* options that should come up twice are typically ro / rw , which
2019-04-05 10:17:03 +02:00
* are turned into MS_RDONLY or the inversion of it .
umount: Don't use options from fstab on remount
The fstab entry may contain comment/application-specific options, like
for example x-systemd.automount or x-initrd.mount.
With the recent switch to libmount, the mount options during remount are
now gathered via mnt_fs_get_options(), which returns the merged fstab
options with the effective options in mountinfo.
Unfortunately if one of these application-specific options are set in
fstab, the remount will fail with -EINVAL.
In systemd 238:
Remounting '/test-x-initrd-mount' read-only in with options
'errors=continue,user_xattr,acl'.
In systemd 239:
Remounting '/test-x-initrd-mount' read-only in with options
'errors=continue,user_xattr,acl,x-initrd.mount'.
Failed to remount '/test-x-initrd-mount' read-only: Invalid argument
So instead of using mnt_fs_get_options(), we're now using both
mnt_fs_get_fs_options() and mnt_fs_get_vfs_options() and merging the
results together so we don't get any non-relevant options from fstab.
Signed-off-by: aszlig <aszlig@nix.build>
2018-08-20 05:33:58 +02:00
*
* Even if there are duplicates later in mount_option_mangle ( )
2019-04-05 10:17:03 +02:00
* they shouldn ' t hurt anyways as they override each other .
umount: Don't use options from fstab on remount
The fstab entry may contain comment/application-specific options, like
for example x-systemd.automount or x-initrd.mount.
With the recent switch to libmount, the mount options during remount are
now gathered via mnt_fs_get_options(), which returns the merged fstab
options with the effective options in mountinfo.
Unfortunately if one of these application-specific options are set in
fstab, the remount will fail with -EINVAL.
In systemd 238:
Remounting '/test-x-initrd-mount' read-only in with options
'errors=continue,user_xattr,acl'.
In systemd 239:
Remounting '/test-x-initrd-mount' read-only in with options
'errors=continue,user_xattr,acl,x-initrd.mount'.
Failed to remount '/test-x-initrd-mount' read-only: Invalid argument
So instead of using mnt_fs_get_options(), we're now using both
mnt_fs_get_fs_options() and mnt_fs_get_vfs_options() and merging the
results together so we don't get any non-relevant options from fstab.
Signed-off-by: aszlig <aszlig@nix.build>
2018-08-20 05:33:58 +02:00
*/
2021-01-05 15:03:41 +01:00
if ( ! strextend_with_separator ( & options , " , " , mnt_fs_get_vfs_options ( fs ) ) )
umount: Don't use options from fstab on remount
The fstab entry may contain comment/application-specific options, like
for example x-systemd.automount or x-initrd.mount.
With the recent switch to libmount, the mount options during remount are
now gathered via mnt_fs_get_options(), which returns the merged fstab
options with the effective options in mountinfo.
Unfortunately if one of these application-specific options are set in
fstab, the remount will fail with -EINVAL.
In systemd 238:
Remounting '/test-x-initrd-mount' read-only in with options
'errors=continue,user_xattr,acl'.
In systemd 239:
Remounting '/test-x-initrd-mount' read-only in with options
'errors=continue,user_xattr,acl,x-initrd.mount'.
Failed to remount '/test-x-initrd-mount' read-only: Invalid argument
So instead of using mnt_fs_get_options(), we're now using both
mnt_fs_get_fs_options() and mnt_fs_get_vfs_options() and merging the
results together so we don't get any non-relevant options from fstab.
Signed-off-by: aszlig <aszlig@nix.build>
2018-08-20 05:33:58 +02:00
return log_oom ( ) ;
2021-01-05 15:03:41 +01:00
if ( ! strextend_with_separator ( & options , " , " , mnt_fs_get_fs_options ( fs ) ) )
umount: Don't use options from fstab on remount
The fstab entry may contain comment/application-specific options, like
for example x-systemd.automount or x-initrd.mount.
With the recent switch to libmount, the mount options during remount are
now gathered via mnt_fs_get_options(), which returns the merged fstab
options with the effective options in mountinfo.
Unfortunately if one of these application-specific options are set in
fstab, the remount will fail with -EINVAL.
In systemd 238:
Remounting '/test-x-initrd-mount' read-only in with options
'errors=continue,user_xattr,acl'.
In systemd 239:
Remounting '/test-x-initrd-mount' read-only in with options
'errors=continue,user_xattr,acl,x-initrd.mount'.
Failed to remount '/test-x-initrd-mount' read-only: Invalid argument
So instead of using mnt_fs_get_options(), we're now using both
mnt_fs_get_fs_options() and mnt_fs_get_vfs_options() and merging the
results together so we don't get any non-relevant options from fstab.
Signed-off-by: aszlig <aszlig@nix.build>
2018-08-20 05:33:58 +02:00
return log_oom ( ) ;
2012-04-12 13:34:09 +02:00
/* Ignore mount points we can't unmount because they
* are API or because we are keeping them open ( like
2015-01-23 13:44:44 +01:00
* / dev / console ) . Also , ignore all mounts below API
* file systems , since they are likely virtual too ,
* and hence not worth spending time on . Also , in
* unprivileged containers we might lack the rights to
* unmount these things , hence don ' t bother . */
2019-04-05 10:17:03 +02:00
if ( mount_point_is_api ( path ) | |
mount_point_ignore ( path ) | |
PATH_STARTSWITH_SET ( path , " /dev " , " /sys " , " /proc " ) )
2010-10-14 00:41:57 +02:00
continue ;
2018-03-08 17:40:44 +01:00
/* If we are in a container, don't attempt to
* read - only mount anything as that brings no real
* benefits , but might confuse the host , as we remount
* the superblock here , not the bind mount .
*
* If the filesystem is a network fs , also skip the
* remount . It brings no value ( we cannot leave
* a " dirty fs " ) and could hang if the network is down .
* Note that umount2 ( ) is more careful and will not
* hang because of the network being down . */
2018-03-14 11:32:30 +01:00
try_remount_ro = detect_container ( ) < = 0 & &
! fstype_is_network ( fstype ) & &
! fstype_is_api_vfs ( fstype ) & &
! fstype_is_ro ( fstype ) & &
! fstab_test_yes_no_option ( options , " ro \0 rw \0 " ) ;
2018-03-08 18:37:21 +01:00
2018-03-14 11:32:30 +01:00
if ( try_remount_ro ) {
2018-03-08 18:37:21 +01:00
/* mount(2) states that mount flags and options need to be exactly the same
* as they were when the filesystem was mounted , except for the desired
* changes . So we reconstruct both here and adjust them for the later
* remount call too . */
2018-03-14 11:32:30 +01:00
r = mnt_fs_get_propagation ( fs , & remount_flags ) ;
if ( r < 0 ) {
log_warning_errno ( r , " mnt_fs_get_propagation() failed for %s, ignoring: %m " , path ) ;
continue ;
}
2018-03-08 18:37:21 +01:00
2018-03-14 11:32:30 +01:00
r = mount_option_mangle ( options , remount_flags , & remount_flags , & remount_options ) ;
if ( r < 0 ) {
log_warning_errno ( r , " mount_option_mangle failed for %s, ignoring: %m " , path ) ;
continue ;
}
2018-03-08 18:37:21 +01:00
/* MS_BIND is special. If it is provided it will only make the mount-point
* read - only . If left out , the super block itself is remounted , which we want . */
2018-03-14 11:32:30 +01:00
remount_flags = ( remount_flags | MS_REMOUNT | MS_RDONLY ) & ~ MS_BIND ;
2018-03-08 18:37:21 +01:00
}
2015-10-26 15:13:28 +01:00
2018-03-14 11:32:30 +01:00
m = new0 ( MountPoint , 1 ) ;
if ( ! m )
return log_oom ( ) ;
2019-04-05 10:17:03 +02:00
m - > path = strdup ( path ) ;
if ( ! m - > path )
return log_oom ( ) ;
m - > remount_options = TAKE_PTR ( remount_options ) ;
2018-03-14 11:32:30 +01:00
m - > remount_flags = remount_flags ;
m - > try_remount_ro = try_remount_ro ;
2019-04-05 10:17:03 +02:00
LIST_PREPEND ( mount_point , * head , TAKE_PTR ( m ) ) ;
2010-10-07 14:43:57 +02:00
}
2014-06-05 21:35:15 +02:00
return 0 ;
2010-10-07 14:43:57 +02:00
}
2018-03-14 12:06:34 +01:00
int swap_list_get ( const char * swaps , MountPoint * * head ) {
2018-03-14 12:22:27 +01:00
_cleanup_ ( mnt_free_tablep ) struct libmnt_table * t = NULL ;
_cleanup_ ( mnt_free_iterp ) struct libmnt_iter * i = NULL ;
2015-04-06 20:11:41 +02:00
int r ;
2010-10-07 14:43:57 +02:00
2010-10-14 18:55:04 +02:00
assert ( head ) ;
2018-03-14 12:22:27 +01:00
t = mnt_new_table ( ) ;
i = mnt_new_iter ( MNT_ITER_FORWARD ) ;
if ( ! t | | ! i )
return log_oom ( ) ;
2010-10-07 14:43:57 +02:00
2018-03-14 12:22:27 +01:00
r = mnt_table_parse_swaps ( t , swaps ) ;
2019-11-15 14:57:27 +01:00
if ( r = = - ENOENT ) /* no /proc/swaps is fine */
return 0 ;
2018-03-14 12:22:27 +01:00
if ( r < 0 )
2019-11-15 14:56:35 +01:00
return log_error_errno ( r , " Failed to parse %s: %m " , swaps ? : " /proc/swaps " ) ;
2018-03-14 12:22:27 +01:00
for ( ; ; ) {
struct libmnt_fs * fs ;
2019-04-05 10:17:03 +02:00
_cleanup_free_ MountPoint * swap = NULL ;
2018-03-14 12:22:27 +01:00
const char * source ;
r = mnt_table_next_fs ( t , i , & fs ) ;
if ( r = = 1 )
break ;
if ( r < 0 )
2019-11-15 14:56:35 +01:00
return log_error_errno ( r , " Failed to get next entry from %s: %m " , swaps ? : " /proc/swaps " ) ;
2010-10-07 14:43:57 +02:00
2018-03-14 12:22:27 +01:00
source = mnt_fs_get_source ( fs ) ;
if ( ! source )
2010-10-07 14:43:57 +02:00
continue ;
2015-04-06 20:11:41 +02:00
swap = new0 ( MountPoint , 1 ) ;
2017-11-27 17:13:04 +01:00
if ( ! swap )
2019-11-15 14:58:06 +01:00
return log_oom ( ) ;
2010-10-07 14:43:57 +02:00
2019-04-05 10:17:03 +02:00
swap - > path = strdup ( source ) ;
if ( ! swap - > path )
2019-11-15 14:58:06 +01:00
return log_oom ( ) ;
2019-04-05 10:17:03 +02:00
LIST_PREPEND ( mount_point , * head , TAKE_PTR ( swap ) ) ;
2010-10-07 14:43:57 +02:00
}
2014-06-24 19:00:32 +02:00
return 0 ;
2010-10-07 14:43:57 +02:00
}
2010-10-14 18:55:04 +02:00
static int loopback_list_get ( MountPoint * * head ) {
2018-08-22 07:39:12 +02:00
_cleanup_ ( sd_device_enumerator_unrefp ) sd_device_enumerator * e = NULL ;
sd_device * d ;
2013-12-18 17:13:42 +01:00
int r ;
2010-10-07 14:43:57 +02:00
2010-10-14 18:55:04 +02:00
assert ( head ) ;
2018-08-22 07:39:12 +02:00
r = sd_device_enumerator_new ( & e ) ;
if ( r < 0 )
return r ;
2010-10-07 14:43:57 +02:00
2018-08-22 07:39:12 +02:00
r = sd_device_enumerator_allow_uninitialized ( e ) ;
if ( r < 0 )
return r ;
2010-10-07 14:43:57 +02:00
2018-08-22 07:39:12 +02:00
r = sd_device_enumerator_add_match_subsystem ( e , " block " , true ) ;
2013-12-18 17:13:42 +01:00
if ( r < 0 )
return r ;
2018-08-22 07:39:12 +02:00
r = sd_device_enumerator_add_match_sysname ( e , " loop* " ) ;
2013-12-18 17:13:42 +01:00
if ( r < 0 )
return r ;
2018-08-22 07:39:12 +02:00
r = sd_device_enumerator_add_match_sysattr ( e , " loop/backing_file " , NULL , true ) ;
2013-12-18 17:13:42 +01:00
if ( r < 0 )
return r ;
2010-10-07 14:43:57 +02:00
2018-08-28 09:05:35 +02:00
FOREACH_DEVICE ( e , d ) {
2018-09-01 16:04:42 +02:00
_cleanup_free_ char * p = NULL ;
2018-08-22 07:39:12 +02:00
const char * dn ;
2018-09-01 16:04:42 +02:00
MountPoint * lb ;
2019-12-20 17:02:05 +01:00
dev_t devnum ;
2010-10-07 14:43:57 +02:00
2019-12-20 17:02:05 +01:00
if ( sd_device_get_devnum ( d , & devnum ) < 0 | |
sd_device_get_devname ( d , & dn ) < 0 )
2010-10-14 18:17:23 +02:00
continue ;
2010-10-14 00:42:44 +02:00
2018-09-01 16:04:42 +02:00
p = strdup ( dn ) ;
if ( ! p )
return - ENOMEM ;
lb = new ( MountPoint , 1 ) ;
2018-03-14 11:32:13 +01:00
if ( ! lb )
2013-10-13 02:28:21 +02:00
return - ENOMEM ;
2010-10-07 14:43:57 +02:00
2018-09-01 16:04:42 +02:00
* lb = ( MountPoint ) {
. path = TAKE_PTR ( p ) ,
2019-12-20 17:02:05 +01:00
. devnum = devnum ,
2018-09-01 16:04:42 +02:00
} ;
2018-03-14 11:32:13 +01:00
2013-10-14 06:10:14 +02:00
LIST_PREPEND ( mount_point , * head , lb ) ;
2010-10-07 14:43:57 +02:00
}
2013-10-13 02:28:21 +02:00
return 0 ;
2010-10-07 14:43:57 +02:00
}
2010-10-14 18:55:04 +02:00
static int dm_list_get ( MountPoint * * head ) {
2018-08-22 07:39:12 +02:00
_cleanup_ ( sd_device_enumerator_unrefp ) sd_device_enumerator * e = NULL ;
sd_device * d ;
2013-12-18 17:13:42 +01:00
int r ;
2010-10-14 02:33:09 +02:00
2010-10-14 18:55:04 +02:00
assert ( head ) ;
2018-08-22 07:39:12 +02:00
r = sd_device_enumerator_new ( & e ) ;
if ( r < 0 )
return r ;
2010-10-14 02:33:09 +02:00
2018-08-22 07:39:12 +02:00
r = sd_device_enumerator_allow_uninitialized ( e ) ;
if ( r < 0 )
return r ;
2010-10-14 02:33:09 +02:00
2018-08-22 07:39:12 +02:00
r = sd_device_enumerator_add_match_subsystem ( e , " block " , true ) ;
2013-12-18 17:13:42 +01:00
if ( r < 0 )
return r ;
2010-10-14 02:33:09 +02:00
2018-08-22 07:39:12 +02:00
r = sd_device_enumerator_add_match_sysname ( e , " dm-* " ) ;
2013-12-18 17:13:42 +01:00
if ( r < 0 )
return r ;
2010-10-14 02:33:09 +02:00
2018-08-28 09:05:35 +02:00
FOREACH_DEVICE ( e , d ) {
2018-09-01 16:04:42 +02:00
_cleanup_free_ char * p = NULL ;
2018-08-22 07:39:12 +02:00
const char * dn ;
2018-09-01 16:04:42 +02:00
MountPoint * m ;
2018-08-22 07:39:12 +02:00
dev_t devnum ;
2010-10-14 02:33:09 +02:00
2018-09-01 16:04:42 +02:00
if ( sd_device_get_devnum ( d , & devnum ) < 0 | |
sd_device_get_devname ( d , & dn ) < 0 )
2018-08-22 07:39:12 +02:00
continue ;
2010-10-14 02:33:09 +02:00
2018-09-01 16:04:42 +02:00
p = strdup ( dn ) ;
if ( ! p )
return - ENOMEM ;
2010-10-14 02:33:09 +02:00
2018-09-01 16:04:42 +02:00
m = new ( MountPoint , 1 ) ;
2018-03-14 11:32:13 +01:00
if ( ! m )
2013-10-13 02:28:21 +02:00
return - ENOMEM ;
2010-10-14 02:33:09 +02:00
2018-09-01 16:04:42 +02:00
* m = ( MountPoint ) {
. path = TAKE_PTR ( p ) ,
. devnum = devnum ,
} ;
2018-03-14 11:32:13 +01:00
2013-10-14 06:10:14 +02:00
LIST_PREPEND ( mount_point , * head , m ) ;
2010-10-14 02:33:09 +02:00
}
2013-10-13 02:28:21 +02:00
return 0 ;
2010-10-14 02:33:09 +02:00
}
2020-09-20 18:59:58 +02:00
static int md_list_get ( MountPoint * * head ) {
_cleanup_ ( sd_device_enumerator_unrefp ) sd_device_enumerator * e = NULL ;
sd_device * d ;
int r ;
assert ( head ) ;
r = sd_device_enumerator_new ( & e ) ;
if ( r < 0 )
return r ;
r = sd_device_enumerator_allow_uninitialized ( e ) ;
if ( r < 0 )
return r ;
r = sd_device_enumerator_add_match_subsystem ( e , " block " , true ) ;
if ( r < 0 )
return r ;
r = sd_device_enumerator_add_match_sysname ( e , " md* " ) ;
if ( r < 0 )
return r ;
FOREACH_DEVICE ( e , d ) {
_cleanup_free_ char * p = NULL ;
const char * dn ;
MountPoint * m ;
dev_t devnum ;
if ( sd_device_get_devnum ( d , & devnum ) < 0 | |
sd_device_get_devname ( d , & dn ) < 0 )
continue ;
p = strdup ( dn ) ;
if ( ! p )
return - ENOMEM ;
m = new ( MountPoint , 1 ) ;
if ( ! m )
return - ENOMEM ;
* m = ( MountPoint ) {
. path = TAKE_PTR ( p ) ,
. devnum = devnum ,
} ;
LIST_PREPEND ( mount_point , * head , m ) ;
}
return 0 ;
}
2010-10-07 14:43:57 +02:00
static int delete_loopback ( const char * device ) {
2014-03-18 19:22:43 +01:00
_cleanup_close_ int fd = - 1 ;
2019-12-20 17:58:03 +01:00
struct loop_info64 info ;
2010-10-07 14:43:57 +02:00
2018-03-08 17:22:58 +01:00
assert ( device ) ;
2014-03-18 19:22:43 +01:00
fd = open ( device , O_RDONLY | O_CLOEXEC ) ;
2020-09-22 11:19:37 +02:00
if ( fd < 0 ) {
log_debug_errno ( errno , " Failed to open loopback device %s: %m " , device ) ;
2011-03-14 05:37:47 +01:00
return errno = = ENOENT ? 0 : - errno ;
2020-09-22 11:19:37 +02:00
}
/* Loopback block devices don't sync in-flight blocks when we clear the fd, hence sync explicitly
* first */
if ( fsync ( fd ) < 0 )
log_debug_errno ( errno , " Failed to sync loop block device %s, ignoring: %m " , device ) ;
2010-10-07 14:43:57 +02:00
2019-12-20 17:58:03 +01:00
if ( ioctl ( fd , LOOP_CLR_FD , 0 ) < 0 ) {
if ( errno = = ENXIO ) /* Nothing bound, didn't do anything */
return 0 ;
2019-12-20 18:37:24 +01:00
if ( errno ! = EBUSY )
return log_debug_errno ( errno , " Failed to clear loopback device %s: %m " , device ) ;
if ( ioctl ( fd , LOOP_GET_STATUS64 , & info ) < 0 ) {
if ( errno = = ENXIO ) /* What? Suddenly detached after all? That's fine by us then. */
return 1 ;
log_debug_errno ( errno , " Failed to invoke LOOP_GET_STATUS64 on loopback device %s, ignoring: %m " , device ) ;
return - EBUSY ; /* propagate original error */
}
if ( FLAGS_SET ( info . lo_flags , LO_FLAGS_AUTOCLEAR ) ) /* someone else already set LO_FLAGS_AUTOCLEAR for us? fine by us */
return - EBUSY ; /* propagate original error */
info . lo_flags | = LO_FLAGS_AUTOCLEAR ;
if ( ioctl ( fd , LOOP_SET_STATUS64 , & info ) < 0 ) {
if ( errno = = ENXIO ) /* Suddenly detached after all? Fine by us */
return 1 ;
log_debug_errno ( errno , " Failed to set LO_FLAGS_AUTOCLEAR flag for loop device %s, ignoring: %m " , device ) ;
} else
log_debug ( " Successfully set LO_FLAGS_AUTOCLEAR flag for loop device %s. " , device ) ;
return - EBUSY ;
2019-12-20 17:58:03 +01:00
}
if ( ioctl ( fd , LOOP_GET_STATUS64 , & info ) < 0 ) {
/* If the LOOP_CLR_FD above succeeded we'll see ENXIO here. */
if ( errno = = ENXIO )
log_debug ( " Successfully detached loopback device %s. " , device ) ;
else
log_debug_errno ( errno , " Failed to invoke LOOP_GET_STATUS64 on loopback device %s, ignoring: %m " , device ) ; /* the LOOP_CLR_FD at least worked, let's hope for the best */
2010-10-14 18:55:04 +02:00
return 1 ;
2019-12-20 17:58:03 +01:00
}
2010-10-14 18:55:04 +02:00
2019-12-20 17:58:03 +01:00
/* Linux makes LOOP_CLR_FD succeed whenever LO_FLAGS_AUTOCLEAR is set without actually doing
* anything . Very confusing . Let ' s hence not claim we did anything in this case . */
if ( FLAGS_SET ( info . lo_flags , LO_FLAGS_AUTOCLEAR ) )
log_debug ( " Successfully called LOOP_CLR_FD on a loopback device %s with autoclear set, which is a NOP. " , device ) ;
else
log_debug ( " Weird, LOOP_CLR_FD succeeded but the device is still attached on %s. " , device ) ;
2010-10-14 18:55:04 +02:00
2019-12-20 17:58:03 +01:00
return - EBUSY ; /* Nothing changed, the device is still attached, hence it apparently is still busy */
2010-10-07 14:43:57 +02:00
}
2020-09-22 11:23:35 +02:00
static int delete_dm ( MountPoint * m ) {
2016-12-05 16:09:04 +01:00
_cleanup_close_ int fd = - 1 ;
2020-09-22 11:23:35 +02:00
int r ;
2016-12-05 16:09:04 +01:00
2020-09-22 11:23:35 +02:00
assert ( m ) ;
assert ( major ( m - > devnum ) ! = 0 ) ;
assert ( m - > path ) ;
2010-10-14 02:33:09 +02:00
2013-03-25 00:45:16 +01:00
fd = open ( " /dev/mapper/control " , O_RDWR | O_CLOEXEC ) ;
if ( fd < 0 )
2010-10-14 02:33:09 +02:00
return - errno ;
2020-09-22 11:23:35 +02:00
r = fsync_path_at ( AT_FDCWD , m - > path ) ;
if ( r < 0 )
log_debug_errno ( r , " Failed to sync DM block device %s, ignoring: %m " , m - > path ) ;
if ( ioctl ( fd , DM_DEV_REMOVE , & ( struct dm_ioctl ) {
. version = {
DM_VERSION_MAJOR ,
DM_VERSION_MINOR ,
DM_VERSION_PATCHLEVEL
} ,
. data_size = sizeof ( struct dm_ioctl ) ,
. dev = m - > devnum ,
} ) < 0 )
2016-12-05 16:09:04 +01:00
return - errno ;
return 0 ;
2010-10-14 02:33:09 +02:00
}
2020-09-20 18:59:58 +02:00
static int delete_md ( MountPoint * m ) {
_cleanup_close_ int fd = - 1 ;
2020-09-22 11:21:19 +02:00
assert ( m ) ;
2020-09-20 18:59:58 +02:00
assert ( major ( m - > devnum ) ! = 0 ) ;
2020-09-22 11:21:19 +02:00
assert ( m - > path ) ;
2020-09-20 18:59:58 +02:00
fd = open ( m - > path , O_RDONLY | O_CLOEXEC | O_EXCL ) ;
if ( fd < 0 )
return - errno ;
2020-09-22 11:21:27 +02:00
if ( fsync ( fd ) < 0 )
log_debug_errno ( errno , " Failed to sync MD block device %s, ignoring: %m " , m - > path ) ;
2020-09-20 18:59:58 +02:00
if ( ioctl ( fd , STOP_ARRAY , NULL ) < 0 )
return - errno ;
return 0 ;
}
pid1: improve logging when failing to remount / ro (#5940)
https://bugzilla.redhat.com/show_bug.cgi?id=1227736#c49
We counted how many filesystems could not be unmounted, but only for those
filesystems which we tried to unmount. Since we only remount / ro, without
attempting to unmount, we would emit a confusing error message:
Remounting '/' read-only with options 'seclabel,space_cache,subvolid=5,subvol=/'.
Remounting '/' read-only with options 'seclabel,space_cache,subvolid=5,subvol=/'.
Remounting '/' read-only with options 'seclabel,space_cache,subvolid=5,subvol=/'.
All filesystems unmounted.
Warn when remount-ro fails, and for filesystems which we won't try to unmount,
include the failure to remount-ro in n_failed.
A few minor cleanups:
- remove unecessary goto which jumps to the next line anyway
- always calculate n_failed, even if log_error is false. This causes no change
in behaviour, but I think the code is easier to follow, since the log setting
cannot influence other logic.
2017-05-11 18:12:41 +02:00
static bool nonunmountable_path ( const char * path ) {
return path_equal ( path , " / " )
2017-10-03 10:41:51 +02:00
# if ! HAVE_SPLIT_USR
pid1: improve logging when failing to remount / ro (#5940)
https://bugzilla.redhat.com/show_bug.cgi?id=1227736#c49
We counted how many filesystems could not be unmounted, but only for those
filesystems which we tried to unmount. Since we only remount / ro, without
attempting to unmount, we would emit a confusing error message:
Remounting '/' read-only with options 'seclabel,space_cache,subvolid=5,subvol=/'.
Remounting '/' read-only with options 'seclabel,space_cache,subvolid=5,subvol=/'.
Remounting '/' read-only with options 'seclabel,space_cache,subvolid=5,subvol=/'.
All filesystems unmounted.
Warn when remount-ro fails, and for filesystems which we won't try to unmount,
include the failure to remount-ro in n_failed.
A few minor cleanups:
- remove unecessary goto which jumps to the next line anyway
- always calculate n_failed, even if log_error is false. This causes no change
in behaviour, but I think the code is easier to follow, since the log setting
cannot influence other logic.
2017-05-11 18:12:41 +02:00
| | path_equal ( path , " /usr " )
# endif
| | path_startswith ( path , " /run/initramfs " ) ;
}
2018-03-12 13:33:16 +01:00
static int remount_with_timeout ( MountPoint * m , int umount_log_level ) {
2017-12-13 18:49:26 +01:00
pid_t pid ;
int r ;
BLOCK_SIGNALS ( SIGCHLD ) ;
2018-03-08 17:22:58 +01:00
assert ( m ) ;
2020-11-18 08:38:49 +01:00
/* Due to the possibility of a remount operation hanging, we fork a child process and set a
* timeout . If the timeout lapses , the assumption is that the particular remount failed . */
2018-02-22 00:35:00 +01:00
r = safe_fork ( " (sd-remount) " , FORK_RESET_SIGNALS | FORK_CLOSE_ALL_FDS | FORK_LOG | FORK_REOPEN_LOG , & pid ) ;
2017-12-22 13:08:14 +01:00
if ( r < 0 )
2017-12-27 21:49:19 +01:00
return r ;
2017-12-22 13:08:14 +01:00
if ( r = = 0 ) {
2018-03-08 18:37:21 +01:00
log_info ( " Remounting '%s' read-only in with options '%s'. " , m - > path , m - > remount_options ) ;
2017-12-13 18:49:26 +01:00
/* Start the mount operation here in the child */
2018-03-08 18:37:21 +01:00
r = mount ( NULL , m - > path , NULL , m - > remount_flags , m - > remount_options ) ;
2017-12-13 18:49:26 +01:00
if ( r < 0 )
2018-03-12 13:33:16 +01:00
log_full_errno ( umount_log_level , errno , " Failed to remount '%s' read-only: %m " , m - > path ) ;
2017-12-13 18:49:26 +01:00
_exit ( r < 0 ? EXIT_FAILURE : EXIT_SUCCESS ) ;
}
r = wait_for_terminate_with_timeout ( pid , DEFAULT_TIMEOUT_USEC ) ;
if ( r = = - ETIMEDOUT ) {
2018-02-21 23:57:21 +01:00
log_error_errno ( r , " Remounting '%s' timed out, issuing SIGKILL to PID " PID_FMT " . " , m - > path , pid ) ;
2017-12-13 18:49:26 +01:00
( void ) kill ( pid , SIGKILL ) ;
2018-02-21 23:57:21 +01:00
} else if ( r = = - EPROTO )
2018-03-12 13:33:16 +01:00
log_debug_errno ( r , " Remounting '%s' failed abnormally, child process " PID_FMT " aborted or exited non-zero. " , m - > path , pid ) ;
2018-02-21 23:57:21 +01:00
else if ( r < 0 )
log_error_errno ( r , " Remounting '%s' failed unexpectedly, couldn't wait for child process " PID_FMT " : %m " , m - > path , pid ) ;
2017-12-13 18:49:26 +01:00
return r ;
}
2018-03-12 13:33:16 +01:00
static int umount_with_timeout ( MountPoint * m , int umount_log_level ) {
2017-12-13 18:49:26 +01:00
pid_t pid ;
int r ;
BLOCK_SIGNALS ( SIGCHLD ) ;
2018-03-08 17:22:58 +01:00
assert ( m ) ;
2020-11-18 08:38:49 +01:00
/* Due to the possibility of a umount operation hanging, we fork a child process and set a
* timeout . If the timeout lapses , the assumption is that the particular umount failed . */
2018-02-22 00:35:00 +01:00
r = safe_fork ( " (sd-umount) " , FORK_RESET_SIGNALS | FORK_CLOSE_ALL_FDS | FORK_LOG | FORK_REOPEN_LOG , & pid ) ;
2017-12-22 13:08:14 +01:00
if ( r < 0 )
2017-12-27 21:49:19 +01:00
return r ;
2017-12-22 13:08:14 +01:00
if ( r = = 0 ) {
2017-12-13 18:49:26 +01:00
log_info ( " Unmounting '%s'. " , m - > path ) ;
/* Start the mount operation here in the child Using MNT_FORCE
* causes some filesystems ( e . g . FUSE and NFS and other network
* filesystems ) to abort any pending requests and return - EIO
* rather than blocking indefinitely . If the filesysten is
* " busy " , this may allow processes to die , thus making the
* filesystem less busy so the unmount might succeed ( rather
* then return EBUSY ) . */
r = umount2 ( m - > path , MNT_FORCE ) ;
if ( r < 0 )
2018-03-12 13:33:16 +01:00
log_full_errno ( umount_log_level , errno , " Failed to unmount %s: %m " , m - > path ) ;
2017-12-13 18:49:26 +01:00
_exit ( r < 0 ? EXIT_FAILURE : EXIT_SUCCESS ) ;
}
r = wait_for_terminate_with_timeout ( pid , DEFAULT_TIMEOUT_USEC ) ;
if ( r = = - ETIMEDOUT ) {
2018-02-21 23:57:21 +01:00
log_error_errno ( r , " Unmounting '%s' timed out, issuing SIGKILL to PID " PID_FMT " . " , m - > path , pid ) ;
2017-12-13 18:49:26 +01:00
( void ) kill ( pid , SIGKILL ) ;
2018-02-21 23:57:21 +01:00
} else if ( r = = - EPROTO )
2018-03-12 13:33:16 +01:00
log_debug_errno ( r , " Unmounting '%s' failed abnormally, child process " PID_FMT " aborted or exited non-zero. " , m - > path , pid ) ;
2018-02-21 23:57:21 +01:00
else if ( r < 0 )
log_error_errno ( r , " Unmounting '%s' failed unexpectedly, couldn't wait for child process " PID_FMT " : %m " , m - > path , pid ) ;
2017-12-13 18:49:26 +01:00
return r ;
}
2019-12-20 16:57:29 +01:00
/* This includes remounting readonly, which changes the kernel mount options. Therefore the list passed to
* this function is invalidated , and should not be reused . */
2018-03-12 13:33:16 +01:00
static int mount_points_list_umount ( MountPoint * * head , bool * changed , int umount_log_level ) {
2017-10-19 16:02:12 +02:00
MountPoint * m ;
2010-10-14 18:55:04 +02:00
int n_failed = 0 ;
2010-10-07 14:43:57 +02:00
2010-10-14 18:55:04 +02:00
assert ( head ) ;
2018-03-08 17:22:58 +01:00
assert ( changed ) ;
2010-10-14 18:55:04 +02:00
2017-10-19 16:02:12 +02:00
LIST_FOREACH ( mount_point , m , * head ) {
2018-03-08 17:40:44 +01:00
if ( m - > try_remount_ro ) {
2019-12-20 16:57:29 +01:00
/* We always try to remount directories read-only first, before we go on and umount
2012-11-16 18:36:28 +01:00
* them .
*
2019-12-20 16:57:29 +01:00
* Mount points can be stacked . If a mount point is stacked below / or / usr , we
* cannot umount or remount it directly , since there is no way to refer to the
* underlying mount . There ' s nothing we can do about it for the general case , but we
* can do something about it if it is aliased somewhere else via a bind mount . If we
* explicitly remount the super block of that alias read - only we hence should be
* relatively safe regarding keeping a dirty fs we cannot otherwise see .
2017-12-13 18:49:26 +01:00
*
2019-12-20 16:57:29 +01:00
* Since the remount can hang in the instance of remote filesystems , we remount
* asynchronously and skip the subsequent umount if it fails . */
2018-03-12 13:33:16 +01:00
if ( remount_with_timeout ( m , umount_log_level ) < 0 ) {
2018-03-08 18:46:58 +01:00
/* Remount failed, but try unmounting anyway,
* unless this is a mount point we want to skip . */
if ( nonunmountable_path ( m - > path ) ) {
pid1: improve logging when failing to remount / ro (#5940)
https://bugzilla.redhat.com/show_bug.cgi?id=1227736#c49
We counted how many filesystems could not be unmounted, but only for those
filesystems which we tried to unmount. Since we only remount / ro, without
attempting to unmount, we would emit a confusing error message:
Remounting '/' read-only with options 'seclabel,space_cache,subvolid=5,subvol=/'.
Remounting '/' read-only with options 'seclabel,space_cache,subvolid=5,subvol=/'.
Remounting '/' read-only with options 'seclabel,space_cache,subvolid=5,subvol=/'.
All filesystems unmounted.
Warn when remount-ro fails, and for filesystems which we won't try to unmount,
include the failure to remount-ro in n_failed.
A few minor cleanups:
- remove unecessary goto which jumps to the next line anyway
- always calculate n_failed, even if log_error is false. This causes no change
in behaviour, but I think the code is easier to follow, since the log setting
cannot influence other logic.
2017-05-11 18:12:41 +02:00
n_failed + + ;
2018-03-08 18:46:58 +01:00
continue ;
}
pid1: improve logging when failing to remount / ro (#5940)
https://bugzilla.redhat.com/show_bug.cgi?id=1227736#c49
We counted how many filesystems could not be unmounted, but only for those
filesystems which we tried to unmount. Since we only remount / ro, without
attempting to unmount, we would emit a confusing error message:
Remounting '/' read-only with options 'seclabel,space_cache,subvolid=5,subvol=/'.
Remounting '/' read-only with options 'seclabel,space_cache,subvolid=5,subvol=/'.
Remounting '/' read-only with options 'seclabel,space_cache,subvolid=5,subvol=/'.
All filesystems unmounted.
Warn when remount-ro fails, and for filesystems which we won't try to unmount,
include the failure to remount-ro in n_failed.
A few minor cleanups:
- remove unecessary goto which jumps to the next line anyway
- always calculate n_failed, even if log_error is false. This causes no change
in behaviour, but I think the code is easier to follow, since the log setting
cannot influence other logic.
2017-05-11 18:12:41 +02:00
}
2012-11-16 18:36:28 +01:00
}
2019-12-20 16:57:29 +01:00
/* Skip / and /usr since we cannot unmount that anyway, since we are running from it. They
* have already been remounted ro . */
pid1: improve logging when failing to remount / ro (#5940)
https://bugzilla.redhat.com/show_bug.cgi?id=1227736#c49
We counted how many filesystems could not be unmounted, but only for those
filesystems which we tried to unmount. Since we only remount / ro, without
attempting to unmount, we would emit a confusing error message:
Remounting '/' read-only with options 'seclabel,space_cache,subvolid=5,subvol=/'.
Remounting '/' read-only with options 'seclabel,space_cache,subvolid=5,subvol=/'.
Remounting '/' read-only with options 'seclabel,space_cache,subvolid=5,subvol=/'.
All filesystems unmounted.
Warn when remount-ro fails, and for filesystems which we won't try to unmount,
include the failure to remount-ro in n_failed.
A few minor cleanups:
- remove unecessary goto which jumps to the next line anyway
- always calculate n_failed, even if log_error is false. This causes no change
in behaviour, but I think the code is easier to follow, since the log setting
cannot influence other logic.
2017-05-11 18:12:41 +02:00
if ( nonunmountable_path ( m - > path ) )
2010-10-07 14:43:57 +02:00
continue ;
2017-12-13 18:49:26 +01:00
/* Trying to umount */
2018-03-12 13:33:16 +01:00
if ( umount_with_timeout ( m , umount_log_level ) < 0 )
2017-12-13 18:49:26 +01:00
n_failed + + ;
2018-03-08 17:22:58 +01:00
else
* changed = true ;
2010-10-07 14:43:57 +02:00
}
2010-10-14 18:55:04 +02:00
return n_failed ;
2010-10-07 14:43:57 +02:00
}
2010-10-14 18:55:04 +02:00
static int swap_points_list_off ( MountPoint * * head , bool * changed ) {
MountPoint * m , * n ;
int n_failed = 0 ;
assert ( head ) ;
2018-03-08 17:22:58 +01:00
assert ( changed ) ;
2010-10-07 14:43:57 +02:00
2010-10-14 18:55:04 +02:00
LIST_FOREACH_SAFE ( mount_point , m , n , * head ) {
2012-12-07 18:02:43 +01:00
log_info ( " Deactivating swap %s. " , m - > path ) ;
2019-12-20 16:59:42 +01:00
if ( swapoff ( m - > path ) < 0 ) {
2014-11-28 19:29:59 +01:00
log_warning_errno ( errno , " Could not deactivate swap %s: %m " , m - > path ) ;
2010-10-14 18:55:04 +02:00
n_failed + + ;
2019-12-20 16:59:42 +01:00
continue ;
2010-10-07 14:43:57 +02:00
}
2019-12-20 16:59:42 +01:00
* changed = true ;
mount_point_free ( head , m ) ;
2010-10-07 14:43:57 +02:00
}
2010-10-14 18:55:04 +02:00
return n_failed ;
2010-10-07 14:43:57 +02:00
}
2018-03-12 13:33:16 +01:00
static int loopback_points_list_detach ( MountPoint * * head , bool * changed , int umount_log_level ) {
2010-10-14 18:55:04 +02:00
MountPoint * m , * n ;
2019-12-20 17:02:05 +01:00
int n_failed = 0 , r ;
dev_t rootdev = 0 ;
2010-10-14 18:55:04 +02:00
assert ( head ) ;
2018-03-08 17:22:58 +01:00
assert ( changed ) ;
2010-10-14 18:55:04 +02:00
2019-12-20 17:02:05 +01:00
( void ) get_block_device ( " / " , & rootdev ) ;
2011-01-06 19:10:17 +01:00
2010-10-14 18:55:04 +02:00
LIST_FOREACH_SAFE ( mount_point , m , n , * head ) {
2019-12-20 17:02:05 +01:00
if ( major ( rootdev ) ! = 0 & & rootdev = = m - > devnum ) {
2016-02-23 05:32:04 +01:00
n_failed + + ;
2011-01-06 19:10:17 +01:00
continue ;
}
2010-10-07 14:43:57 +02:00
2012-12-07 18:02:43 +01:00
log_info ( " Detaching loopback %s. " , m - > path ) ;
2012-12-07 17:44:50 +01:00
r = delete_loopback ( m - > path ) ;
2019-12-20 16:59:42 +01:00
if ( r < 0 ) {
log_full_errno ( umount_log_level , r , " Could not detach loopback %s: %m " , m - > path ) ;
2010-10-14 18:55:04 +02:00
n_failed + + ;
2019-12-20 16:59:42 +01:00
continue ;
2010-10-07 14:43:57 +02:00
}
2019-12-20 16:59:42 +01:00
if ( r > 0 )
* changed = true ;
mount_point_free ( head , m ) ;
2010-10-07 14:43:57 +02:00
}
2010-10-14 18:55:04 +02:00
return n_failed ;
2010-10-07 14:43:57 +02:00
}
2018-03-12 13:33:16 +01:00
static int dm_points_list_detach ( MountPoint * * head , bool * changed , int umount_log_level ) {
2010-10-14 18:55:04 +02:00
MountPoint * m , * n ;
2017-09-13 11:04:17 +02:00
int n_failed = 0 , r ;
2019-12-20 17:02:05 +01:00
dev_t rootdev = 0 ;
2010-10-14 18:55:04 +02:00
assert ( head ) ;
2018-03-08 17:22:58 +01:00
assert ( changed ) ;
2010-10-14 18:55:04 +02:00
2019-12-20 17:02:05 +01:00
( void ) get_block_device ( " / " , & rootdev ) ;
2011-01-06 19:10:17 +01:00
2010-10-14 18:55:04 +02:00
LIST_FOREACH_SAFE ( mount_point , m , n , * head ) {
2018-03-08 17:22:58 +01:00
if ( major ( rootdev ) ! = 0 & & rootdev = = m - > devnum ) {
n_failed + + ;
continue ;
}
2011-01-06 19:10:17 +01:00
2019-12-20 16:59:42 +01:00
log_info ( " Detaching DM %s (%u:%u). " , m - > path , major ( m - > devnum ) , minor ( m - > devnum ) ) ;
2020-09-22 11:23:35 +02:00
r = delete_dm ( m ) ;
2019-12-20 16:59:42 +01:00
if ( r < 0 ) {
log_full_errno ( umount_log_level , r , " Could not detach DM %s: %m " , m - > path ) ;
2010-10-14 18:55:04 +02:00
n_failed + + ;
2019-12-20 16:59:42 +01:00
continue ;
2010-10-14 02:33:09 +02:00
}
2019-12-20 16:59:42 +01:00
* changed = true ;
mount_point_free ( head , m ) ;
2010-10-14 02:33:09 +02:00
}
2010-10-14 18:55:04 +02:00
return n_failed ;
2010-10-14 02:33:09 +02:00
}
2020-09-20 18:59:58 +02:00
static int md_points_list_detach ( MountPoint * * head , bool * changed , int umount_log_level ) {
MountPoint * m , * n ;
int n_failed = 0 , r ;
dev_t rootdev = 0 ;
assert ( head ) ;
assert ( changed ) ;
( void ) get_block_device ( " / " , & rootdev ) ;
LIST_FOREACH_SAFE ( mount_point , m , n , * head ) {
if ( major ( rootdev ) ! = 0 & & rootdev = = m - > devnum ) {
n_failed + + ;
continue ;
}
log_info ( " Stopping MD %s (%u:%u). " , m - > path , major ( m - > devnum ) , minor ( m - > devnum ) ) ;
r = delete_md ( m ) ;
if ( r < 0 ) {
log_full_errno ( umount_log_level , r , " Could not stop MD %s: %m " , m - > path ) ;
n_failed + + ;
continue ;
}
* changed = true ;
mount_point_free ( head , m ) ;
}
return n_failed ;
}
2018-03-12 13:33:16 +01:00
static int umount_all_once ( bool * changed , int umount_log_level ) {
2018-03-14 11:32:13 +01:00
_cleanup_ ( mount_points_list_free ) LIST_HEAD ( MountPoint , mp_list_head ) ;
2019-12-20 16:59:42 +01:00
int r ;
2010-10-07 14:43:57 +02:00
2018-03-08 17:22:58 +01:00
assert ( changed ) ;
2013-10-14 06:10:14 +02:00
LIST_HEAD_INIT ( mp_list_head ) ;
2018-03-14 11:03:36 +01:00
r = mount_points_list_get ( NULL , & mp_list_head ) ;
2010-10-07 14:43:57 +02:00
if ( r < 0 )
2018-03-14 11:32:13 +01:00
return r ;
2017-10-19 16:02:12 +02:00
2018-03-14 11:32:13 +01:00
return mount_points_list_umount ( & mp_list_head , changed , umount_log_level ) ;
2017-10-19 16:02:12 +02:00
}
2018-03-12 13:33:16 +01:00
int umount_all ( bool * changed , int umount_log_level ) {
2017-10-19 16:02:12 +02:00
bool umount_changed ;
int r ;
2018-03-08 17:22:58 +01:00
assert ( changed ) ;
2017-12-13 18:49:26 +01:00
/* Retry umount, until nothing can be umounted anymore. Mounts are
* processed in order , newest first . The retries are needed when
* an old mount has been moved , to a path inside a newer mount . */
2011-05-05 12:26:31 +02:00
do {
umount_changed = false ;
2011-09-23 02:39:54 +02:00
2018-03-12 13:33:16 +01:00
r = umount_all_once ( & umount_changed , umount_log_level ) ;
2011-05-05 12:26:31 +02:00
if ( umount_changed )
* changed = true ;
2011-09-23 02:39:54 +02:00
} while ( umount_changed ) ;
2010-10-07 14:43:57 +02:00
return r ;
}
2010-10-14 18:55:04 +02:00
int swapoff_all ( bool * changed ) {
2018-03-14 11:32:13 +01:00
_cleanup_ ( mount_points_list_free ) LIST_HEAD ( MountPoint , swap_list_head ) ;
2010-10-07 14:43:57 +02:00
int r ;
2018-03-08 17:22:58 +01:00
assert ( changed ) ;
2013-10-14 06:10:14 +02:00
LIST_HEAD_INIT ( swap_list_head ) ;
2010-10-07 14:43:57 +02:00
2018-03-14 12:06:34 +01:00
r = swap_list_get ( NULL , & swap_list_head ) ;
2010-10-07 14:43:57 +02:00
if ( r < 0 )
2018-03-14 11:32:13 +01:00
return r ;
2010-10-07 14:43:57 +02:00
2018-03-14 11:32:13 +01:00
return swap_points_list_off ( & swap_list_head , changed ) ;
2010-10-07 14:43:57 +02:00
}
2018-03-12 13:33:16 +01:00
int loopback_detach_all ( bool * changed , int umount_log_level ) {
2018-03-14 11:32:13 +01:00
_cleanup_ ( mount_points_list_free ) LIST_HEAD ( MountPoint , loopback_list_head ) ;
2010-10-07 14:43:57 +02:00
int r ;
2018-03-08 17:22:58 +01:00
assert ( changed ) ;
2013-10-14 06:10:14 +02:00
LIST_HEAD_INIT ( loopback_list_head ) ;
2010-10-07 14:43:57 +02:00
r = loopback_list_get ( & loopback_list_head ) ;
if ( r < 0 )
2018-03-14 11:32:13 +01:00
return r ;
2010-10-07 14:43:57 +02:00
2018-03-14 11:32:13 +01:00
return loopback_points_list_detach ( & loopback_list_head , changed , umount_log_level ) ;
2010-10-07 14:43:57 +02:00
}
2010-10-14 02:33:09 +02:00
2018-03-12 13:33:16 +01:00
int dm_detach_all ( bool * changed , int umount_log_level ) {
2018-03-14 11:32:13 +01:00
_cleanup_ ( mount_points_list_free ) LIST_HEAD ( MountPoint , dm_list_head ) ;
2010-10-14 02:33:09 +02:00
int r ;
2018-03-08 17:22:58 +01:00
assert ( changed ) ;
2013-10-14 06:10:14 +02:00
LIST_HEAD_INIT ( dm_list_head ) ;
2010-10-14 02:33:09 +02:00
r = dm_list_get ( & dm_list_head ) ;
if ( r < 0 )
2018-03-14 11:32:13 +01:00
return r ;
2010-10-14 02:33:09 +02:00
2018-03-14 11:32:13 +01:00
return dm_points_list_detach ( & dm_list_head , changed , umount_log_level ) ;
2010-10-14 02:33:09 +02:00
}
2020-09-20 18:59:58 +02:00
int md_detach_all ( bool * changed , int umount_log_level ) {
_cleanup_ ( mount_points_list_free ) LIST_HEAD ( MountPoint , md_list_head ) ;
int r ;
assert ( changed ) ;
LIST_HEAD_INIT ( md_list_head ) ;
r = md_list_get ( & md_list_head ) ;
if ( r < 0 )
return r ;
return md_points_list_detach ( & md_list_head , changed , umount_log_level ) ;
}