]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/core/umount.c
dns-domain: add code for verifying validity of DNS-SD service names and types
[thirdparty/systemd.git] / src / core / umount.c
CommitLineData
e3478379
FF
1/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3/***
4 This file is part of systemd.
5
6 Copyright 2010 ProFUSION embedded systems
7
8 systemd is free software; you can redistribute it and/or modify it
5430f7f2
LP
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
e3478379
FF
11 (at your option) any later version.
12
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
5430f7f2 16 Lesser General Public License for more details.
e3478379 17
5430f7f2 18 You should have received a copy of the GNU Lesser General Public License
e3478379
FF
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
20***/
21
22#include <errno.h>
23#include <fcntl.h>
4f5dd394
LP
24#include <linux/dm-ioctl.h>
25#include <linux/loop.h>
e3478379
FF
26#include <string.h>
27#include <sys/mount.h>
28#include <sys/swap.h>
e3478379 29
b4bbcaa9
TA
30#include "libudev.h"
31
b5efdb8a 32#include "alloc-util.h"
07630cea 33#include "escape.h"
3ffd4af2 34#include "fd-util.h"
471b48ed 35#include "fstab-util.h"
e3478379
FF
36#include "list.h"
37#include "mount-setup.h"
9eb977db 38#include "path-util.h"
07630cea 39#include "string-util.h"
4f5dd394 40#include "udev-util.h"
3ffd4af2 41#include "umount.h"
e3478379 42#include "util.h"
024f268d 43#include "virt.h"
e3478379
FF
44
45typedef struct MountPoint {
46 char *path;
471b48ed 47 char *options;
2d9a3397 48 dev_t devnum;
71fda00f 49 LIST_FIELDS(struct MountPoint, mount_point);
e3478379
FF
50} MountPoint;
51
12aad1d0
LP
52static void mount_point_free(MountPoint **head, MountPoint *m) {
53 assert(head);
54 assert(m);
e3478379 55
71fda00f 56 LIST_REMOVE(mount_point, *head, m);
12aad1d0
LP
57
58 free(m->path);
59 free(m);
e3478379
FF
60}
61
12aad1d0
LP
62static void mount_points_list_free(MountPoint **head) {
63 assert(head);
64
65 while (*head)
66 mount_point_free(head, *head);
e3478379
FF
67}
68
12aad1d0 69static int mount_points_list_get(MountPoint **head) {
c3544e8d 70 _cleanup_fclose_ FILE *proc_self_mountinfo = NULL;
e3478379 71 unsigned int i;
527b7a42 72 int r;
e3478379 73
12aad1d0
LP
74 assert(head);
75
c3544e8d
LP
76 proc_self_mountinfo = fopen("/proc/self/mountinfo", "re");
77 if (!proc_self_mountinfo)
e3478379
FF
78 return -errno;
79
80 for (i = 1;; i++) {
471b48ed 81 _cleanup_free_ char *path = NULL, *options = NULL;
c3544e8d 82 char *p = NULL;
12aad1d0 83 MountPoint *m;
c3544e8d 84 int k;
e3478379 85
c3544e8d
LP
86 k = fscanf(proc_self_mountinfo,
87 "%*s " /* (1) mount id */
88 "%*s " /* (2) parent id */
89 "%*s " /* (3) major:minor */
90 "%*s " /* (4) root */
91 "%ms " /* (5) mount point */
471b48ed 92 "%*s" /* (6) mount flags */
c3544e8d
LP
93 "%*[^-]" /* (7) optional fields */
94 "- " /* (8) separator */
95 "%*s " /* (9) file system type */
96 "%*s" /* (10) mount source */
471b48ed 97 "%ms" /* (11) mount options */
c3544e8d 98 "%*[^\n]", /* some rubbish at the end */
471b48ed
JJ
99 &path, &options);
100 if (k != 2) {
e3478379
FF
101 if (k == EOF)
102 break;
103
104 log_warning("Failed to parse /proc/self/mountinfo:%u.", i);
e3478379
FF
105 continue;
106 }
107
527b7a42
LP
108 r = cunescape(path, UNESCAPE_RELAX, &p);
109 if (r < 0)
110 return r;
e3478379 111
46108b3b
LP
112 /* Ignore mount points we can't unmount because they
113 * are API or because we are keeping them open (like
874d3404
LP
114 * /dev/console). Also, ignore all mounts below API
115 * file systems, since they are likely virtual too,
116 * and hence not worth spending time on. Also, in
117 * unprivileged containers we might lack the rights to
118 * unmount these things, hence don't bother. */
46108b3b
LP
119 if (mount_point_is_api(p) ||
120 mount_point_ignore(p) ||
874d3404
LP
121 path_startswith(p, "/dev") ||
122 path_startswith(p, "/sys") ||
123 path_startswith(p, "/proc")) {
2054a5b8
LP
124 free(p);
125 continue;
126 }
127
c3544e8d
LP
128 m = new0(MountPoint, 1);
129 if (!m) {
2054a5b8 130 free(p);
c3544e8d 131 return -ENOMEM;
e3478379 132 }
e3478379 133
12aad1d0 134 m->path = p;
471b48ed
JJ
135 m->options = options;
136 options = NULL;
137
71fda00f 138 LIST_PREPEND(mount_point, *head, m);
e3478379
FF
139 }
140
c3544e8d 141 return 0;
e3478379
FF
142}
143
12aad1d0 144static int swap_list_get(MountPoint **head) {
e1d75803 145 _cleanup_fclose_ FILE *proc_swaps = NULL;
e3478379 146 unsigned int i;
527b7a42 147 int r;
e3478379 148
12aad1d0
LP
149 assert(head);
150
527b7a42
LP
151 proc_swaps = fopen("/proc/swaps", "re");
152 if (!proc_swaps)
dee87d61 153 return (errno == ENOENT) ? 0 : -errno;
e3478379
FF
154
155 (void) fscanf(proc_swaps, "%*s %*s %*s %*s %*s\n");
156
157 for (i = 2;; i++) {
158 MountPoint *swap;
159 char *dev = NULL, *d;
160 int k;
161
527b7a42
LP
162 k = fscanf(proc_swaps,
163 "%ms " /* device/file */
164 "%*s " /* type of swap */
165 "%*s " /* swap size */
166 "%*s " /* used */
167 "%*s\n", /* priority */
168 &dev);
e3478379 169
527b7a42 170 if (k != 1) {
e3478379
FF
171 if (k == EOF)
172 break;
173
174 log_warning("Failed to parse /proc/swaps:%u.", i);
e3478379
FF
175 free(dev);
176 continue;
177 }
178
a87f0f72 179 if (endswith(dev, " (deleted)")) {
e3478379
FF
180 free(dev);
181 continue;
182 }
183
527b7a42 184 r = cunescape(dev, UNESCAPE_RELAX, &d);
e3478379 185 free(dev);
527b7a42
LP
186 if (r < 0)
187 return r;
e3478379 188
527b7a42
LP
189 swap = new0(MountPoint, 1);
190 if (!swap) {
e3478379 191 free(d);
e1d75803 192 return -ENOMEM;
e3478379
FF
193 }
194
2d9a3397 195 swap->path = d;
71fda00f 196 LIST_PREPEND(mount_point, *head, swap);
e3478379
FF
197 }
198
e1d75803 199 return 0;
e3478379
FF
200}
201
12aad1d0 202static int loopback_list_get(MountPoint **head) {
1ca208fb 203 _cleanup_udev_enumerate_unref_ struct udev_enumerate *e = NULL;
e3478379 204 struct udev_list_entry *item = NULL, *first = NULL;
06acf2d4
LP
205 _cleanup_udev_unref_ struct udev *udev = NULL;
206 int r;
e3478379 207
12aad1d0
LP
208 assert(head);
209
1ca208fb
ZJS
210 udev = udev_new();
211 if (!udev)
212 return -ENOMEM;
e3478379 213
1ca208fb
ZJS
214 e = udev_enumerate_new(udev);
215 if (!e)
216 return -ENOMEM;
e3478379 217
06acf2d4
LP
218 r = udev_enumerate_add_match_subsystem(e, "block");
219 if (r < 0)
220 return r;
221
222 r = udev_enumerate_add_match_sysname(e, "loop*");
223 if (r < 0)
224 return r;
225
226 r = udev_enumerate_add_match_sysattr(e, "loop/backing_file", NULL);
227 if (r < 0)
228 return r;
e3478379 229
06acf2d4
LP
230 r = udev_enumerate_scan_devices(e);
231 if (r < 0)
232 return r;
e3478379
FF
233
234 first = udev_enumerate_get_list_entry(e);
e3478379
FF
235 udev_list_entry_foreach(item, first) {
236 MountPoint *lb;
1ca208fb 237 _cleanup_udev_device_unref_ struct udev_device *d;
e3478379 238 char *loop;
b854a7e7 239 const char *dn;
e3478379 240
1ca208fb
ZJS
241 d = udev_device_new_from_syspath(udev, udev_list_entry_get_name(item));
242 if (!d)
243 return -ENOMEM;
e3478379 244
1ca208fb
ZJS
245 dn = udev_device_get_devnode(d);
246 if (!dn)
2d9a3397 247 continue;
b854a7e7 248
2d9a3397 249 loop = strdup(dn);
1ca208fb
ZJS
250 if (!loop)
251 return -ENOMEM;
b854a7e7 252
1ca208fb
ZJS
253 lb = new0(MountPoint, 1);
254 if (!lb) {
e3478379 255 free(loop);
1ca208fb 256 return -ENOMEM;
e3478379
FF
257 }
258
2d9a3397 259 lb->path = loop;
71fda00f 260 LIST_PREPEND(mount_point, *head, lb);
e3478379
FF
261 }
262
1ca208fb 263 return 0;
e3478379
FF
264}
265
12aad1d0 266static int dm_list_get(MountPoint **head) {
1ca208fb 267 _cleanup_udev_enumerate_unref_ struct udev_enumerate *e = NULL;
d48141ba 268 struct udev_list_entry *item = NULL, *first = NULL;
06acf2d4
LP
269 _cleanup_udev_unref_ struct udev *udev = NULL;
270 int r;
d48141ba 271
12aad1d0
LP
272 assert(head);
273
1ca208fb
ZJS
274 udev = udev_new();
275 if (!udev)
276 return -ENOMEM;
d48141ba 277
1ca208fb
ZJS
278 e = udev_enumerate_new(udev);
279 if (!e)
280 return -ENOMEM;
d48141ba 281
06acf2d4
LP
282 r = udev_enumerate_add_match_subsystem(e, "block");
283 if (r < 0)
284 return r;
d48141ba 285
06acf2d4
LP
286 r = udev_enumerate_add_match_sysname(e, "dm-*");
287 if (r < 0)
288 return r;
d48141ba 289
06acf2d4
LP
290 r = udev_enumerate_scan_devices(e);
291 if (r < 0)
292 return r;
d48141ba 293
06acf2d4 294 first = udev_enumerate_get_list_entry(e);
d48141ba 295 udev_list_entry_foreach(item, first) {
2d9a3397 296 MountPoint *m;
1ca208fb 297 _cleanup_udev_device_unref_ struct udev_device *d;
2d9a3397
LP
298 dev_t devnum;
299 char *node;
300 const char *dn;
d48141ba 301
1ca208fb
ZJS
302 d = udev_device_new_from_syspath(udev, udev_list_entry_get_name(item));
303 if (!d)
304 return -ENOMEM;
d48141ba 305
2d9a3397
LP
306 devnum = udev_device_get_devnum(d);
307 dn = udev_device_get_devnode(d);
1ca208fb 308 if (major(devnum) == 0 || !dn)
2d9a3397 309 continue;
d48141ba 310
2d9a3397 311 node = strdup(dn);
1ca208fb
ZJS
312 if (!node)
313 return -ENOMEM;
d48141ba 314
1ca208fb
ZJS
315 m = new(MountPoint, 1);
316 if (!m) {
2d9a3397 317 free(node);
1ca208fb 318 return -ENOMEM;
d48141ba
LP
319 }
320
2d9a3397
LP
321 m->path = node;
322 m->devnum = devnum;
71fda00f 323 LIST_PREPEND(mount_point, *head, m);
d48141ba
LP
324 }
325
1ca208fb 326 return 0;
d48141ba
LP
327}
328
e3478379 329static int delete_loopback(const char *device) {
03e334a1
LP
330 _cleanup_close_ int fd = -1;
331 int r;
e3478379 332
03e334a1
LP
333 fd = open(device, O_RDONLY|O_CLOEXEC);
334 if (fd < 0)
c4f8bd1a 335 return errno == ENOENT ? 0 : -errno;
e3478379 336
ce726252 337 r = ioctl(fd, LOOP_CLR_FD, 0);
12aad1d0
LP
338 if (r >= 0)
339 return 1;
340
ce726252 341 /* ENXIO: not bound, so no error */
12aad1d0
LP
342 if (errno == ENXIO)
343 return 0;
344
345 return -errno;
e3478379
FF
346}
347
2d9a3397 348static int delete_dm(dev_t devnum) {
7fd1b19b 349 _cleanup_close_ int fd = -1;
e62d8c39 350 int r;
b92bea5d
ZJS
351 struct dm_ioctl dm = {
352 .version = {DM_VERSION_MAJOR,
353 DM_VERSION_MINOR,
354 DM_VERSION_PATCHLEVEL},
355 .data_size = sizeof(dm),
356 .dev = devnum,
357 };
d48141ba 358
2d9a3397 359 assert(major(devnum) != 0);
d48141ba 360
e62d8c39
ZJS
361 fd = open("/dev/mapper/control", O_RDWR|O_CLOEXEC);
362 if (fd < 0)
d48141ba
LP
363 return -errno;
364
d48141ba 365 r = ioctl(fd, DM_DEV_REMOVE, &dm);
d48141ba
LP
366 return r >= 0 ? 0 : -errno;
367}
368
31657718 369static int mount_points_list_umount(MountPoint **head, bool *changed, bool log_error) {
12aad1d0
LP
370 MountPoint *m, *n;
371 int n_failed = 0;
e3478379 372
12aad1d0
LP
373 assert(head);
374
375 LIST_FOREACH_SAFE(mount_point, m, n, *head) {
93bd1577
LP
376
377 /* If we are in a container, don't attempt to
378 read-only mount anything as that brings no real
379 benefits, but might confuse the host, as we remount
380 the superblock here, not the bind mound. */
75f86906 381 if (detect_container() <= 0) {
471b48ed
JJ
382 _cleanup_free_ char *options = NULL;
383 /* MS_REMOUNT requires that the data parameter
384 * should be the same from the original mount
385 * except for the desired changes. Since we want
386 * to remount read-only, we should filter out
387 * rw (and ro too, because it confuses the kernel) */
388 (void) fstab_filter_options(m->options, "rw\0ro\0", NULL, NULL, &options);
389
93bd1577
LP
390 /* We always try to remount directories
391 * read-only first, before we go on and umount
392 * them.
393 *
394 * Mount points can be stacked. If a mount
395 * point is stacked below / or /usr, we
ab06eef8 396 * cannot umount or remount it directly,
93bd1577
LP
397 * since there is no way to refer to the
398 * underlying mount. There's nothing we can do
399 * about it for the general case, but we can
400 * do something about it if it is aliased
401 * somehwere else via a bind mount. If we
402 * explicitly remount the super block of that
403 * alias read-only we hence should be
404 * relatively safe regarding keeping the fs we
405 * can otherwise not see dirty. */
471b48ed
JJ
406 log_info("Remounting '%s' read-only with options '%s'.", m->path, options);
407 (void) mount(NULL, m->path, NULL, MS_REMOUNT|MS_RDONLY, options);
93bd1577
LP
408 }
409
410 /* Skip / and /usr since we cannot unmount that
5a6f9d23
HG
411 * anyway, since we are running from it. They have
412 * already been remounted ro. */
9cacf564
LP
413 if (path_equal(m->path, "/")
414#ifndef HAVE_SPLIT_USR
415 || path_equal(m->path, "/usr")
416#endif
14088340 417 )
e3478379
FF
418 continue;
419
0c08f5cd
LP
420 /* Trying to umount. We don't force here since we rely
421 * on busy NFS and FUSE file systems to return EBUSY
422 * until we closed everything on top of them. */
bce93b7a 423 log_info("Unmounting %s.", m->path);
0c08f5cd 424 if (umount2(m->path, 0) == 0) {
12aad1d0
LP
425 if (changed)
426 *changed = true;
427
428 mount_point_free(head, m);
31657718 429 } else if (log_error) {
56f64d95 430 log_warning_errno(errno, "Could not unmount %s: %m", m->path);
12aad1d0 431 n_failed++;
e3478379
FF
432 }
433 }
434
12aad1d0 435 return n_failed;
e3478379
FF
436}
437
12aad1d0
LP
438static int swap_points_list_off(MountPoint **head, bool *changed) {
439 MountPoint *m, *n;
440 int n_failed = 0;
441
442 assert(head);
e3478379 443
12aad1d0 444 LIST_FOREACH_SAFE(mount_point, m, n, *head) {
735e0712 445 log_info("Deactivating swap %s.", m->path);
12aad1d0
LP
446 if (swapoff(m->path) == 0) {
447 if (changed)
448 *changed = true;
449
450 mount_point_free(head, m);
451 } else {
56f64d95 452 log_warning_errno(errno, "Could not deactivate swap %s: %m", m->path);
12aad1d0 453 n_failed++;
e3478379
FF
454 }
455 }
456
12aad1d0 457 return n_failed;
e3478379
FF
458}
459
12aad1d0
LP
460static int loopback_points_list_detach(MountPoint **head, bool *changed) {
461 MountPoint *m, *n;
7fc942b2
LP
462 int n_failed = 0, k;
463 struct stat root_st;
12aad1d0
LP
464
465 assert(head);
466
7fc942b2
LP
467 k = lstat("/", &root_st);
468
12aad1d0
LP
469 LIST_FOREACH_SAFE(mount_point, m, n, *head) {
470 int r;
7fc942b2
LP
471 struct stat loopback_st;
472
473 if (k >= 0 &&
474 major(root_st.st_dev) != 0 &&
475 lstat(m->path, &loopback_st) >= 0 &&
476 root_st.st_dev == loopback_st.st_rdev) {
477 n_failed ++;
478 continue;
479 }
e3478379 480
735e0712 481 log_info("Detaching loopback %s.", m->path);
bce93b7a
MS
482 r = delete_loopback(m->path);
483 if (r >= 0) {
12aad1d0
LP
484 if (r > 0 && changed)
485 *changed = true;
486
487 mount_point_free(head, m);
488 } else {
56f64d95 489 log_warning_errno(errno, "Could not detach loopback %s: %m", m->path);
12aad1d0 490 n_failed++;
e3478379
FF
491 }
492 }
493
12aad1d0 494 return n_failed;
e3478379
FF
495}
496
12aad1d0
LP
497static int dm_points_list_detach(MountPoint **head, bool *changed) {
498 MountPoint *m, *n;
7fc942b2
LP
499 int n_failed = 0, k;
500 struct stat root_st;
12aad1d0
LP
501
502 assert(head);
503
7fc942b2
LP
504 k = lstat("/", &root_st);
505
12aad1d0
LP
506 LIST_FOREACH_SAFE(mount_point, m, n, *head) {
507 int r;
508
7fc942b2
LP
509 if (k >= 0 &&
510 major(root_st.st_dev) != 0 &&
511 root_st.st_dev == m->devnum) {
512 n_failed ++;
513 continue;
514 }
515
735e0712 516 log_info("Detaching DM %u:%u.", major(m->devnum), minor(m->devnum));
bce93b7a
MS
517 r = delete_dm(m->devnum);
518 if (r >= 0) {
c6784066 519 if (changed)
12aad1d0 520 *changed = true;
d48141ba 521
12aad1d0
LP
522 mount_point_free(head, m);
523 } else {
56f64d95 524 log_warning_errno(errno, "Could not detach DM %s: %m", m->path);
12aad1d0 525 n_failed++;
d48141ba
LP
526 }
527 }
528
12aad1d0 529 return n_failed;
d48141ba
LP
530}
531
12aad1d0 532int umount_all(bool *changed) {
e3478379 533 int r;
6f7f51f7 534 bool umount_changed;
e3478379
FF
535 LIST_HEAD(MountPoint, mp_list_head);
536
71fda00f 537 LIST_HEAD_INIT(mp_list_head);
e3478379
FF
538 r = mount_points_list_get(&mp_list_head);
539 if (r < 0)
540 goto end;
541
6f7f51f7
HH
542 /* retry umount, until nothing can be umounted anymore */
543 do {
544 umount_changed = false;
3e085b6c
LP
545
546 mount_points_list_umount(&mp_list_head, &umount_changed, false);
6f7f51f7
HH
547 if (umount_changed)
548 *changed = true;
3e085b6c
LP
549
550 } while (umount_changed);
551
31657718
HH
552 /* umount one more time with logging enabled */
553 r = mount_points_list_umount(&mp_list_head, &umount_changed, true);
e3478379
FF
554 if (r <= 0)
555 goto end;
556
e3478379
FF
557 end:
558 mount_points_list_free(&mp_list_head);
559
560 return r;
561}
562
12aad1d0 563int swapoff_all(bool *changed) {
e3478379
FF
564 int r;
565 LIST_HEAD(MountPoint, swap_list_head);
566
71fda00f 567 LIST_HEAD_INIT(swap_list_head);
e3478379
FF
568
569 r = swap_list_get(&swap_list_head);
570 if (r < 0)
571 goto end;
572
12aad1d0 573 r = swap_points_list_off(&swap_list_head, changed);
e3478379
FF
574
575 end:
576 mount_points_list_free(&swap_list_head);
577
578 return r;
579}
580
12aad1d0 581int loopback_detach_all(bool *changed) {
e3478379
FF
582 int r;
583 LIST_HEAD(MountPoint, loopback_list_head);
584
71fda00f 585 LIST_HEAD_INIT(loopback_list_head);
e3478379
FF
586
587 r = loopback_list_get(&loopback_list_head);
588 if (r < 0)
589 goto end;
590
12aad1d0 591 r = loopback_points_list_detach(&loopback_list_head, changed);
e3478379
FF
592
593 end:
594 mount_points_list_free(&loopback_list_head);
595
596 return r;
597}
d48141ba 598
12aad1d0 599int dm_detach_all(bool *changed) {
d48141ba
LP
600 int r;
601 LIST_HEAD(MountPoint, dm_list_head);
602
71fda00f 603 LIST_HEAD_INIT(dm_list_head);
d48141ba
LP
604
605 r = dm_list_get(&dm_list_head);
606 if (r < 0)
607 goto end;
608
12aad1d0 609 r = dm_points_list_detach(&dm_list_head, changed);
d48141ba
LP
610
611 end:
612 mount_points_list_free(&dm_list_head);
613
614 return r;
615}