9b316031bc524ff14687424468f533781a565208
[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
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[64];
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 }