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