kpartx: compare image filenames with backing files
[multipath-tools/.git] / kpartx / lopart.c
1 /* Taken from Ted's losetup.c - Mitch <m.dsouza@mrc-apu.cam.ac.uk> */
2 /* Added vfs mount options - aeb - 960223 */
3 /* Removed lomount - aeb - 960224 */
4
5 /* 1999-02-22 Arkadiusz Miƛkiewicz <misiek@pld.ORG.PL>
6  * - added Native Language Support
7  * Sun Mar 21 1999 - Arnaldo Carvalho de Melo <acme@conectiva.com.br>
8  * - fixed strerr(errno) in gettext calls
9  */
10
11 #define PROC_DEVICES    "/proc/devices"
12
13 /*
14  * losetup.c - setup and control loop devices
15  */
16
17 #include "kpartx.h"
18 #include <stdio.h>
19 #include <string.h>
20 #include <ctype.h>
21 #include <fcntl.h>
22 #include <errno.h>
23 #include <stdlib.h>
24 #include <stdint.h>
25 #include <unistd.h>
26 #include <sys/ioctl.h>
27 #include <sys/stat.h>
28 #include <sys/mman.h>
29 #include <sys/types.h>
30 #include <dirent.h>
31 #include <sys/sysmacros.h>
32 #include <linux/loop.h>
33 #include <limits.h>
34
35 #include "lopart.h"
36 #include "xstrncpy.h"
37
38 #ifndef LOOP_CTL_GET_FREE
39 #define LOOP_CTL_GET_FREE       0x4C82
40 #endif
41
42 static char *
43 xstrdup (const char *s)
44 {
45         char *t;
46
47         if (s == NULL)
48                 return NULL;
49
50         t = strdup (s);
51
52         if (t == NULL) {
53                 fprintf(stderr, "not enough memory");
54                 exit(1);
55         }
56
57         return t;
58 }
59
60 #define SIZE(a) (sizeof(a)/sizeof(a[0]))
61
62 char *find_loop_by_file(const char *filename)
63 {
64         DIR *dir;
65         struct dirent *dent;
66         char dev[64], *found = NULL, *p;
67         int fd, bytes_read;
68         struct stat statbuf;
69         struct loop_info loopinfo;
70         const char VIRT_BLOCK[] = "/sys/devices/virtual/block";
71         char path[PATH_MAX];
72         char bf_path[PATH_MAX];
73         char backing_file[PATH_MAX];
74
75         dir = opendir(VIRT_BLOCK);
76         if (!dir)
77                 return NULL;
78
79         while ((dent = readdir(dir)) != NULL) {
80                 if (strncmp(dent->d_name,"loop",4))
81                         continue;
82
83                 if (snprintf(path, PATH_MAX, "%s/%s/dev", VIRT_BLOCK,
84                              dent->d_name) >= PATH_MAX)
85                         continue;
86
87                 fd = open(path, O_RDONLY);
88                 if (fd < 0)
89                         continue;
90
91                 bytes_read = read(fd, dev, sizeof(dev) - 1);
92                 if (bytes_read <= 0) {
93                         close(fd);
94                         continue;
95                 }
96
97                 close(fd);
98
99                 dev[bytes_read] = '\0';
100                 p = strchr(dev, '\n');
101                 if (p != NULL)
102                         *p = '\0';
103                 if (snprintf(path, PATH_MAX, "/dev/block/%s", dev) >= PATH_MAX)
104                         continue;
105
106                 fd = open (path, O_RDONLY);
107                 if (fd < 0)
108                         continue;
109
110                 if (fstat (fd, &statbuf) != 0 ||
111                     !S_ISBLK(statbuf.st_mode)) {
112                         close (fd);
113                         continue;
114                 }
115
116                 if (ioctl (fd, LOOP_GET_STATUS, &loopinfo) != 0) {
117                         close (fd);
118                         continue;
119                 }
120
121                 close (fd);
122
123                 if (0 == strcmp(filename, loopinfo.lo_name)) {
124                         found = realpath(path, NULL);
125                         break;
126                 }
127
128                 /*
129                  * filename is a realpath, while loopinfo.lo_name may hold just the
130                  * basename.  If that's the case, try to match filename against the
131                  * backing_file entry for this loop entry
132                  */
133                 if (snprintf(bf_path, PATH_MAX, "%s/%s/loop/backing_file", VIRT_BLOCK,
134                                          dent->d_name) >= PATH_MAX)
135                         continue;
136
137                 fd = open(bf_path, O_RDONLY);
138                 if (fd < 0)
139                         continue;
140
141                 bytes_read = read(fd, backing_file, sizeof(backing_file) - 1);
142                 if (bytes_read <= 0) {
143                         close(fd);
144                         continue;
145                 }
146
147                 close(fd);
148
149                 backing_file[bytes_read-1] = '\0';
150
151                 if (0 == strcmp(filename, backing_file)) {
152                         found = realpath(path, NULL);
153                         break;
154                 }
155         }
156         closedir(dir);
157         return found;
158 }
159
160 char *find_unused_loop_device(void)
161 {
162         char dev[20], *next_loop_dev = NULL;
163         int fd, next_loop = 0, somedev = 0, someloop = 0, loop_known = 0;
164         struct stat statbuf;
165         struct loop_info loopinfo;
166         FILE *procdev;
167
168         while (next_loop_dev == NULL) {
169                 if (stat("/dev/loop-control", &statbuf) == 0 &&
170                     S_ISCHR(statbuf.st_mode)) {
171                         int next_loop_fd;
172
173                         next_loop_fd = open("/dev/loop-control", O_RDWR);
174                         if (next_loop_fd < 0)
175                                 return NULL;
176                         next_loop = ioctl(next_loop_fd, LOOP_CTL_GET_FREE);
177                         close(next_loop_fd);
178                         if (next_loop < 0)
179                                 return NULL;
180                 }
181
182                 sprintf(dev, "/dev/loop%d", next_loop);
183
184                 fd = open (dev, O_RDONLY);
185                 if (fd >= 0) {
186                         if (fstat (fd, &statbuf) == 0 &&
187                             S_ISBLK(statbuf.st_mode)) {
188                                 somedev++;
189                                 if(ioctl (fd, LOOP_GET_STATUS, &loopinfo) == 0)
190                                         someloop++;             /* in use */
191                                 else if (errno == ENXIO)
192                                         next_loop_dev = xstrdup(dev);
193
194                         }
195                         close (fd);
196
197                         /* continue trying as long as devices exist */
198                         continue;
199                 }
200                 break;
201         }
202         if (next_loop_dev)
203                 return next_loop_dev;
204
205         /* Nothing found. Why not? */
206         if ((procdev = fopen(PROC_DEVICES, "r")) != NULL) {
207                 char line[100];
208
209                 while (fgets (line, sizeof(line), procdev))
210
211                         if (strstr (line, " loop\n")) {
212                                 loop_known = 1;
213                                 break;
214                         }
215
216                 fclose(procdev);
217
218                 if (!loop_known)
219                         loop_known = -1;
220         }
221
222         if (!somedev)
223                 fprintf(stderr, "mount: could not find any device /dev/loop#");
224
225         else if (!someloop) {
226                 if (loop_known == 1)
227                         fprintf(stderr,
228                                 "mount: Could not find any loop device.\n"
229                                 "       Maybe /dev/loop# has a wrong major number?");
230                 else if (loop_known == -1)
231                         fprintf(stderr,
232                                 "mount: Could not find any loop device, and, according to %s,\n"
233                                 "       this kernel does not know about the loop device.\n"
234                                 "       (If so, then recompile or `modprobe loop'.)",
235                                 PROC_DEVICES);
236                 else
237                         fprintf(stderr,
238                                 "mount: Could not find any loop device. Maybe this kernel does not know\n"
239                                 "       about the loop device (then recompile or `modprobe loop'), or\n"
240                                 "       maybe /dev/loop# has the wrong major number?");
241         } else
242                 fprintf(stderr, "mount: could not find any free loop device");
243         return NULL;
244 }
245
246 int set_loop(const char *device, const char *file, int offset, int *loopro)
247 {
248         struct loop_info loopinfo;
249         int fd, ffd, mode;
250
251         mode = (*loopro ? O_RDONLY : O_RDWR);
252
253         if ((ffd = open (file, mode)) < 0) {
254
255                 if (!*loopro && (errno == EROFS || errno == EACCES))
256                         ffd = open (file, mode = O_RDONLY);
257
258                 if (ffd < 0) {
259                         perror (file);
260                         return 1;
261                 }
262         }
263
264         if ((fd = open (device, mode)) < 0) {
265                 close(ffd);
266                 perror (device);
267                 return 1;
268         }
269
270         *loopro = (mode == O_RDONLY);
271         memset (&loopinfo, 0, sizeof (loopinfo));
272
273         xstrncpy (loopinfo.lo_name, file, LO_NAME_SIZE);
274         loopinfo.lo_offset = offset;
275         loopinfo.lo_encrypt_type = LO_CRYPT_NONE;
276         loopinfo.lo_encrypt_key_size = 0;
277
278         if (ioctl(fd, LOOP_SET_FD, (void*)(uintptr_t)(ffd)) < 0) {
279                 perror ("ioctl: LOOP_SET_FD");
280                 close (fd);
281                 close (ffd);
282                 return 1;
283         }
284
285         if (ioctl (fd, LOOP_SET_STATUS, &loopinfo) < 0) {
286                 (void) ioctl (fd, LOOP_CLR_FD, 0);
287                 perror ("ioctl: LOOP_SET_STATUS");
288                 close (fd);
289                 close (ffd);
290                 return 1;
291         }
292
293         close (fd);
294         close (ffd);
295         return 0;
296 }
297
298 int del_loop(const char *device)
299 {
300         int retries = 5;
301         int fd;
302
303         if ((fd = open (device, O_RDONLY)) < 0) {
304                 int errsv = errno;
305                 fprintf(stderr, "loop: can't delete device %s: %s\n",
306                         device, strerror (errsv));
307                 return 1;
308         }
309
310         while (ioctl (fd, LOOP_CLR_FD, 0) < 0) {
311                 if (errno != EBUSY || retries-- <= 0) {
312                         perror ("ioctl: LOOP_CLR_FD");
313                         close (fd);
314                         return 1;
315                 }
316                 fprintf(stderr,
317                         "loop: device %s still in use, retrying delete\n",
318                         device);
319                 sleep(1);
320                 continue;
321         }
322
323         close (fd);
324         return 0;
325 }