]>
Commit | Line | Data |
---|---|---|
e3478379 FF |
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 | |
5430f7f2 LP |
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 | |
e3478379 FF |
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 | |
5430f7f2 | 14 | Lesser General Public License for more details. |
e3478379 | 15 | |
5430f7f2 | 16 | You should have received a copy of the GNU Lesser General Public License |
e3478379 FF |
17 | along with systemd; If not, see <http://www.gnu.org/licenses/>. |
18 | ***/ | |
19 | ||
20 | #include <errno.h> | |
21 | #include <fcntl.h> | |
4f5dd394 | 22 | #include <linux/loop.h> |
e3478379 FF |
23 | #include <string.h> |
24 | #include <sys/mount.h> | |
25 | #include <sys/swap.h> | |
e3478379 | 26 | |
b4bbcaa9 TA |
27 | #include "libudev.h" |
28 | ||
b5efdb8a | 29 | #include "alloc-util.h" |
07630cea | 30 | #include "escape.h" |
3ffd4af2 | 31 | #include "fd-util.h" |
471b48ed | 32 | #include "fstab-util.h" |
dcce98a4 | 33 | #include "linux-3.13/dm-ioctl.h" |
e3478379 FF |
34 | #include "list.h" |
35 | #include "mount-setup.h" | |
9eb977db | 36 | #include "path-util.h" |
07630cea | 37 | #include "string-util.h" |
4f5dd394 | 38 | #include "udev-util.h" |
3ffd4af2 | 39 | #include "umount.h" |
9cbc4547 | 40 | #include "mount-util.h" |
e3478379 | 41 | #include "util.h" |
024f268d | 42 | #include "virt.h" |
e3478379 FF |
43 | |
44 | typedef struct MountPoint { | |
45 | char *path; | |
471b48ed | 46 | char *options; |
9cbc4547 | 47 | char *type; |
2d9a3397 | 48 | dev_t devnum; |
71fda00f | 49 | LIST_FIELDS(struct MountPoint, mount_point); |
e3478379 FF |
50 | } MountPoint; |
51 | ||
12aad1d0 LP |
52 | static void mount_point_free(MountPoint **head, MountPoint *m) { |
53 | assert(head); | |
54 | assert(m); | |
e3478379 | 55 | |
71fda00f | 56 | LIST_REMOVE(mount_point, *head, m); |
12aad1d0 LP |
57 | |
58 | free(m->path); | |
59 | free(m); | |
e3478379 FF |
60 | } |
61 | ||
12aad1d0 LP |
62 | static void mount_points_list_free(MountPoint **head) { |
63 | assert(head); | |
64 | ||
65 | while (*head) | |
66 | mount_point_free(head, *head); | |
e3478379 FF |
67 | } |
68 | ||
12aad1d0 | 69 | static int mount_points_list_get(MountPoint **head) { |
c3544e8d | 70 | _cleanup_fclose_ FILE *proc_self_mountinfo = NULL; |
e3478379 | 71 | unsigned int i; |
527b7a42 | 72 | int r; |
e3478379 | 73 | |
12aad1d0 LP |
74 | assert(head); |
75 | ||
c3544e8d LP |
76 | proc_self_mountinfo = fopen("/proc/self/mountinfo", "re"); |
77 | if (!proc_self_mountinfo) | |
e3478379 FF |
78 | return -errno; |
79 | ||
80 | for (i = 1;; i++) { | |
9cbc4547 | 81 | _cleanup_free_ char *path = NULL, *options = NULL, *type = NULL; |
c3544e8d | 82 | char *p = NULL; |
12aad1d0 | 83 | MountPoint *m; |
c3544e8d | 84 | int k; |
e3478379 | 85 | |
c3544e8d LP |
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 */ | |
471b48ed | 92 | "%*s" /* (6) mount flags */ |
c3544e8d LP |
93 | "%*[^-]" /* (7) optional fields */ |
94 | "- " /* (8) separator */ | |
9cbc4547 | 95 | "%ms " /* (9) file system type */ |
c3544e8d | 96 | "%*s" /* (10) mount source */ |
471b48ed | 97 | "%ms" /* (11) mount options */ |
c3544e8d | 98 | "%*[^\n]", /* some rubbish at the end */ |
9cbc4547 | 99 | &path, &type, &options); |
3d4ec012 | 100 | if (k != 3) { |
e3478379 FF |
101 | if (k == EOF) |
102 | break; | |
103 | ||
104 | log_warning("Failed to parse /proc/self/mountinfo:%u.", i); | |
e3478379 FF |
105 | continue; |
106 | } | |
107 | ||
527b7a42 LP |
108 | r = cunescape(path, UNESCAPE_RELAX, &p); |
109 | if (r < 0) | |
110 | return r; | |
e3478379 | 111 | |
46108b3b LP |
112 | /* Ignore mount points we can't unmount because they |
113 | * are API or because we are keeping them open (like | |
874d3404 LP |
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. */ | |
46108b3b LP |
119 | if (mount_point_is_api(p) || |
120 | mount_point_ignore(p) || | |
874d3404 LP |
121 | path_startswith(p, "/dev") || |
122 | path_startswith(p, "/sys") || | |
123 | path_startswith(p, "/proc")) { | |
2054a5b8 LP |
124 | free(p); |
125 | continue; | |
126 | } | |
127 | ||
c3544e8d LP |
128 | m = new0(MountPoint, 1); |
129 | if (!m) { | |
2054a5b8 | 130 | free(p); |
c3544e8d | 131 | return -ENOMEM; |
e3478379 | 132 | } |
e3478379 | 133 | |
12aad1d0 | 134 | m->path = p; |
471b48ed JJ |
135 | m->options = options; |
136 | options = NULL; | |
9cbc4547 N |
137 | m->type = type; |
138 | type = NULL; | |
471b48ed | 139 | |
71fda00f | 140 | LIST_PREPEND(mount_point, *head, m); |
e3478379 FF |
141 | } |
142 | ||
c3544e8d | 143 | return 0; |
e3478379 FF |
144 | } |
145 | ||
12aad1d0 | 146 | static int swap_list_get(MountPoint **head) { |
e1d75803 | 147 | _cleanup_fclose_ FILE *proc_swaps = NULL; |
e3478379 | 148 | unsigned int i; |
527b7a42 | 149 | int r; |
e3478379 | 150 | |
12aad1d0 LP |
151 | assert(head); |
152 | ||
527b7a42 LP |
153 | proc_swaps = fopen("/proc/swaps", "re"); |
154 | if (!proc_swaps) | |
dee87d61 | 155 | return (errno == ENOENT) ? 0 : -errno; |
e3478379 FF |
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 | ||
527b7a42 LP |
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); | |
e3478379 | 171 | |
527b7a42 | 172 | if (k != 1) { |
e3478379 FF |
173 | if (k == EOF) |
174 | break; | |
175 | ||
176 | log_warning("Failed to parse /proc/swaps:%u.", i); | |
e3478379 FF |
177 | free(dev); |
178 | continue; | |
179 | } | |
180 | ||
a87f0f72 | 181 | if (endswith(dev, " (deleted)")) { |
e3478379 FF |
182 | free(dev); |
183 | continue; | |
184 | } | |
185 | ||
527b7a42 | 186 | r = cunescape(dev, UNESCAPE_RELAX, &d); |
e3478379 | 187 | free(dev); |
527b7a42 LP |
188 | if (r < 0) |
189 | return r; | |
e3478379 | 190 | |
527b7a42 LP |
191 | swap = new0(MountPoint, 1); |
192 | if (!swap) { | |
e3478379 | 193 | free(d); |
e1d75803 | 194 | return -ENOMEM; |
e3478379 FF |
195 | } |
196 | ||
2d9a3397 | 197 | swap->path = d; |
71fda00f | 198 | LIST_PREPEND(mount_point, *head, swap); |
e3478379 FF |
199 | } |
200 | ||
e1d75803 | 201 | return 0; |
e3478379 FF |
202 | } |
203 | ||
12aad1d0 | 204 | static int loopback_list_get(MountPoint **head) { |
1ca208fb | 205 | _cleanup_udev_enumerate_unref_ struct udev_enumerate *e = NULL; |
e3478379 | 206 | struct udev_list_entry *item = NULL, *first = NULL; |
06acf2d4 LP |
207 | _cleanup_udev_unref_ struct udev *udev = NULL; |
208 | int r; | |
e3478379 | 209 | |
12aad1d0 LP |
210 | assert(head); |
211 | ||
1ca208fb ZJS |
212 | udev = udev_new(); |
213 | if (!udev) | |
214 | return -ENOMEM; | |
e3478379 | 215 | |
1ca208fb ZJS |
216 | e = udev_enumerate_new(udev); |
217 | if (!e) | |
218 | return -ENOMEM; | |
e3478379 | 219 | |
06acf2d4 LP |
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; | |
e3478379 | 231 | |
06acf2d4 LP |
232 | r = udev_enumerate_scan_devices(e); |
233 | if (r < 0) | |
234 | return r; | |
e3478379 FF |
235 | |
236 | first = udev_enumerate_get_list_entry(e); | |
e3478379 FF |
237 | udev_list_entry_foreach(item, first) { |
238 | MountPoint *lb; | |
1ca208fb | 239 | _cleanup_udev_device_unref_ struct udev_device *d; |
e3478379 | 240 | char *loop; |
b854a7e7 | 241 | const char *dn; |
e3478379 | 242 | |
1ca208fb ZJS |
243 | d = udev_device_new_from_syspath(udev, udev_list_entry_get_name(item)); |
244 | if (!d) | |
245 | return -ENOMEM; | |
e3478379 | 246 | |
1ca208fb ZJS |
247 | dn = udev_device_get_devnode(d); |
248 | if (!dn) | |
2d9a3397 | 249 | continue; |
b854a7e7 | 250 | |
2d9a3397 | 251 | loop = strdup(dn); |
1ca208fb ZJS |
252 | if (!loop) |
253 | return -ENOMEM; | |
b854a7e7 | 254 | |
1ca208fb ZJS |
255 | lb = new0(MountPoint, 1); |
256 | if (!lb) { | |
e3478379 | 257 | free(loop); |
1ca208fb | 258 | return -ENOMEM; |
e3478379 FF |
259 | } |
260 | ||
2d9a3397 | 261 | lb->path = loop; |
71fda00f | 262 | LIST_PREPEND(mount_point, *head, lb); |
e3478379 FF |
263 | } |
264 | ||
1ca208fb | 265 | return 0; |
e3478379 FF |
266 | } |
267 | ||
12aad1d0 | 268 | static int dm_list_get(MountPoint **head) { |
1ca208fb | 269 | _cleanup_udev_enumerate_unref_ struct udev_enumerate *e = NULL; |
d48141ba | 270 | struct udev_list_entry *item = NULL, *first = NULL; |
06acf2d4 LP |
271 | _cleanup_udev_unref_ struct udev *udev = NULL; |
272 | int r; | |
d48141ba | 273 | |
12aad1d0 LP |
274 | assert(head); |
275 | ||
1ca208fb ZJS |
276 | udev = udev_new(); |
277 | if (!udev) | |
278 | return -ENOMEM; | |
d48141ba | 279 | |
1ca208fb ZJS |
280 | e = udev_enumerate_new(udev); |
281 | if (!e) | |
282 | return -ENOMEM; | |
d48141ba | 283 | |
06acf2d4 LP |
284 | r = udev_enumerate_add_match_subsystem(e, "block"); |
285 | if (r < 0) | |
286 | return r; | |
d48141ba | 287 | |
06acf2d4 LP |
288 | r = udev_enumerate_add_match_sysname(e, "dm-*"); |
289 | if (r < 0) | |
290 | return r; | |
d48141ba | 291 | |
06acf2d4 LP |
292 | r = udev_enumerate_scan_devices(e); |
293 | if (r < 0) | |
294 | return r; | |
d48141ba | 295 | |
06acf2d4 | 296 | first = udev_enumerate_get_list_entry(e); |
d48141ba | 297 | udev_list_entry_foreach(item, first) { |
2d9a3397 | 298 | MountPoint *m; |
1ca208fb | 299 | _cleanup_udev_device_unref_ struct udev_device *d; |
2d9a3397 LP |
300 | dev_t devnum; |
301 | char *node; | |
302 | const char *dn; | |
d48141ba | 303 | |
1ca208fb ZJS |
304 | d = udev_device_new_from_syspath(udev, udev_list_entry_get_name(item)); |
305 | if (!d) | |
306 | return -ENOMEM; | |
d48141ba | 307 | |
2d9a3397 LP |
308 | devnum = udev_device_get_devnum(d); |
309 | dn = udev_device_get_devnode(d); | |
1ca208fb | 310 | if (major(devnum) == 0 || !dn) |
2d9a3397 | 311 | continue; |
d48141ba | 312 | |
2d9a3397 | 313 | node = strdup(dn); |
1ca208fb ZJS |
314 | if (!node) |
315 | return -ENOMEM; | |
d48141ba | 316 | |
1ca208fb ZJS |
317 | m = new(MountPoint, 1); |
318 | if (!m) { | |
2d9a3397 | 319 | free(node); |
1ca208fb | 320 | return -ENOMEM; |
d48141ba LP |
321 | } |
322 | ||
2d9a3397 LP |
323 | m->path = node; |
324 | m->devnum = devnum; | |
71fda00f | 325 | LIST_PREPEND(mount_point, *head, m); |
d48141ba LP |
326 | } |
327 | ||
1ca208fb | 328 | return 0; |
d48141ba LP |
329 | } |
330 | ||
e3478379 | 331 | static int delete_loopback(const char *device) { |
03e334a1 LP |
332 | _cleanup_close_ int fd = -1; |
333 | int r; | |
e3478379 | 334 | |
03e334a1 LP |
335 | fd = open(device, O_RDONLY|O_CLOEXEC); |
336 | if (fd < 0) | |
c4f8bd1a | 337 | return errno == ENOENT ? 0 : -errno; |
e3478379 | 338 | |
ce726252 | 339 | r = ioctl(fd, LOOP_CLR_FD, 0); |
12aad1d0 LP |
340 | if (r >= 0) |
341 | return 1; | |
342 | ||
ce726252 | 343 | /* ENXIO: not bound, so no error */ |
12aad1d0 LP |
344 | if (errno == ENXIO) |
345 | return 0; | |
346 | ||
347 | return -errno; | |
e3478379 FF |
348 | } |
349 | ||
2d9a3397 | 350 | static int delete_dm(dev_t devnum) { |
cf139e60 | 351 | |
b92bea5d | 352 | struct dm_ioctl dm = { |
cf139e60 LP |
353 | .version = { |
354 | DM_VERSION_MAJOR, | |
355 | DM_VERSION_MINOR, | |
356 | DM_VERSION_PATCHLEVEL | |
357 | }, | |
b92bea5d ZJS |
358 | .data_size = sizeof(dm), |
359 | .dev = devnum, | |
360 | }; | |
d48141ba | 361 | |
cf139e60 LP |
362 | _cleanup_close_ int fd = -1; |
363 | ||
2d9a3397 | 364 | assert(major(devnum) != 0); |
d48141ba | 365 | |
e62d8c39 ZJS |
366 | fd = open("/dev/mapper/control", O_RDWR|O_CLOEXEC); |
367 | if (fd < 0) | |
d48141ba LP |
368 | return -errno; |
369 | ||
cf139e60 LP |
370 | if (ioctl(fd, DM_DEV_REMOVE, &dm) < 0) |
371 | return -errno; | |
372 | ||
373 | return 0; | |
d48141ba LP |
374 | } |
375 | ||
c826cd3f ZJS |
376 | static bool nonunmountable_path(const char *path) { |
377 | return path_equal(path, "/") | |
349cc4a5 | 378 | #if ! HAVE_SPLIT_USR |
c826cd3f ZJS |
379 | || path_equal(path, "/usr") |
380 | #endif | |
381 | || path_startswith(path, "/run/initramfs"); | |
382 | } | |
383 | ||
31657718 | 384 | static int mount_points_list_umount(MountPoint **head, bool *changed, bool log_error) { |
12aad1d0 LP |
385 | MountPoint *m, *n; |
386 | int n_failed = 0; | |
e3478379 | 387 | |
12aad1d0 LP |
388 | assert(head); |
389 | ||
390 | LIST_FOREACH_SAFE(mount_point, m, n, *head) { | |
93bd1577 LP |
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 | |
9cbc4547 N |
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)) { | |
471b48ed JJ |
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 | ||
93bd1577 LP |
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 | |
ab06eef8 | 415 | * cannot umount or remount it directly, |
93bd1577 LP |
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 | |
c826cd3f ZJS |
423 | * relatively safe regarding keeping dirty an fs |
424 | * we cannot otherwise see. */ | |
471b48ed | 425 | log_info("Remounting '%s' read-only with options '%s'.", m->path, options); |
c826cd3f ZJS |
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 | } | |
93bd1577 LP |
432 | } |
433 | ||
434 | /* Skip / and /usr since we cannot unmount that | |
5a6f9d23 HG |
435 | * anyway, since we are running from it. They have |
436 | * already been remounted ro. */ | |
c826cd3f | 437 | if (nonunmountable_path(m->path)) |
e3478379 FF |
438 | continue; |
439 | ||
0c08f5cd LP |
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. */ | |
bce93b7a | 443 | log_info("Unmounting %s.", m->path); |
0c08f5cd | 444 | if (umount2(m->path, 0) == 0) { |
12aad1d0 LP |
445 | if (changed) |
446 | *changed = true; | |
447 | ||
448 | mount_point_free(head, m); | |
c826cd3f ZJS |
449 | } else { |
450 | if (log_error) | |
451 | log_warning_errno(errno, "Could not unmount %s: %m", m->path); | |
12aad1d0 | 452 | n_failed++; |
e3478379 FF |
453 | } |
454 | } | |
455 | ||
12aad1d0 | 456 | return n_failed; |
e3478379 FF |
457 | } |
458 | ||
12aad1d0 LP |
459 | static int swap_points_list_off(MountPoint **head, bool *changed) { |
460 | MountPoint *m, *n; | |
461 | int n_failed = 0; | |
462 | ||
463 | assert(head); | |
e3478379 | 464 | |
12aad1d0 | 465 | LIST_FOREACH_SAFE(mount_point, m, n, *head) { |
735e0712 | 466 | log_info("Deactivating swap %s.", m->path); |
12aad1d0 LP |
467 | if (swapoff(m->path) == 0) { |
468 | if (changed) | |
469 | *changed = true; | |
470 | ||
471 | mount_point_free(head, m); | |
472 | } else { | |
56f64d95 | 473 | log_warning_errno(errno, "Could not deactivate swap %s: %m", m->path); |
12aad1d0 | 474 | n_failed++; |
e3478379 FF |
475 | } |
476 | } | |
477 | ||
12aad1d0 | 478 | return n_failed; |
e3478379 FF |
479 | } |
480 | ||
12aad1d0 LP |
481 | static int loopback_points_list_detach(MountPoint **head, bool *changed) { |
482 | MountPoint *m, *n; | |
7fc942b2 LP |
483 | int n_failed = 0, k; |
484 | struct stat root_st; | |
12aad1d0 LP |
485 | |
486 | assert(head); | |
487 | ||
7fc942b2 LP |
488 | k = lstat("/", &root_st); |
489 | ||
12aad1d0 LP |
490 | LIST_FOREACH_SAFE(mount_point, m, n, *head) { |
491 | int r; | |
7fc942b2 LP |
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) { | |
313cefa1 | 498 | n_failed++; |
7fc942b2 LP |
499 | continue; |
500 | } | |
e3478379 | 501 | |
735e0712 | 502 | log_info("Detaching loopback %s.", m->path); |
bce93b7a MS |
503 | r = delete_loopback(m->path); |
504 | if (r >= 0) { | |
12aad1d0 LP |
505 | if (r > 0 && changed) |
506 | *changed = true; | |
507 | ||
508 | mount_point_free(head, m); | |
509 | } else { | |
56f64d95 | 510 | log_warning_errno(errno, "Could not detach loopback %s: %m", m->path); |
12aad1d0 | 511 | n_failed++; |
e3478379 FF |
512 | } |
513 | } | |
514 | ||
12aad1d0 | 515 | return n_failed; |
e3478379 FF |
516 | } |
517 | ||
12aad1d0 LP |
518 | static int dm_points_list_detach(MountPoint **head, bool *changed) { |
519 | MountPoint *m, *n; | |
33e8d8af FB |
520 | int n_failed = 0, r; |
521 | dev_t rootdev; | |
12aad1d0 LP |
522 | |
523 | assert(head); | |
524 | ||
33e8d8af FB |
525 | r = get_block_device("/", &rootdev); |
526 | if (r <= 0) | |
527 | rootdev = 0; | |
7fc942b2 | 528 | |
12aad1d0 | 529 | LIST_FOREACH_SAFE(mount_point, m, n, *head) { |
12aad1d0 | 530 | |
33e8d8af FB |
531 | if (major(rootdev) != 0) |
532 | if (rootdev == m->devnum) { | |
533 | n_failed ++; | |
534 | continue; | |
535 | } | |
7fc942b2 | 536 | |
735e0712 | 537 | log_info("Detaching DM %u:%u.", major(m->devnum), minor(m->devnum)); |
bce93b7a MS |
538 | r = delete_dm(m->devnum); |
539 | if (r >= 0) { | |
c6784066 | 540 | if (changed) |
12aad1d0 | 541 | *changed = true; |
d48141ba | 542 | |
12aad1d0 LP |
543 | mount_point_free(head, m); |
544 | } else { | |
56f64d95 | 545 | log_warning_errno(errno, "Could not detach DM %s: %m", m->path); |
12aad1d0 | 546 | n_failed++; |
d48141ba LP |
547 | } |
548 | } | |
549 | ||
12aad1d0 | 550 | return n_failed; |
d48141ba LP |
551 | } |
552 | ||
12aad1d0 | 553 | int umount_all(bool *changed) { |
e3478379 | 554 | int r; |
6f7f51f7 | 555 | bool umount_changed; |
e3478379 FF |
556 | LIST_HEAD(MountPoint, mp_list_head); |
557 | ||
71fda00f | 558 | LIST_HEAD_INIT(mp_list_head); |
e3478379 FF |
559 | r = mount_points_list_get(&mp_list_head); |
560 | if (r < 0) | |
561 | goto end; | |
562 | ||
6f7f51f7 HH |
563 | /* retry umount, until nothing can be umounted anymore */ |
564 | do { | |
565 | umount_changed = false; | |
3e085b6c LP |
566 | |
567 | mount_points_list_umount(&mp_list_head, &umount_changed, false); | |
6f7f51f7 HH |
568 | if (umount_changed) |
569 | *changed = true; | |
3e085b6c LP |
570 | |
571 | } while (umount_changed); | |
572 | ||
31657718 HH |
573 | /* umount one more time with logging enabled */ |
574 | r = mount_points_list_umount(&mp_list_head, &umount_changed, true); | |
e3478379 | 575 | |
e3478379 FF |
576 | end: |
577 | mount_points_list_free(&mp_list_head); | |
578 | ||
579 | return r; | |
580 | } | |
581 | ||
12aad1d0 | 582 | int swapoff_all(bool *changed) { |
e3478379 FF |
583 | int r; |
584 | LIST_HEAD(MountPoint, swap_list_head); | |
585 | ||
71fda00f | 586 | LIST_HEAD_INIT(swap_list_head); |
e3478379 FF |
587 | |
588 | r = swap_list_get(&swap_list_head); | |
589 | if (r < 0) | |
590 | goto end; | |
591 | ||
12aad1d0 | 592 | r = swap_points_list_off(&swap_list_head, changed); |
e3478379 FF |
593 | |
594 | end: | |
595 | mount_points_list_free(&swap_list_head); | |
596 | ||
597 | return r; | |
598 | } | |
599 | ||
12aad1d0 | 600 | int loopback_detach_all(bool *changed) { |
e3478379 FF |
601 | int r; |
602 | LIST_HEAD(MountPoint, loopback_list_head); | |
603 | ||
71fda00f | 604 | LIST_HEAD_INIT(loopback_list_head); |
e3478379 FF |
605 | |
606 | r = loopback_list_get(&loopback_list_head); | |
607 | if (r < 0) | |
608 | goto end; | |
609 | ||
12aad1d0 | 610 | r = loopback_points_list_detach(&loopback_list_head, changed); |
e3478379 FF |
611 | |
612 | end: | |
613 | mount_points_list_free(&loopback_list_head); | |
614 | ||
615 | return r; | |
616 | } | |
d48141ba | 617 | |
12aad1d0 | 618 | int dm_detach_all(bool *changed) { |
d48141ba LP |
619 | int r; |
620 | LIST_HEAD(MountPoint, dm_list_head); | |
621 | ||
71fda00f | 622 | LIST_HEAD_INIT(dm_list_head); |
d48141ba LP |
623 | |
624 | r = dm_list_get(&dm_list_head); | |
625 | if (r < 0) | |
626 | goto end; | |
627 | ||
12aad1d0 | 628 | r = dm_points_list_detach(&dm_list_head, changed); |
d48141ba LP |
629 | |
630 | end: | |
631 | mount_points_list_free(&dm_list_head); | |
632 | ||
633 | return r; | |
634 | } |