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