"Fossies" - the Fresh Open Source Software Archive 
Member "cryptsetup-2.4.3/lib/utils_loop.c" (13 Jan 2022, 6703 Bytes) of package /linux/misc/cryptsetup-2.4.3.tar.xz:
As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style:
standard) with prefixed line numbers and
code folding option.
Alternatively you can here
view or
download the uninterpreted source code file.
For more information about "utils_loop.c" see the
Fossies "Dox" file reference documentation and the last
Fossies "Diffs" side-by-side code changes report:
2.3.6_vs_2.4.0.
1 /*
2 * loopback block device utilities
3 *
4 * Copyright (C) 2009-2021 Red Hat, Inc. All rights reserved.
5 * Copyright (C) 2009-2021 Milan Broz
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version 2
10 * of the License, or (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20 */
21
22 #include <stdlib.h>
23 #include <string.h>
24 #include <stdio.h>
25 #include <unistd.h>
26 #include <fcntl.h>
27 #include <errno.h>
28 #include <limits.h>
29 #include <sys/ioctl.h>
30 #include <sys/stat.h>
31 #ifdef HAVE_SYS_SYSMACROS_H
32 # include <sys/sysmacros.h> /* for major, minor */
33 #endif
34 #include <linux/types.h>
35 #include <linux/loop.h>
36
37 #include "utils_loop.h"
38 #include "libcryptsetup_macros.h"
39
40 #define LOOP_DEV_MAJOR 7
41
42 #ifndef LO_FLAGS_AUTOCLEAR
43 #define LO_FLAGS_AUTOCLEAR 4
44 #endif
45
46 #ifndef LOOP_CTL_GET_FREE
47 #define LOOP_CTL_GET_FREE 0x4C82
48 #endif
49
50 #ifndef LOOP_SET_CAPACITY
51 #define LOOP_SET_CAPACITY 0x4C07
52 #endif
53
54 #ifndef LOOP_SET_BLOCK_SIZE
55 #define LOOP_SET_BLOCK_SIZE 0x4C09
56 #endif
57
58 #ifndef LOOP_CONFIGURE
59 #define LOOP_CONFIGURE 0x4C0A
60 struct loop_config {
61 __u32 fd;
62 __u32 block_size;
63 struct loop_info64 info;
64 __u64 __reserved[8];
65 };
66 #endif
67
68 static char *crypt_loop_get_device_old(void)
69 {
70 char dev[20];
71 int i, loop_fd;
72 struct loop_info64 lo64 = {0};
73
74 for (i = 0; i < 256; i++) {
75 sprintf(dev, "/dev/loop%d", i);
76
77 loop_fd = open(dev, O_RDONLY);
78 if (loop_fd < 0)
79 return NULL;
80
81 if (ioctl(loop_fd, LOOP_GET_STATUS64, &lo64) &&
82 errno == ENXIO) {
83 close(loop_fd);
84 return strdup(dev);
85 }
86 close(loop_fd);
87 }
88
89 return NULL;
90 }
91
92 static char *crypt_loop_get_device(void)
93 {
94 char dev[64];
95 int i, loop_fd;
96 struct stat st;
97
98 loop_fd = open("/dev/loop-control", O_RDONLY);
99 if (loop_fd < 0)
100 return crypt_loop_get_device_old();
101
102 i = ioctl(loop_fd, LOOP_CTL_GET_FREE);
103 if (i < 0) {
104 close(loop_fd);
105 return NULL;
106 }
107 close(loop_fd);
108
109 if (sprintf(dev, "/dev/loop%d", i) < 0)
110 return NULL;
111
112 if (stat(dev, &st) || !S_ISBLK(st.st_mode))
113 return NULL;
114
115 return strdup(dev);
116 }
117
118 int crypt_loop_attach(char **loop, const char *file, int offset,
119 int autoclear, int *readonly, size_t blocksize)
120 {
121 struct loop_config config = {0};
122 char *lo_file_name;
123 int loop_fd = -1, file_fd = -1, r = 1;
124 int fallback = 0;
125
126 *loop = NULL;
127
128 file_fd = open(file, (*readonly ? O_RDONLY : O_RDWR) | O_EXCL);
129 if (file_fd < 0 && (errno == EROFS || errno == EACCES) && !*readonly) {
130 *readonly = 1;
131 file_fd = open(file, O_RDONLY | O_EXCL);
132 }
133 if (file_fd < 0)
134 goto out;
135
136 config.fd = file_fd;
137
138 lo_file_name = (char*)config.info.lo_file_name;
139 lo_file_name[LO_NAME_SIZE-1] = '\0';
140 strncpy(lo_file_name, file, LO_NAME_SIZE-1);
141 config.info.lo_offset = offset;
142 if (autoclear)
143 config.info.lo_flags |= LO_FLAGS_AUTOCLEAR;
144 if (blocksize > SECTOR_SIZE)
145 config.block_size = blocksize;
146
147 while (loop_fd < 0) {
148 *loop = crypt_loop_get_device();
149 if (!*loop)
150 goto out;
151
152 loop_fd = open(*loop, *readonly ? O_RDONLY : O_RDWR);
153 if (loop_fd < 0)
154 goto out;
155 if (ioctl(loop_fd, LOOP_CONFIGURE, &config) < 0) {
156 if (errno == EINVAL || errno == ENOTTY) {
157 free(*loop);
158 *loop = NULL;
159
160 close(loop_fd);
161 loop_fd = -1;
162
163 /* kernel doesn't support LOOP_CONFIGURE */
164 fallback = 1;
165 break;
166 }
167 if (errno != EBUSY)
168 goto out;
169 free(*loop);
170 *loop = NULL;
171
172 close(loop_fd);
173 loop_fd = -1;
174 }
175 }
176
177 if (fallback) {
178 while (loop_fd < 0) {
179 *loop = crypt_loop_get_device();
180 if (!*loop)
181 goto out;
182
183 loop_fd = open(*loop, *readonly ? O_RDONLY : O_RDWR);
184 if (loop_fd < 0)
185 goto out;
186 if (ioctl(loop_fd, LOOP_SET_FD, file_fd) < 0) {
187 if (errno != EBUSY)
188 goto out;
189 free(*loop);
190 *loop = NULL;
191
192 close(loop_fd);
193 loop_fd = -1;
194 }
195 }
196
197 if (blocksize > SECTOR_SIZE)
198 (void)ioctl(loop_fd, LOOP_SET_BLOCK_SIZE, (unsigned long)blocksize);
199
200 if (ioctl(loop_fd, LOOP_SET_STATUS64, &config.info) < 0) {
201 (void)ioctl(loop_fd, LOOP_CLR_FD, 0);
202 goto out;
203 }
204 }
205
206 /* Verify that autoclear is really set */
207 if (autoclear) {
208 memset(&config.info, 0, sizeof(config.info));
209 if (ioctl(loop_fd, LOOP_GET_STATUS64, &config.info) < 0 ||
210 !(config.info.lo_flags & LO_FLAGS_AUTOCLEAR)) {
211 (void)ioctl(loop_fd, LOOP_CLR_FD, 0);
212 goto out;
213 }
214 }
215
216 r = 0;
217 out:
218 if (r && loop_fd >= 0)
219 close(loop_fd);
220 if (file_fd >= 0)
221 close(file_fd);
222 if (r && *loop) {
223 free(*loop);
224 *loop = NULL;
225 }
226 return r ? -1 : loop_fd;
227 }
228
229 int crypt_loop_detach(const char *loop)
230 {
231 int loop_fd = -1, r = 1;
232
233 loop_fd = open(loop, O_RDONLY);
234 if (loop_fd < 0)
235 return 1;
236
237 if (!ioctl(loop_fd, LOOP_CLR_FD, 0))
238 r = 0;
239
240 close(loop_fd);
241 return r;
242 }
243
244 int crypt_loop_resize(const char *loop)
245 {
246 int loop_fd = -1, r = 1;
247
248 loop_fd = open(loop, O_RDONLY);
249 if (loop_fd < 0)
250 return 1;
251
252 if (!ioctl(loop_fd, LOOP_SET_CAPACITY, 0))
253 r = 0;
254
255 close(loop_fd);
256 return r;
257 }
258
259 static char *_ioctl_backing_file(const char *loop)
260 {
261 struct loop_info64 lo64 = {0};
262 int loop_fd;
263
264 loop_fd = open(loop, O_RDONLY);
265 if (loop_fd < 0)
266 return NULL;
267
268 if (ioctl(loop_fd, LOOP_GET_STATUS64, &lo64) < 0) {
269 close(loop_fd);
270 return NULL;
271 }
272
273 lo64.lo_file_name[LO_NAME_SIZE-2] = '*';
274 lo64.lo_file_name[LO_NAME_SIZE-1] = 0;
275
276 close(loop_fd);
277
278 return strdup((char*)lo64.lo_file_name);
279 }
280
281 static char *_sysfs_backing_file(const char *loop)
282 {
283 struct stat st;
284 char buf[PATH_MAX];
285 size_t len;
286 int fd;
287
288 if (stat(loop, &st) || !S_ISBLK(st.st_mode))
289 return NULL;
290
291 if (snprintf(buf, sizeof(buf), "/sys/dev/block/%d:%d/loop/backing_file",
292 major(st.st_rdev), minor(st.st_rdev)) < 0)
293 return NULL;
294
295 fd = open(buf, O_RDONLY);
296 if (fd < 0)
297 return NULL;
298
299 len = read(fd, buf, PATH_MAX);
300 close(fd);
301 if (len < 2)
302 return NULL;
303
304 buf[len - 1] = '\0';
305 return strdup(buf);
306 }
307
308 char *crypt_loop_backing_file(const char *loop)
309 {
310 char *bf;
311
312 if (!crypt_loop_device(loop))
313 return NULL;
314
315 bf = _sysfs_backing_file(loop);
316 return bf ?: _ioctl_backing_file(loop);
317 }
318
319 int crypt_loop_device(const char *loop)
320 {
321 struct stat st;
322
323 if (!loop)
324 return 0;
325
326 if (stat(loop, &st) || !S_ISBLK(st.st_mode) ||
327 major(st.st_rdev) != LOOP_DEV_MAJOR)
328 return 0;
329
330 return 1;
331 }