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"
38 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")))
81 if ((k = fscanf(proc_self_mountinfo,
82 "%*s " /* (1) mount id */
83 "%*s " /* (2) parent id */
84 "%*s " /* (3) major:minor */
86 "%ms " /* (5) mount point */
87 "%*s" /* (6) mount options */
88 "%*[^-]" /* (7) optional fields */
89 "- " /* (8) separator */
90 "%*s " /* (9) file system type */
91 "%*s" /* (10) mount source */
92 "%*s" /* (11) mount options 2 */
93 "%*[^\n]", /* some rubbish at the end */
99 log_warning("Failed to parse /proc/self/mountinfo:%u.", i);
105 /* If we encounter a bind mount, don't try to remount
106 * the source dir too early */
107 skip_ro = !streq(root, "/");
118 /* Ignore mount points we can't unmount because they
119 * are API or because we are keeping them open (like
121 if (mount_point_is_api(p) ||
122 mount_point_ignore(p) ||
123 path_equal(p, "/dev/console")) {
128 if (!(m = new0(MountPoint, 1))) {
135 m->skip_ro = skip_ro;
136 LIST_PREPEND(MountPoint, mount_point, *head, m);
142 fclose(proc_self_mountinfo);
147 static int swap_list_get(MountPoint **head) {
154 if (!(proc_swaps = fopen("/proc/swaps", "re")))
155 return (errno == ENOENT) ? 0 : -errno;
157 (void) fscanf(proc_swaps, "%*s %*s %*s %*s %*s\n");
161 char *dev = NULL, *d;
164 if ((k = fscanf(proc_swaps,
165 "%ms " /* device/file */
166 "%*s " /* type of swap */
167 "%*s " /* swap size */
169 "%*s\n", /* priority */
175 log_warning("Failed to parse /proc/swaps:%u.", i);
181 if (endswith(dev, "(deleted)")) {
194 if (!(swap = new0(MountPoint, 1))) {
201 LIST_PREPEND(MountPoint, mount_point, *head, swap);
212 static int loopback_list_get(MountPoint **head) {
215 struct udev_enumerate *e = NULL;
216 struct udev_list_entry *item = NULL, *first = NULL;
220 if (!(udev = udev_new())) {
225 if (!(e = udev_enumerate_new(udev))) {
230 if (udev_enumerate_add_match_subsystem(e, "block") < 0 ||
231 udev_enumerate_add_match_sysname(e, "loop*") < 0) {
236 if (udev_enumerate_scan_devices(e) < 0) {
241 first = udev_enumerate_get_list_entry(e);
242 udev_list_entry_foreach(item, first) {
244 struct udev_device *d;
248 if (!(d = udev_device_new_from_syspath(udev, udev_list_entry_get_name(item)))) {
253 if (!(dn = udev_device_get_devnode(d))) {
254 udev_device_unref(d);
259 udev_device_unref(d);
266 if (!(lb = new0(MountPoint, 1))) {
273 LIST_PREPEND(MountPoint, mount_point, *head, lb);
280 udev_enumerate_unref(e);
288 static int dm_list_get(MountPoint **head) {
291 struct udev_enumerate *e = NULL;
292 struct udev_list_entry *item = NULL, *first = NULL;
296 if (!(udev = udev_new())) {
301 if (!(e = udev_enumerate_new(udev))) {
306 if (udev_enumerate_add_match_subsystem(e, "block") < 0 ||
307 udev_enumerate_add_match_sysname(e, "dm-*") < 0) {
312 if (udev_enumerate_scan_devices(e) < 0) {
317 first = udev_enumerate_get_list_entry(e);
319 udev_list_entry_foreach(item, first) {
321 struct udev_device *d;
326 if (!(d = udev_device_new_from_syspath(udev, udev_list_entry_get_name(item)))) {
331 devnum = udev_device_get_devnum(d);
332 dn = udev_device_get_devnode(d);
334 if (major(devnum) == 0 || !dn) {
335 udev_device_unref(d);
340 udev_device_unref(d);
347 if (!(m = new(MountPoint, 1))) {
355 LIST_PREPEND(MountPoint, mount_point, *head, m);
362 udev_enumerate_unref(e);
370 static int delete_loopback(const char *device) {
373 if ((fd = open(device, O_RDONLY|O_CLOEXEC)) < 0)
374 return errno == ENOENT ? 0 : -errno;
376 r = ioctl(fd, LOOP_CLR_FD, 0);
377 close_nointr_nofail(fd);
382 /* ENXIO: not bound, so no error */
389 static int delete_dm(dev_t devnum) {
393 assert(major(devnum) != 0);
395 if ((fd = open("/dev/mapper/control", O_RDWR|O_CLOEXEC)) < 0)
399 dm.version[0] = DM_VERSION_MAJOR;
400 dm.version[1] = DM_VERSION_MINOR;
401 dm.version[2] = DM_VERSION_PATCHLEVEL;
403 dm.data_size = sizeof(dm);
406 r = ioctl(fd, DM_DEV_REMOVE, &dm);
407 close_nointr_nofail(fd);
409 return r >= 0 ? 0 : -errno;
412 static int mount_points_list_umount(MountPoint **head, bool *changed, bool log_error) {
418 LIST_FOREACH_SAFE(mount_point, m, n, *head) {
419 if (path_equal(m->path, "/")
420 #ifndef HAVE_SPLIT_USR
421 || path_equal(m->path, "/usr")
428 /* Trying to umount. Forcing to umount if busy (only for NFS mounts) */
429 if (umount2(m->path, MNT_FORCE) == 0) {
430 log_info("Unmounted %s.", m->path);
434 mount_point_free(head, m);
435 } else if (log_error) {
436 log_warning("Could not unmount %s: %m", m->path);
444 static int mount_points_list_remount_read_only(MountPoint **head, bool *changed) {
450 LIST_FOREACH_SAFE(mount_point, m, n, *head) {
457 /* Trying to remount read-only */
458 if (mount(NULL, m->path, NULL, MS_MGC_VAL|MS_REMOUNT|MS_RDONLY, NULL) == 0) {
462 mount_point_free(head, m);
464 log_warning("Could not remount as read-only %s: %m", m->path);
472 static int swap_points_list_off(MountPoint **head, bool *changed) {
478 LIST_FOREACH_SAFE(mount_point, m, n, *head) {
479 if (swapoff(m->path) == 0) {
483 mount_point_free(head, m);
485 log_warning("Could not deactivate swap %s: %m", m->path);
493 static int loopback_points_list_detach(MountPoint **head, bool *changed) {
500 k = lstat("/", &root_st);
502 LIST_FOREACH_SAFE(mount_point, m, n, *head) {
504 struct stat loopback_st;
507 major(root_st.st_dev) != 0 &&
508 lstat(m->path, &loopback_st) >= 0 &&
509 root_st.st_dev == loopback_st.st_rdev) {
514 if ((r = delete_loopback(m->path)) >= 0) {
516 if (r > 0 && changed)
519 mount_point_free(head, m);
521 log_warning("Could not delete 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 if ((r = delete_dm(m->devnum)) >= 0) {
550 if (r > 0 && changed)
553 mount_point_free(head, m);
555 log_warning("Could not delete dm %s: %m", m->path);
563 int umount_all(bool *changed) {
567 LIST_HEAD(MountPoint, mp_list_head);
569 LIST_HEAD_INIT(MountPoint, mp_list_head);
571 r = mount_points_list_get(&mp_list_head);
575 /* retry umount, until nothing can be umounted anymore */
577 umount_changed = false;
579 mount_points_list_umount(&mp_list_head, &umount_changed, false);
583 } while (umount_changed);
585 /* umount one more time with logging enabled */
586 r = mount_points_list_umount(&mp_list_head, &umount_changed, true);
590 r = mount_points_list_remount_read_only(&mp_list_head, changed);
593 mount_points_list_free(&mp_list_head);
598 int swapoff_all(bool *changed) {
600 LIST_HEAD(MountPoint, swap_list_head);
602 LIST_HEAD_INIT(MountPoint, swap_list_head);
604 r = swap_list_get(&swap_list_head);
608 r = swap_points_list_off(&swap_list_head, changed);
611 mount_points_list_free(&swap_list_head);
616 int loopback_detach_all(bool *changed) {
618 LIST_HEAD(MountPoint, loopback_list_head);
620 LIST_HEAD_INIT(MountPoint, loopback_list_head);
622 r = loopback_list_get(&loopback_list_head);
626 r = loopback_points_list_detach(&loopback_list_head, changed);
629 mount_points_list_free(&loopback_list_head);
634 int dm_detach_all(bool *changed) {
636 LIST_HEAD(MountPoint, dm_list_head);
638 LIST_HEAD_INIT(MountPoint, dm_list_head);
640 r = dm_list_get(&dm_list_head);
644 r = dm_points_list_detach(&dm_list_head, changed);
647 mount_points_list_free(&dm_list_head);