1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
4 This file is part of systemd.
6 Copyright 2010 ProFUSION embedded systems
8 systemd is free software; you can redistribute it and/or modify it
9 under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 2.1 of the License, or
11 (at your option) any later version.
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Lesser General Public License for more details.
18 You should have received a copy of the GNU Lesser General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
24 #include <linux/dm-ioctl.h>
25 #include <linux/loop.h>
27 #include <sys/mount.h>
34 #include "fstab-util.h"
36 #include "mount-setup.h"
37 #include "path-util.h"
38 #include "string-util.h"
39 #include "udev-util.h"
44 typedef struct MountPoint
{
48 LIST_FIELDS(struct MountPoint
, mount_point
);
51 static void mount_point_free(MountPoint
**head
, MountPoint
*m
) {
55 LIST_REMOVE(mount_point
, *head
, m
);
61 static void mount_points_list_free(MountPoint
**head
) {
65 mount_point_free(head
, *head
);
68 static int mount_points_list_get(MountPoint
**head
) {
69 _cleanup_fclose_
FILE *proc_self_mountinfo
= NULL
;
75 proc_self_mountinfo
= fopen("/proc/self/mountinfo", "re");
76 if (!proc_self_mountinfo
)
80 _cleanup_free_
char *path
= NULL
, *options
= NULL
;
85 k
= fscanf(proc_self_mountinfo
,
86 "%*s " /* (1) mount id */
87 "%*s " /* (2) parent id */
88 "%*s " /* (3) major:minor */
90 "%ms " /* (5) mount point */
91 "%*s" /* (6) mount flags */
92 "%*[^-]" /* (7) optional fields */
93 "- " /* (8) separator */
94 "%*s " /* (9) file system type */
95 "%*s" /* (10) mount source */
96 "%ms" /* (11) mount options */
97 "%*[^\n]", /* some rubbish at the end */
103 log_warning("Failed to parse /proc/self/mountinfo:%u.", i
);
107 r
= cunescape(path
, UNESCAPE_RELAX
, &p
);
111 /* Ignore mount points we can't unmount because they
112 * are API or because we are keeping them open (like
113 * /dev/console). Also, ignore all mounts below API
114 * file systems, since they are likely virtual too,
115 * and hence not worth spending time on. Also, in
116 * unprivileged containers we might lack the rights to
117 * unmount these things, hence don't bother. */
118 if (mount_point_is_api(p
) ||
119 mount_point_ignore(p
) ||
120 path_startswith(p
, "/dev") ||
121 path_startswith(p
, "/sys") ||
122 path_startswith(p
, "/proc")) {
127 m
= new0(MountPoint
, 1);
134 m
->options
= options
;
137 LIST_PREPEND(mount_point
, *head
, m
);
143 static int swap_list_get(MountPoint
**head
) {
144 _cleanup_fclose_
FILE *proc_swaps
= NULL
;
150 proc_swaps
= fopen("/proc/swaps", "re");
152 return (errno
== ENOENT
) ? 0 : -errno
;
154 (void) fscanf(proc_swaps
, "%*s %*s %*s %*s %*s\n");
158 char *dev
= NULL
, *d
;
161 k
= fscanf(proc_swaps
,
162 "%ms " /* device/file */
163 "%*s " /* type of swap */
164 "%*s " /* swap size */
166 "%*s\n", /* priority */
173 log_warning("Failed to parse /proc/swaps:%u.", i
);
178 if (endswith(dev
, " (deleted)")) {
183 r
= cunescape(dev
, UNESCAPE_RELAX
, &d
);
188 swap
= new0(MountPoint
, 1);
195 LIST_PREPEND(mount_point
, *head
, swap
);
201 static int loopback_list_get(MountPoint
**head
) {
202 _cleanup_udev_enumerate_unref_
struct udev_enumerate
*e
= NULL
;
203 struct udev_list_entry
*item
= NULL
, *first
= NULL
;
204 _cleanup_udev_unref_
struct udev
*udev
= NULL
;
213 e
= udev_enumerate_new(udev
);
217 r
= udev_enumerate_add_match_subsystem(e
, "block");
221 r
= udev_enumerate_add_match_sysname(e
, "loop*");
225 r
= udev_enumerate_add_match_sysattr(e
, "loop/backing_file", NULL
);
229 r
= udev_enumerate_scan_devices(e
);
233 first
= udev_enumerate_get_list_entry(e
);
234 udev_list_entry_foreach(item
, first
) {
236 _cleanup_udev_device_unref_
struct udev_device
*d
;
240 d
= udev_device_new_from_syspath(udev
, udev_list_entry_get_name(item
));
244 dn
= udev_device_get_devnode(d
);
252 lb
= new0(MountPoint
, 1);
259 LIST_PREPEND(mount_point
, *head
, lb
);
265 static int dm_list_get(MountPoint
**head
) {
266 _cleanup_udev_enumerate_unref_
struct udev_enumerate
*e
= NULL
;
267 struct udev_list_entry
*item
= NULL
, *first
= NULL
;
268 _cleanup_udev_unref_
struct udev
*udev
= NULL
;
277 e
= udev_enumerate_new(udev
);
281 r
= udev_enumerate_add_match_subsystem(e
, "block");
285 r
= udev_enumerate_add_match_sysname(e
, "dm-*");
289 r
= udev_enumerate_scan_devices(e
);
293 first
= udev_enumerate_get_list_entry(e
);
294 udev_list_entry_foreach(item
, first
) {
296 _cleanup_udev_device_unref_
struct udev_device
*d
;
301 d
= udev_device_new_from_syspath(udev
, udev_list_entry_get_name(item
));
305 devnum
= udev_device_get_devnum(d
);
306 dn
= udev_device_get_devnode(d
);
307 if (major(devnum
) == 0 || !dn
)
314 m
= new(MountPoint
, 1);
322 LIST_PREPEND(mount_point
, *head
, m
);
328 static int delete_loopback(const char *device
) {
329 _cleanup_close_
int fd
= -1;
332 fd
= open(device
, O_RDONLY
|O_CLOEXEC
);
334 return errno
== ENOENT
? 0 : -errno
;
336 r
= ioctl(fd
, LOOP_CLR_FD
, 0);
340 /* ENXIO: not bound, so no error */
347 static int delete_dm(dev_t devnum
) {
348 _cleanup_close_
int fd
= -1;
350 struct dm_ioctl dm
= {
351 .version
= {DM_VERSION_MAJOR
,
353 DM_VERSION_PATCHLEVEL
},
354 .data_size
= sizeof(dm
),
358 assert(major(devnum
) != 0);
360 fd
= open("/dev/mapper/control", O_RDWR
|O_CLOEXEC
);
364 r
= ioctl(fd
, DM_DEV_REMOVE
, &dm
);
365 return r
>= 0 ? 0 : -errno
;
368 static int mount_points_list_umount(MountPoint
**head
, bool *changed
, bool log_error
) {
374 LIST_FOREACH_SAFE(mount_point
, m
, n
, *head
) {
376 /* If we are in a container, don't attempt to
377 read-only mount anything as that brings no real
378 benefits, but might confuse the host, as we remount
379 the superblock here, not the bind mound. */
380 if (detect_container() <= 0) {
381 _cleanup_free_
char *options
= NULL
;
382 /* MS_REMOUNT requires that the data parameter
383 * should be the same from the original mount
384 * except for the desired changes. Since we want
385 * to remount read-only, we should filter out
386 * rw (and ro too, because it confuses the kernel) */
387 (void) fstab_filter_options(m
->options
, "rw\0ro\0", NULL
, NULL
, &options
);
389 /* We always try to remount directories
390 * read-only first, before we go on and umount
393 * Mount points can be stacked. If a mount
394 * point is stacked below / or /usr, we
395 * cannot umount or remount it directly,
396 * since there is no way to refer to the
397 * underlying mount. There's nothing we can do
398 * about it for the general case, but we can
399 * do something about it if it is aliased
400 * somehwere else via a bind mount. If we
401 * explicitly remount the super block of that
402 * alias read-only we hence should be
403 * relatively safe regarding keeping the fs we
404 * can otherwise not see dirty. */
405 log_info("Remounting '%s' read-only with options '%s'.", m
->path
, options
);
406 (void) mount(NULL
, m
->path
, NULL
, MS_REMOUNT
|MS_RDONLY
, options
);
409 /* Skip / and /usr since we cannot unmount that
410 * anyway, since we are running from it. They have
411 * already been remounted ro. */
412 if (path_equal(m
->path
, "/")
413 #ifndef HAVE_SPLIT_USR
414 || path_equal(m
->path
, "/usr")
419 /* Trying to umount. We don't force here since we rely
420 * on busy NFS and FUSE file systems to return EBUSY
421 * until we closed everything on top of them. */
422 log_info("Unmounting %s.", m
->path
);
423 if (umount2(m
->path
, 0) == 0) {
427 mount_point_free(head
, m
);
428 } else if (log_error
) {
429 log_warning_errno(errno
, "Could not unmount %s: %m", m
->path
);
437 static int swap_points_list_off(MountPoint
**head
, bool *changed
) {
443 LIST_FOREACH_SAFE(mount_point
, m
, n
, *head
) {
444 log_info("Deactivating swap %s.", m
->path
);
445 if (swapoff(m
->path
) == 0) {
449 mount_point_free(head
, m
);
451 log_warning_errno(errno
, "Could not deactivate swap %s: %m", m
->path
);
459 static int loopback_points_list_detach(MountPoint
**head
, bool *changed
) {
466 k
= lstat("/", &root_st
);
468 LIST_FOREACH_SAFE(mount_point
, m
, n
, *head
) {
470 struct stat loopback_st
;
473 major(root_st
.st_dev
) != 0 &&
474 lstat(m
->path
, &loopback_st
) >= 0 &&
475 root_st
.st_dev
== loopback_st
.st_rdev
) {
480 log_info("Detaching loopback %s.", m
->path
);
481 r
= delete_loopback(m
->path
);
483 if (r
> 0 && changed
)
486 mount_point_free(head
, m
);
488 log_warning_errno(errno
, "Could not detach loopback %s: %m", m
->path
);
496 static int dm_points_list_detach(MountPoint
**head
, bool *changed
) {
503 k
= lstat("/", &root_st
);
505 LIST_FOREACH_SAFE(mount_point
, m
, n
, *head
) {
509 major(root_st
.st_dev
) != 0 &&
510 root_st
.st_dev
== m
->devnum
) {
515 log_info("Detaching DM %u:%u.", major(m
->devnum
), minor(m
->devnum
));
516 r
= delete_dm(m
->devnum
);
521 mount_point_free(head
, m
);
523 log_warning_errno(errno
, "Could not detach DM %s: %m", m
->path
);
531 int umount_all(bool *changed
) {
534 LIST_HEAD(MountPoint
, mp_list_head
);
536 LIST_HEAD_INIT(mp_list_head
);
537 r
= mount_points_list_get(&mp_list_head
);
541 /* retry umount, until nothing can be umounted anymore */
543 umount_changed
= false;
545 mount_points_list_umount(&mp_list_head
, &umount_changed
, false);
549 } while (umount_changed
);
551 /* umount one more time with logging enabled */
552 r
= mount_points_list_umount(&mp_list_head
, &umount_changed
, true);
557 mount_points_list_free(&mp_list_head
);
562 int swapoff_all(bool *changed
) {
564 LIST_HEAD(MountPoint
, swap_list_head
);
566 LIST_HEAD_INIT(swap_list_head
);
568 r
= swap_list_get(&swap_list_head
);
572 r
= swap_points_list_off(&swap_list_head
, changed
);
575 mount_points_list_free(&swap_list_head
);
580 int loopback_detach_all(bool *changed
) {
582 LIST_HEAD(MountPoint
, loopback_list_head
);
584 LIST_HEAD_INIT(loopback_list_head
);
586 r
= loopback_list_get(&loopback_list_head
);
590 r
= loopback_points_list_detach(&loopback_list_head
, changed
);
593 mount_points_list_free(&loopback_list_head
);
598 int dm_detach_all(bool *changed
) {
600 LIST_HEAD(MountPoint
, dm_list_head
);
602 LIST_HEAD_INIT(dm_list_head
);
604 r
= dm_list_get(&dm_list_head
);
608 r
= dm_points_list_detach(&dm_list_head
, changed
);
611 mount_points_list_free(&dm_list_head
);