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) {
227 if (udev_enumerate_scan_devices(e) < 0) {
232 first = udev_enumerate_get_list_entry(e);
233 udev_list_entry_foreach(item, first) {
235 struct udev_device *d;
239 if (!(d = udev_device_new_from_syspath(udev, udev_list_entry_get_name(item)))) {
244 if (!(dn = udev_device_get_devnode(d))) {
245 udev_device_unref(d);
250 udev_device_unref(d);
257 if (!(lb = new0(MountPoint, 1))) {
264 LIST_PREPEND(MountPoint, mount_point, *head, lb);
271 udev_enumerate_unref(e);
279 static int dm_list_get(MountPoint **head) {
282 struct udev_enumerate *e = NULL;
283 struct udev_list_entry *item = NULL, *first = NULL;
287 if (!(udev = udev_new())) {
292 if (!(e = udev_enumerate_new(udev))) {
297 if (udev_enumerate_add_match_subsystem(e, "block") < 0 ||
298 udev_enumerate_add_match_sysname(e, "dm-*") < 0) {
303 if (udev_enumerate_scan_devices(e) < 0) {
308 first = udev_enumerate_get_list_entry(e);
310 udev_list_entry_foreach(item, first) {
312 struct udev_device *d;
317 if (!(d = udev_device_new_from_syspath(udev, udev_list_entry_get_name(item)))) {
322 devnum = udev_device_get_devnum(d);
323 dn = udev_device_get_devnode(d);
325 if (major(devnum) == 0 || !dn) {
326 udev_device_unref(d);
331 udev_device_unref(d);
338 if (!(m = new(MountPoint, 1))) {
346 LIST_PREPEND(MountPoint, mount_point, *head, m);
353 udev_enumerate_unref(e);
361 static int delete_loopback(const char *device) {
364 if ((fd = open(device, O_RDONLY|O_CLOEXEC)) < 0)
365 return errno == ENOENT ? 0 : -errno;
367 r = ioctl(fd, LOOP_CLR_FD, 0);
368 close_nointr_nofail(fd);
373 /* ENXIO: not bound, so no error */
380 static int delete_dm(dev_t devnum) {
384 assert(major(devnum) != 0);
386 if ((fd = open("/dev/mapper/control", O_RDWR|O_CLOEXEC)) < 0)
390 dm.version[0] = DM_VERSION_MAJOR;
391 dm.version[1] = DM_VERSION_MINOR;
392 dm.version[2] = DM_VERSION_PATCHLEVEL;
394 dm.data_size = sizeof(dm);
397 r = ioctl(fd, DM_DEV_REMOVE, &dm);
398 close_nointr_nofail(fd);
400 return r >= 0 ? 0 : -errno;
403 static int mount_points_list_umount(MountPoint **head, bool *changed, bool log_error) {
409 LIST_FOREACH_SAFE(mount_point, m, n, *head) {
410 if (path_equal(m->path, "/")
411 #ifndef HAVE_SPLIT_USR
412 || path_equal(m->path, "/usr")
419 /* Trying to umount. Forcing to umount if busy (only for NFS mounts) */
420 if (umount2(m->path, MNT_FORCE) == 0) {
421 log_info("Unmounted %s.", m->path);
425 mount_point_free(head, m);
426 } else if (log_error) {
427 log_warning("Could not unmount %s: %m", m->path);
435 static int mount_points_list_remount_read_only(MountPoint **head, bool *changed) {
441 LIST_FOREACH_SAFE(mount_point, m, n, *head) {
443 /* Trying to remount read-only */
444 if (mount(NULL, m->path, NULL, MS_REMOUNT|MS_RDONLY, NULL) == 0) {
448 mount_point_free(head, m);
450 log_warning("Could not remount as read-only %s: %m", m->path);
458 static int swap_points_list_off(MountPoint **head, bool *changed) {
464 LIST_FOREACH_SAFE(mount_point, m, n, *head) {
465 if (swapoff(m->path) == 0) {
469 mount_point_free(head, m);
471 log_warning("Could not deactivate swap %s: %m", m->path);
479 static int loopback_points_list_detach(MountPoint **head, bool *changed) {
486 k = lstat("/", &root_st);
488 LIST_FOREACH_SAFE(mount_point, m, n, *head) {
490 struct stat loopback_st;
493 major(root_st.st_dev) != 0 &&
494 lstat(m->path, &loopback_st) >= 0 &&
495 root_st.st_dev == loopback_st.st_rdev) {
500 if ((r = delete_loopback(m->path)) >= 0) {
502 if (r > 0 && changed)
505 mount_point_free(head, m);
507 log_warning("Could not delete loopback %s: %m", m->path);
515 static int dm_points_list_detach(MountPoint **head, bool *changed) {
522 k = lstat("/", &root_st);
524 LIST_FOREACH_SAFE(mount_point, m, n, *head) {
528 major(root_st.st_dev) != 0 &&
529 root_st.st_dev == m->devnum) {
534 if ((r = delete_dm(m->devnum)) >= 0) {
536 if (r > 0 && changed)
539 mount_point_free(head, m);
541 log_warning("Could not delete dm %s: %m", m->path);
549 int umount_all(bool *changed) {
552 LIST_HEAD(MountPoint, mp_list_head);
554 LIST_HEAD_INIT(MountPoint, mp_list_head);
555 r = mount_points_list_get(&mp_list_head);
559 /* retry umount, until nothing can be umounted anymore */
561 umount_changed = false;
563 mount_points_list_umount(&mp_list_head, &umount_changed, false);
567 } while (umount_changed);
569 /* umount one more time with logging enabled */
570 r = mount_points_list_umount(&mp_list_head, &umount_changed, true);
574 /* If we are in a container, don't attempt to read-only mount
575 anything as that brings no real benefits, but might confuse
576 the host, as we remount the superblock here, not the bind
578 if (detect_container(NULL) <= 0)
579 r = mount_points_list_remount_read_only(&mp_list_head, changed);
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);