Imported Upstream version 0.7.6
[platform/upstream/multipath-tools.git] / kpartx / lopart.c
index 6f83048..69c1eda 100644 (file)
@@ -2,7 +2,7 @@
 /* Added vfs mount options - aeb - 960223 */
 /* Removed lomount - aeb - 960224 */
 
-/* 1999-02-22 Arkadiusz Mikiewicz <misiek@pld.ORG.PL>
+/* 1999-02-22 Arkadiusz Miśkiewicz <misiek@pld.ORG.PL>
  * - added Native Language Support
  * Sun Mar 21 1999 - Arnaldo Carvalho de Melo <acme@conectiva.com.br>
  * - fixed strerr(errno) in gettext calls
 #include <fcntl.h>
 #include <errno.h>
 #include <stdlib.h>
+#include <stdint.h>
 #include <unistd.h>
 #include <sys/ioctl.h>
 #include <sys/stat.h>
 #include <sys/mman.h>
-#include <sysmacros.h>
-#include <asm/posix_types.h>
+#include <sys/types.h>
+#include <dirent.h>
+#include <sys/sysmacros.h>
 #include <linux/loop.h>
+#include <limits.h>
 
 #include "lopart.h"
 #include "xstrncpy.h"
 #define LOOP_CTL_GET_FREE       0x4C82
 #endif
 
-#if !defined (__alpha__) && !defined (__ia64__) && !defined (__x86_64__) \
-        && !defined (__s390x__)
-#define int2ptr(x)     ((void *) ((int) x))
-#else
-#define int2ptr(x)     ((void *) ((long) x))
-#endif
-
 static char *
 xstrdup (const char *s)
 {
@@ -61,131 +57,120 @@ xstrdup (const char *s)
        return t;
 }
 
-extern int
-is_loop_device (const char *device)
-{
-       struct stat statbuf;
-       int loopmajor;
-#if 1
-       loopmajor = 7;
-#else
-       FILE *procdev;
-       char line[100], *cp;
-
-       loopmajor = 0;
-
-       if ((procdev = fopen(PROC_DEVICES, "r")) != NULL) {
-               
-               while (fgets (line, sizeof(line), procdev)) {
-                       
-                       if ((cp = strstr (line, " loop\n")) != NULL) {
-                               *cp='\0';
-                               loopmajor=atoi(line);
-                               break;
-                       }
-               }
-
-               fclose(procdev);
-       }
-#endif
-       return (loopmajor && stat(device, &statbuf) == 0 &&
-               S_ISBLK(statbuf.st_mode) &&
-               major(statbuf.st_rdev) == loopmajor);
-}
-
 #define SIZE(a) (sizeof(a)/sizeof(a[0]))
 
-extern char *
-find_loop_by_file (const char * filename)
+char *find_loop_by_file(const char *filename)
 {
-       char dev[64];
-       char *loop_formats[] = { "/dev/loop%d", "/dev/loop/%d" };
-       int i, j, fd;
+       DIR *dir;
+       struct dirent *dent;
+       char dev[64], *found = NULL, *p;
+       int fd, bytes_read;
        struct stat statbuf;
        struct loop_info loopinfo;
+       const char VIRT_BLOCK[] = "/sys/devices/virtual/block";
+       char path[PATH_MAX];
 
-       for (j = 0; j < SIZE(loop_formats); j++) {
+       dir = opendir(VIRT_BLOCK);
+       if (!dir)
+               return NULL;
 
-               for (i = 0; i < 256; i++) {
-                       sprintf (dev, loop_formats[j], i);
+       while ((dent = readdir(dir)) != NULL) {
+               if (strncmp(dent->d_name,"loop",4))
+                       continue;
 
-                       if (stat (dev, &statbuf) != 0 ||
-                           !S_ISBLK(statbuf.st_mode))
-                               continue;
+               if (snprintf(path, PATH_MAX, "%s/%s/dev", VIRT_BLOCK,
+                            dent->d_name) >= PATH_MAX)
+                       continue;
 
-                       fd = open (dev, O_RDONLY);
+               fd = open(path, O_RDONLY);
+               if (fd < 0)
+                       continue;
 
-                       if (fd < 0)
-                               break;
+               bytes_read = read(fd, dev, sizeof(dev) - 1);
+               if (bytes_read <= 0) {
+                       close(fd);
+                       continue;
+               }
 
-                       if (ioctl (fd, LOOP_GET_STATUS, &loopinfo) != 0) {
-                               close (fd);
-                               continue;
-                       }
+               close(fd);
 
-                       if (0 == strcmp(filename, loopinfo.lo_name)) {
-                               close (fd);
-                               return xstrdup(dev); /*found */
-                       }
+               dev[bytes_read] = '\0';
+               p = strchr(dev, '\n');
+               if (p != NULL)
+                       *p = '\0';
+               if (snprintf(path, PATH_MAX, "/dev/block/%s", dev) >= PATH_MAX)
+                       continue;
 
