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