chiark / gitweb /
e7460cb6bffd14dfaab1cc845ce5182ead92ab56
[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_unref_ struct udev *udev;
206         _cleanup_udev_enumerate_unref_ struct udev_enumerate *e = NULL;
207         struct udev_list_entry *item = NULL, *first = NULL;
208
209         assert(head);
210
211         udev = udev_new();
212         if (!udev)
213                 return -ENOMEM;
214
215         e = udev_enumerate_new(udev);
216         if (!e)
217                 return -ENOMEM;
218
219         if (udev_enumerate_add_match_subsystem(e, "block") < 0 ||
220             udev_enumerate_add_match_sysname(e, "loop*") < 0 ||
221             udev_enumerate_add_match_sysattr(e, "loop/backing_file", NULL) < 0)
222                 return -EIO;
223
224         if (udev_enumerate_scan_devices(e) < 0)
225                 return -EIO;
226
227         first = udev_enumerate_get_list_entry(e);
228         udev_list_entry_foreach(item, first) {
229                 MountPoint *lb;
230                 _cleanup_udev_device_unref_ struct udev_device *d;
231                 char *loop;
232                 const char *dn;
233
234                 d = udev_device_new_from_syspath(udev, udev_list_entry_get_name(item));
235                 if (!d)
236                         return -ENOMEM;
237
238                 dn = udev_device_get_devnode(d);
239                 if (!dn)
240                         continue;
241
242                 loop = strdup(dn);
243                 if (!loop)
244                         return -ENOMEM;
245
246                 lb = new0(MountPoint, 1);
247                 if (!lb) {
248                         free(loop);
249                         return -ENOMEM;
250                 }
251
252                 lb->path = loop;
253                 LIST_PREPEND(mount_point, *head, lb);
254         }
255
256         return 0;
257 }
258
259 static int dm_list_get(MountPoint **head) {
260         _cleanup_udev_unref_ struct udev *udev;
261         _cleanup_udev_enumerate_unref_ struct udev_enumerate *e = NULL;
262         struct udev_list_entry *item = NULL, *first = NULL;
263
264         assert(head);
265
266         udev = udev_new();
267         if (!udev)
268                 return -ENOMEM;
269
270         e = udev_enumerate_new(udev);
271         if (!e)
272                 return -ENOMEM;
273
274         if (udev_enumerate_add_match_subsystem(e, "block") < 0 ||
275             udev_enumerate_add_match_sysname(e, "dm-*") < 0)
276                 return -EIO;
277
278         if (udev_enumerate_scan_devices(e) < 0)
279                 return -EIO;
280
281         first = udev_enumerate_get_list_entry(e);
282
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         int fd, r;
319
320         if ((fd = open(device, O_RDONLY|O_CLOEXEC)) < 0)
321                 return errno == ENOENT ? 0 : -errno;
322
323         r = ioctl(fd, LOOP_CLR_FD, 0);
324         close_nointr_nofail(fd);
325
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("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("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("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("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 }