+               fd = open (path, O_RDONLY);
+               if (fd < 0)
+                       continue;
+
+               if (fstat (fd, &statbuf) != 0 ||
+                   !S_ISBLK(statbuf.st_mode)) {
                        close (fd);
                        continue;
                }
+
+               if (ioctl (fd, LOOP_GET_STATUS, &loopinfo) != 0) {
+                       close (fd);
+                       continue;
+               }
+
+               close (fd);
+
+               if (0 == strcmp(filename, loopinfo.lo_name)) {
+                       found = realpath(path, NULL);
+                       break;
+               }
        }
-       return NULL;
+       closedir(dir);
+       return found;
 }
 
-extern char *
-find_unused_loop_device (void)
+char *find_unused_loop_device(void)
 {
-       /* Just creating a device, say in /tmp, is probably a bad idea -
-          people might have problems with backup or so.
-          So, we just try /dev/loop[0-7]. */
-
-       char dev[20];
-       char *loop_formats[] = { "/dev/loop%d", "/dev/loop/%d" };
-       int i, j, fd, first = 0, somedev = 0, someloop = 0, loop_known = 0;
+       char dev[20], *next_loop_dev = NULL;
+       int fd, next_loop = 0, somedev = 0, someloop = 0, loop_known = 0;
        struct stat statbuf;
        struct loop_info loopinfo;
        FILE *procdev;
 
-       if (stat("/dev/loop-control", &statbuf) == 0 &&
-           S_ISCHR(statbuf.st_mode)) {
-               fd = open("/dev/loop-control", O_RDWR);
-               if (fd >= 0)
-                       first = ioctl(fd, LOOP_CTL_GET_FREE);
-               close(fd);
-               if (first < 0)
-                       first = 0;
-       }
-       for (j = 0; j < SIZE(loop_formats); j++) {
-
-           for(i = first; i < 256; i++) {
-               sprintf(dev, loop_formats[j], i);
-
-               if (stat (dev, &statbuf) == 0 && S_ISBLK(statbuf.st_mode)) {
-                       somedev++;
-                       fd = open (dev, O_RDONLY);
+       while (next_loop_dev == NULL) {
+               if (stat("/dev/loop-control", &statbuf) == 0 &&
+                   S_ISCHR(statbuf.st_mode)) {
+                       int next_loop_fd;
+
+                       next_loop_fd = open("/dev/loop-control", O_RDWR);
+                       if (next_loop_fd < 0)
+                               return NULL;
+                       next_loop = ioctl(next_loop_fd, LOOP_CTL_GET_FREE);
+                       close(next_loop_fd);
+                       if (next_loop < 0)
+                               return NULL;
+               }
 
-                       if (fd >= 0) {
+               sprintf(dev, "/dev/loop%d", next_loop);
 
+               fd = open (dev, O_RDONLY);
+               if (fd >= 0) {
+                       if (fstat (fd, &statbuf) == 0 &&
+                           S_ISBLK(statbuf.st_mode)) {
+                               somedev++;
                                if(ioctl (fd, LOOP_GET_STATUS, &loopinfo) == 0)
                                        someloop++;             /* in use */
+                               else if (errno == ENXIO)
+                                       next_loop_dev = xstrdup(dev);
 
-                               else if (errno == ENXIO) {
-                                       close (fd);
-                                       return xstrdup(dev);/* probably free */
-                               }
-
-                               close (fd);
                        }
-                       
+                       close (fd);
+
                        /* continue trying as long as devices exist */
                        continue;
                }
                break;
-           }
        }
+       if (next_loop_dev)
+               return next_loop_dev;
 
        /* Nothing found. Why not? */
        if ((procdev = fopen(PROC_DEVICES, "r")) != NULL) {
@@ -208,33 +193,27 @@ find_unused_loop_device (void)
                fprintf(stderr, "mount: could not find any device /dev/loop#");
 
        else if (!someloop) {
-
-           if (loop_known == 1)
-               fprintf(stderr,
-                   "mount: Could not find any loop device.\n"
-                   "       Maybe /dev/loop# has a wrong major number?");
-           
-           else if (loop_known == -1)
-               fprintf(stderr,
-                   "mount: Could not find any loop device, and, according to %s,\n"
-                   "       this kernel does not know about the loop device.\n"
-                   "       (If so, then recompile or `modprobe loop'.)",
-                     PROC_DEVICES);
-
-           else
-               fprintf(stderr,
-                   "mount: Could not find any loop device. Maybe this kernel does not know\n"
-                   "       about the loop device (then recompile or `modprobe loop'), or\n"
-                   "       maybe /dev/loop# has the wrong major number?");
-
+               if (loop_known == 1)
+                       fprintf(stderr,
+                               "mount: Could not find any loop device.\n"
+                               "       Maybe /dev/loop# has a wrong major number?");
+               else if (loop_known == -1)
+                       fprintf(stderr,
+                               "mount: Could not find any loop device, and, according to %s,\n"
+                               "       this kernel does not know about the loop device.\n"
+                               "       (If so, then recompile or `modprobe loop'.)",
+                               PROC_DEVICES);
+               else
+                       fprintf(stderr,
+                               "mount: Could not find any loop device. Maybe this kernel does not know\n"
+                               "       about the loop device (then recompile or `modprobe loop'), or\n"
+                               "       maybe /dev/loop# has the wrong major number?");
        } else
                fprintf(stderr, "mount: could not find any free loop device");
-       
-       return 0;
+       return NULL;
 }
 
-extern int
-set_loop (const char *device, const char *file, int offset, int *loopro)
+int set_loop(const char *device, const char *file, int offset, int *loopro)
 {
        struct loop_info loopinfo;
        int fd, ffd, mode;
@@ -253,6 +232,7 @@ set_loop (const char *device, const char *file, int offset, int *loopro)
        }
 
        if ((fd = open (device, mode)) < 0) {
+               close(ffd);
                perror (device);
                return 1;
        }
@@ -265,7 +245,7 @@ set_loop (const char *device, const char *file, int offset, int *loopro)
        loopinfo.lo_encrypt_type = LO_CRYPT_NONE;
        loopinfo.lo_encrypt_key_size = 0;
 
-       if (ioctl (fd, LOOP_SET_FD, int2ptr(ffd)) < 0) {
+       if (ioctl(fd, LOOP_SET_FD, (void*)(uintptr_t)(ffd)) < 0) {
                perror ("ioctl: LOOP_SET_FD");
                close (fd);
                close (ffd);
@@ -285,10 +265,9 @@ set_loop (const char *device, const char *file, int offset, int *loopro)
        return 0;
 }
 
-extern int 
-del_loop (const char *device)
+int del_loop(const char *device)
 {
-       int retries = 3;
+       int retries = 5;
        int fd;
 
        if ((fd = open (device, O_RDONLY)) < 0) {