Imported Upstream version 0.6.0
[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 <unistd.h>
25 #include <sys/ioctl.h>
26 #include <sys/stat.h>
27 #include <sys/mman.h>
28 #include <sysmacros.h>
29 #include <asm/posix_types.h>
30 #include <linux/loop.h>
31
32 #include "lopart.h"
33 #include "xstrncpy.h"
34
35 #ifndef LOOP_CTL_GET_FREE
36 #define LOOP_CTL_GET_FREE       0x4C82
37 #endif
38
39 #if !defined (__alpha__) && !defined (__ia64__) && !defined (__x86_64__) \
40         && !defined (__s390x__)
41 #define int2ptr(x)      ((void *) ((int) x))
42 #else
43 #define int2ptr(x)      ((void *) ((long) x))
44 #endif
45
46 static char *
47 xstrdup (const char *s)
48 {
49         char *t;
50
51         if (s == NULL)
52                 return NULL;
53
54         t = strdup (s);
55
56         if (t == NULL) {
57                 fprintf(stderr, "not enough memory");
58                 exit(1);
59         }
60
61         return t;
62 }
63
64 extern int
65 is_loop_device (const char *device)
66 {
67         struct stat statbuf;
68         int loopmajor;
69 #if 1
70         loopmajor = 7;
71 #else
72         FILE *procdev;
73         char line[100], *cp;
74
75         loopmajor = 0;
76
77         if ((procdev = fopen(PROC_DEVICES, "r")) != NULL) {
78                 
79                 while (fgets (line, sizeof(line), procdev)) {
80                         
81                         if ((cp = strstr (line, " loop\n")) != NULL) {
82                                 *cp='\0';
83                                 loopmajor=atoi(line);
84                                 break;
85                         }
86                 }
87
88                 fclose(procdev);
89         }
90 #endif
91         return (loopmajor && stat(device, &statbuf) == 0 &&
92                 S_ISBLK(statbuf.st_mode) &&
93                 major(statbuf.st_rdev) == loopmajor);
94 }
95
96 #define SIZE(a) (sizeof(a)/sizeof(a[0]))
97
98 extern char *
99 find_loop_by_file (const char * filename)
100 {
101         char dev[64];
102         char *loop_formats[] = { "/dev/loop%d", "/dev/loop/%d" };
103         int i, j, fd;
104         struct stat statbuf;
105         struct loop_info loopinfo;
106         dev_t file_dev;
107         ino_t file_ino;
108
109         if (stat (filename, &statbuf) != 0) {
110                 return NULL;
111         }
112         file_dev = statbuf.st_dev;
113         file_ino = statbuf.st_ino;
114
115         for (j = 0; j < SIZE(loop_formats); j++) {
116
117                 for (i = 0; i < 256; i++) {
118                         sprintf (dev, loop_formats[j], i);
119
120                         if (stat (dev, &statbuf) != 0 ||
121                             !S_ISBLK(statbuf.st_mode))
122                                 continue;
123
124                         fd = open (dev, O_RDONLY);
125
126                         if (fd < 0)
127                                 break;
128
129                         if (ioctl (fd, LOOP_GET_STATUS, &loopinfo) != 0) {
130                                 close (fd);
131                                 continue;
132                         }
133
134                         if (loopinfo.lo_device == file_dev && loopinfo.lo_inode == file_ino) {
135                                 close (fd);
136                                 return xstrdup(dev); /*found */
137                         }
138
139                         close (fd);
140                         continue;
141                 }
142         }
143         return NULL;
144 }
145
146 extern char *
147 find_unused_loop_device (void)
148 {
149         /* Just creating a device, say in /tmp, is probably a bad idea -
150            people might have problems with backup or so.
151            So, we just try /dev/loop[0-7]. */
152
153         char dev[20];
154         char *loop_formats[] = { "/dev/loop%d", "/dev/loop/%d" };
155         int i, j, fd, first = 0, somedev = 0, someloop = 0, loop_known = 0;
156         struct stat statbuf;
157         struct loop_info loopinfo;
158         FILE *procdev;
159
160         if (stat("/dev/loop-control", &statbuf) == 0 &&
161             S_ISCHR(statbuf.st_mode)) {
162                 fd = open("/dev/loop-control", O_RDWR);
163                 if (fd >= 0)
164                         first = ioctl(fd, LOOP_CTL_GET_FREE);
165                 close(fd);
166                 if (first < 0)
167                         first = 0;
168         }
169         for (j = 0; j < SIZE(loop_formats); j++) {
170
171             for(i = first; i < 256; i++) {
172                 sprintf(dev, loop_formats[j], i);
173
174                 if (stat (dev, &statbuf) == 0 && S_ISBLK(statbuf.st_mode)) {
175                         somedev++;
176                         fd = open (dev, O_RDONLY);
177
178                         if (fd >= 0) {
179
180                                 if(ioctl (fd, LOOP_GET_STATUS, &loopinfo) == 0)
181                                         someloop++;             /* in use */
182
183                                 else if (errno == ENXIO) {
184                                         close (fd);
185                                         return xstrdup(dev);/* probably free */
186                                 }
187
188                                 close (fd);
189                         }
190                         
191                         /* continue trying as long as devices exist */
192                         continue;
193                 }
194                 break;
195             }
196         }
197
198         /* Nothing found. Why not? */
199         if ((procdev = fopen(PROC_DEVICES, "r")) != NULL) {
200                 char line[100];
201
202                 while (fgets (line, sizeof(line), procdev))
203
204                         if (strstr (line, " loop\n")) {
205                                 loop_known = 1;
206                                 break;
207                         }
208
209                 fclose(procdev);
210
211                 if (!loop_known)
212                         loop_known = -1;
213         }
214
215         if (!somedev)
216                 fprintf(stderr, "mount: could not find any device /dev/loop#");
217
218         else if (!someloop) {
219
220             if (loop_known == 1)
221                 fprintf(stderr,
222                     "mount: Could not find any loop device.\n"
223                     "       Maybe /dev/loop# has a wrong major number?");
224             
225             else if (loop_known == -1)
226                 fprintf(stderr,
227                     "mount: Could not find any loop device, and, according to %s,\n"
228                     "       this kernel does not know about the loop device.\n"
229                     "       (If so, then recompile or `modprobe loop'.)",
230                       PROC_DEVICES);
231
232             else
233                 fprintf(stderr,
234                     "mount: Could not find any loop device. Maybe this kernel does not know\n"
235                     "       about the loop device (then recompile or `modprobe loop'), or\n"
236                     "       maybe /dev/loop# has the wrong major number?");
237
238         } else
239                 fprintf(stderr, "mount: could not find any free loop device");
240         
241         return 0;
242 }
243
244 extern int
245 set_loop (const char *device, const char *file, int offset, int *loopro)
246 {
247         struct loop_info loopinfo;
248         int fd, ffd, mode;
249
250         mode = (*loopro ? O_RDONLY : O_RDWR);
251
252         if ((ffd = open (file, mode)) < 0) {
253
254                 if (!*loopro && (errno == EROFS || errno == EACCES))
255                         ffd = open (file, mode = O_RDONLY);
256
257                 if (ffd < 0) {
258                         perror (file);
259                         return 1;
260                 }
261         }
262
263         if ((fd = open (device, mode)) < 0) {
264                 perror (device);
265                 return 1;
266         }
267
268         *loopro = (mode == O_RDONLY);
269         memset (&loopinfo, 0, sizeof (loopinfo));
270
271         xstrncpy (loopinfo.lo_name, file, LO_NAME_SIZE);
272         loopinfo.lo_offset = offset;
273         loopinfo.lo_encrypt_type = LO_CRYPT_NONE;
274         loopinfo.lo_encrypt_key_size = 0;
275
276         if (ioctl (fd, LOOP_SET_FD, int2ptr(ffd)) < 0) {
277                 perror ("ioctl: LOOP_SET_FD");
278                 close (fd);
279                 close (ffd);
280                 return 1;
281         }
282
283         if (ioctl (fd, LOOP_SET_STATUS, &loopinfo) < 0) {
284                 (void) ioctl (fd, LOOP_CLR_FD, 0);
285                 perror ("ioctl: LOOP_SET_STATUS");
286                 close (fd);
287                 close (ffd);
288                 return 1;
289         }
290
291         close (fd);
292         close (ffd);
293         return 0;
294 }
295
296 extern int 
297 del_loop (const char *device)
298 {
299         int retries = 3;
300         int fd;
301
302         if ((fd = open (device, O_RDONLY)) < 0) {
303                 int errsv = errno;
304                 fprintf(stderr, "loop: can't delete device %s: %s\n",
305                         device, strerror (errsv));
306                 return 1;
307         }
308
309         while (ioctl (fd, LOOP_CLR_FD, 0) < 0) {
310                 if (errno != EBUSY || retries-- <= 0) {
311                         perror ("ioctl: LOOP_CLR_FD");
312                         close (fd);
313                         return 1;
314                 }
315                 fprintf(stderr,
316                         "loop: device %s still in use, retrying delete\n",
317                         device);
318                 sleep(1);
319                 continue;
320         }
321
322         close (fd);
323         return 0;
324 }