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