2 This file is part of systemd.
4 Copyright 2010 ProFUSION embedded systems
6 systemd is free software; you can redistribute it and/or modify it
7 under the terms of the GNU Lesser General Public License as published by
8 the Free Software Foundation; either version 2.1 of the License, or
9 (at your option) any later version.
11 systemd is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Lesser General Public License for more details.
16 You should have received a copy of the GNU Lesser General Public License
17 along with systemd; If not, see <http://www.gnu.org/licenses/>.
22 #include <linux/dm-ioctl.h>
23 #include <linux/loop.h>
25 #include <sys/mount.h>
30 #include "alloc-util.h"
33 #include "fstab-util.h"
35 #include "mount-setup.h"
36 #include "path-util.h"
37 #include "string-util.h"
38 #include "udev-util.h"
43 typedef struct MountPoint
{
47 LIST_FIELDS(struct MountPoint
, mount_point
);
50 static void mount_point_free(MountPoint
**head
, MountPoint
*m
) {
54 LIST_REMOVE(mount_point
, *head
, m
);
60 static void mount_points_list_free(MountPoint
**head
) {
64 mount_point_free(head
, *head
);
67 static int mount_points_list_get(MountPoint
**head
) {
68 _cleanup_fclose_
FILE *proc_self_mountinfo
= NULL
;
74 proc_self_mountinfo
= fopen("/proc/self/mountinfo", "re");
75 if (!proc_self_mountinfo
)
79 _cleanup_free_
char *path
= NULL
, *options
= NULL
;
84 k
= fscanf(proc_self_mountinfo
,
85 "%*s " /* (1) mount id */
86 "%*s " /* (2) parent id */
87 "%*s " /* (3) major:minor */
89 "%ms " /* (5) mount point */
90 "%*s" /* (6) mount flags */
91 "%*[^-]" /* (7) optional fields */
92 "- " /* (8) separator */
93 "%*s " /* (9) file system type */
94 "%*s" /* (10) mount source */
95 "%ms" /* (11) mount options */
96 "%*[^\n]", /* some rubbish at the end */
102 log_warning("Failed to parse /proc/self/mountinfo:%u.", i
);
106 r
= cunescape(path
, UNESCAPE_RELAX
, &p
);
110 /* Ignore mount points we can't unmount because they
111 * are API or because we are keeping them open (like
112 * /dev/console). Also, ignore all mounts below API
113 * file systems, since they are likely virtual too,
114 * and hence not worth spending time on. Also, in
115 * unprivileged containers we might lack the rights to
116 * unmount these things, hence don't bother. */
117 if (mount_point_is_api(p
) ||
118 mount_point_ignore(p
) ||
119 path_startswith(p
, "/dev") ||
120 path_startswith(p
, "/sys") ||
121 path_startswith(p
, "/proc")) {
126 m
= new0(MountPoint
, 1);
133 m
->options
= options
;
136 LIST_PREPEND(mount_point
, *head
, m
);
142 static int swap_list_get(MountPoint
**head
) {
143 _cleanup_fclose_
FILE *proc_swaps
= NULL
;
149 proc_swaps
= fopen("/proc/swaps", "re");
151 return (errno
== ENOENT
) ? 0 : -errno
;
153 (void) fscanf(proc_swaps
, "%*s %*s %*s %*s %*s\n");
157 char *dev
= NULL
, *d
;
160 k
= fscanf(proc_swaps
,
161 "%ms " /* device/file */
162 "%*s " /* type of swap */
163 "%*s " /* swap size */
165 "%*s\n", /* priority */
172 log_warning("Failed to parse /proc/swaps:%u.", i
);
177 if (endswith(dev
, " (deleted)")) {
182 r
= cunescape(dev
, UNESCAPE_RELAX
, &d
);
187 swap
= new0(MountPoint
, 1);
194 LIST_PREPEND(mount_point
, *head
, swap
);
200 static int loopback_list_get(MountPoint
**head
) {
201 _cleanup_udev_enumerate_unref_
struct udev_enumerate
*e
= NULL
;
202 struct udev_list_entry
*item
= NULL
, *first
= NULL
;
203 _cleanup_udev_unref_
struct udev
*udev
= NULL
;
212 e
= udev_enumerate_new(udev
);
216 r
= udev_enumerate_add_match_subsystem(e
, "block");
220 r
= udev_enumerate_add_match_sysname(e
, "loop*");
224 r
= udev_enumerate_add_match_sysattr(e
, "loop/backing_file", NULL
);
228 r
= udev_enumerate_scan_devices(e
);
232 first
= udev_enumerate_get_list_entry(e
);
233 udev_list_entry_foreach(item
, first
) {
235 _cleanup_udev_device_unref_
struct udev_device
*d
;
239 d
= udev_device_new_from_syspath(udev
, udev_list_entry_get_name(item
));
243 dn
= udev_device_get_devnode(d
);
251 lb
= new0(MountPoint
, 1);
258 LIST_PREPEND(mount_point
, *head
, lb
);
264 static int dm_list_get(MountPoint
**head
) {
265 _cleanup_udev_enumerate_unref_
struct udev_enumerate
*e
= NULL
;
266 struct udev_list_entry
*item
= NULL
, *first
= NULL
;
267 _cleanup_udev_unref_
struct udev
*udev
= NULL
;
276 e
= udev_enumerate_new(udev
);
280 r
= udev_enumerate_add_match_subsystem(e
, "block");
284 r
= udev_enumerate_add_match_sysname(e
, "dm-*");
288 r
= udev_enumerate_scan_devices(e
);
292 first
= udev_enumerate_get_list_entry(e
);
293 udev_list_entry_foreach(item
, first
) {
295 _cleanup_udev_device_unref_
struct udev_device
*d
;
300 d
= udev_device_new_from_syspath(udev
, udev_list_entry_get_name(item
));
304 devnum
= udev_device_get_devnum(d
);
305 dn
= udev_device_get_devnode(d
);
306 if (major(devnum
) == 0 || !dn
)
313 m
= new(MountPoint
, 1);
321 LIST_PREPEND(mount_point
, *head
, m
);
327 static int delete_loopback(const char *device
) {
328 _cleanup_close_
int fd
= -1;
331 fd
= open(device
, O_RDONLY
|O_CLOEXEC
);
333 return errno
== ENOENT
? 0 : -errno
;
335 r
= ioctl(fd
, LOOP_CLR_FD
, 0);
339 /* ENXIO: not bound, so no error */
346 static int delete_dm(dev_t devnum
) {
347 _cleanup_close_
int fd
= -1;
349 struct dm_ioctl dm
= {
350 .version
= {DM_VERSION_MAJOR
,
352 DM_VERSION_PATCHLEVEL
},
353 .data_size
= sizeof(dm
),
357 assert(major(devnum
) != 0);
359 fd
= open("/dev/mapper/control", O_RDWR
|O_CLOEXEC
);
363 r
= ioctl(fd
, DM_DEV_REMOVE
, &dm
);
364 return r
>= 0 ? 0 : -errno
;
367 static int mount_points_list_umount(MountPoint
**head
, bool *changed
, bool log_error
) {
373 LIST_FOREACH_SAFE(mount_point
, m
, n
, *head
) {
375 /* If we are in a container, don't attempt to
376 read-only mount anything as that brings no real
377 benefits, but might confuse the host, as we remount
378 the superblock here, not the bind mound. */
379 if (detect_container() <= 0) {
380 _cleanup_free_
char *options
= NULL
;
381 /* MS_REMOUNT requires that the data parameter
382 * should be the same from the original mount
383 * except for the desired changes. Since we want
384 * to remount read-only, we should filter out
385 * rw (and ro too, because it confuses the kernel) */
386 (void) fstab_filter_options(m
->options
, "rw\0ro\0", NULL
, NULL
, &options
);
388 /* We always try to remount directories
389 * read-only first, before we go on and umount
392 * Mount points can be stacked. If a mount
393 * point is stacked below / or /usr, we
394 * cannot umount or remount it directly,
395 * since there is no way to refer to the
396 * underlying mount. There's nothing we can do
397 * about it for the general case, but we can
398 * do something about it if it is aliased
399 * somehwere else via a bind mount. If we
400 * explicitly remount the super block of that
401 * alias read-only we hence should be
402 * relatively safe regarding keeping the fs we
403 * can otherwise not see dirty. */
404 log_info("Remounting '%s' read-only with options '%s'.", m
->path
, options
);
405 (void) mount(NULL
, m
->path
, NULL
, MS_REMOUNT
|MS_RDONLY
, options
);
408 /* Skip / and /usr since we cannot unmount that
409 * anyway, since we are running from it. They have
410 * already been remounted ro. */
411 if (path_equal(m
->path
, "/")
412 #ifndef HAVE_SPLIT_USR
413 || path_equal(m
->path
, "/usr")
418 /* Trying to umount. We don't force here since we rely
419 * on busy NFS and FUSE file systems to return EBUSY
420 * until we closed everything on top of them. */
421 log_info("Unmounting %s.", m
->path
);
422 if (umount2(m
->path
, 0) == 0) {
426 mount_point_free(head
, m
);
427 } else if (log_error
) {
428 log_warning_errno(errno
, "Could not unmount %s: %m", m
->path
);
436 static int swap_points_list_off(MountPoint
**head
, bool *changed
) {
442 LIST_FOREACH_SAFE(mount_point
, m
, n
, *head
) {
443 log_info("Deactivating swap %s.", m
->path
);
444 if (swapoff(m
->path
) == 0) {
448 mount_point_free(head
, m
);
450 log_warning_errno(errno
, "Could not deactivate swap %s: %m", m
->path
);
458 static int loopback_points_list_detach(MountPoint
**head
, bool *changed
) {
465 k
= lstat("/", &root_st
);
467 LIST_FOREACH_SAFE(mount_point
, m
, n
, *head
) {
469 struct stat loopback_st
;
472 major(root_st
.st_dev
) != 0 &&
473 lstat(m
->path
, &loopback_st
) >= 0 &&
474 root_st
.st_dev
== loopback_st
.st_rdev
) {
479 log_info("Detaching loopback %s.", m
->path
);
480 r
= delete_loopback(m
->path
);
482 if (r
> 0 && changed
)
485 mount_point_free(head
, m
);
487 log_warning_errno(errno
, "Could not detach loopback %s: %m", m
->path
);
495 static int dm_points_list_detach(MountPoint
**head
, bool *changed
) {
502 k
= lstat("/", &root_st
);
504 LIST_FOREACH_SAFE(mount_point
, m
, n
, *head
) {
508 major(root_st
.st_dev
) != 0 &&
509 root_st
.st_dev
== m
->devnum
) {
514 log_info("Detaching DM %u:%u.", major(m
->devnum
), minor(m
->devnum
));
515 r
= delete_dm(m
->devnum
);
520 mount_point_free(head
, m
);
522 log_warning_errno(errno
, "Could not detach DM %s: %m", m
->path
);
530 int umount_all(bool *changed
) {
533 LIST_HEAD(MountPoint
, mp_list_head
);
535 LIST_HEAD_INIT(mp_list_head
);
536 r
= mount_points_list_get(&mp_list_head
);
540 /* retry umount, until nothing can be umounted anymore */
542 umount_changed
= false;
544 mount_points_list_umount(&mp_list_head
, &umount_changed
, false);
548 } while (umount_changed
);
550 /* umount one more time with logging enabled */
551 r
= mount_points_list_umount(&mp_list_head
, &umount_changed
, true);
556 mount_points_list_free(&mp_list_head
);
561 int swapoff_all(bool *changed
) {
563 LIST_HEAD(MountPoint
, swap_list_head
);
565 LIST_HEAD_INIT(swap_list_head
);
567 r
= swap_list_get(&swap_list_head
);
571 r
= swap_points_list_off(&swap_list_head
, changed
);
574 mount_points_list_free(&swap_list_head
);
579 int loopback_detach_all(bool *changed
) {
581 LIST_HEAD(MountPoint
, loopback_list_head
);
583 LIST_HEAD_INIT(loopback_list_head
);
585 r
= loopback_list_get(&loopback_list_head
);
589 r
= loopback_points_list_detach(&loopback_list_head
, changed
);
592 mount_points_list_free(&loopback_list_head
);
597 int dm_detach_all(bool *changed
) {
599 LIST_HEAD(MountPoint
, dm_list_head
);
601 LIST_HEAD_INIT(dm_list_head
);
603 r
= dm_list_get(&dm_list_head
);
607 r
= dm_points_list_detach(&dm_list_head
, changed
);
610 mount_points_list_free(&dm_list_head
);