]>
git.ipfire.org Git - thirdparty/systemd.git/blob - src/umount.c
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 General Public License as published by
10 the Free Software Foundation; either version 2 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 General Public License for more details.
18 You should have received a copy of the GNU 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"
37 typedef struct MountPoint
{
41 LIST_FIELDS (struct MountPoint
, mount_point
);
44 static void mount_point_free(MountPoint
**head
, MountPoint
*m
) {
48 LIST_REMOVE(MountPoint
, mount_point
, *head
, m
);
54 static void mount_points_list_free(MountPoint
**head
) {
58 mount_point_free(head
, *head
);
61 static int mount_points_list_get(MountPoint
**head
) {
62 FILE *proc_self_mountinfo
;
69 if (!(proc_self_mountinfo
= fopen("/proc/self/mountinfo", "re")))
80 if ((k
= fscanf(proc_self_mountinfo
,
81 "%*s " /* (1) mount id */
82 "%*s " /* (2) parent id */
83 "%*s " /* (3) major:minor */
85 "%ms " /* (5) mount point */
86 "%*s" /* (6) mount options */
87 "%*[^-]" /* (7) optional fields */
88 "- " /* (8) separator */
89 "%*s " /* (9) file system type */
90 "%*s" /* (10) mount source */
91 "%*s" /* (11) mount options 2 */
92 "%*[^\n]", /* some rubbish at the end */
98 log_warning("Failed to parse /proc/self/mountinfo:%u.", i
);
104 /* If we encounter a bind mount, don't try to remount
105 * the source dir too early */
106 skip_ro
= !streq(root
, "/");
117 if (mount_point_is_api(p
) || mount_point_ignore(p
)) {
122 if (!(m
= new0(MountPoint
, 1))) {
129 m
->skip_ro
= skip_ro
;
130 LIST_PREPEND(MountPoint
, mount_point
, *head
, m
);
136 fclose(proc_self_mountinfo
);
141 static int swap_list_get(MountPoint
**head
) {
148 if (!(proc_swaps
= fopen("/proc/swaps", "re")))
149 return (errno
== ENOENT
) ? 0 : -errno
;
151 (void) fscanf(proc_swaps
, "%*s %*s %*s %*s %*s\n");
155 char *dev
= NULL
, *d
;
158 if ((k
= fscanf(proc_swaps
,
159 "%ms " /* device/file */
160 "%*s " /* type of swap */
161 "%*s " /* swap size */
163 "%*s\n", /* priority */
169 log_warning("Failed to parse /proc/swaps:%u.", i
);
175 if (endswith(dev
, "(deleted)")) {
188 if (!(swap
= new0(MountPoint
, 1))) {
195 LIST_PREPEND(MountPoint
, mount_point
, *head
, swap
);
206 static int loopback_list_get(MountPoint
**head
) {
209 struct udev_enumerate
*e
= NULL
;
210 struct udev_list_entry
*item
= NULL
, *first
= NULL
;
214 if (!(udev
= udev_new())) {
219 if (!(e
= udev_enumerate_new(udev
))) {
224 if (udev_enumerate_add_match_subsystem(e
, "block") < 0 ||
225 udev_enumerate_add_match_sysname(e
, "loop*") < 0) {
230 if (udev_enumerate_scan_devices(e
) < 0) {
235 first
= udev_enumerate_get_list_entry(e
);
236 udev_list_entry_foreach(item
, first
) {
238 struct udev_device
*d
;
242 if (!(d
= udev_device_new_from_syspath(udev
, udev_list_entry_get_name(item
)))) {
247 if (!(dn
= udev_device_get_devnode(d
))) {
248 udev_device_unref(d
);
253 udev_device_unref(d
);
260 if (!(lb
= new0(MountPoint
, 1))) {
267 LIST_PREPEND(MountPoint
, mount_point
, *head
, lb
);
274 udev_enumerate_unref(e
);
282 static int dm_list_get(MountPoint
**head
) {
285 struct udev_enumerate
*e
= NULL
;
286 struct udev_list_entry
*item
= NULL
, *first
= NULL
;
290 if (!(udev
= udev_new())) {
295 if (!(e
= udev_enumerate_new(udev
))) {
300 if (udev_enumerate_add_match_subsystem(e
, "block") < 0 ||
301 udev_enumerate_add_match_sysname(e
, "dm-*") < 0) {
306 if (udev_enumerate_scan_devices(e
) < 0) {
311 first
= udev_enumerate_get_list_entry(e
);
313 udev_list_entry_foreach(item
, first
) {
315 struct udev_device
*d
;
320 if (!(d
= udev_device_new_from_syspath(udev
, udev_list_entry_get_name(item
)))) {
325 devnum
= udev_device_get_devnum(d
);
326 dn
= udev_device_get_devnode(d
);
328 if (major(devnum
) == 0 || !dn
) {
329 udev_device_unref(d
);
334 udev_device_unref(d
);
341 if (!(m
= new(MountPoint
, 1))) {
349 LIST_PREPEND(MountPoint
, mount_point
, *head
, m
);
356 udev_enumerate_unref(e
);
364 static int delete_loopback(const char *device
) {
367 if ((fd
= open(device
, O_RDONLY
|O_CLOEXEC
)) < 0)
368 return errno
== ENOENT
? 0 : -errno
;
370 r
= ioctl(fd
, LOOP_CLR_FD
, 0);
371 close_nointr_nofail(fd
);
376 /* ENXIO: not bound, so no error */
383 static int delete_dm(dev_t devnum
) {
387 assert(major(devnum
) != 0);
389 if ((fd
= open("/dev/mapper/control", O_RDWR
|O_CLOEXEC
)) < 0)
393 dm
.version
[0] = DM_VERSION_MAJOR
;
394 dm
.version
[1] = DM_VERSION_MINOR
;
395 dm
.version
[2] = DM_VERSION_PATCHLEVEL
;
397 dm
.data_size
= sizeof(dm
);
400 r
= ioctl(fd
, DM_DEV_REMOVE
, &dm
);
401 close_nointr_nofail(fd
);
403 return r
>= 0 ? 0 : -errno
;
406 static int mount_points_list_umount(MountPoint
**head
, bool *changed
, bool log_error
) {
412 LIST_FOREACH_SAFE(mount_point
, m
, n
, *head
) {
413 if (streq(m
->path
, "/")) {
418 /* Trying to umount. Forcing to umount if busy (only for NFS mounts) */
419 if (umount2(m
->path
, MNT_FORCE
) == 0) {
420 log_info("Unmounted %s.", m
->path
);
424 mount_point_free(head
, m
);
425 } else if (log_error
) {
426 log_warning("Could not unmount %s: %m", m
->path
);
434 static int mount_points_list_remount_read_only(MountPoint
**head
, bool *changed
) {
440 LIST_FOREACH_SAFE(mount_point
, m
, n
, *head
) {
447 /* Trying to remount read-only */
448 if (mount(NULL
, m
->path
, NULL
, MS_MGC_VAL
|MS_REMOUNT
|MS_RDONLY
, NULL
) == 0) {
452 mount_point_free(head
, m
);
454 log_warning("Could not remount as read-only %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
) {
557 LIST_HEAD(MountPoint
, mp_list_head
);
559 LIST_HEAD_INIT(MountPoint
, mp_list_head
);
561 r
= mount_points_list_get(&mp_list_head
);
565 /* retry umount, until nothing can be umounted anymore */
567 umount_changed
= false;
568 r
= mount_points_list_umount(&mp_list_head
, &umount_changed
, false);
571 } while(umount_changed
);
572 /* umount one more time with logging enabled */
573 r
= mount_points_list_umount(&mp_list_head
, &umount_changed
, true);
577 r
= mount_points_list_remount_read_only(&mp_list_head
, changed
);
580 mount_points_list_free(&mp_list_head
);
585 int swapoff_all(bool *changed
) {
587 LIST_HEAD(MountPoint
, swap_list_head
);
589 LIST_HEAD_INIT(MountPoint
, swap_list_head
);
591 r
= swap_list_get(&swap_list_head
);
595 r
= swap_points_list_off(&swap_list_head
, changed
);
598 mount_points_list_free(&swap_list_head
);
603 int loopback_detach_all(bool *changed
) {
605 LIST_HEAD(MountPoint
, loopback_list_head
);
607 LIST_HEAD_INIT(MountPoint
, loopback_list_head
);
609 r
= loopback_list_get(&loopback_list_head
);
613 r
= loopback_points_list_detach(&loopback_list_head
, changed
);
616 mount_points_list_free(&loopback_list_head
);
621 int dm_detach_all(bool *changed
) {
623 LIST_HEAD(MountPoint
, dm_list_head
);
625 LIST_HEAD_INIT(MountPoint
, dm_list_head
);
627 r
= dm_list_get(&dm_list_head
);
631 r
= dm_points_list_detach(&dm_list_head
, changed
);
634 mount_points_list_free(&dm_list_head
);