chiark / gitweb /
main: add configuration option to alter capability bounding set for PID 1
[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
38 typedef struct MountPoint {
39         char *path;
40         dev_t devnum;
41         bool skip_ro;
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                 char *root;
77                 bool skip_ro;
78
79                 path = p = NULL;
80
81                 if ((k = fscanf(proc_self_mountinfo,
82                                 "%*s "       /* (1) mount id */
83                                 "%*s "       /* (2) parent id */
84                                 "%*s "       /* (3) major:minor */
85                                 "%ms "       /* (4) root */
86                                 "%ms "       /* (5) mount point */
87                                 "%*s"        /* (6) mount options */
88                                 "%*[^-]"     /* (7) optional fields */
89                                 "- "         /* (8) separator */
90                                 "%*s "       /* (9) file system type */
91                                 "%*s"        /* (10) mount source */
92                                 "%*s"        /* (11) mount options 2 */
93                                 "%*[^\n]",   /* some rubbish at the end */
94                                 &root,
95                                 &path)) != 2) {
96                         if (k == EOF)
97                                 break;
98
99                         log_warning("Failed to parse /proc/self/mountinfo:%u.", i);
100
101                         free(path);
102                         continue;
103                 }
104
105                 /* If we encounter a bind mount, don't try to remount
106                  * the source dir too early */
107                 skip_ro = !streq(root, "/");
108                 free(root);
109
110                 p = cunescape(path);
111                 free(path);
112
113                 if (!p) {
114                         r = -ENOMEM;
115                         goto finish;
116                 }
117
118                 /* Ignore mount points we can't unmount because they
119                  * are API or because we are keeping them open (like
120                  * /dev/console) */
121                 if (mount_point_is_api(p) ||
122                     mount_point_ignore(p) ||
123                     path_equal(p, "/dev/console")) {
124                         free(p);
125                         continue;
126                 }
127
128                 if (!(m = new0(MountPoint, 1))) {
129                         free(p);
130                         r = -ENOMEM;
131                         goto finish;
132                 }
133
134                 m->path = p;
135                 m->skip_ro = skip_ro;
136                 LIST_PREPEND(MountPoint, mount_point, *head, m);
137         }
138
139         r = 0;
140
141 finish:
142         fclose(proc_self_mountinfo);
143
144         return r;
145 }
146
147 static int swap_list_get(MountPoint **head) {
148         FILE *proc_swaps;
149         unsigned int i;
150         int r;
151
152         assert(head);
153
154         if (!(proc_swaps = fopen("/proc/swaps", "re")))
155                 return (errno == ENOENT) ? 0 : -errno;
156
157         (void) fscanf(proc_swaps, "%*s %*s %*s %*s %*s\n");
158
159         for (i = 2;; i++) {
160                 MountPoint *swap;
161                 char *dev = NULL, *d;
162                 int k;
163
164                 if ((k = fscanf(proc_swaps,
165                                 "%ms " /* device/file */
166                                 "%*s " /* type of swap */
167                                 "%*s " /* swap size */
168                                 "%*s " /* used */
169                                 "%*s\n", /* priority */
170                                 &dev)) != 1) {
171
172                         if (k == EOF)
173                                 break;
174
175                         log_warning("Failed to parse /proc/swaps:%u.", i);
176
177                         free(dev);
178                         continue;
179                 }
180
181                 if (endswith(dev, "(deleted)")) {
182                         free(dev);
183                         continue;
184                 }
185
186                 d = cunescape(dev);
187                 free(dev);
188
189                 if (!d) {
190                         r = -ENOMEM;
191                         goto finish;
192                 }
193
194                 if (!(swap = new0(MountPoint, 1))) {
195                         free(d);
196                         r = -ENOMEM;
197                         goto finish;
198                 }
199
200                 swap->path = d;
201                 LIST_PREPEND(MountPoint, mount_point, *head, swap);
202         }
203
204         r = 0;
205
206 finish:
207         fclose(proc_swaps);
208
209         return r;
210 }
211
212 static int loopback_list_get(MountPoint **head) {
213         int r;
214         struct udev *udev;
215         struct udev_enumerate *e = NULL;
216         struct udev_list_entry *item = NULL, *first = NULL;
217
218         assert(head);
219
220         if (!(udev = udev_new())) {
221                 r = -ENOMEM;
222                 goto finish;
223         }
224
225         if (!(e = udev_enumerate_new(udev))) {
226                 r = -ENOMEM;
227                 goto finish;
228         }
229
230         if (udev_enumerate_add_match_subsystem(e, "block") < 0 ||
231             udev_enumerate_add_match_sysname(e, "loop*") < 0) {
232                 r = -EIO;
233                 goto finish;
234         }
235
236         if (udev_enumerate_scan_devices(e) < 0) {
237                 r = -EIO;
238                 goto finish;
239         }
240
241         first = udev_enumerate_get_list_entry(e);
242         udev_list_entry_foreach(item, first) {
243                 MountPoint *lb;
244                 struct udev_device *d;
245                 char *loop;
246                 const char *dn;
247
248                 if (!(d = udev_device_new_from_syspath(udev, udev_list_entry_get_name(item)))) {
249                         r = -ENOMEM;
250                         goto finish;
251                 }
252
253                 if (!(dn = udev_device_get_devnode(d))) {
254                         udev_device_unref(d);
255                         continue;
256                 }
257
258                 loop = strdup(dn);
259                 udev_device_unref(d);
260
261                 if (!loop) {
262                         r = -ENOMEM;
263                         goto finish;
264                 }
265
266                 if (!(lb = new0(MountPoint, 1))) {
267                         free(loop);
268                         r = -ENOMEM;
269                         goto finish;
270                 }
271
272                 lb->path = loop;
273                 LIST_PREPEND(MountPoint, mount_point, *head, lb);
274         }
275
276         r = 0;
277
278 finish:
279         if (e)
280                 udev_enumerate_unref(e);
281
282         if (udev)
283                 udev_unref(udev);
284
285         return r;
286 }
287
288 static int dm_list_get(MountPoint **head) {
289         int r;
290         struct udev *udev;
291         struct udev_enumerate *e = NULL;
292         struct udev_list_entry *item = NULL, *first = NULL;
293
294         assert(head);
295
296         if (!(udev = udev_new())) {
297                 r = -ENOMEM;
298                 goto finish;
299         }
300
301         if (!(e = udev_enumerate_new(udev))) {
302                 r = -ENOMEM;
303                 goto finish;
304         }
305
306         if (udev_enumerate_add_match_subsystem(e, "block") < 0 ||
307             udev_enumerate_add_match_sysname(e, "dm-*") < 0) {
308                 r = -EIO;
309                 goto finish;
310         }
311
312         if (udev_enumerate_scan_devices(e) < 0) {
313                 r = -EIO;
314                 goto finish;
315         }
316
317         first = udev_enumerate_get_list_entry(e);
318
319         udev_list_entry_foreach(item, first) {
320                 MountPoint *m;
321                 struct udev_device *d;
322                 dev_t devnum;
323                 char *node;
324                 const char *dn;
325
326                 if (!(d = udev_device_new_from_syspath(udev, udev_list_entry_get_name(item)))) {
327                         r = -ENOMEM;
328                         goto finish;
329                 }
330
331                 devnum = udev_device_get_devnum(d);
332                 dn = udev_device_get_devnode(d);
333
334                 if (major(devnum) == 0 || !dn) {
335                         udev_device_unref(d);
336                         continue;
337                 }
338
339                 node = strdup(dn);
340                 udev_device_unref(d);
341
342                 if (!node) {
343                         r = -ENOMEM;
344                         goto finish;
345                 }
346
347                 if (!(m = new(MountPoint, 1))) {
348                         free(node);
349                         r = -ENOMEM;
350                         goto finish;
351                 }
352
353                 m->path = node;
354                 m->devnum = devnum;
355                 LIST_PREPEND(MountPoint, mount_point, *head, m);
356         }
357
358         r = 0;
359
360 finish:
361         if (e)
362                 udev_enumerate_unref(e);
363
364         if (udev)
365                 udev_unref(udev);
366
367         return r;
368 }
369
370 static int delete_loopback(const char *device) {
371         int fd, r;
372
373         if ((fd = open(device, O_RDONLY|O_CLOEXEC)) < 0)
374                 return errno == ENOENT ? 0 : -errno;
375
376         r = ioctl(fd, LOOP_CLR_FD, 0);
377         close_nointr_nofail(fd);
378
379         if (r >= 0)
380                 return 1;
381
382         /* ENXIO: not bound, so no error */
383         if (errno == ENXIO)
384                 return 0;
385
386         return -errno;
387 }
388
389 static int delete_dm(dev_t devnum) {
390         int fd, r;
391         struct dm_ioctl dm;
392
393         assert(major(devnum) != 0);
394
395         if ((fd = open("/dev/mapper/control", O_RDWR|O_CLOEXEC)) < 0)
396                 return -errno;
397
398         zero(dm);
399         dm.version[0] = DM_VERSION_MAJOR;
400         dm.version[1] = DM_VERSION_MINOR;
401         dm.version[2] = DM_VERSION_PATCHLEVEL;
402
403         dm.data_size = sizeof(dm);
404         dm.dev = devnum;
405
406         r = ioctl(fd, DM_DEV_REMOVE, &dm);
407         close_nointr_nofail(fd);
408
409         return r >= 0 ? 0 : -errno;
410 }
411
412 static int mount_points_list_umount(MountPoint **head, bool *changed, bool log_error) {
413         MountPoint *m, *n;
414         int n_failed = 0;
415
416         assert(head);
417
418         LIST_FOREACH_SAFE(mount_point, m, n, *head) {
419                 if (path_equal(m->path, "/")
420 #ifndef HAVE_SPLIT_USR
421                     || path_equal(m->path, "/usr")
422 #endif
423                 ) {
424                         n_failed++;
425                         continue;
426                 }
427
428                 /* Trying to umount. Forcing to umount if busy (only for NFS mounts) */
429                 if (umount2(m->path, MNT_FORCE) == 0) {
430                         log_info("Unmounted %s.", m->path);
431                         if (changed)
432                                 *changed = true;
433
434                         mount_point_free(head, m);
435                 } else if (log_error) {
436                         log_warning("Could not unmount %s: %m", m->path);
437                         n_failed++;
438                 }
439         }
440
441         return n_failed;
442 }
443
444 static int mount_points_list_remount_read_only(MountPoint **head, bool *changed) {
445         MountPoint *m, *n;
446         int n_failed = 0;
447
448         assert(head);
449
450         LIST_FOREACH_SAFE(mount_point, m, n, *head) {
451
452                 if (m->skip_ro) {
453                         n_failed++;
454                         continue;
455                 }
456
457                 /* Trying to remount read-only */
458                 if (mount(NULL, m->path, NULL, MS_MGC_VAL|MS_REMOUNT|MS_RDONLY, NULL) == 0) {
459                         if (changed)
460                                 *changed = true;
461
462                         mount_point_free(head, m);
463                 } else {
464                         log_warning("Could not remount as read-only %s: %m", m->path);
465                         n_failed++;
466                 }
467         }
468
469         return n_failed;
470 }
471
472 static int swap_points_list_off(MountPoint **head, bool *changed) {
473         MountPoint *m, *n;
474         int n_failed = 0;
475
476         assert(head);
477
478         LIST_FOREACH_SAFE(mount_point, m, n, *head) {
479                 if (swapoff(m->path) == 0) {
480                         if (changed)
481                                 *changed = true;
482
483                         mount_point_free(head, m);
484                 } else {
485                         log_warning("Could not deactivate swap %s: %m", m->path);
486                         n_failed++;
487                 }
488         }
489
490         return n_failed;
491 }
492
493 static int loopback_points_list_detach(MountPoint **head, bool *changed) {
494         MountPoint *m, *n;
495         int n_failed = 0, k;
496         struct stat root_st;
497
498         assert(head);
499
500         k = lstat("/", &root_st);
501
502         LIST_FOREACH_SAFE(mount_point, m, n, *head) {
503                 int r;
504                 struct stat loopback_st;
505
506                 if (k >= 0 &&
507                     major(root_st.st_dev) != 0 &&
508                     lstat(m->path, &loopback_st) >= 0 &&
509                     root_st.st_dev == loopback_st.st_rdev) {
510                         n_failed ++;
511                         continue;
512                 }
513
514                 if ((r = delete_loopback(m->path)) >= 0) {
515
516                         if (r > 0 && changed)
517                                 *changed = true;
518
519                         mount_point_free(head, m);
520                 } else {
521                         log_warning("Could not delete loopback %s: %m", m->path);
522                         n_failed++;
523                 }
524         }
525
526         return n_failed;
527 }
528
529 static int dm_points_list_detach(MountPoint **head, bool *changed) {
530         MountPoint *m, *n;
531         int n_failed = 0, k;
532         struct stat root_st;
533
534         assert(head);
535
536         k = lstat("/", &root_st);
537
538         LIST_FOREACH_SAFE(mount_point, m, n, *head) {
539                 int r;
540
541                 if (k >= 0 &&
542                     major(root_st.st_dev) != 0 &&
543                     root_st.st_dev == m->devnum) {
544                         n_failed ++;
545                         continue;
546                 }
547
548                 if ((r = delete_dm(m->devnum)) >= 0) {
549
550                         if (r > 0 && changed)
551                                 *changed = true;
552
553                         mount_point_free(head, m);
554                 } else {
555                         log_warning("Could not delete dm %s: %m", m->path);
556                         n_failed++;
557                 }
558         }
559
560         return n_failed;
561 }
562
563 int umount_all(bool *changed) {
564         int r;
565         bool umount_changed;
566
567         LIST_HEAD(MountPoint, mp_list_head);
568
569         LIST_HEAD_INIT(MountPoint, mp_list_head);
570
571         r = mount_points_list_get(&mp_list_head);
572         if (r < 0)
573                 goto end;
574
575         /* retry umount, until nothing can be umounted anymore */
576         do {
577                 umount_changed = false;
578
579                 mount_points_list_umount(&mp_list_head, &umount_changed, false);
580                 if (umount_changed)
581                         *changed = true;
582
583         } while (umount_changed);
584
585         /* umount one more time with logging enabled */
586         r = mount_points_list_umount(&mp_list_head, &umount_changed, true);
587         if (r <= 0)
588                 goto end;
589
590         r = mount_points_list_remount_read_only(&mp_list_head, changed);
591
592   end:
593         mount_points_list_free(&mp_list_head);
594
595         return r;
596 }
597
598 int swapoff_all(bool *changed) {
599         int r;
600         LIST_HEAD(MountPoint, swap_list_head);
601
602         LIST_HEAD_INIT(MountPoint, swap_list_head);
603
604         r = swap_list_get(&swap_list_head);
605         if (r < 0)
606                 goto end;
607
608         r = swap_points_list_off(&swap_list_head, changed);
609
610   end:
611         mount_points_list_free(&swap_list_head);
612
613         return r;
614 }
615
616 int loopback_detach_all(bool *changed) {
617         int r;
618         LIST_HEAD(MountPoint, loopback_list_head);
619
620         LIST_HEAD_INIT(MountPoint, loopback_list_head);
621
622         r = loopback_list_get(&loopback_list_head);
623         if (r < 0)
624                 goto end;
625
626         r = loopback_points_list_detach(&loopback_list_head, changed);
627
628   end:
629         mount_points_list_free(&loopback_list_head);
630
631         return r;
632 }
633
634 int dm_detach_all(bool *changed) {
635         int r;
636         LIST_HEAD(MountPoint, dm_list_head);
637
638         LIST_HEAD_INIT(MountPoint, dm_list_head);
639
640         r = dm_list_get(&dm_list_head);
641         if (r < 0)
642                 goto end;
643
644         r = dm_points_list_detach(&dm_list_head, changed);
645
646   end:
647         mount_points_list_free(&dm_list_head);
648
649         return r;
650 }