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