]> git.ipfire.org Git - thirdparty/util-linux.git/blame - libmount/src/context_loopdev.c
mount: losetup: remove obsolete encryption support
[thirdparty/util-linux.git] / libmount / src / context_loopdev.c
CommitLineData
7f8b2bf3
KZ
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
7f8b2bf3
KZ
10 */
11
12#include <blkid.h>
13
14#include "mountP.h"
15#include "loopdev.h"
16#include "linux_version.h"
17
18
19int mnt_context_is_loopdev(struct libmnt_context *cxt)
20{
21 const char *type, *src;
7f8b2bf3
KZ
22
23 assert(cxt);
c8512236 24
7f8b2bf3
KZ
25 /* The mount flags have to be merged, otherwise we have to use
26 * expensive mnt_context_get_user_mflags() instead of cxt->user_mountflags. */
27 assert((cxt->flags & MNT_FL_MOUNTFLAGS_MERGED));
28
29 if (!cxt->fs)
30 return 0;
31 src = mnt_fs_get_srcpath(cxt->fs);
32 if (!src)
33 return 0; /* backing file not set */
34
35 if (cxt->user_mountflags & (MNT_MS_LOOP |
36 MNT_MS_OFFSET |
5cf05c71 37 MNT_MS_SIZELIMIT)) {
c8512236
KZ
38
39 DBG(CXT, mnt_debug_h(cxt, "loopdev specific options detected"));
7f8b2bf3 40 return 1;
c8512236 41 }
7f8b2bf3
KZ
42
43 if (cxt->mountflags & (MS_BIND | MS_MOVE | MS_PROPAGATION))
44 return 0;
45
c8512236
KZ
46 /* Automatically create a loop device from a regular file if a
47 * filesystem is not specified or the filesystem is known for libblkid
48 * (these filesystems work with block devices only). The file size
49 * should be at least 1KiB otherwise we will create empty loopdev where
50 * is no mountable filesystem...
7f8b2bf3
KZ
51 *
52 * Note that there is not a restriction (on kernel side) that prevents regular
53 * file as a mount(2) source argument. A filesystem that is able to mount
54 * regular files could be implemented.
55 */
56 type = mnt_fs_get_fstype(cxt->fs);
7f8b2bf3 57
c70d9d76 58 if (mnt_fs_is_regular(cxt->fs) &&
7f8b2bf3
KZ
59 (!type || strcmp(type, "auto") == 0 || blkid_known_fstype(type))) {
60 struct stat st;
61
c8512236
KZ
62 if (stat(src, &st) == 0 && S_ISREG(st.st_mode) &&
63 st.st_size > 1024)
64 return 1;
7f8b2bf3
KZ
65 }
66
c8512236 67 return 0;
7f8b2bf3
KZ
68}
69
8b470b20
KZ
70
71/* Check, if there already exists a mounted loop device on the mountpoint node
72 * with the same parameters.
73 */
74static int is_mounted_same_loopfile(struct libmnt_context *cxt,
75 const char *target,
76 const char *backing_file,
77 uint64_t offset)
78{
79 struct libmnt_table *tb;
80 struct libmnt_iter itr;
81 struct libmnt_fs *fs;
82 struct libmnt_cache *cache;
83
84 assert(cxt);
85 assert(cxt->fs);
86 assert((cxt->flags & MNT_FL_MOUNTFLAGS_MERGED));
87
88 if (!target || !backing_file || mnt_context_get_mtab(cxt, &tb))
89 return 0;
90
b2ddfb59 91 DBG(CXT, mnt_debug_h(cxt, "checking if %s mounted on %s",
8b470b20
KZ
92 backing_file, target));
93
94 cache = mnt_context_get_cache(cxt);
95 mnt_reset_iter(&itr, MNT_ITER_BACKWARD);
96
97 /* Search for mountpoint node in mtab, procceed if any of these has the
98 * loop option set or the device is a loop device
99 */
100 while (mnt_table_next_fs(tb, &itr, &fs) == 0) {
101 const char *src = mnt_fs_get_source(fs);
102 const char *opts = mnt_fs_get_user_options(fs);
103 char *val;
104 size_t len;
105 int res = 0;
106
107 if (!src || !mnt_fs_match_target(fs, target, cache))
108 continue;
109
110 if (strncmp(src, "/dev/loop", 9) == 0) {
111 res = loopdev_is_used((char *) src, backing_file,
112 offset, LOOPDEV_FL_OFFSET);
113
114 } else if (opts && (cxt->user_mountflags & MNT_MS_LOOP) &&
115 mnt_optstr_get_option(opts, "loop", &val, &len) == 0 && val) {
116
117 val = strndup(val, len);
118 res = loopdev_is_used((char *) val, backing_file,
119 offset, LOOPDEV_FL_OFFSET);
120 free(val);
121 }
122
123 if (res) {
124 DBG(CXT, mnt_debug_h(cxt, "%s already mounted", backing_file));
125 return 1;
126 }
127 }
128
129 return 0;
130}
131
7f8b2bf3
KZ
132int mnt_context_setup_loopdev(struct libmnt_context *cxt)
133{
f0d3ff0a 134 const char *backing_file, *optstr, *loopdev = NULL;
5cf05c71 135 char *val = NULL;
7f8b2bf3
KZ
136 size_t len;
137 struct loopdev_cxt lc;
b9fd3340
KZ
138 int rc = 0, lo_flags = 0;
139 uint64_t offset = 0, sizelimit = 0;
7f8b2bf3
KZ
140
141 assert(cxt);
142 assert(cxt->fs);
143 assert((cxt->flags & MNT_FL_MOUNTFLAGS_MERGED));
144
145 backing_file = mnt_fs_get_srcpath(cxt->fs);
146 if (!backing_file)
147 return -EINVAL;
148
149 DBG(CXT, mnt_debug_h(cxt, "trying to setup loopdev for %s", backing_file));
150
151 if (cxt->mountflags & MS_RDONLY) {
152 DBG(CXT, mnt_debug_h(cxt, "enabling READ-ONLY flag"));
153 lo_flags |= LO_FLAGS_READ_ONLY;
154 }
365e5a7c 155
defa0710
KZ
156 rc = loopcxt_init(&lc, 0);
157 if (rc)
158 return rc;
7f8b2bf3 159
365e5a7c
KZ
160 ON_DBG(CXT, loopcxt_enable_debug(&lc, 1));
161
b9fd3340 162 optstr = mnt_fs_get_user_options(cxt->fs);
7f8b2bf3 163
b9fd3340
KZ
164 /*
165 * loop=
166 */
167 if (rc == 0 && (cxt->user_mountflags & MNT_MS_LOOP) &&
168 mnt_optstr_get_option(optstr, "loop", &val, &len) == 0 && val) {
169
170 val = strndup(val, len);
171 rc = val ? loopcxt_set_device(&lc, val) : -ENOMEM;
172 free(val);
f0d3ff0a
KZ
173
174 if (rc == 0)
175 loopdev = loopcxt_get_device(&lc);
b9fd3340
KZ
176 }
177
178 /*
179 * offset=
180 */
181 if (rc == 0 && (cxt->user_mountflags & MNT_MS_OFFSET) &&
182 mnt_optstr_get_option(optstr, "offset", &val, &len) == 0) {
183 rc = mnt_parse_offset(val, len, &offset);
61f5ff6c 184 if (rc) {
b9fd3340 185 DBG(CXT, mnt_debug_h(cxt, "failed to parse offset="));
61f5ff6c
KZ
186 rc = -MNT_ERR_MOUNTOPT;
187 }
7f8b2bf3
KZ
188 }
189
b9fd3340
KZ
190 /*
191 * sizelimit=
192 */
193 if (rc == 0 && (cxt->user_mountflags & MNT_MS_SIZELIMIT) &&
194 mnt_optstr_get_option(optstr, "sizelimit", &val, &len) == 0) {
195 rc = mnt_parse_offset(val, len, &sizelimit);
61f5ff6c 196 if (rc) {
b9fd3340 197 DBG(CXT, mnt_debug_h(cxt, "failed to parse sizelimit="));
61f5ff6c
KZ
198 rc = -MNT_ERR_MOUNTOPT;
199 }
b9fd3340
KZ
200 }
201
1a7a421e
KZ
202 /*
203 * encryption=
204 */
205 if (rc == 0 && (cxt->user_mountflags & MNT_MS_ENCRYPTION) &&
206 mnt_optstr_get_option(optstr, "encryption", &val, &len) == 0) {
5cf05c71
LN
207 DBG(CXT, mnt_debug_h(cxt, "encryption no longer supported"));
208 rc = -MNT_ERR_MOUNTOPT;
1a7a421e
KZ
209 }
210
8b470b20
KZ
211 if (rc == 0 && is_mounted_same_loopfile(cxt,
212 mnt_context_get_target(cxt),
213 backing_file, offset))
214 rc = -EBUSY;
215
b9fd3340
KZ
216 if (rc)
217 goto done;
218
7f8b2bf3
KZ
219 /* since 2.6.37 we don't have to store backing filename to mtab
220 * because kernel provides the name in /sys.
221 */
222 if (get_linux_version() >= KERNEL_VERSION(2, 6, 37) ||
223 !cxt->mtab_writable) {
224 DBG(CXT, mnt_debug_h(cxt, "enabling AUTOCLEAR flag"));
225 lo_flags |= LO_FLAGS_AUTOCLEAR;
226 }
227
228 do {
229 /* found free device */
230 if (!loopdev) {
231 rc = loopcxt_find_unused(&lc);
232 if (rc)
233 goto done;
234 DBG(CXT, mnt_debug_h(cxt, "trying to use %s",
235 loopcxt_get_device(&lc)));
236 }
237
b9fd3340
KZ
238 /* set device attributes
239 * -- note that loopcxt_find_unused() resets "lc"
240 */
7f8b2bf3 241 rc = loopcxt_set_backing_file(&lc, backing_file);
7f8b2bf3 242
b9fd3340
KZ
243 if (!rc && offset)
244 rc = loopcxt_set_offset(&lc, offset);
245 if (!rc && sizelimit)
246 rc = loopcxt_set_sizelimit(&lc, sizelimit);
247 if (!rc)
248 loopcxt_set_flags(&lc, lo_flags);
249 if (rc) {
250 DBG(CXT, mnt_debug_h(cxt, "failed to set loopdev attributes"));
251 goto done;
252 }
7f8b2bf3
KZ
253
254 /* setup the device */
255 rc = loopcxt_setup_device(&lc);
256 if (!rc)
257 break; /* success */
258
259 if (loopdev || rc != -EBUSY) {
260 DBG(CXT, mnt_debug_h(cxt, "failed to setup device"));
82756a74 261 rc = -MNT_ERR_LOOPDEV;
b9fd3340 262 goto done;
7f8b2bf3
KZ
263 }
264 DBG(CXT, mnt_debug_h(cxt, "loopdev stolen...trying again"));
265 } while (1);
266
267 if (!rc)
268 rc = mnt_fs_set_source(cxt->fs, loopcxt_get_device(&lc));
269
270 if (!rc) {
271 /* success */
272 cxt->flags |= MNT_FL_LOOPDEV_READY;
273
274 if ((cxt->user_mountflags & MNT_MS_LOOP) &&
f0d3ff0a 275 loopcxt_is_autoclear(&lc)) {
7f8b2bf3
KZ
276 /*
277 * autoclear flag accepted by kernel, don't store
278 * the "loop=" option to mtab.
279 */
280 cxt->user_mountflags &= ~MNT_MS_LOOP;
f0d3ff0a
KZ
281 mnt_optstr_remove_option(&cxt->fs->user_optstr, "loop");
282 }
7f8b2bf3
KZ
283
284 if (!(cxt->mountflags & MS_RDONLY) &&
285 loopcxt_is_readonly(&lc))
286 /*
287 * mount planned read-write, but loopdev is read-only,
288 * let's fix mount options...
289 */
f9906424 290 mnt_context_set_mflags(cxt, cxt->mountflags | MS_RDONLY);
7f8b2bf3
KZ
291
292 /* we have to keep the device open until mount(1),
293 * otherwise it will auto-cleared by kernel
294 */
295 cxt->loopdev_fd = loopcxt_get_fd(&lc);
296 loopcxt_set_fd(&lc, -1, 0);
297 }
298done:
299 loopcxt_deinit(&lc);
300 return rc;
301}
302
303/*
304 * Deletes loop device
305 */
306int mnt_context_delete_loopdev(struct libmnt_context *cxt)
307{
308 const char *src;
309 int rc;
310
311 assert(cxt);
312 assert(cxt->fs);
313
314 src = mnt_fs_get_srcpath(cxt->fs);
315 if (!src)
316 return -EINVAL;
317
318 if (cxt->loopdev_fd > -1)
319 close(cxt->loopdev_fd);
320
321 rc = loopdev_delete(src);
322 cxt->flags &= ~MNT_FL_LOOPDEV_READY;
323 cxt->loopdev_fd = -1;
324
325 DBG(CXT, mnt_debug_h(cxt, "loopdev deleted [rc=%d]", rc));
326 return rc;
327}
328
329/*
330 * Clears loopdev stuff in context, should be called after
331 * failed or successful mount(2).
332 */
333int mnt_context_clear_loopdev(struct libmnt_context *cxt)
334{
335 assert(cxt);
336
337 if (mnt_context_get_status(cxt) == 0 &&
338 (cxt->flags & MNT_FL_LOOPDEV_READY)) {
339 /*
340 * mount(2) failed, delete loopdev
341 */
342 mnt_context_delete_loopdev(cxt);
343
344 } else if (cxt->loopdev_fd > -1) {
345 /*
346 * mount(2) success, close the device
347 */
348 DBG(CXT, mnt_debug_h(cxt, "closing loopdev FD"));
349 close(cxt->loopdev_fd);
350 }
351 cxt->loopdev_fd = -1;
352 return 0;
353}
354