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