chiark / gitweb /
shutdown: in the final umount loop don't use MNT_FORCE
[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 #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. We don't force here since we rely
446                  * on busy NFS and FUSE file systems to return EBUSY
447                  * until we closed everything on top of them. */
448                 log_info("Unmounting %s.", m->path);
449                 if (umount2(m->path, 0) == 0) {
450                         if (changed)
451                                 *changed = true;
452
453                         mount_point_free(head, m);
454                 } else if (log_error) {
455                         log_warning("Could not unmount %s: %m", m->path);
456                         n_failed++;
457                 }
458         }
459
460         return n_failed;
461 }
462
463 static int swap_points_list_off(MountPoint **head, bool *changed) {
464         MountPoint *m, *n;
465         int n_failed = 0;
466
467         assert(head);
468
469         LIST_FOREACH_SAFE(mount_point, m, n, *head) {
470                 log_info("Deactivating swap %s.", m->path);
471                 if (swapoff(m->path) == 0) {
472                         if (changed)
473                                 *changed = true;
474
475                         mount_point_free(head, m);
476                 } else {
477                         log_warning("Could not deactivate swap %s: %m", m->path);
478                         n_failed++;
479                 }
480         }
481
482         return n_failed;
483 }
484
485 static int loopback_points_list_detach(MountPoint **head, bool *changed) {
486         MountPoint *m, *n;
487         int n_failed = 0, k;
488         struct stat root_st;
489
490         assert(head);
491
492         k = lstat("/", &root_st);
493
494         LIST_FOREACH_SAFE(mount_point, m, n, *head) {
495                 int r;
496                 struct stat loopback_st;
497
498                 if (k >= 0 &&
499                     major(root_st.st_dev) != 0 &&
500                     lstat(m->path, &loopback_st) >= 0 &&
501                     root_st.st_dev == loopback_st.st_rdev) {
502                         n_failed ++;
503                         continue;
504                 }
505
506                 log_info("Detaching loopback %s.", m->path);
507                 r = delete_loopback(m->path);
508                 if (r >= 0) {
509                         if (r > 0 && changed)
510                                 *changed = true;
511
512                         mount_point_free(head, m);
513                 } else {
514                         log_warning("Could not detach loopback %s: %m", m->path);
515                         n_failed++;
516                 }
517         }
518
519         return n_failed;
520 }
521
522 static int dm_points_list_detach(MountPoint **head, bool *changed) {
523         MountPoint *m, *n;
524         int n_failed = 0, k;
525         struct stat root_st;
526
527         assert(head);
528
529         k = lstat("/", &root_st);
530
531         LIST_FOREACH_SAFE(mount_point, m, n, *head) {
532                 int r;
533
534                 if (k >= 0 &&
535                     major(root_st.st_dev) != 0 &&
536                     root_st.st_dev == m->devnum) {
537                         n_failed ++;
538                         continue;
539                 }
540
541                 log_info("Detaching DM %u:%u.", major(m->devnum), minor(m->devnum));
542                 r = delete_dm(m->devnum);
543                 if (r >= 0) {
544                         if (changed)
545                                 *changed = true;
546
547                         mount_point_free(head, m);
548                 } else {
549                         log_warning("Could not detach DM %s: %m", m->path);
550                         n_failed++;
551                 }
552         }
553
554         return n_failed;
555 }
556
557 int umount_all(bool *changed) {
558         int r;
559         bool umount_changed;
560         LIST_HEAD(MountPoint, mp_list_head);
561
562         LIST_HEAD_INIT(MountPoint, mp_list_head);
563         r = mount_points_list_get(&mp_list_head);
564         if (r < 0)
565                 goto end;
566
567         /* retry umount, until nothing can be umounted anymore */
568         do {
569                 umount_changed = false;
570
571                 mount_points_list_umount(&mp_list_head, &umount_changed, false);
572                 if (umount_changed)
573                         *changed = true;
574
575         } while (umount_changed);
576
577         /* umount one more time with logging enabled */
578         r = mount_points_list_umount(&mp_list_head, &umount_changed, true);
579         if (r <= 0)
580                 goto end;
581
582   end:
583         mount_points_list_free(&mp_list_head);
584
585         return r;
586 }
587
588 int swapoff_all(bool *changed) {
589         int r;
590         LIST_HEAD(MountPoint, swap_list_head);
591
592         LIST_HEAD_INIT(MountPoint, swap_list_head);
593
594         r = swap_list_get(&swap_list_head);
595         if (r < 0)
596                 goto end;
597
598         r = swap_points_list_off(&swap_list_head, changed);
599
600   end:
601         mount_points_list_free(&swap_list_head);
602
603         return r;
604 }
605
606 int loopback_detach_all(bool *changed) {
607         int r;
608         LIST_HEAD(MountPoint, loopback_list_head);
609
610         LIST_HEAD_INIT(MountPoint, loopback_list_head);
611
612         r = loopback_list_get(&loopback_list_head);
613         if (r < 0)
614                 goto end;
615
616         r = loopback_points_list_detach(&loopback_list_head, changed);
617
618   end:
619         mount_points_list_free(&loopback_list_head);
620
621         return r;
622 }
623
624 int dm_detach_all(bool *changed) {
625         int r;
626         LIST_HEAD(MountPoint, dm_list_head);
627
628         LIST_HEAD_INIT(MountPoint, dm_list_head);
629
630         r = dm_list_get(&dm_list_head);
631         if (r < 0)
632                 goto end;
633
634         r = dm_points_list_detach(&dm_list_head, changed);
635
636   end:
637         mount_points_list_free(&dm_list_head);
638
639         return r;
640 }