source: branches/3.2/mindi-busybox/util-linux/umount.c @ 3232

Last change on this file since 3232 was 3232, checked in by bruno, 5 years ago
  • Update mindi-busybox to 1.21.1
File size: 6.3 KB
Line 
1/* vi: set sw=4 ts=4: */
2/*
3 * Mini umount implementation for busybox
4 *
5 * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org>
6 * Copyright (C) 2005 by Rob Landley <rob@landley.net>
7 *
8 * Licensed under GPLv2, see file LICENSE in this source tree.
9 */
10
11//usage:#define umount_trivial_usage
12//usage:       "[OPTIONS] FILESYSTEM|DIRECTORY"
13//usage:#define umount_full_usage "\n\n"
14//usage:       "Unmount file systems\n"
15//usage:    IF_FEATURE_UMOUNT_ALL(
16//usage:     "\n    -a  Unmount all file systems" IF_FEATURE_MTAB_SUPPORT(" in /etc/mtab")
17//usage:    )
18//usage:    IF_FEATURE_MTAB_SUPPORT(
19//usage:     "\n    -n  Don't erase /etc/mtab entries"
20//usage:    )
21//usage:     "\n    -r  Try to remount devices as read-only if mount is busy"
22//usage:     "\n    -l  Lazy umount (detach filesystem)"
23//usage:     "\n    -f  Force umount (i.e., unreachable NFS server)"
24//usage:    IF_FEATURE_MOUNT_LOOP(
25//usage:     "\n    -D  Don't free loop device even if it has been used"
26//usage:    )
27//usage:
28//usage:#define umount_example_usage
29//usage:       "$ umount /dev/hdc1\n"
30
31#include <mntent.h>
32#include <sys/mount.h>
33#include "libbb.h"
34
35#if defined(__dietlibc__)
36// TODO: This does not belong here.
37/* 16.12.2006, Sampo Kellomaki (sampo@iki.fi)
38 * dietlibc-0.30 does not have implementation of getmntent_r() */
39static struct mntent *getmntent_r(FILE* stream, struct mntent* result,
40        char* buffer UNUSED_PARAM, int bufsize UNUSED_PARAM)
41{
42    struct mntent* ment = getmntent(stream);
43    return memcpy(result, ment, sizeof(*ment));
44}
45#endif
46
47/* Ignored: -v -t -i
48 * bbox always acts as if -d is present.
49 * -D can be used to suppress it (bbox extension).
50 * Rationale:
51 * (1) util-linux's umount does it if "loop=..." is seen in /etc/mtab:
52 * thus, on many systems, bare umount _does_ drop loop devices.
53 * (2) many users request this feature.
54 */
55#define OPTION_STRING           "fldDnra" "vt:i"
56#define OPT_FORCE               (1 << 0) // Same as MNT_FORCE
57#define OPT_LAZY                (1 << 1) // Same as MNT_DETACH
58//#define OPT_FREE_LOOP           (1 << 2) // -d is assumed always present
59#define OPT_DONT_FREE_LOOP      (1 << 3)
60#define OPT_NO_MTAB             (1 << 4)
61#define OPT_REMOUNT             (1 << 5)
62#define OPT_ALL                 (ENABLE_FEATURE_UMOUNT_ALL ? (1 << 6) : 0)
63
64int umount_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
65int umount_main(int argc UNUSED_PARAM, char **argv)
66{
67    int doForce;
68    struct mntent me;
69    FILE *fp;
70    char *fstype = NULL;
71    int status = EXIT_SUCCESS;
72    unsigned opt;
73    struct mtab_list {
74        char *dir;
75        char *device;
76        struct mtab_list *next;
77    } *mtl, *m;
78
79    opt = getopt32(argv, OPTION_STRING, &fstype);
80    //argc -= optind;
81    argv += optind;
82
83    // MNT_FORCE and MNT_DETACH (from linux/fs.h) must match
84    // OPT_FORCE and OPT_LAZY, otherwise this trick won't work:
85    doForce = MAX((opt & OPT_FORCE), (opt & OPT_LAZY));
86
87    /* Get a list of mount points from mtab.  We read them all in now mostly
88     * for umount -a (so we don't have to worry about the list changing while
89     * we iterate over it, or about getting stuck in a loop on the same failing
90     * entry.  Notice that this also naturally reverses the list so that -a
91     * umounts the most recent entries first. */
92    m = mtl = NULL;
93
94    // If we're umounting all, then m points to the start of the list and
95    // the argument list should be empty (which will match all).
96    fp = setmntent(bb_path_mtab_file, "r");
97    if (!fp) {
98        if (opt & OPT_ALL)
99            bb_error_msg_and_die("can't open '%s'", bb_path_mtab_file);
100    } else {
101        while (getmntent_r(fp, &me, bb_common_bufsiz1, sizeof(bb_common_bufsiz1))) {
102            /* Match fstype if passed */
103            if (!match_fstype(&me, fstype))
104                continue;
105            m = xzalloc(sizeof(*m));
106            m->next = mtl;
107            m->device = xstrdup(me.mnt_fsname);
108            m->dir = xstrdup(me.mnt_dir);
109            mtl = m;
110        }
111        endmntent(fp);
112    }
113
114    // If we're not umounting all, we need at least one argument.
115    if (!(opt & OPT_ALL) && !fstype) {
116        if (!argv[0])
117            bb_show_usage();
118        m = NULL;
119    }
120
121    // Loop through everything we're supposed to umount, and do so.
122    for (;;) {
123        int curstat;
124        char *zapit = *argv;
125        char *path;
126
127        // Do we already know what to umount this time through the loop?
128        if (m)
129            path = xstrdup(m->dir);
130        // For umount -a, end of mtab means time to exit.
131        else if (opt & OPT_ALL)
132            break;
133        // Use command line argument (and look it up in mtab list)
134        else {
135            if (!zapit)
136                break;
137            argv++;
138            path = xmalloc_realpath(zapit);
139            if (path) {
140                for (m = mtl; m; m = m->next)
141                    if (strcmp(path, m->dir) == 0 || strcmp(path, m->device) == 0)
142                        break;
143            }
144        }
145        // If we couldn't find this sucker in /etc/mtab, punt by passing our
146        // command line argument straight to the umount syscall.  Otherwise,
147        // umount the directory even if we were given the block device.
148        if (m) zapit = m->dir;
149
150        // Let's ask the thing nicely to unmount.
151        curstat = umount(zapit);
152
153        // Force the unmount, if necessary.
154        if (curstat && doForce)
155            curstat = umount2(zapit, doForce);
156
157        // If still can't umount, maybe remount read-only?
158        if (curstat) {
159            if ((opt & OPT_REMOUNT) && errno == EBUSY && m) {
160                // Note! Even if we succeed here, later we should not
161                // free loop device or erase mtab entry!
162                const char *msg = "%s busy - remounted read-only";
163                curstat = mount(m->device, zapit, NULL, MS_REMOUNT|MS_RDONLY, NULL);
164                if (curstat) {
165                    msg = "can't remount %s read-only";
166                    status = EXIT_FAILURE;
167                }
168                bb_error_msg(msg, m->device);
169            } else {
170                status = EXIT_FAILURE;
171                bb_perror_msg("can't %sumount %s", (doForce ? "forcibly " : ""), zapit);
172            }
173        } else {
174            // De-allocate the loop device.  This ioctl should be ignored on
175            // any non-loop block devices.
176            if (ENABLE_FEATURE_MOUNT_LOOP && !(opt & OPT_DONT_FREE_LOOP) && m)
177                del_loop(m->device);
178            if (ENABLE_FEATURE_MTAB_SUPPORT && !(opt & OPT_NO_MTAB) && m)
179                erase_mtab(m->dir);
180        }
181
182        // Find next matching mtab entry for -a or umount /dev
183        // Note this means that "umount /dev/blah" will unmount all instances
184        // of /dev/blah, not just the most recent.
185        if (m) {
186            while ((m = m->next) != NULL)
187                // NB: if m is non-NULL, path is non-NULL as well
188                if ((opt & OPT_ALL) || strcmp(path, m->device) == 0)
189                    break;
190        }
191        free(path);
192    }
193
194    // Free mtab list if necessary
195    if (ENABLE_FEATURE_CLEAN_UP) {
196        while (mtl) {
197            m = mtl->next;
198            free(mtl->device);
199            free(mtl->dir);
200            free(mtl);
201            mtl = m;
202        }
203    }
204
205    return status;
206}
Note: See TracBrowser for help on using the repository browser.