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/>.
25 #include <sys/mount.h>
28 #include <linux/loop.h>
29 #include <linux/dm-ioctl.h>
33 #include "mount-setup.h"
35 #include "path-util.h"
39 typedef struct MountPoint {
42 LIST_FIELDS (struct MountPoint, mount_point);
45 static void mount_point_free(MountPoint **head, MountPoint *m) {
49 LIST_REMOVE(MountPoint, mount_point, *head, m);
55 static void mount_points_list_free(MountPoint **head) {
59 mount_point_free(head, *head);
62 static int mount_points_list_get(MountPoint **head) {
63 FILE *proc_self_mountinfo;
70 if (!(proc_self_mountinfo = fopen("/proc/self/mountinfo", "re")))
79 if ((k = fscanf(proc_self_mountinfo,
80 "%*s " /* (1) mount id */
81 "%*s " /* (2) parent id */
82 "%*s " /* (3) major:minor */
84 "%ms " /* (5) mount point */
85 "%*s" /* (6) mount options */
86 "%*[^-]" /* (7) optional fields */
87 "- " /* (8) separator */
88 "%*s " /* (9) file system type */
89 "%*s" /* (10) mount source */
90 "%*s" /* (11) mount options 2 */
91 "%*[^\n]", /* some rubbish at the end */
96 log_warning("Failed to parse /proc/self/mountinfo:%u.", i);
110 /* Ignore mount points we can't unmount because they
111 * are API or because we are keeping them open (like
113 if (mount_point_is_api(p) ||
114 mount_point_ignore(p) ||
115 path_equal(p, "/dev/console")) {
120 if (!(m = new0(MountPoint, 1))) {
127 LIST_PREPEND(MountPoint, mount_point, *head, m);
133 fclose(proc_self_mountinfo);
138 static int swap_list_get(MountPoint **head) {
145 if (!(proc_swaps = fopen("/proc/swaps", "re")))
146 return (errno == ENOENT) ? 0 : -errno;
148 (void) fscanf(proc_swaps, "%*s %*s %*s %*s %*s\n");
152 char *dev = NULL, *d;
155 if ((k = fscanf(proc_swaps,
156 "%ms " /* device/file */
157 "%*s " /* type of swap */
158 "%*s " /* swap size */
160 "%*s\n", /* priority */
166 log_warning("Failed to parse /proc/swaps:%u.", i);
172 if (endswith(dev, "(deleted)")) {
185 if (!(swap = new0(MountPoint, 1))) {
192 LIST_PREPEND(MountPoint, mount_point, *head, swap);
203 static int loopback_list_get(MountPoint **head) {
206 struct udev_enumerate *e = NULL;
207 struct udev_list_entry *item = NULL, *first = NULL;
211 if (!(udev = udev_new())) {
216 if (!(e = udev_enumerate_new(udev))) {
221 if (udev_enumerate_add_match_subsystem(e, "block") < 0 ||
222 udev_enumerate_add_match_sysname(e, "loop*") < 0 ||
223 udev_enumerate_add_match_sysattr(e, "loop/backing_file", NULL) < 0) {
228 if (udev_enumerate_scan_devices(e) < 0) {
233 first = udev_enumerate_get_list_entry(e);
234 udev_list_entry_foreach(item, first) {
236 struct udev_device *d;
240 if (!(d = udev_device_new_from_syspath(udev, udev_list_entry_get_name(item)))) {
245 if (!(dn = udev_device_get_devnode(d))) {
246 udev_device_unref(d);
251 udev_device_unref(d);
258 if (!(lb = new0(MountPoint, 1))) {
265 LIST_PREPEND(MountPoint, mount_point, *head, lb);
272 udev_enumerate_unref(e);
280 static int dm_list_get(MountPoint **head) {
283 struct udev_enumerate *e = NULL;
284 struct udev_list_entry *item = NULL, *first = NULL;
288 if (!(udev = udev_new())) {
293 if (!(e = udev_enumerate_new(udev))) {
298 if (udev_enumerate_add_match_subsystem(e, "block") < 0 ||
299 udev_enumerate_add_match_sysname(e, "dm-*") < 0) {
304 if (udev_enumerate_scan_devices(e) < 0) {
309 first = udev_enumerate_get_list_entry(e);
311 udev_list_entry_foreach(item, first) {
313 struct udev_device *d;
318 if (!(d = udev_device_new_from_syspath(udev, udev_list_entry_get_name(item)))) {
323 devnum = udev_device_get_devnum(d);
324 dn = udev_device_get_devnode(d);
326 if (major(devnum) == 0 || !dn) {
327 udev_device_unref(d);
332 udev_device_unref(d);
339 if (!(m = new(MountPoint, 1))) {
347 LIST_PREPEND(MountPoint, mount_point, *head, m);
354 udev_enumerate_unref(e);
362 static int delete_loopback(const char *device) {
365 if ((fd = open(device, O_RDONLY|O_CLOEXEC)) < 0)
366 return errno == ENOENT ? 0 : -errno;
368 r = ioctl(fd, LOOP_CLR_FD, 0);
369 close_nointr_nofail(fd);
374 /* ENXIO: not bound, so no error */
381 static int delete_dm(dev_t devnum) {
382 int _cleanup_close_ fd = -1;
384 struct dm_ioctl dm = {
385 .version = {DM_VERSION_MAJOR,
387 DM_VERSION_PATCHLEVEL},
388 .data_size = sizeof(dm),
392 assert(major(devnum) != 0);
394 fd = open("/dev/mapper/control", O_RDWR|O_CLOEXEC);
398 r = ioctl(fd, DM_DEV_REMOVE, &dm);
399 return r >= 0 ? 0 : -errno;
402 static int mount_points_list_umount(MountPoint **head, bool *changed, bool log_error) {
408 LIST_FOREACH_SAFE(mount_point, m, n, *head) {
410 /* If we are in a container, don't attempt to
411 read-only mount anything as that brings no real
412 benefits, but might confuse the host, as we remount
413 the superblock here, not the bind mound. */
414 if (detect_container(NULL) <= 0) {
415 /* We always try to remount directories
416 * read-only first, before we go on and umount
419 * Mount points can be stacked. If a mount
420 * point is stacked below / or /usr, we
421 * cannot umount or remount it directly,
422 * since there is no way to refer to the
423 * underlying mount. There's nothing we can do
424 * about it for the general case, but we can
425 * do something about it if it is aliased
426 * somehwere else via a bind mount. If we
427 * explicitly remount the super block of that
428 * alias read-only we hence should be
429 * relatively safe regarding keeping the fs we
430 * can otherwise not see dirty. */
431 mount(NULL, m->path, NULL, MS_REMOUNT|MS_RDONLY, NULL);
434 /* Skip / and /usr since we cannot unmount that
435 * anyway, since we are running from it. They have
436 * already been remounted ro. */
437 if (path_equal(m->path, "/")
438 #ifndef HAVE_SPLIT_USR
439 || path_equal(m->path, "/usr")
444 /* Trying to umount. We don't force here since we rely
445 * on busy NFS and FUSE file systems to return EBUSY
446 * until we closed everything on top of them. */
447 log_info("Unmounting %s.", m->path);
448 if (umount2(m->path, 0) == 0) {
452 mount_point_free(head, m);
453 } else if (log_error) {
454 log_warning("Could not unmount %s: %m", m->path);
462 static int swap_points_list_off(MountPoint **head, bool *changed) {
468 LIST_FOREACH_SAFE(mount_point, m, n, *head) {
469 log_info("Deactivating swap %s.", m->path);
470 if (swapoff(m->path) == 0) {
474 mount_point_free(head, m);
476 log_warning("Could not deactivate swap %s: %m", m->path);
484 static int loopback_points_list_detach(MountPoint **head, bool *changed) {
491 k = lstat("/", &root_st);
493 LIST_FOREACH_SAFE(mount_point, m, n, *head) {
495 struct stat loopback_st;
498 major(root_st.st_dev) != 0 &&
499 lstat(m->path, &loopback_st) >= 0 &&
500 root_st.st_dev == loopback_st.st_rdev) {
505 log_info("Detaching loopback %s.", m->path);
506 r = delete_loopback(m->path);
508 if (r > 0 && changed)
511 mount_point_free(head, m);
513 log_warning("Could not detach loopback %s: %m", m->path);
521 static int dm_points_list_detach(MountPoint **head, bool *changed) {
528 k = lstat("/", &root_st);
530 LIST_FOREACH_SAFE(mount_point, m, n, *head) {
534 major(root_st.st_dev) != 0 &&
535 root_st.st_dev == m->devnum) {
540 log_info("Detaching DM %u:%u.", major(m->devnum), minor(m->devnum));
541 r = delete_dm(m->devnum);
546 mount_point_free(head, m);
548 log_warning("Could not detach DM %s: %m", m->path);
556 int umount_all(bool *changed) {
559 LIST_HEAD(MountPoint, mp_list_head);
561 LIST_HEAD_INIT(MountPoint, mp_list_head);
562 r = mount_points_list_get(&mp_list_head);
566 /* retry umount, until nothing can be umounted anymore */
568 umount_changed = false;
570 mount_points_list_umount(&mp_list_head, &umount_changed, false);
574 } while (umount_changed);
576 /* umount one more time with logging enabled */
577 r = mount_points_list_umount(&mp_list_head, &umount_changed, true);
582 mount_points_list_free(&mp_list_head);
587 int swapoff_all(bool *changed) {
589 LIST_HEAD(MountPoint, swap_list_head);
591 LIST_HEAD_INIT(MountPoint, swap_list_head);
593 r = swap_list_get(&swap_list_head);
597 r = swap_points_list_off(&swap_list_head, changed);
600 mount_points_list_free(&swap_list_head);
605 int loopback_detach_all(bool *changed) {
607 LIST_HEAD(MountPoint, loopback_list_head);
609 LIST_HEAD_INIT(MountPoint, loopback_list_head);
611 r = loopback_list_get(&loopback_list_head);
615 r = loopback_points_list_detach(&loopback_list_head, changed);
618 mount_points_list_free(&loopback_list_head);
623 int dm_detach_all(bool *changed) {
625 LIST_HEAD(MountPoint, dm_list_head);
627 LIST_HEAD_INIT(MountPoint, dm_list_head);
629 r = dm_list_get(&dm_list_head);
633 r = dm_points_list_detach(&dm_list_head, changed);
636 mount_points_list_free(&dm_list_head);