Bump to 0.9.7
[platform/upstream/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 #define SIZE(a) (sizeof(a)/sizeof(a[0]))
43
44 char *find_loop_by_file(const char *filename)
45 {
46         DIR *dir;
47         struct dirent *dent;
48         char dev[64], *found = NULL, *p;
49         int fd, bytes_read;
50         struct stat statbuf;
51         struct loop_info loopinfo;
52         const char VIRT_BLOCK[] = "/sys/devices/virtual/block";
53         char path[PATH_MAX];
54         char bf_path[PATH_MAX];
55         char backing_file[PATH_MAX];
56
57         dir = opendir(VIRT_BLOCK);
58         if (!dir)
59                 return NULL;
60
61         while ((dent = readdir(dir)) != NULL) {
62                 if (strncmp(dent->d_name,"loop",4))
63                         continue;
64
65                 if (snprintf(path, PATH_MAX, "%s/%s/dev", VIRT_BLOCK,
66                              dent->d_name) >= PATH_MAX)
67                         continue;
68
69                 fd = open(path, O_RDONLY);
70                 if (fd < 0)
71                         continue;
72
73                 bytes_read = read(fd, dev, sizeof(dev) - 1);
74                 if (bytes_read <= 0) {
75                         close(fd);
76                         continue;
77                 }
78
79                 close(fd);
80
81                 dev[bytes_read] = '\0';
82                 p = strchr(dev, '\n');
83                 if (p != NULL)
84                         *p = '\0';
85                 if (snprintf(path, PATH_MAX, "/dev/block/%s", dev) >= PATH_MAX)
86                         continue;
87
88                 fd = open (path, O_RDONLY);
89                 if (fd < 0)
90                         continue;
91
92                 if (fstat (fd, &statbuf) != 0 ||
93                     !S_ISBLK(statbuf.st_mode)) {
94                         close (fd);
95                         continue;
96                 }
97
98                 if (ioctl (fd, LOOP_GET_STATUS, &loopinfo) != 0) {
99                         close (fd);
100                         continue;
101                 }
102
103                 close (fd);
104
105                 if (0 == strcmp(filename, loopinfo.lo_name)) {
106                         found = realpath(path, NULL);
107                         break;
108                 }
109
110                 /*
111                  * filename is a realpath, while loopinfo.lo_name may hold just the
112                  * basename.  If that's the case, try to match filename against the
113                  * backing_file entry for this loop entry
114                  */
115                 if (snprintf(bf_path, PATH_MAX, "%s/%s/loop/backing_file", VIRT_BLOCK,
116                                          dent->d_name) >= PATH_MAX)
117                         continue;
118
119                 fd = open(bf_path, O_RDONLY);
120                 if (fd < 0)
121                         continue;
122
123                 bytes_read = read(fd, backing_file, sizeof(backing_file) - 1);
124                 if (bytes_read <= 0) {
125                         close(fd);
126                         continue;
127                 }
128
129                 close(fd);
130
131                 backing_file[bytes_read-1] = '\0';
132
133                 if (0 == strcmp(filename, backing_file)) {
134                         found = realpath(path, NULL);
135                         break;
136                 }
137         }
138         closedir(dir);
139         return found;
140 }
141
142 static char *find_unused_loop_device(int mode, int *loop_fd)
143 {
144         char dev[21];
145         int fd, next_loop = 0, somedev = 0, someloop = 0, loop_known = 0;
146         int next_loop_fd;
147         struct stat statbuf;
148         struct loop_info loopinfo;
149         FILE *procdev;
150
151         next_loop_fd = open("/dev/loop-control", O_RDWR);
152         if (next_loop_fd < 0)
153                 goto no_loop_fd;
154
155         if (!(fstat(next_loop_fd, &statbuf) == 0 && S_ISCHR(statbuf.st_mode)))
156                 goto nothing_found;
157
158         for (;;) {
159                 next_loop = ioctl(next_loop_fd, LOOP_CTL_GET_FREE);
160                 if (next_loop < 0)
161                         goto nothing_found;
162
163                 sprintf(dev, "/dev/loop%d", next_loop);
164
165                 fd = open (dev, mode);
166                 if (fd >= 0) {
167                         if (fstat (fd, &statbuf) == 0 &&
168                             S_ISBLK(statbuf.st_mode)) {
169                                 somedev++;
170                                 if(ioctl (fd, LOOP_GET_STATUS, &loopinfo) == 0)
171                                         someloop++;             /* in use */
172                                 else if (errno == ENXIO) {
173                                         char *name = strdup(dev);
174
175                                         if (name == NULL)
176                                                 close(fd);
177                                         else
178                                                 *loop_fd = fd;
179                                         close(next_loop_fd);
180                                         return name;
181                                 }
182
183                         }
184                         close (fd);
185
186                         /* continue trying as long as devices exist */
187                 } else
188                         break;
189         }
190
191 nothing_found:
192         close(next_loop_fd);
193
194 no_loop_fd:
195         /* Nothing found. Why not? */
196         if ((procdev = fopen(PROC_DEVICES, "r")) != NULL) {
197                 char line[100];
198
199                 while (fgets (line, sizeof(line), procdev))
200
201                         if (strstr (line, " loop\n")) {
202                                 loop_known = 1;
203                                 break;
204                         }
205
206                 fclose(procdev);
207
208                 if (!loop_known)
209                         loop_known = -1;
210         }
211
212         if (!somedev)
213                 fprintf(stderr, "mount: could not find any device /dev/loop#\n");
214
215         else if (!someloop) {
216                 if (loop_known == 1)
217                         fprintf(stderr,
218                                 "mount: Could not find any loop device.\n"
219                                 "       Maybe /dev/loop# has a wrong major number?\n");
220                 else if (loop_known == -1)
221                         fprintf(stderr,
222                                 "mount: Could not find any loop device, and, according to %s,\n"
223                                 "       this kernel does not know about the loop device.\n"
224                                 "       (If so, then recompile or `modprobe loop'.)\n",
225                                 PROC_DEVICES);
226                 else
227                         fprintf(stderr,
228                                 "mount: Could not find any loop device. Maybe this kernel does not know\n"
229                                 "       about the loop device (then recompile or `modprobe loop'), or\n"
230                                 "       maybe /dev/loop# has the wrong major number?\n");
231         } else
232                 fprintf(stderr, "mount: could not find any free loop device\n");
233         return NULL;
234 }
235
236 int set_loop(char **device, const char *file, int offset, int *loopro)
237 {
238         struct loop_info loopinfo;
239         int fd = -1, ret = 1, ffd, mode;
240
241         mode = (*loopro ? O_RDONLY : O_RDWR);
242
243         if ((ffd = open (file, mode)) < 0) {
244
245                 if (!*loopro && (errno == EROFS || errno == EACCES))
246                         ffd = open (file, mode = O_RDONLY);
247
248                 if (ffd < 0) {
249                         perror (file);
250                         return 1;
251                 }
252         }
253
254         *device = find_unused_loop_device(mode, &fd);
255         if (!*device) {
256                 close(ffd);
257                 return 1;
258         }
259
260         *loopro = (mode == O_RDONLY);
261         memset (&loopinfo, 0, sizeof (loopinfo));
262
263         xstrncpy (loopinfo.lo_name, file, LO_NAME_SIZE);
264         loopinfo.lo_offset = offset;
265         loopinfo.lo_encrypt_type = LO_CRYPT_NONE;
266         loopinfo.lo_encrypt_key_size = 0;
267
268         if (ioctl(fd, LOOP_SET_FD, (void*)(uintptr_t)(ffd)) < 0) {
269                 perror ("ioctl: LOOP_SET_FD");
270                 goto out;
271         }
272
273         if (ioctl (fd, LOOP_SET_STATUS, &loopinfo) < 0) {
274                 (void) ioctl (fd, LOOP_CLR_FD, 0);
275                 perror ("ioctl: LOOP_SET_STATUS");
276                 goto out;
277         }
278         ret = 0;
279
280 out:
281         close (fd);
282         close (ffd);
283         return ret;
284 }
285
286 int del_loop(const char *device)
287 {
288         int retries = 5;
289         int fd;
290
291         if ((fd = open (device, O_RDONLY)) < 0) {
292                 int errsv = errno;
293                 fprintf(stderr, "loop: can't delete device %s: %s\n",
294                         device, strerror (errsv));
295                 return 1;
296         }
297
298         while (ioctl (fd, LOOP_CLR_FD, 0) < 0) {
299                 if (errno != EBUSY || retries-- <= 0) {
300                         perror ("ioctl: LOOP_CLR_FD");
301                         close (fd);
302                         return 1;
303                 }
304                 fprintf(stderr,
305                         "loop: device %s still in use, retrying delete\n",
306                         device);
307                 sleep(1);
308                 continue;
309         }
310
311         close (fd);
312         return 0;
313 }