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