diff options
Diffstat (limited to 'libbb/loop.c')
-rw-r--r-- | libbb/loop.c | 163 |
1 files changed, 71 insertions, 92 deletions
diff --git a/libbb/loop.c b/libbb/loop.c index c4c3da4b1..25f66fcea 100644 --- a/libbb/loop.c +++ b/libbb/loop.c | |||
@@ -19,10 +19,8 @@ | |||
19 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | 19 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
20 | */ | 20 | */ |
21 | 21 | ||
22 | |||
22 | #include <features.h> | 23 | #include <features.h> |
23 | #if defined (__GLIBC__) && !defined(__UCLIBC__) | ||
24 | #include <linux/posix_types.h> | ||
25 | #endif | ||
26 | #include <stdio.h> | 24 | #include <stdio.h> |
27 | #include <errno.h> | 25 | #include <errno.h> |
28 | #include <fcntl.h> | 26 | #include <fcntl.h> |
@@ -30,127 +28,108 @@ | |||
30 | #include <unistd.h> | 28 | #include <unistd.h> |
31 | #include <sys/ioctl.h> | 29 | #include <sys/ioctl.h> |
32 | #include "libbb.h" | 30 | #include "libbb.h" |
33 | #ifdef CONFIG_FEATURE_MOUNT_LOOP | ||
34 | 31 | ||
35 | /* Grumble... The 2.6.x kernel breaks asm/posix_types.h | 32 | /* For 2.6, use the cleaned up header to get the 64 bit API. */ |
36 | * so we get to try and cope as best we can... */ | ||
37 | #include <linux/version.h> | 33 | #include <linux/version.h> |
38 | |||
39 | #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0) | 34 | #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0) |
40 | #define __bb_kernel_dev_t __kernel_old_dev_t | 35 | #include <linux/loop.h> |
41 | #elif LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0) | 36 | typedef struct loop_info64 bb_loop_info; |
42 | #define __bb_kernel_dev_t __kernel_dev_t | 37 | #define BB_LOOP_SET_STATUS LOOP_SET_STATUS64 |
43 | #else | 38 | #define BB_LOOP_GET_STATUS LOOP_GET_STATUS64 |
44 | #define __bb_kernel_dev_t unsigned short | ||
45 | #endif | ||
46 | 39 | ||
47 | /* Stuff stolen from linux/loop.h */ | 40 | /* For 2.4 and earlier, use the 32 bit API (and don't trust the headers) */ |
41 | #else | ||
42 | /* Stuff stolen from linux/loop.h for 2.4 and earlier kernels*/ | ||
43 | #include <linux/posix_types.h> | ||
48 | #define LO_NAME_SIZE 64 | 44 | #define LO_NAME_SIZE 64 |
49 | #define LO_KEY_SIZE 32 | 45 | #define LO_KEY_SIZE 32 |
50 | #define LOOP_SET_FD 0x4C00 | 46 | #define LOOP_SET_FD 0x4C00 |
51 | #define LOOP_CLR_FD 0x4C01 | 47 | #define LOOP_CLR_FD 0x4C01 |
52 | #define LOOP_SET_STATUS 0x4C02 | 48 | #define BB_LOOP_SET_STATUS 0x4C02 |
53 | #define LOOP_GET_STATUS 0x4C03 | 49 | #define BB_LOOP_GET_STATUS 0x4C03 |
54 | struct loop_info { | 50 | typedef struct { |
55 | int lo_number; | 51 | int lo_number; |
56 | __bb_kernel_dev_t lo_device; | 52 | __kernel_dev_t lo_device; |
57 | unsigned long lo_inode; | 53 | unsigned long lo_inode; |
58 | __bb_kernel_dev_t lo_rdevice; | 54 | __kernel_dev_t lo_rdevice; |
59 | int lo_offset; | 55 | int lo_offset; |
60 | int lo_encrypt_type; | 56 | int lo_encrypt_type; |
61 | int lo_encrypt_key_size; | 57 | int lo_encrypt_key_size; |
62 | int lo_flags; | 58 | int lo_flags; |
63 | char lo_name[LO_NAME_SIZE]; | 59 | char lo_file_name[LO_NAME_SIZE]; |
64 | unsigned char lo_encrypt_key[LO_KEY_SIZE]; | 60 | unsigned char lo_encrypt_key[LO_KEY_SIZE]; |
65 | unsigned long lo_init[2]; | 61 | unsigned long lo_init[2]; |
66 | char reserved[4]; | 62 | char reserved[4]; |
67 | }; | 63 | } bb_loop_info; |
64 | #endif | ||
68 | 65 | ||
69 | extern int del_loop(const char *device) | 66 | extern int del_loop(const char *device) |
70 | { | 67 | { |
71 | int fd; | 68 | int fd,rc=0; |
72 | 69 | ||
73 | if ((fd = open(device, O_RDONLY)) < 0) { | 70 | if ((fd = open(device, O_RDONLY)) < 0) rc=1; |
74 | bb_perror_msg("%s", device); | 71 | else { |
75 | return (FALSE); | 72 | if (ioctl(fd, LOOP_CLR_FD, 0) < 0) rc=1; |
76 | } | ||
77 | if (ioctl(fd, LOOP_CLR_FD, 0) < 0) { | ||
78 | close(fd); | 73 | close(fd); |
79 | bb_perror_msg("ioctl: LOOP_CLR_FD"); | ||
80 | return (FALSE); | ||
81 | } | 74 | } |
82 | close(fd); | 75 | return rc; |
83 | return (TRUE); | ||
84 | } | 76 | } |
85 | 77 | ||
86 | extern int set_loop(const char *device, const char *file, int offset, | 78 | // Returns 0 if mounted RW, 1 if mounted read-only, <0 for error. |
87 | int *loopro) | 79 | // *device is loop device to use, or if *device==NULL finds a loop device to |
88 | { | 80 | // mount it on and sets *device to a strdup of that loop device name. This |
89 | struct loop_info loopinfo; | 81 | // search will re-use an existing loop device already bound to that |
90 | int fd, ffd, mode; | 82 | // file/offset if it finds one. |
91 | 83 | extern int set_loop(char **device, const char *file, int offset) | |
92 | mode = *loopro ? O_RDONLY : O_RDWR; | ||
93 | if ((ffd = open(file, mode)) < 0 && !*loopro | ||
94 | && (errno != EROFS || (ffd = open(file, mode = O_RDONLY)) < 0)) { | ||
95 | bb_perror_msg("%s", file); | ||
96 | return 1; | ||
97 | } | ||
98 | if ((fd = open(device, mode)) < 0) { | ||
99 | close(ffd); | ||
100 | bb_perror_msg("%s", device); | ||
101 | return 1; | ||
102 | } | ||
103 | *loopro = (mode == O_RDONLY); | ||
104 | |||
105 | memset(&loopinfo, 0, sizeof(loopinfo)); | ||
106 | safe_strncpy(loopinfo.lo_name, file, LO_NAME_SIZE); | ||
107 | |||
108 | loopinfo.lo_offset = offset; | ||
109 | |||
110 | loopinfo.lo_encrypt_key_size = 0; | ||
111 | if (ioctl(fd, LOOP_SET_FD, ffd) < 0) { | ||
112 | bb_perror_msg("ioctl: LOOP_SET_FD"); | ||
113 | close(fd); | ||
114 | close(ffd); | ||
115 | return 1; | ||
116 | } | ||
117 | if (ioctl(fd, LOOP_SET_STATUS, &loopinfo) < 0) { | ||
118 | (void) ioctl(fd, LOOP_CLR_FD, 0); | ||
119 | bb_perror_msg("ioctl: LOOP_SET_STATUS"); | ||
120 | close(fd); | ||
121 | close(ffd); | ||
122 | return 1; | ||
123 | } | ||
124 | close(fd); | ||
125 | close(ffd); | ||
126 | return 0; | ||
127 | } | ||
128 | |||
129 | extern char *find_unused_loop_device(void) | ||
130 | { | 84 | { |
131 | char dev[20]; | 85 | char dev[20]; |
132 | int i, fd; | 86 | bb_loop_info loopinfo; |
133 | struct stat statbuf; | 87 | struct stat statbuf; |
134 | struct loop_info loopinfo; | 88 | int i, dfd, ffd, mode, rc=1; |
135 | 89 | ||
136 | for (i = 0; i <= CONFIG_FEATURE_MOUNT_LOOP_MAX; i++) { | 90 | // Open the file. Barf if this doesn't work. |
137 | sprintf(dev, LOOP_FORMAT, i); | 91 | if((ffd = open(file, mode=O_RDWR))<0) |
138 | if (stat(dev, &statbuf) == 0 && S_ISBLK(statbuf.st_mode)) { | 92 | if(errno!=EROFS || (ffd=open(file,mode=O_RDONLY))<0) |
139 | if ((fd = open(dev, O_RDONLY)) >= 0) { | 93 | return errno; |
140 | if (ioctl(fd, LOOP_GET_STATUS, &loopinfo) != 0) { | 94 | |
141 | if (errno == ENXIO) { /* probably free */ | 95 | // Find a loop device |
142 | close(fd); | 96 | for(i=0;rc;i++) { |
143 | return strdup(dev); | 97 | sprintf(dev, LOOP_FORMAT, i++); |
144 | } | 98 | // Ran out of block devices, return failure. |
145 | } | 99 | if(stat(*device ? : dev, &statbuf) || !S_ISBLK(statbuf.st_mode)) { |
146 | close(fd); | 100 | rc=ENOENT; |
147 | } | 101 | break; |
148 | } | 102 | } |
103 | // Open the sucker and check its loopiness. | ||
104 | if((dfd=open(dev, mode))<0 && errno==EROFS) | ||
105 | dfd=open(dev,mode=O_RDONLY); | ||
106 | if(dfd<0) continue; | ||
107 | |||
108 | rc=ioctl(dfd, BB_LOOP_GET_STATUS, &loopinfo); | ||
109 | // If device free, claim it. | ||
110 | if(rc && errno==ENXIO) { | ||
111 | memset(&loopinfo, 0, sizeof(loopinfo)); | ||
112 | safe_strncpy(loopinfo.lo_file_name, file, LO_NAME_SIZE); | ||
113 | loopinfo.lo_offset = offset; | ||
114 | // Associate free loop device with file | ||
115 | if(!ioctl(dfd, LOOP_SET_FD, ffd) && | ||
116 | !ioctl(dfd, BB_LOOP_SET_STATUS, &loopinfo)) rc=0; | ||
117 | else ioctl(dfd, LOOP_CLR_FD, 0); | ||
118 | // If this block device already set up right, re-use it. | ||
119 | // (Yes this is racy, but associating two loop devices with the same | ||
120 | // file isn't pretty either. In general, mounting the same file twice | ||
121 | // without using losetup manually is problematic.) | ||
122 | } else if(strcmp(file,loopinfo.lo_file_name) | ||
123 | || offset!=loopinfo.lo_offset) rc=1; | ||
124 | close(dfd); | ||
125 | if(*device) break; | ||
149 | } | 126 | } |
150 | return NULL; | 127 | close(ffd); |
128 | if(!rc) { | ||
129 | if(!*device) *device=strdup(dev); | ||
130 | return mode==O_RDONLY ? 1 : 0; | ||
131 | } else return rc; | ||
151 | } | 132 | } |
152 | #endif | ||
153 | |||
154 | 133 | ||
155 | /* END CODE */ | 134 | /* END CODE */ |
156 | /* | 135 | /* |