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