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) {
411 /* If we are in a container, don't attempt to
412 read-only mount anything as that brings no real
413 benefits, but might confuse the host, as we remount
414 the superblock here, not the bind mound. */
415 if (detect_container(NULL) <= 0) {
416 /* We always try to remount directories
417 * read-only first, before we go on and umount
420 * Mount points can be stacked. If a mount
421 * point is stacked below / or /usr, we
422 * cannnot umount or remount it directly,
423 * since there is no way to refer to the
424 * underlying mount. There's nothing we can do
425 * about it for the general case, but we can
426 * do something about it if it is aliased
427 * somehwere else via a bind mount. If we
428 * explicitly remount the super block of that
429 * alias read-only we hence should be
430 * relatively safe regarding keeping the fs we
431 * can otherwise not see dirty. */
432 mount(NULL, m->path, NULL, MS_REMOUNT|MS_RDONLY, NULL);
435 /* Skip / and /usr since we cannot unmount that
436 * anyway, since we are running from it */
437 if (path_equal(m->path, "/")
438 #ifndef HAVE_SPLIT_USR
439 || path_equal(m->path, "/usr")
446 /* Trying to umount. Forcing to umount if busy (only for NFS mounts) */
447 if (umount2(m->path, MNT_FORCE) == 0) {
448 log_info("Unmounted %s.", m->path);
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 if (swapoff(m->path) == 0) {
473 mount_point_free(head, m);
475 log_warning("Could not deactivate swap %s: %m", m->path);
483 static int loopback_points_list_detach(MountPoint **head, bool *changed) {
490 k = lstat("/", &root_st);
492 LIST_FOREACH_SAFE(mount_point, m, n, *head) {
494 struct stat loopback_st;
497 major(root_st.st_dev) != 0 &&
498 lstat(m->path, &loopback_st) >= 0 &&
499 root_st.st_dev == loopback_st.st_rdev) {
504 if ((r = delete_loopback(m->path)) >= 0) {
506 if (r > 0 && changed)
509 mount_point_free(head, m);
511 log_warning("Could not delete loopback %s: %m", m->path);
519 static int dm_points_list_detach(MountPoint **head, bool *changed) {
526 k = lstat("/", &root_st);
528 LIST_FOREACH_SAFE(mount_point, m, n, *head) {
532 major(root_st.st_dev) != 0 &&
533 root_st.st_dev == m->devnum) {
538 if ((r = delete_dm(m->devnum)) >= 0) {
540 if (r > 0 && changed)
543 mount_point_free(head, m);
545 log_warning("Could not delete dm %s: %m", m->path);
553 int umount_all(bool *changed) {
556 LIST_HEAD(MountPoint, mp_list_head);
558 LIST_HEAD_INIT(MountPoint, mp_list_head);
559 r = mount_points_list_get(&mp_list_head);
563 /* retry umount, until nothing can be umounted anymore */
565 umount_changed = false;
567 mount_points_list_umount(&mp_list_head, &umount_changed, false);
571 } while (umount_changed);
573 /* umount one more time with logging enabled */
574 r = mount_points_list_umount(&mp_list_head, &umount_changed, true);
579 mount_points_list_free(&mp_list_head);
584 int swapoff_all(bool *changed) {
586 LIST_HEAD(MountPoint, swap_list_head);
588 LIST_HEAD_INIT(MountPoint, swap_list_head);
590 r = swap_list_get(&swap_list_head);
594 r = swap_points_list_off(&swap_list_head, changed);
597 mount_points_list_free(&swap_list_head);
602 int loopback_detach_all(bool *changed) {
604 LIST_HEAD(MountPoint, loopback_list_head);
606 LIST_HEAD_INIT(MountPoint, loopback_list_head);
608 r = loopback_list_get(&loopback_list_head);
612 r = loopback_points_list_detach(&loopback_list_head, changed);
615 mount_points_list_free(&loopback_list_head);
620 int dm_detach_all(bool *changed) {
622 LIST_HEAD(MountPoint, dm_list_head);
624 LIST_HEAD_INIT(MountPoint, dm_list_head);
626 r = dm_list_get(&dm_list_head);
630 r = dm_points_list_detach(&dm_list_head, changed);
633 mount_points_list_free(&dm_list_head);