]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/core/umount.c
core: systemd-shutdown: add missing check for umount_changed
[thirdparty/systemd.git] / src / core / umount.c
1 /***
2 This file is part of systemd.
3
4 Copyright 2010 ProFUSION embedded systems
5
6 systemd is free software; you can redistribute it and/or modify it
7 under the terms of the GNU Lesser General Public License as published by
8 the Free Software Foundation; either version 2.1 of the License, or
9 (at your option) any later version.
10
11 systemd is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Lesser General Public License for more details.
15
16 You should have received a copy of the GNU Lesser General Public License
17 along with systemd; If not, see <http://www.gnu.org/licenses/>.
18 ***/
19
20 #include <errno.h>
21 #include <fcntl.h>
22 #include <linux/loop.h>
23 #include <string.h>
24 #include <sys/mount.h>
25 #include <sys/swap.h>
26
27 #include "libudev.h"
28
29 #include "alloc-util.h"
30 #include "escape.h"
31 #include "fd-util.h"
32 #include "fstab-util.h"
33 #include "linux-3.13/dm-ioctl.h"
34 #include "list.h"
35 #include "mount-setup.h"
36 #include "path-util.h"
37 #include "string-util.h"
38 #include "udev-util.h"
39 #include "umount.h"
40 #include "mount-util.h"
41 #include "util.h"
42 #include "virt.h"
43
44 typedef struct MountPoint {
45 char *path;
46 char *options;
47 char *type;
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, *type = 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 "%ms " /* (9) file system type */
96 "%*s" /* (10) mount source */
97 "%ms" /* (11) mount options */
98 "%*[^\n]", /* some rubbish at the end */
99 &path, &type, &options);
100 if (k != 3) {
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 m->type = type;
138 type = NULL;
139
140 LIST_PREPEND(mount_point, *head, m);
141 }
142
143 return 0;
144 }
145
146 static int swap_list_get(MountPoint **head) {
147 _cleanup_fclose_ FILE *proc_swaps = NULL;
148 unsigned int i;
149 int r;
150
151 assert(head);
152
153 proc_swaps = fopen("/proc/swaps", "re");
154 if (!proc_swaps)
155 return (errno == ENOENT) ? 0 : -errno;
156
157 (void) fscanf(proc_swaps, "%*s %*s %*s %*s %*s\n");
158
159 for (i = 2;; i++) {
160 MountPoint *swap;
161 char *dev = NULL, *d;
162 int k;
163
164 k = fscanf(proc_swaps,
165 "%ms " /* device/file */
166 "%*s " /* type of swap */
167 "%*s " /* swap size */
168 "%*s " /* used */
169 "%*s\n", /* priority */
170 &dev);
171
172 if (k != 1) {
173 if (k == EOF)
174 break;
175
176 log_warning("Failed to parse /proc/swaps:%u.", i);
177 free(dev);
178 continue;
179 }
180
181 if (endswith(dev, " (deleted)")) {
182 free(dev);
183 continue;
184 }
185
186 r = cunescape(dev, UNESCAPE_RELAX, &d);
187 free(dev);
188 if (r < 0)
189 return r;
190
191 swap = new0(MountPoint, 1);
192 if (!swap) {
193 free(d);
194 return -ENOMEM;
195 }
196
197 swap->path = d;
198 LIST_PREPEND(mount_point, *head, swap);
199 }
200
201 return 0;
202 }
203
204 static int loopback_list_get(MountPoint **head) {
205 _cleanup_udev_enumerate_unref_ struct udev_enumerate *e = NULL;
206 struct udev_list_entry *item = NULL, *first = NULL;
207 _cleanup_udev_unref_ struct udev *udev = NULL;
208 int r;
209
210 assert(head);
211
212 udev = udev_new();
213 if (!udev)
214 return -ENOMEM;
215
216 e = udev_enumerate_new(udev);
217 if (!e)
218 return -ENOMEM;
219
220 r = udev_enumerate_add_match_subsystem(e, "block");
221 if (r < 0)
222 return r;
223
224 r = udev_enumerate_add_match_sysname(e, "loop*");
225 if (r < 0)
226 return r;
227
228 r = udev_enumerate_add_match_sysattr(e, "loop/backing_file", NULL);
229 if (r < 0)
230 return r;
231
232 r = udev_enumerate_scan_devices(e);
233 if (r < 0)
234 return r;
235
236 first = udev_enumerate_get_list_entry(e);
237 udev_list_entry_foreach(item, first) {
238 MountPoint *lb;
239 _cleanup_udev_device_unref_ struct udev_device *d;
240 char *loop;
241 const char *dn;
242
243 d = udev_device_new_from_syspath(udev, udev_list_entry_get_name(item));
244 if (!d)
245 return -ENOMEM;
246
247 dn = udev_device_get_devnode(d);
248 if (!dn)
249 continue;
250
251 loop = strdup(dn);
252 if (!loop)
253 return -ENOMEM;
254
255 lb = new0(MountPoint, 1);
256 if (!lb) {
257 free(loop);
258 return -ENOMEM;
259 }
260
261 lb->path = loop;
262 LIST_PREPEND(mount_point, *head, lb);
263 }
264
265 return 0;
266 }
267
268 static int dm_list_get(MountPoint **head) {
269 _cleanup_udev_enumerate_unref_ struct udev_enumerate *e = NULL;
270 struct udev_list_entry *item = NULL, *first = NULL;
271 _cleanup_udev_unref_ struct udev *udev = NULL;
272 int r;
273
274 assert(head);
275
276 udev = udev_new();
277 if (!udev)
278 return -ENOMEM;
279
280 e = udev_enumerate_new(udev);
281 if (!e)
282 return -ENOMEM;
283
284 r = udev_enumerate_add_match_subsystem(e, "block");
285 if (r < 0)
286 return r;
287
288 r = udev_enumerate_add_match_sysname(e, "dm-*");
289 if (r < 0)
290 return r;
291
292 r = udev_enumerate_scan_devices(e);
293 if (r < 0)
294 return r;
295
296 first = udev_enumerate_get_list_entry(e);
297 udev_list_entry_foreach(item, first) {
298 MountPoint *m;
299 _cleanup_udev_device_unref_ struct udev_device *d;
300 dev_t devnum;
301 char *node;
302 const char *dn;
303
304 d = udev_device_new_from_syspath(udev, udev_list_entry_get_name(item));
305 if (!d)
306 return -ENOMEM;
307
308 devnum = udev_device_get_devnum(d);
309 dn = udev_device_get_devnode(d);
310 if (major(devnum) == 0 || !dn)
311 continue;
312
313 node = strdup(dn);
314 if (!node)
315 return -ENOMEM;
316
317 m = new(MountPoint, 1);
318 if (!m) {
319 free(node);
320 return -ENOMEM;
321 }
322
323 m->path = node;
324 m->devnum = devnum;
325 LIST_PREPEND(mount_point, *head, m);
326 }
327
328 return 0;
329 }
330
331 static int delete_loopback(const char *device) {
332 _cleanup_close_ int fd = -1;
333 int r;
334
335 fd = open(device, O_RDONLY|O_CLOEXEC);
336 if (fd < 0)
337 return errno == ENOENT ? 0 : -errno;
338
339 r = ioctl(fd, LOOP_CLR_FD, 0);
340 if (r >= 0)
341 return 1;
342
343 /* ENXIO: not bound, so no error */
344 if (errno == ENXIO)
345 return 0;
346
347 return -errno;
348 }
349
350 static int delete_dm(dev_t devnum) {
351
352 struct dm_ioctl dm = {
353 .version = {
354 DM_VERSION_MAJOR,
355 DM_VERSION_MINOR,
356 DM_VERSION_PATCHLEVEL
357 },
358 .data_size = sizeof(dm),
359 .dev = devnum,
360 };
361
362 _cleanup_close_ int fd = -1;
363
364 assert(major(devnum) != 0);
365
366 fd = open("/dev/mapper/control", O_RDWR|O_CLOEXEC);
367 if (fd < 0)
368 return -errno;
369
370 if (ioctl(fd, DM_DEV_REMOVE, &dm) < 0)
371 return -errno;
372
373 return 0;
374 }
375
376 static bool nonunmountable_path(const char *path) {
377 return path_equal(path, "/")
378 #if ! HAVE_SPLIT_USR
379 || path_equal(path, "/usr")
380 #endif
381 || path_startswith(path, "/run/initramfs");
382 }
383
384 static int mount_points_list_umount(MountPoint **head, bool *changed, bool log_error) {
385 MountPoint *m, *n;
386 int n_failed = 0;
387
388 assert(head);
389
390 LIST_FOREACH_SAFE(mount_point, m, n, *head) {
391
392 /* If we are in a container, don't attempt to
393 read-only mount anything as that brings no real
394 benefits, but might confuse the host, as we remount
395 the superblock here, not the bind mount.
396 If the filesystem is a network fs, also skip the
397 remount. It brings no value (we cannot leave
398 a "dirty fs") and could hang if the network is down. */
399 if (detect_container() <= 0 &&
400 !fstype_is_network(m->type)) {
401 _cleanup_free_ char *options = NULL;
402 /* MS_REMOUNT requires that the data parameter
403 * should be the same from the original mount
404 * except for the desired changes. Since we want
405 * to remount read-only, we should filter out
406 * rw (and ro too, because it confuses the kernel) */
407 (void) fstab_filter_options(m->options, "rw\0ro\0", NULL, NULL, &options);
408
409 /* We always try to remount directories
410 * read-only first, before we go on and umount
411 * them.
412 *
413 * Mount points can be stacked. If a mount
414 * point is stacked below / or /usr, we
415 * cannot umount or remount it directly,
416 * since there is no way to refer to the
417 * underlying mount. There's nothing we can do
418 * about it for the general case, but we can
419 * do something about it if it is aliased
420 * somehwere else via a bind mount. If we
421 * explicitly remount the super block of that
422 * alias read-only we hence should be
423 * relatively safe regarding keeping dirty an fs
424 * we cannot otherwise see. */
425 log_info("Remounting '%s' read-only with options '%s'.", m->path, options);
426 if (mount(NULL, m->path, NULL, MS_REMOUNT|MS_RDONLY, options) < 0) {
427 if (log_error)
428 log_notice_errno(errno, "Failed to remount '%s' read-only: %m", m->path);
429 if (nonunmountable_path(m->path))
430 n_failed++;
431 }
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 (nonunmountable_path(m->path))
438 continue;
439
440 /* Trying to umount. We don't force here since we rely
441 * on busy NFS and FUSE file systems to return EBUSY
442 * until we closed everything on top of them. */
443 log_info("Unmounting %s.", m->path);
444 if (umount2(m->path, 0) == 0) {
445 if (changed)
446 *changed = true;
447
448 mount_point_free(head, m);
449 } else {
450 if (log_error)
451 log_warning_errno(errno, "Could not unmount %s: %m", m->path);
452 n_failed++;
453 }
454 }
455
456 return n_failed;
457 }
458
459 static int swap_points_list_off(MountPoint **head, bool *changed) {
460 MountPoint *m, *n;
461 int n_failed = 0;
462
463 assert(head);
464
465 LIST_FOREACH_SAFE(mount_point, m, n, *head) {
466 log_info("Deactivating swap %s.", m->path);
467 if (swapoff(m->path) == 0) {
468 if (changed)
469 *changed = true;
470
471 mount_point_free(head, m);
472 } else {
473 log_warning_errno(errno, "Could not deactivate swap %s: %m", m->path);
474 n_failed++;
475 }
476 }
477
478 return n_failed;
479 }
480
481 static int loopback_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 struct stat loopback_st;
493
494 if (k >= 0 &&
495 major(root_st.st_dev) != 0 &&
496 lstat(m->path, &loopback_st) >= 0 &&
497 root_st.st_dev == loopback_st.st_rdev) {
498 n_failed++;
499 continue;
500 }
501
502 log_info("Detaching loopback %s.", m->path);
503 r = delete_loopback(m->path);
504 if (r >= 0) {
505 if (r > 0 && changed)
506 *changed = true;
507
508 mount_point_free(head, m);
509 } else {
510 log_warning_errno(errno, "Could not detach loopback %s: %m", m->path);
511 n_failed++;
512 }
513 }
514
515 return n_failed;
516 }
517
518 static int dm_points_list_detach(MountPoint **head, bool *changed) {
519 MountPoint *m, *n;
520 int n_failed = 0, r;
521 dev_t rootdev;
522
523 assert(head);
524
525 r = get_block_device("/", &rootdev);
526 if (r <= 0)
527 rootdev = 0;
528
529 LIST_FOREACH_SAFE(mount_point, m, n, *head) {
530
531 if (major(rootdev) != 0)
532 if (rootdev == m->devnum) {
533 n_failed ++;
534 continue;
535 }
536
537 log_info("Detaching DM %u:%u.", major(m->devnum), minor(m->devnum));
538 r = delete_dm(m->devnum);
539 if (r >= 0) {
540 if (changed)
541 *changed = true;
542
543 mount_point_free(head, m);
544 } else {
545 log_warning_errno(errno, "Could not detach DM %s: %m", m->path);
546 n_failed++;
547 }
548 }
549
550 return n_failed;
551 }
552
553 int umount_all(bool *changed) {
554 int r;
555 bool umount_changed;
556 LIST_HEAD(MountPoint, mp_list_head);
557
558 LIST_HEAD_INIT(mp_list_head);
559 r = mount_points_list_get(&mp_list_head);
560 if (r < 0)
561 goto end;
562
563 /* retry umount, until nothing can be umounted anymore */
564 do {
565 umount_changed = false;
566
567 mount_points_list_umount(&mp_list_head, &umount_changed, false);
568 if (umount_changed)
569 *changed = true;
570
571 } while (umount_changed);
572
573 /* umount one more time with logging enabled */
574 r = mount_points_list_umount(&mp_list_head, &umount_changed, true);
575 if (umount_changed)
576 *changed = true;
577
578 end:
579 mount_points_list_free(&mp_list_head);
580
581 return r;
582 }
583
584 int swapoff_all(bool *changed) {
585 int r;
586 LIST_HEAD(MountPoint, swap_list_head);
587
588 LIST_HEAD_INIT(swap_list_head);
589
590 r = swap_list_get(&swap_list_head);
591 if (r < 0)
592 goto end;
593
594 r = swap_points_list_off(&swap_list_head, changed);
595
596 end:
597 mount_points_list_free(&swap_list_head);
598
599 return r;
600 }
601
602 int loopback_detach_all(bool *changed) {
603 int r;
604 LIST_HEAD(MountPoint, loopback_list_head);
605
606 LIST_HEAD_INIT(loopback_list_head);
607
608 r = loopback_list_get(&loopback_list_head);
609 if (r < 0)
610 goto end;
611
612 r = loopback_points_list_detach(&loopback_list_head, changed);
613
614 end:
615 mount_points_list_free(&loopback_list_head);
616
617 return r;
618 }
619
620 int dm_detach_all(bool *changed) {
621 int r;
622 LIST_HEAD(MountPoint, dm_list_head);
623
624 LIST_HEAD_INIT(dm_list_head);
625
626 r = dm_list_get(&dm_list_head);
627 if (r < 0)
628 goto end;
629
630 r = dm_points_list_detach(&dm_list_head, changed);
631
632 end:
633 mount_points_list_free(&dm_list_head);
634
635 return r;
636 }