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