chiark / gitweb /
2d166c1c92c967a69f6d060b3b8c5c8bc15faf67
[elogind.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         FILE *proc_self_mountinfo;
65         char *path, *p;
66         unsigned int i;
67         int r;
68
69         assert(head);
70
71         if (!(proc_self_mountinfo = fopen("/proc/self/mountinfo", "re")))
72                 return -errno;
73
74         for (i = 1;; i++) {
75                 int k;
76                 MountPoint *m;
77
78                 path = p = NULL;
79
80                 if ((k = fscanf(proc_self_mountinfo,
81                                 "%*s "       /* (1) mount id */
82                                 "%*s "       /* (2) parent id */
83                                 "%*s "       /* (3) major:minor */
84                                 "%*s "       /* (4) root */
85                                 "%ms "       /* (5) mount point */
86                                 "%*s"        /* (6) mount options */
87                                 "%*[^-]"     /* (7) optional fields */
88                                 "- "         /* (8) separator */
89                                 "%*s "       /* (9) file system type */
90                                 "%*s"        /* (10) mount source */
91                                 "%*s"        /* (11) mount options 2 */
92                                 "%*[^\n]",   /* some rubbish at the end */
93                                 &path)) != 1) {
94                         if (k == EOF)
95                                 break;
96
97                         log_warning("Failed to parse /proc/self/mountinfo:%u.", i);
98
99                         free(path);
100                         continue;
101                 }
102
103                 p = cunescape(path);
104                 free(path);
105
106                 if (!p) {
107                         r = -ENOMEM;
108                         goto finish;
109                 }
110
111                 /* Ignore mount points we can't unmount because they
112                  * are API or because we are keeping them open (like
113                  * /dev/console) */
114                 if (mount_point_is_api(p) ||
115                     mount_point_ignore(p) ||
116                     path_equal(p, "/dev/console")) {
117                         free(p);
118                         continue;
119                 }
120
121                 if (!(m = new0(MountPoint, 1))) {
122                         free(p);
123                         r = -ENOMEM;
124                         goto finish;
125                 }
126
127                 m->path = p;
128                 LIST_PREPEND(mount_point, *head, m);
129         }
130
131         r = 0;
132
133 finish:
134         fclose(proc_self_mountinfo);
135
136         return r;
137 }
138
139 static int swap_list_get(MountPoint **head) {
140         FILE *proc_swaps;
141         unsigned int i;
142         int r;
143
144         assert(head);
145
146         if (!(proc_swaps = fopen("/proc/swaps", "re")))
147                 return (errno == ENOENT) ? 0 : -errno;
148
149         (void) fscanf(proc_swaps, "%*s %*s %*s %*s %*s\n");
150
151         for (i = 2;; i++) {
152                 MountPoint *swap;
153                 char *dev = NULL, *d;
154                 int k;
155
156                 if ((k = fscanf(proc_swaps,
157                                 "%ms " /* device/file */
158                                 "%*s " /* type of swap */
159                                 "%*s " /* swap size */
160                                 "%*s " /* used */
161                                 "%*s\n", /* priority */
162                                 &dev)) != 1) {
163
164                         if (k == EOF)
165                                 break;
166
167                         log_warning("Failed to parse /proc/swaps:%u.", i);
168
169                         free(dev);
170                         continue;
171                 }
172
173                 if (endswith(dev, " (deleted)")) {
174                         free(dev);
175                         continue;
176                 }
177
178                 d = cunescape(dev);
179                 free(dev);
180
181                 if (!d) {
182                         r = -ENOMEM;
183                         goto finish;
184                 }
185
186                 if (!(swap = new0(MountPoint, 1))) {
187                         free(d);
188                         r = -ENOMEM;
189                         goto finish;
190                 }
191
192                 swap->path = d;
193                 LIST_PREPEND(mount_point, *head, swap);
194         }
195
196         r = 0;
197
198 finish:
199         fclose(proc_swaps);
200
201         return r;
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         int fd, r;
333
334         if ((fd = open(device, O_RDONLY|O_CLOEXEC)) < 0)
335                 return errno == ENOENT ? 0 : -errno;
336
337         r = ioctl(fd, LOOP_CLR_FD, 0);
338         close_nointr_nofail(fd);
339
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         _cleanup_close_ int fd = -1;
352         int r;
353         struct dm_ioctl dm = {
354                 .version = {DM_VERSION_MAJOR,
355                             DM_VERSION_MINOR,
356                             DM_VERSION_PATCHLEVEL},
357                 .data_size = sizeof(dm),
358                 .dev = devnum,
359         };
360
361         assert(major(devnum) != 0);
362
363         fd = open("/dev/mapper/control", O_RDWR|O_CLOEXEC);
364         if (fd < 0)
365                 return -errno;
366
367         r = ioctl(fd, DM_DEV_REMOVE, &dm);
368         return r >= 0 ? 0 : -errno;
369 }
370
371 static int mount_points_list_umount(MountPoint **head, bool *changed, bool log_error) {
372         MountPoint *m, *n;
373         int n_failed = 0;
374
375         assert(head);
376
377         LIST_FOREACH_SAFE(mount_point, m, n, *head) {
378
379                 /* If we are in a container, don't attempt to
380                    read-only mount anything as that brings no real
381                    benefits, but might confuse the host, as we remount
382                    the superblock here, not the bind mound. */
383                 if (detect_container(NULL) <= 0)  {
384                         /* We always try to remount directories
385                          * read-only first, before we go on and umount
386                          * them.
387                          *
388                          * Mount points can be stacked. If a mount
389                          * point is stacked below / or /usr, we
390                          * cannot umount or remount it directly,
391                          * since there is no way to refer to the
392                          * underlying mount. There's nothing we can do
393                          * about it for the general case, but we can
394                          * do something about it if it is aliased
395                          * somehwere else via a bind mount. If we
396                          * explicitly remount the super block of that
397                          * alias read-only we hence should be
398                          * relatively safe regarding keeping the fs we
399                          * can otherwise not see dirty. */
400                         mount(NULL, m->path, NULL, MS_REMOUNT|MS_RDONLY, NULL);
401                 }
402
403                 /* Skip / and /usr since we cannot unmount that
404                  * anyway, since we are running from it. They have
405                  * already been remounted ro. */
406                 if (path_equal(m->path, "/")
407 #ifndef HAVE_SPLIT_USR
408                     || path_equal(m->path, "/usr")
409 #endif
410                 )
411                         continue;
412
413                 /* Trying to umount. We don't force here since we rely
414                  * on busy NFS and FUSE file systems to return EBUSY
415                  * until we closed everything on top of them. */
416                 log_info("Unmounting %s.", m->path);
417                 if (umount2(m->path, 0) == 0) {
418                         if (changed)
419                                 *changed = true;
420
421                         mount_point_free(head, m);
422                 } else if (log_error) {
423                         log_warning("Could not unmount %s: %m", m->path);
424                         n_failed++;
425                 }
426         }
427
428         return n_failed;
429 }
430
431 static int swap_points_list_off(MountPoint **head, bool *changed) {
432         MountPoint *m, *n;
433         int n_failed = 0;
434
435         assert(head);
436
437         LIST_FOREACH_SAFE(mount_point, m, n, *head) {
438                 log_info("Deactivating swap %s.", m->path);
439                 if (swapoff(m->path) == 0) {
440                         if (changed)
441                                 *changed = true;
442
443                         mount_point_free(head, m);
444                 } else {
445                         log_warning("Could not deactivate swap %s: %m", m->path);
446                         n_failed++;
447                 }
448         }
449
450         return n_failed;
451 }
452
453 static int loopback_points_list_detach(MountPoint **head, bool *changed) {
454         MountPoint *m, *n;
455         int n_failed = 0, k;
456         struct stat root_st;
457
458         assert(head);
459
460         k = lstat("/", &root_st);
461
462         LIST_FOREACH_SAFE(mount_point, m, n, *head) {
463                 int r;
464                 struct stat loopback_st;
465
466                 if (k >= 0 &&
467                     major(root_st.st_dev) != 0 &&
468                     lstat(m->path, &loopback_st) >= 0 &&
469                     root_st.st_dev == loopback_st.st_rdev) {
470                         n_failed ++;
471                         continue;
472                 }
473
474                 log_info("Detaching loopback %s.", m->path);
475                 r = delete_loopback(m->path);
476                 if (r >= 0) {
477                         if (r > 0 && changed)
478                                 *changed = true;
479
480                         mount_point_free(head, m);
481                 } else {
482                         log_warning("Could not detach loopback %s: %m", m->path);
483                         n_failed++;
484                 }
485         }
486
487         return n_failed;
488 }
489
490 static int dm_points_list_detach(MountPoint **head, bool *changed) {
491         MountPoint *m, *n;
492         int n_failed = 0, k;
493         struct stat root_st;
494
495         assert(head);
496
497         k = lstat("/", &root_st);
498
499         LIST_FOREACH_SAFE(mount_point, m, n, *head) {
500                 int r;
501
502                 if (k >= 0 &&
503                     major(root_st.st_dev) != 0 &&
504                     root_st.st_dev == m->devnum) {
505                         n_failed ++;
506                         continue;
507                 }
508
509                 log_info("Detaching DM %u:%u.", major(m->devnum), minor(m->devnum));
510                 r = delete_dm(m->devnum);
511                 if (r >= 0) {
512                         if (changed)
513                                 *changed = true;
514
515                         mount_point_free(head, m);
516                 } else {
517                         log_warning("Could not detach DM %s: %m", m->path);
518                         n_failed++;
519                 }
520         }
521
522         return n_failed;
523 }
524
525 int umount_all(bool *changed) {
526         int r;
527         bool umount_changed;
528         LIST_HEAD(MountPoint, mp_list_head);
529
530         LIST_HEAD_INIT(mp_list_head);
531         r = mount_points_list_get(&mp_list_head);
532         if (r < 0)
533                 goto end;
534
535         /* retry umount, until nothing can be umounted anymore */
536         do {
537                 umount_changed = false;
538
539                 mount_points_list_umount(&mp_list_head, &umount_changed, false);
540                 if (umount_changed)
541                         *changed = true;
542
543         } while (umount_changed);
544
545         /* umount one more time with logging enabled */
546         r = mount_points_list_umount(&mp_list_head, &umount_changed, true);
547         if (r <= 0)
548                 goto end;
549
550   end:
551         mount_points_list_free(&mp_list_head);
552
553         return r;
554 }
555
556 int swapoff_all(bool *changed) {
557         int r;
558         LIST_HEAD(MountPoint, swap_list_head);
559
560         LIST_HEAD_INIT(swap_list_head);
561
562         r = swap_list_get(&swap_list_head);
563         if (r < 0)
564                 goto end;
565
566         r = swap_points_list_off(&swap_list_head, changed);
567
568   end:
569         mount_points_list_free(&swap_list_head);
570
571         return r;
572 }
573
574 int loopback_detach_all(bool *changed) {
575         int r;
576         LIST_HEAD(MountPoint, loopback_list_head);
577
578         LIST_HEAD_INIT(loopback_list_head);
579
580         r = loopback_list_get(&loopback_list_head);
581         if (r < 0)
582                 goto end;
583
584         r = loopback_points_list_detach(&loopback_list_head, changed);
585
586   end:
587         mount_points_list_free(&loopback_list_head);
588
589         return r;
590 }
591
592 int dm_detach_all(bool *changed) {
593         int r;
594         LIST_HEAD(MountPoint, dm_list_head);
595
596         LIST_HEAD_INIT(dm_list_head);
597
598         r = dm_list_get(&dm_list_head);
599         if (r < 0)
600                 goto end;
601
602         r = dm_points_list_detach(&dm_list_head, changed);
603
604   end:
605         mount_points_list_free(&dm_list_head);
606
607         return r;
608 }