Merge "Add -o loop= option to mount, and fix error detection in mount and umount"
diff --git a/toolbox/mount.c b/toolbox/mount.c
index 82ecc56..27cf3c9 100644
--- a/toolbox/mount.c
+++ b/toolbox/mount.c
@@ -15,8 +15,8 @@
 
 #define ARRAY_SIZE(x)	(sizeof(x) / sizeof(x[0]))
 
-// FIXME - only one loop mount is supported at a time
-#define LOOP_DEVICE "/dev/block/loop0"
+#define DEFAULT_LOOP_DEVICE "/dev/block/loop0"
+#define LOOPDEV_MAXLEN 64
 
 struct mount_opts {
 	const char str[8];
@@ -87,7 +87,7 @@
 }
 
 static unsigned long
-parse_mount_options(char *arg, unsigned long rwflag, struct extra_opts *extra, int* loop)
+parse_mount_options(char *arg, unsigned long rwflag, struct extra_opts *extra, int* loop, char *loopdev)
 {
 	char *s;
     
@@ -100,8 +100,15 @@
 		if (no)
 			s += 2;
 
+        if (strncmp(s, "loop=", 5) == 0) {
+            *loop = 1;
+            strlcpy(loopdev, s + 5, LOOPDEV_MAXLEN);
+            continue;
+        }
+
         if (strcmp(s, "loop") == 0) {
             *loop = 1;
+            strlcpy(loopdev, DEFAULT_LOOP_DEVICE, LOOPDEV_MAXLEN);
             continue;
         }
 		for (i = 0, res = 1; i < ARRAY_SIZE(options); i++) {
@@ -131,7 +138,8 @@
 static unsigned long rwflag;
 
 static int
-do_mount(char *dev, char *dir, char *type, unsigned long rwflag, void *data, int loop)
+do_mount(char *dev, char *dir, char *type, unsigned long rwflag, void *data, int loop,
+         char *loopdev)
 {
 	char *s;
 	int error = 0;
@@ -142,14 +150,13 @@
 
         flags = (rwflag & MS_RDONLY) ? O_RDONLY : O_RDWR;
         
-        // FIXME - only one loop mount supported at a time
         file_fd = open(dev, flags);
-        if (file_fd < -1) {
+        if (file_fd < 0) {
             perror("open backing file failed");
             return 1;
         }
-        device_fd = open(LOOP_DEVICE, flags);
-        if (device_fd < -1) {
+        device_fd = open(loopdev, flags);
+        if (device_fd < 0) {
             perror("open loop device failed");
             close(file_fd);
             return 1;
@@ -163,7 +170,7 @@
 
         close(file_fd);
         close(device_fd);
-        dev = LOOP_DEVICE;
+        dev = loopdev;
     }
 
 	while ((s = strsep(&type, ",")) != NULL) {
@@ -268,6 +275,7 @@
 	char *dir = NULL;
 	int c;
 	int loop = 0;
+	char loopdev[LOOPDEV_MAXLEN];
 
 	progname = argv[0];
 	rwflag = MS_VERBOSE;
@@ -281,7 +289,7 @@
 			break;
 		switch (c) {
 		case 'o':
-			rwflag = parse_mount_options(optarg, rwflag, &extra, &loop);
+			rwflag = parse_mount_options(optarg, rwflag, &extra, &loop, loopdev);
 			break;
 		case 'r':
 			rwflag |= MS_RDONLY;
@@ -319,6 +327,6 @@
 		exit(1);
 	}
 
-	return do_mount(dev, dir, type, rwflag, extra.str, loop);
+	return do_mount(dev, dir, type, rwflag, extra.str, loop, loopdev);
 	/* We leak dev and dir in some cases, but we're about to exit */
 }
diff --git a/toolbox/umount.c b/toolbox/umount.c
index 92c6076..6eb8b92 100644
--- a/toolbox/umount.c
+++ b/toolbox/umount.c
@@ -7,10 +7,24 @@
 #include <unistd.h>
 #include <linux/loop.h>
 
-// FIXME - only one loop mount is supported at a time
-#define LOOP_DEVICE "/dev/block/loop0"
+#define LOOPDEV_MAXLEN 64
+#define LOOP_MAJOR 7
 
-static int is_loop_mount(const char* path)
+static int is_loop(char *dev)
+{
+    struct stat st;
+    int ret = 0;
+
+    if (stat(dev, &st) == 0) {
+        if (S_ISBLK(st.st_mode) && (major(st.st_rdev) == LOOP_MAJOR)) {
+            ret = 1;
+        }
+    }
+
+    return ret;
+}
+
+static int is_loop_mount(const char* path, char *loopdev)
 {
     FILE* f;
     int count;
@@ -29,7 +43,8 @@
     do {
         count = fscanf(f, "%255s %255s %255s\n", device, mount_path, rest);
         if (count == 3) {
-            if (strcmp(LOOP_DEVICE, device) == 0 && strcmp(path, mount_path) == 0) {
+            if (is_loop(device) && strcmp(path, mount_path) == 0) {
+                strlcpy(loopdev, device, LOOPDEV_MAXLEN);
                 result = 1;
                 break;
             }
@@ -43,13 +58,14 @@
 int umount_main(int argc, char *argv[])
 {
     int loop, loop_fd;
-    
+    char loopdev[LOOPDEV_MAXLEN];
+
     if(argc != 2) {
         fprintf(stderr,"umount <path>\n");
         return 1;
     }
 
-    loop = is_loop_mount(argv[1]);
+    loop = is_loop_mount(argv[1], loopdev);
     if(umount(argv[1])){
         fprintf(stderr,"failed.\n");
         return 1;
@@ -57,8 +73,8 @@
 
     if (loop) {
         // free the loop device
-        loop_fd = open(LOOP_DEVICE, O_RDONLY);
-        if (loop_fd < -1) {
+        loop_fd = open(loopdev, O_RDONLY);
+        if (loop_fd < 0) {
             perror("open loop device failed");
             return 1;
         }