]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/core/umount.c
Merge pull request #1962 from mbiebl/install-completion-networkctl
[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 "alloc-util.h"
33 #include "escape.h"
34 #include "fd-util.h"
35 #include "fstab-util.h"
36 #include "list.h"
37 #include "mount-setup.h"
38 #include "path-util.h"
39 #include "string-util.h"
40 #include "udev-util.h"
41 #include "umount.h"
42 #include "util.h"
43 #include "virt.h"
44
45 typedef struct MountPoint {
46 char *path;
47 char *options;
48 dev_t devnum;
49 LIST_FIELDS(struct MountPoint, mount_point);
50 } MountPoint;
51
52 static void mount_point_free(MountPoint **head, MountPoint *m) {
53 assert(head);
54 assert(m);
55
56 LIST_REMOVE(mount_point, *head, m);
57
58 free(m->path);
59 free(m);
60 }
61
62 static void mount_points_list_free(MountPoint **head) {
63 assert(head);
64
65 while (*head)
66 mount_point_free(head, *head);
67 }
68
69 static int mount_points_list_get(MountPoint **head) {
70 _cleanup_fclose_ FILE *proc_self_mountinfo = NULL;
71 unsigned int i;
72 int r;
73
74 assert(head);
75
76 proc_self_mountinfo = fopen("/proc/self/mountinfo", "re");
77 if (!proc_self_mountinfo)
78 return -errno;
79
80 for (i = 1;; i++) {
81 _cleanup_free_ char *path = NULL, *options = NULL;
82 char *p = NULL;
83 MountPoint *m;
84 int k;
85
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 */
92 "%*s" /* (6) mount flags */
93 "%*[^-]" /* (7) optional fields */
94 "- " /* (8) separator */
95 "%*s " /* (9) file system type */
96 "%*s" /* (10) mount source */
97 "%ms" /* (11) mount options */
98 "%*[^\n]", /* some rubbish at the end */
99 &path, &options);
100 if (k != 2) {
101 if (k == EOF)
102 break;
103
104 log_warning("Failed to parse /proc/self/mountinfo:%u.", i);
105 continue;
106 }
107
108 r = cunescape(path, UNESCAPE_RELAX, &p);
109 if (r < 0)
110 return r;
111
112 /* Ignore mount points we can't unmount because they
113 * are API or because we are keeping them open (like
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. */
119 if (mount_point_is_api(p) ||
120 mount_point_ignore(p) ||
121 path_startswith(p, "/dev") ||
122 path_startswith(p, "/sys") ||
123 path_startswith(p, "/proc")) {
124 free(p);
125 continue;
126 }
127
128 m = new0(MountPoint, 1);
129 if (!m) {
130 free(p);
131 return -ENOMEM;
132 }
133
134 m->path = p;
135 m->options = options;
136 options = NULL;
137
138 LIST_PREPEND(mount_point, *head, m);
139 }
140
141 return 0;
142 }
143
144 static int swap_list_get(MountPoint **head) {
145 _cleanup_fclose_ FILE *proc_swaps = NULL;
146 unsigned int i;
147 int r;
148
149 assert(head);
150
151 proc_swaps = fopen("/proc/swaps", "re");
152 if (!proc_swaps)
153 return (errno == ENOENT) ? 0 : -errno;
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
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);
169
170 if (k != 1) {
171 if (k == EOF)
172 break;
173
174 log_warning("Failed to parse /proc/swaps:%u.", i);
175 free(dev);
176 continue;
177 }
178
179 if (endswith(dev, " (deleted)")) {
180 free(dev);
181 continue;
182 }
183
184 r = cunescape(dev, UNESCAPE_RELAX, &d);
185 free(dev);
186 if (r < 0)
187 return r;
188
189 swap = new0(MountPoint, 1);
190 if (!swap) {
191 free(d);
192 return -ENOMEM;
193 }
194
195 swap->path = d;
196 LIST_PREPEND(mount_point, *head, swap);
197 }
198
199 return 0;
200 }
201
202 static int loopback_list_get(MountPoint **head) {
203 _cleanup_udev_enumerate_unref_ struct udev_enumerate *e = NULL;
204 struct udev_list_entry *item = NULL, *first = NULL;
205 _cleanup_udev_unref_ struct udev *udev = NULL;
206 int r;
207
208 assert(head);
209
210 udev = udev_new();
211 if (!udev)
212 return -ENOMEM;
213
214 e = udev_enumerate_new(udev);
215 if (!e)
216 return -ENOMEM;
217
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;
229
230 r = udev_enumerate_scan_devices(e);
231 if (r < 0)
232 return r;
233
234 first = udev_enumerate_get_list_entry(e);
235 udev_list_entry_foreach(item, first) {
236 MountPoint *lb;
237 _cleanup_udev_device_unref_ struct udev_device *d;
238 char *loop;
239 const char *dn;
240
241 d = udev_device_new_from_syspath(udev, udev_list_entry_get_name(item));
242 if (!d)
243 return -ENOMEM;
244
245 dn = udev_device_get_devnode(d);
246 if (!dn)
247 continue;
248
249 loop = strdup(dn);
250 if (!loop)
251 return -ENOMEM;
252
253 lb = new0(MountPoint, 1);
254 if (!lb) {
255 free(loop);
256 return -ENOMEM;
257 }
258
259 lb->path = loop;
260 LIST_PREPEND(mount_point, *head, lb);
261 }
262
263 return 0;
264 }
265
266 static int dm_list_get(MountPoint **head) {
267 _cleanup_udev_enumerate_unref_ struct udev_enumerate *e = NULL;
268 struct udev_list_entry *item = NULL, *first = NULL;
269 _cleanup_udev_unref_ struct udev *udev = NULL;
270 int r;
271
272 assert(head);
273
274 udev = udev_new();
275 if (!udev)
276 return -ENOMEM;
277
278 e = udev_enumerate_new(udev);
279 if (!e)
280 return -ENOMEM;
281
282 r = udev_enumerate_add_match_subsystem(e, "block");
283 if (r < 0)
284 return r;
285
286 r = udev_enumerate_add_match_sysname(e, "dm-*");
287 if (r < 0)
288 return r;
289
290 r = udev_enumerate_scan_devices(e);
291 if (r < 0)
292 return r;
293
294 first = udev_enumerate_get_list_entry(e);
295 udev_list_entry_foreach(item, first) {
296 MountPoint *m;
297 _cleanup_udev_device_unref_ struct udev_device *d;
298 dev_t devnum;
299 char *node;
300 const char *dn;
301
302 d = udev_device_new_from_syspath(udev, udev_list_entry_get_name(item));
303 if (!d)
304 return -ENOMEM;
305
306 devnum = udev_device_get_devnum(d);
307 dn = udev_device_get_devnode(d);
308 if (major(devnum) == 0 || !dn)
309 continue;
310
311 node = strdup(dn);
312 if (!node)
313 return -ENOMEM;
314
315 m = new(MountPoint, 1);
316 if (!m) {
317 free(node);
318 return -ENOMEM;
319 }
320
321 m->path = node;
322 m->devnum = devnum;
323 LIST_PREPEND(mount_point, *head, m);
324 }
325
326 return 0;
327 }
328
329 static int delete_loopback(const char *device) {
330 _cleanup_close_ int fd = -1;
331 int r;
332
333 fd = open(device, O_RDONLY|O_CLOEXEC);
334 if (fd < 0)
335 return errno == ENOENT ? 0 : -errno;
336
337 r = ioctl(fd, LOOP_CLR_FD, 0);
338 if (r >= 0)
339 return 1;
340
341 /* ENXIO: not bound, so no error */
342 if (errno == ENXIO)
343 return 0;
344
345 return -errno;
346 }
347
348 static int delete_dm(dev_t devnum) {
349 _cleanup_close_ int fd = -1;
350 int r;
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 };
358
359 assert(major(devnum) != 0);
360
361 fd = open("/dev/mapper/control", O_RDWR|O_CLOEXEC);
362 if (fd < 0)
363 return -errno;
364
365 r = ioctl(fd, DM_DEV_REMOVE, &dm);
366 return r >= 0 ? 0 : -errno;
367 }
368
369 static int mount_points_list_umount(MountPoint **head, bool *changed, bool log_error) {
370 MountPoint *m, *n;
371 int n_failed = 0;
372
373 assert(head);
374
375 LIST_FOREACH_SAFE(mount_point, m, n, *head) {
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. */
381 if (detect_container() <= 0) {
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
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
396 * cannot umount or remount it directly,
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. */
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);
408 }
409
410 /* Skip / and /usr since we cannot unmount that
411 * anyway, since we are running from it. They have
412 * already been remounted ro. */
413 if (path_equal(m->path, "/")
414 #ifndef HAVE_SPLIT_USR
415 || path_equal(m->path, "/usr")
416 #endif
417 )
418 continue;
419
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. */
423 log_info("Unmounting %s.", m->path);
424 if (umount2(m->path, 0) == 0) {
425 if (changed)
426 *changed = true;
427
428 mount_point_free(head, m);
429 } else if (log_error) {
430 log_warning_errno(errno, "Could not unmount %s: %m", m->path);
431 n_failed++;
432 }
433 }
434
435 return n_failed;
436 }
437
438 static int swap_points_list_off(MountPoint **head, bool *changed) {
439 MountPoint *m, *n;
440 int n_failed = 0;
441
442 assert(head);
443
444 LIST_FOREACH_SAFE(mount_point, m, n, *head) {
445 log_info("Deactivating swap %s.", m->path);
446 if (swapoff(m->path) == 0) {
447 if (changed)
448 *changed = true;
449
450 mount_point_free(head, m);
451 } else {
452 log_warning_errno(errno, "Could not deactivate swap %s: %m", m->path);
453 n_failed++;
454 }
455 }
456
457 return n_failed;
458 }
459
460 static int loopback_points_list_detach(MountPoint **head, bool *changed) {
461 MountPoint *m, *n;
462 int n_failed = 0, k;
463 struct stat root_st;
464
465 assert(head);
466
467 k = lstat("/", &root_st);
468
469 LIST_FOREACH_SAFE(mount_point, m, n, *head) {
470 int r;
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 }
480
481 log_info("Detaching loopback %s.", m->path);
482 r = delete_loopback(m->path);
483 if (r >= 0) {
484 if (r > 0 && changed)
485 *changed = true;
486
487 mount_point_free(head, m);
488 } else {
489 log_warning_errno(errno, "Could not detach loopback %s: %m", m->path);
490 n_failed++;
491 }
492 }
493
494 return n_failed;
495 }
496
497 static int dm_points_list_detach(MountPoint **head, bool *changed) {
498 MountPoint *m, *n;
499 int n_failed = 0, k;
500 struct stat root_st;
501
502 assert(head);
503
504 k = lstat("/", &root_st);
505
506 LIST_FOREACH_SAFE(mount_point, m, n, *head) {
507 int r;
508
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
516 log_info("Detaching DM %u:%u.", major(m->devnum), minor(m->devnum));
517 r = delete_dm(m->devnum);
518 if (r >= 0) {
519 if (changed)
520 *changed = true;
521
522 mount_point_free(head, m);
523 } else {
524 log_warning_errno(errno, "Could not detach DM %s: %m", m->path);
525 n_failed++;
526 }
527 }
528
529 return n_failed;
530 }
531
532 int umount_all(bool *changed) {
533 int r;
534 bool umount_changed;
535 LIST_HEAD(MountPoint, mp_list_head);
536
537 LIST_HEAD_INIT(mp_list_head);
538 r = mount_points_list_get(&mp_list_head);
539 if (r < 0)
540 goto end;
541
542 /* retry umount, until nothing can be umounted anymore */
543 do {
544 umount_changed = false;
545
546 mount_points_list_umount(&mp_list_head, &umount_changed, false);
547 if (umount_changed)
548 *changed = true;
549
550 } while (umount_changed);
551
552 /* umount one more time with logging enabled */
553 r = mount_points_list_umount(&mp_list_head, &umount_changed, true);
554 if (r <= 0)
555 goto end;
556
557 end:
558 mount_points_list_free(&mp_list_head);
559
560 return r;
561 }
562
563 int swapoff_all(bool *changed) {
564 int r;
565 LIST_HEAD(MountPoint, swap_list_head);
566
567 LIST_HEAD_INIT(swap_list_head);
568
569 r = swap_list_get(&swap_list_head);
570 if (r < 0)
571 goto end;
572
573 r = swap_points_list_off(&swap_list_head, changed);
574
575 end:
576 mount_points_list_free(&swap_list_head);
577
578 return r;
579 }
580
581 int loopback_detach_all(bool *changed) {
582 int r;
583 LIST_HEAD(MountPoint, loopback_list_head);
584
585 LIST_HEAD_INIT(loopback_list_head);
586
587 r = loopback_list_get(&loopback_list_head);
588 if (r < 0)
589 goto end;
590
591 r = loopback_points_list_detach(&loopback_list_head, changed);
592
593 end:
594 mount_points_list_free(&loopback_list_head);
595
596 return r;
597 }
598
599 int dm_detach_all(bool *changed) {
600 int r;
601 LIST_HEAD(MountPoint, dm_list_head);
602
603 LIST_HEAD_INIT(dm_list_head);
604
605 r = dm_list_get(&dm_list_head);
606 if (r < 0)
607 goto end;
608
609 r = dm_points_list_detach(&dm_list_head, changed);
610
611 end:
612 mount_points_list_free(&dm_list_head);
613
614 return r;
615 }