~ubuntu-branches/ubuntu/trusty/util-linux/trusty-proposed

« back to all changes in this revision

Viewing changes to libmount/src/context_loopdev.c

  • Committer: Package Import Robot
  • Author(s): LaMont Jones
  • Date: 2011-11-03 15:38:23 UTC
  • mto: (4.5.5 sid) (1.6.4)
  • mto: This revision was merged to the branch mainline in revision 85.
  • Revision ID: package-import@ubuntu.com-20111103153823-10sx16jprzxlhkqf
ImportĀ upstreamĀ versionĀ 2.20.1

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * Copyright (C) 2011 Karel Zak <kzak@redhat.com>
 
3
 *
 
4
 * This file may be redistributed under the terms of the
 
5
 * GNU Lesser General Public License.
 
6
 */
 
7
 
 
8
/*
 
9
 * DOCS: - "lo@" prefix for fstype is unsupported
 
10
 *       - encyption= mount option for loop device is unssuported
 
11
 */
 
12
 
 
13
#include <blkid.h>
 
14
 
 
15
#include "mountP.h"
 
16
#include "loopdev.h"
 
17
#include "linux_version.h"
 
18
 
 
19
 
 
20
int mnt_context_is_loopdev(struct libmnt_context *cxt)
 
21
{
 
22
        const char *type, *src;
 
23
        int fl;
 
24
 
 
25
        assert(cxt);
 
26
        /* The mount flags have to be merged, otherwise we have to use
 
27
         * expensive mnt_context_get_user_mflags() instead of cxt->user_mountflags. */
 
28
        assert((cxt->flags & MNT_FL_MOUNTFLAGS_MERGED));
 
29
 
 
30
        if (!cxt->fs)
 
31
                return 0;
 
32
        src = mnt_fs_get_srcpath(cxt->fs);
 
33
        if (!src)
 
34
                return 0;               /* backing file not set */
 
35
 
 
36
        if (cxt->user_mountflags & (MNT_MS_LOOP |
 
37
                                    MNT_MS_OFFSET |
 
38
                                    MNT_MS_SIZELIMIT))
 
39
                return 1;
 
40
 
 
41
        if (cxt->mountflags & (MS_BIND | MS_MOVE | MS_PROPAGATION))
 
42
                return 0;
 
43
 
 
44
        /* Automatically create a loop device from a regular file if a filesystem
 
45
         * is not specified or the filesystem is known for libblkid (these
 
46
         * filesystems work with block devices only).
 
47
         *
 
48
         * Note that there is not a restriction (on kernel side) that prevents regular
 
49
         * file as a mount(2) source argument. A filesystem that is able to mount
 
50
         * regular files could be implemented.
 
51
         */
 
52
        type = mnt_fs_get_fstype(cxt->fs);
 
53
        fl = __mnt_fs_get_flags(cxt->fs);
 
54
 
 
55
        if (!(fl & (MNT_FS_PSEUDO | MNT_FS_NET | MNT_FS_SWAP)) &&
 
56
            (!type || strcmp(type, "auto") == 0 || blkid_known_fstype(type))) {
 
57
                struct stat st;
 
58
 
 
59
                if (stat(src, &st) || !S_ISREG(st.st_mode))
 
60
                        return 0;
 
61
        }
 
62
 
 
63
        return 1;
 
64
}
 
65
 
 
66
int mnt_context_setup_loopdev(struct libmnt_context *cxt)
 
