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