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