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;
240 if (!(d = udev_device_new_from_syspath(udev, udev_list_entry_get_name(item)))) {
245 backing = udev_device_get_sysattr_value(d, "loop/backing_file");
247 udev_device_unref(d);
251 if (!(dn = udev_device_get_devnode(d))) {
252 udev_device_unref(d);
257 udev_device_unref(d);
264 if (!(lb = new0(MountPoint, 1))) {
271 LIST_PREPEND(MountPoint, mount_point, *head, lb);
278 udev_enumerate_unref(e);
286 static int dm_list_get(MountPoint **head) {
289 struct udev_enumerate *e = NULL;
290 struct udev_list_entry *item = NULL, *first = NULL;
294 if (!(udev = udev_new())) {
299 if (!(e = udev_enumerate_new(udev))) {
304 if (udev_enumerate_add_match_subsystem(e, "block") < 0 ||
305 udev_enumerate_add_match_sysname(e, "dm-*") < 0) {
310 if (udev_enumerate_scan_devices(e) < 0) {
315 first = udev_enumerate_get_list_entry(e);
317 udev_list_entry_foreach(item, first) {
319 struct udev_device *d;
324 if (!(d = udev_device_new_from_syspath(udev, udev_list_entry_get_name(item)))) {
329 devnum = udev_device_get_devnum(d);
330 dn = udev_device_get_devnode(d);
332 if (major(devnum) == 0 || !dn) {
333 udev_device_unref(d);
338 udev_device_unref(d);
345 if (!(m = new(MountPoint, 1))) {
353 LIST_PREPEND(MountPoint, mount_point, *head, m);
360 udev_enumerate_unref(e);
368 static int delete_loopback(const char *device) {
371 if ((fd = open(device, O_RDONLY|O_CLOEXEC)) < 0)
372 return errno == ENOENT ? 0 : -errno;
374 r = ioctl(fd, LOOP_CLR_FD, 0);
375 close_nointr_nofail(fd);
380 /* ENXIO: not bound, so no error */
387 static int delete_dm(dev_t devnum) {
391 assert(major(devnum) != 0);
393 if ((fd = open("/dev/mapper/control", O_RDWR|O_CLOEXEC)) < 0)
397 dm.version[0] = DM_VERSION_MAJOR;
398 dm.version[1] = DM_VERSION_MINOR;
399 dm.version[2] = DM_VERSION_PATCHLEVEL;
401 dm.data_size = sizeof(dm);
404 r = ioctl(fd, DM_DEV_REMOVE, &dm);
405 close_nointr_nofail(fd);
407 return r >= 0 ? 0 : -errno;
410 static int mount_points_list_umount(MountPoint **head, bool *changed, bool log_error) {
416 LIST_FOREACH_SAFE(mount_point, m, n, *head) {
418 /* If we are in a container, don't attempt to
419 read-only mount anything as that brings no real
420 benefits, but might confuse the host, as we remount
421 the superblock here, not the bind mound. */
422 if (detect_container(NULL) <= 0) {
423 /* We always try to remount directories
424 * read-only first, before we go on and umount
427 * Mount points can be stacked. If a mount
428 * point is stacked below / or /usr, we
429 * cannnot umount or remount it directly,
430 * since there is no way to refer to the
431 * underlying mount. There's nothing we can do
432 * about it for the general case, but we can
433 * do something about it if it is aliased
434 * somehwere else via a bind mount. If we
435 * explicitly remount the super block of that
436 * alias read-only we hence should be
437 * relatively safe regarding keeping the fs we
438 * can otherwise not see dirty. */
439 mount(NULL, m->path, NULL, MS_REMOUNT|MS_RDONLY, NULL);
442 /* Skip / and /usr since we cannot unmount that
443 * anyway, since we are running from it. They have
444 * already been remounted ro. */
445 if (path_equal(m->path, "/")
446 #ifndef HAVE_SPLIT_USR
447 || path_equal(m->path, "/usr")
452 /* Trying to umount. We don't force here since we rely
453 * on busy NFS and FUSE file systems to return EBUSY
454 * until we closed everything on top of them. */
455 log_info("Unmounting %s.", m->path);
456 if (umount2(m->path, 0) == 0) {
460 mount_point_free(head, m);
461 } else if (log_error) {
462 log_warning("Could not unmount %s: %m", m->path);
470 static int swap_points_list_off(MountPoint **head, bool *changed) {
476 LIST_FOREACH_SAFE(mount_point, m, n, *head) {
477 log_info("Deactivating swap %s.", m->path);
478 if (swapoff(m->path) == 0) {
482 mount_point_free(head, m);
484 log_warning("Could not deactivate swap %s: %m", m->path);
492 static int loopback_points_list_detach(MountPoint **head, bool *changed) {
499 k = lstat("/", &root_st);
501 LIST_FOREACH_SAFE(mount_point, m, n, *head) {
503 struct stat loopback_st;
506 major(root_st.st_dev) != 0 &&
507 lstat(m->path, &loopback_st) >= 0 &&
508 root_st.st_dev == loopback_st.st_rdev) {
513 log_info("Detaching loopback %s.", m->path);
514 r = delete_loopback(m->path);
516 if (r > 0 && changed)
519 mount_point_free(head, m);
521 log_warning("Could not detach loopback %s: %m", m->path);
529 static int dm_points_list_detach(MountPoint **head, bool *changed) {
536 k = lstat("/", &root_st);
538 LIST_FOREACH_SAFE(mount_point, m, n, *head) {
542 major(root_st.st_dev) != 0 &&
543 root_st.st_dev == m->devnum) {
548 log_info("Detaching DM %u:%u.", major(m->devnum), minor(m->devnum));
549 r = delete_dm(m->devnum);
554 mount_point_free(head, m);
556 log_warning("Could not detach DM %s: %m", m->path);
564 int umount_all(bool *changed) {
567 LIST_HEAD(MountPoint, mp_list_head);
569 LIST_HEAD_INIT(MountPoint, mp_list_head);
570 r = mount_points_list_get(&mp_list_head);
574 /* retry umount, until nothing can be umounted anymore */
576 umount_changed = false;
578 mount_points_list_umount(&mp_list_head, &umount_changed, false);
582 } while (umount_changed);
584 /* umount one more time with logging enabled */
585 r = mount_points_list_umount(&mp_list_head, &umount_changed, true);
590 mount_points_list_free(&mp_list_head);
595 int swapoff_all(bool *changed) {
597 LIST_HEAD(MountPoint, swap_list_head);
599 LIST_HEAD_INIT(MountPoint, swap_list_head);
601 r = swap_list_get(&swap_list_head);
605 r = swap_points_list_off(&swap_list_head, changed);
608 mount_points_list_free(&swap_list_head);
613 int loopback_detach_all(bool *changed) {
615 LIST_HEAD(MountPoint, loopback_list_head);
617 LIST_HEAD_INIT(MountPoint, loopback_list_head);
619 r = loopback_list_get(&loopback_list_head);
623 r = loopback_points_list_detach(&loopback_list_head, changed);
626 mount_points_list_free(&loopback_list_head);
631 int dm_detach_all(bool *changed) {
633 LIST_HEAD(MountPoint, dm_list_head);
635 LIST_HEAD_INIT(MountPoint, dm_list_head);
637 r = dm_list_get(&dm_list_head);
641 r = dm_points_list_detach(&dm_list_head, changed);
644 mount_points_list_free(&dm_list_head);