Merge branch 'upstream' into tizen
[platform/upstream/cryptsetup.git] / lib / utils_loop.c
1 /*
2  * loopback block device utilities
3  *
4  * Copyright (C) 2009-2023 Red Hat, Inc. All rights reserved.
5  * Copyright (C) 2009-2023 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 #ifdef HAVE_SYS_SYSMACROS_H
37 #include <sys/sysmacros.h>     /* for major, minor */
38 #endif
39
40 #include "utils_loop.h"
41 #include "libcryptsetup_macros.h"
42
43 #define LOOP_DEV_MAJOR 7
44
45 #ifndef LO_FLAGS_AUTOCLEAR
46 #define LO_FLAGS_AUTOCLEAR 4
47 #endif
48
49 #ifndef LOOP_CTL_GET_FREE
50 #define LOOP_CTL_GET_FREE 0x4C82
51 #endif
52
53 #ifndef LOOP_SET_CAPACITY
54 #define LOOP_SET_CAPACITY 0x4C07
55 #endif
56
57 #ifndef LOOP_SET_BLOCK_SIZE
58 #define LOOP_SET_BLOCK_SIZE 0x4C09
59 #endif
60
61 #ifndef LOOP_CONFIGURE
62 #define LOOP_CONFIGURE 0x4C0A
63 struct loop_config {
64   __u32 fd;
65   __u32 block_size;
66   struct loop_info64 info;
67   __u64 __reserved[8];
68 };
69 #endif
70
71 static char *crypt_loop_get_device_old(void)
72 {
73         char dev[64];
74         int i, loop_fd;
75         struct loop_info64 lo64 = {0};
76
77         for (i = 0; i < 256; i++) {
78                 sprintf(dev, "/dev/loop%d", i);
79
80                 loop_fd = open(dev, O_RDONLY);
81                 if (loop_fd < 0)
82                         return NULL;
83
84                 if (ioctl(loop_fd, LOOP_GET_STATUS64, &lo64) &&
85                     errno == ENXIO) {
86                         close(loop_fd);
87                         return strdup(dev);
88                 }
89                 close(loop_fd);
90         }
91
92         return NULL;
93 }
94
95 static char *crypt_loop_get_device(void)
96 {
97         char dev[64];
98         int i, loop_fd;
99         struct stat st;
100
101         loop_fd = open("/dev/loop-control", O_RDONLY);
102         if (loop_fd < 0)
103                 return crypt_loop_get_device_old();
104
105         i = ioctl(loop_fd, LOOP_CTL_GET_FREE);
106         if (i < 0) {
107                 close(loop_fd);
108                 return NULL;
109         }
110         close(loop_fd);
111
112         if (sprintf(dev, "/dev/loop%d", i) < 0)
113                 return NULL;
114
115         if (stat(dev, &st) || !S_ISBLK(st.st_mode))
116                 return NULL;
117
118         return strdup(dev);
119 }
120
121 int crypt_loop_attach(char **loop, const char *file, int offset,
122                       int autoclear, int *readonly, size_t blocksize)
123 {
124         struct loop_config config = {0};
125         char *lo_file_name;
126         int loop_fd = -1, file_fd = -1, r = 1;
127         int fallback = 0;
128
129         *loop = NULL;
130
131         file_fd = open(file, (*readonly ? O_RDONLY : O_RDWR) | O_EXCL);
132         if (file_fd < 0 && (errno == EROFS || errno == EACCES) && !*readonly) {
133                 *readonly = 1;
134                 file_fd = open(file, O_RDONLY | O_EXCL);
135         }
136         if (file_fd < 0)
137                 goto out;
138
139         config.fd = file_fd;
140
141         lo_file_name = (char*)config.info.lo_file_name;
142         lo_file_name[LO_NAME_SIZE-1] = '\0';
143         strncpy(lo_file_name, file, LO_NAME_SIZE-1);
144         config.info.lo_offset = offset;
145         if (autoclear)
146                 config.info.lo_flags |= LO_FLAGS_AUTOCLEAR;
147         if (blocksize > SECTOR_SIZE)
148                 config.block_size = blocksize;
149
150         while (loop_fd < 0) {
151                 *loop = crypt_loop_get_device();
152                 if (!*loop)
153                         goto out;
154
155                 loop_fd = open(*loop, *readonly ? O_RDONLY : O_RDWR);
156                 if (loop_fd < 0)
157                         goto out;
158                 if (ioctl(loop_fd, LOOP_CONFIGURE, &config) < 0) {
159                         if (errno == EINVAL || errno == ENOTTY) {
160                                 free(*loop);
161                                 *loop = NULL;
162
163                                 close(loop_fd);
164                                 loop_fd = -1;
165
166                                 /* kernel doesn't support LOOP_CONFIGURE */
167                                 fallback = 1;
168                                 break;
169                         }
170                         if (errno != EBUSY)
171                                 goto out;
172                         free(*loop);
173                         *loop = NULL;
174
175                         close(loop_fd);
176                         loop_fd = -1;
177                 }
178         }
179
180         if (fallback) {
181                 while (loop_fd < 0) {
182                         *loop = crypt_loop_get_device();
183                         if (!*loop)
184                                 goto out;
185
186                         loop_fd = open(*loop, *readonly ? O_RDONLY : O_RDWR);
187                         if (loop_fd < 0)
188                                 goto out;
189                         if (ioctl(loop_fd, LOOP_SET_FD, file_fd) < 0) {
190                                 if (errno != EBUSY)
191                                         goto out;
192                                 free(*loop);
193                                 *loop = NULL;
194
195                                 close(loop_fd);
196                                 loop_fd = -1;
197                         }
198                 }
199
200                 if (blocksize > SECTOR_SIZE)
201                         (void)ioctl(loop_fd, LOOP_SET_BLOCK_SIZE, (unsigned long)blocksize);
202
203                 if (ioctl(loop_fd, LOOP_SET_STATUS64, &config.info) < 0) {
204                         (void)ioctl(loop_fd, LOOP_CLR_FD, 0);
205                         goto out;
206                 }
207         }
208
209         /* Verify that autoclear is really set */
210         if (autoclear) {
211                 memset(&config.info, 0, sizeof(config.info));
212                 if (ioctl(loop_fd, LOOP_GET_STATUS64, &config.info) < 0 ||
213                    !(config.info.lo_flags & LO_FLAGS_AUTOCLEAR)) {
214                 (void)ioctl(loop_fd, LOOP_CLR_FD, 0);
215                         goto out;
216                 }
217         }
218
219         r = 0;
220 out:
221         if (r && loop_fd >= 0)
222                 close(loop_fd);
223         if (file_fd >= 0)
224                 close(file_fd);
225         if (r && *loop) {
226                 free(*loop);
227                 *loop = NULL;
228         }
229         return r ? -1 : loop_fd;
230 }
231
232 int crypt_loop_detach(const char *loop)
233 {
234         int loop_fd = -1, r = 1;
235
236         loop_fd = open(loop, O_RDONLY);
237         if (loop_fd < 0)
238                 return 1;
239
240         if (!ioctl(loop_fd, LOOP_CLR_FD, 0))
241                 r = 0;
242
243         close(loop_fd);
244         return r;
245 }
246
247 int crypt_loop_resize(const char *loop)
248 {
249         int loop_fd = -1, r = 1;
250
251         loop_fd = open(loop, O_RDONLY);
252         if (loop_fd < 0)
253                 return 1;
254
255         if (!ioctl(loop_fd, LOOP_SET_CAPACITY, 0))
256                 r = 0;
257
258         close(loop_fd);
259         return r;
260 }
261
262 static char *_ioctl_backing_file(const char *loop)
263 {
264         struct loop_info64 lo64 = {0};
265         int loop_fd;
266
267         loop_fd = open(loop, O_RDONLY);
268         if (loop_fd < 0)
269                 return NULL;
270
271         if (ioctl(loop_fd, LOOP_GET_STATUS64, &lo64) < 0) {
272                 close(loop_fd);
273                 return NULL;
274         }
275
276         lo64.lo_file_name[LO_NAME_SIZE-2] = '*';
277         lo64.lo_file_name[LO_NAME_SIZE-1] = 0;
278
279         close(loop_fd);
280
281         return strdup((char*)lo64.lo_file_name);
282 }
283
284 static char *_sysfs_backing_file(const char *loop)
285 {
286         struct stat st;
287         char buf[PATH_MAX];
288         size_t len;
289         int fd;
290
291         if (stat(loop, &st) || !S_ISBLK(st.st_mode))
292                 return NULL;
293
294         if (snprintf(buf, sizeof(buf), "/sys/dev/block/%d:%d/loop/backing_file",
295                      major(st.st_rdev), minor(st.st_rdev)) < 0)
296                 return NULL;
297
298         fd = open(buf, O_RDONLY);
299         if (fd < 0)
300                 return NULL;
301
302         len = read(fd, buf, PATH_MAX);
303         close(fd);
304         if (len < 2)
305                 return NULL;
306
307         buf[len - 1] = '\0';
308         return strdup(buf);
309 }
310
311 char *crypt_loop_backing_file(const char *loop)
312 {
313         char *bf;
314
315         if (!crypt_loop_device(loop))
316                 return NULL;
317
318         bf = _sysfs_backing_file(loop);
319         return bf ?: _ioctl_backing_file(loop);
320 }
321
322 int crypt_loop_device(const char *loop)
323 {
324         struct stat st;
325
326         if (!loop)
327                 return 0;
328
329         if (stat(loop, &st) || !S_ISBLK(st.st_mode) ||
330             major(st.st_rdev) != LOOP_DEV_MAJOR)
331                 return 0;
332
333         return 1;
334 }