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