67
{
 
68
        const char *backing_file;
 
69
        char *loopdev = NULL;
 
70
        size_t len;
 
71
        struct loopdev_cxt lc;
 
72
        int rc, lo_flags = 0;
 
73
 
 
74
        assert(cxt);
 
75
        assert(cxt->fs);
 
76
        assert((cxt->flags & MNT_FL_MOUNTFLAGS_MERGED));
 
77
 
 
78
        backing_file = mnt_fs_get_srcpath(cxt->fs);
 
79
        if (!backing_file)
 
80
                return -EINVAL;
 
81
 
 
82
        DBG(CXT, mnt_debug_h(cxt, "trying to setup loopdev for %s", backing_file));
 
83
 
 
84
        if (cxt->mountflags & MS_RDONLY) {
 
85
                DBG(CXT, mnt_debug_h(cxt, "enabling READ-ONLY flag"));
 
86
                lo_flags |= LO_FLAGS_READ_ONLY;
 
87
        }
 
88
        loopcxt_init(&lc, 0);
 
89
 
 
90
        
 
91
        if ((cxt->user_mountflags & MNT_MS_LOOP) &&
 
92
            mnt_fs_get_option(cxt->fs, "loop", &loopdev, &len) == 0 && loopdev) {
 
93
 
 
94
                char *tmp = strndup(loopdev, len);
 
95
                if (!tmp)
 
96
                        rc = -ENOMEM;
 
97
                else {
 
98
                        rc = loopcxt_set_device(&lc, tmp);
 
99
                        free(tmp);
 
100
                }
 
101
        }
 
102
 
 
103
        /* since 2.6.37 we don't have to store backing filename to mtab
 
104
         * because kernel provides the name in /sys.
 
105
         */
 
106
        if (get_linux_version() >= KERNEL_VERSION(2, 6, 37) ||
 
107
            !cxt->mtab_writable) {
 
108
                DBG(CXT, mnt_debug_h(cxt, "enabling AUTOCLEAR flag"));
 
109
                lo_flags |= LO_FLAGS_AUTOCLEAR;
 
110
        }
 
111
 
 
112
        do {
 
113
                /* found free device */
 
114
                if (!loopdev) {
 
115
                        rc = loopcxt_find_unused(&lc);
 
116
                        if (rc)
 
117
                                goto done;
 
118
                        DBG(CXT, mnt_debug_h(cxt, "trying to use %s",
 
119
                                                loopcxt_get_device(&lc)));
 
120
                }
 
121
 
 
122
                /* set device attributes */
 
123
                rc = loopcxt_set_backing_file(&lc, backing_file);
 
124
                if (rc)
 
125
                        goto done;
 
126
 
 
127
                loopcxt_set_flags(&lc, lo_flags);
 
128
 
 
129
                /* setup the device */
 
130
                rc = loopcxt_setup_device(&lc);
 
131
                if (!rc)
 
132
                        break;          /* success */
 
133
 
 
134
                if (loopdev || rc != -EBUSY) {
 
135
                        DBG(CXT, mnt_debug_h(cxt, "failed to setup device"));
 
136
                        break;
 
137
                }
 
138
                DBG(CXT, mnt_debug_h(cxt, "loopdev stolen...trying again"));
 
139
        } while (1);
 
140
 
 
141
        if (!rc)
 
142
                rc = mnt_fs_set_source(cxt->fs, loopcxt_get_device(&lc));
 
143
 
 
144
        if (!rc) {
 
145
                /* success */
 
146
                cxt->flags |= MNT_FL_LOOPDEV_READY;
 
147
 
 
148
                if ((cxt->user_mountflags & MNT_MS_LOOP) &&
 
149
                    loopcxt_is_autoclear(&lc))
 
150
                        /*
 
151
                         * autoclear flag accepted by kernel, don't store
 
152
                         * the "loop=" option to mtab.
 
153
                         */
 
154
                        cxt->user_mountflags &= ~MNT_MS_LOOP;
 
155
 
 
156
                if (!(cxt->mountflags & MS_RDONLY) &&
 
157
                    loopcxt_is_readonly(&lc))
 
158
                        /*
 
159
                         * mount planned read-write, but loopdev is read-only,
 
160
                         * let's fix mount options...
 
161
                         */
 
162
                        cxt->mountflags |= MS_RDONLY;
 
163
 
 
164
 
 
165
                /* we have to keep the device open until mount(1),
 
166
                 * otherwise it will auto-cleared by kernel
 
167
                 */
 
168
                cxt->loopdev_fd = loopcxt_get_fd(&lc);
 
169
                loopcxt_set_fd(&lc, -1, 0);
 
170
        }
 
171
done:
 
172
        loopcxt_deinit(&lc);
 
173
        return rc;
 
174
}
 
175
 
 
176
/*
 
177
 * Deletes loop device
 
178
 */
 
179
int mnt_context_delete_loopdev(struct libmnt_context *cxt)
 
180
{
 
181
        const char *src;
 
182
        int rc;
 
183
 
 
184
        assert(cxt);
 
185
        assert(cxt->fs);
 
186
 
 
187
        src = mnt_fs_get_srcpath(cxt->fs);
 
188
        if (!src)
 
189
                return -EINVAL;
 
190
 
 
191
        if (cxt->loopdev_fd > -1)
 
192
                close(cxt->loopdev_fd);
 
193
 
 
194
        rc = loopdev_delete(src);
 
195
        cxt->flags &= ~MNT_FL_LOOPDEV_READY;
 
196
        cxt->loopdev_fd = -1;
 
197
 
 
198
        DBG(CXT, mnt_debug_h(cxt, "loopdev deleted [rc=%d]", rc));
 
199
        return rc;
 
200
}
 
201
 
 
202
/*
 
203
 * Clears loopdev stuff in context, should be called after
 
204
 * failed or successful mount(2).
 
205
 */
 
206
int mnt_context_clear_loopdev(struct libmnt_context *cxt)
 
207
{
 
208
        assert(cxt);
 
209
 
 
210
        if (mnt_context_get_status(cxt) == 0 &&
 
211
            (cxt->flags & MNT_FL_LOOPDEV_READY)) {
 
212
                /*
 
213
                 * mount(2) failed, delete loopdev
 
214
                 */
 
215
                mnt_context_delete_loopdev(cxt);
 
216
 
 
217
        } else if (cxt->loopdev_fd > -1) {
 
218
                /*
 
219
                 * mount(2) success, close the device
 
220
                 */
 
221
                DBG(CXT, mnt_debug_h(cxt, "closing loopdev FD"));
 
222
                close(cxt->loopdev_fd);
 
223
        }
 
224
        cxt->loopdev_fd = -1;
 
225
        return 0;
 
226
}
 
227