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