mount,losetup: use /dev/loop-control is it exists
No binary (build failed)
—
(log yok)
| @@ -1461,14 +1461,15 @@ extern void bb_warn_ignoring_args(char *arg) FAST_FUNC; | |
| extern int get_linux_version_code(void) FAST_FUNC; | |
| - | extern char *query_loop(const char *device) FAST_FUNC; |
| - | extern int del_loop(const char *device) FAST_FUNC; |
| + | char *query_loop(const char *device) FAST_FUNC; |
| + | int get_free_loop(void) FAST_FUNC; |
| + | int del_loop(const char *device) FAST_FUNC; |
| /* | |
| * If *devname is not NULL, use that name, otherwise try to find free one, | |
| * malloc and return it in *devname. | |
| * return value is the opened fd to the loop device, or < on error | |
| */ | |
| - | extern int set_loop(char **devname, const char *file, unsigned long long offset, unsigned flags) FAST_FUNC; |
| + | int set_loop(char **devname, const char *file, unsigned long long offset, unsigned flags) FAST_FUNC; |
| /* These constants match linux/loop.h (without BB_ prefix): */ | |
| #define BB_LO_FLAGS_READ_ONLY 1 | |
| #define BB_LO_FLAGS_AUTOCLEAR 4 | |
| @@ -78,6 +78,24 @@ int FAST_FUNC del_loop(const char *device) | |
| return rc; | |
| } | |
| + | /* Obtain an unused loop device number */ |
| + | int FAST_FUNC get_free_loop(void) |
| + | { |
| + | int fd; |
| + | int loopdevno; |
| + | |
| + | fd = open("/dev/loop-control", O_RDWR | O_CLOEXEC); |
| + | if (fd == -1) |
| + | return fd - 1; /* -2: "no /dev/loop-control" */ |
| + | |
| + | #ifndef LOOP_CTL_GET_FREE |
| + | # define LOOP_CTL_GET_FREE 0x4C82 |
| + | #endif |
| + | loopdevno = ioctl(fd, LOOP_CTL_GET_FREE); |
| + | close(fd); |
| + | return loopdevno; /* can be -1 if error */ |
| + | } |
| + | |
| /* Returns opened fd to the loop device, <0 on error. | |
| * *device is loop device to use, or if *device==NULL finds a loop device to | |
| * mount it on and sets *device to a strdup of that loop device name. This | |
| @@ -106,12 +124,24 @@ int FAST_FUNC set_loop(char **device, const char *file, unsigned long long offse | |
| return -errno; | |
| } | |
| - | //TODO: use LOOP_CTL_GET_FREE instead of trying every loopN in sequence? a-la: |
| - | // fd = open("/dev/loop-control", O_RDWR); |
| - | // loopN = ioctl(fd, LOOP_CTL_GET_FREE); |
| - | // |
| + | try = *device; |
| + | if (!try) { |
| + | i = get_free_loop(); |
| + | if (i == -2) { /* no /dev/loop-control */ |
| + | i = 0; |
| + | try = dev; |
| + | goto old_style; |
| + | } |
| + | if (i == -1) { |
| + | close(ffd); |
| + | return -1; /* no free loop devices */ |
| + | } |
| + | try = *device = xasprintf(LOOP_FORMAT, i); |
| + | goto try_to_open; |
| + | } |
| + | |
| + | old_style: |
| /* Find a loop device. */ | |
| - | try = *device ? *device : dev; |
| /* 1048575 (0xfffff) is a max possible minor number in Linux circa 2010 */ | |
| for (i = 0; rc && i < 1048576; i++) { | |
| sprintf(dev, LOOP_FORMAT, i); | |
| @@ -170,7 +200,7 @@ int FAST_FUNC set_loop(char **device, const char *file, unsigned long long offse | |
| rc = ioctl(dfd, BB_LOOP_SET_STATUS, &loopinfo); | |
| } | |
| if (rc != 0) { | |
| - | ioctl(dfd, LOOP_CLR_FD, 0); |
| + | ioctl(dfd, LOOP_CLR_FD, 0); // actually, 0 param is unnecessary |
| } | |
| } | |
| } else { | |
| @@ -114,8 +114,14 @@ int losetup_main(int argc UNUSED_PARAM, char **argv) | |
| /* contains -f */ | |
| if (opt & OPT_f) { | |
| char *s; | |
| - | int n = 0; |
| + | int n; |
| + | n = get_free_loop(); |
| + | if (n == -1) |
| + | bb_error_msg_and_die("no free loop devices"); |
| + | if (n < 0) /* n == -2: no /dev/loop-control, use legacy method */ |
| + | n = 0; |
| + | /* or: n >= 0: the number of next free loopdev, just verify it */ |
| do { | |
| if (n > MAX_LOOP_NUM) | |
| bb_error_msg_and_die("no free loop devices"); | |