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