diff options
| author | Ron Yorston <rmy@pobox.com> | 2023-01-05 08:56:27 +0000 |
|---|---|---|
| committer | Ron Yorston <rmy@pobox.com> | 2023-01-05 08:56:27 +0000 |
| commit | e5e4a2fec5435192d1672e6db2f335cb5e89f877 (patch) | |
| tree | 08cb827a40817ea4824bc9336d57eda669c4d4b2 /libbb | |
| parent | 4343f3926355f55fc023203c992527fc34bf609e (diff) | |
| parent | b1884deb514c35289d37e7bfbf23f770b0bd09b3 (diff) | |
| download | busybox-w32-e5e4a2fec5435192d1672e6db2f335cb5e89f877.tar.gz busybox-w32-e5e4a2fec5435192d1672e6db2f335cb5e89f877.tar.bz2 busybox-w32-e5e4a2fec5435192d1672e6db2f335cb5e89f877.zip | |
Merge branch 'busybox' into merge
Diffstat (limited to 'libbb')
| -rw-r--r-- | libbb/Config.src | 22 | ||||
| -rw-r--r-- | libbb/lineedit.c | 24 | ||||
| -rw-r--r-- | libbb/loop.c | 175 |
3 files changed, 148 insertions, 73 deletions
diff --git a/libbb/Config.src b/libbb/Config.src index 66a3ffa23..b980f19a9 100644 --- a/libbb/Config.src +++ b/libbb/Config.src | |||
| @@ -369,3 +369,25 @@ config UNICODE_PRESERVE_BROKEN | |||
| 369 | For example, this means that entering 'l', 's', ' ', 0xff, [Enter] | 369 | For example, this means that entering 'l', 's', ' ', 0xff, [Enter] |
| 370 | at shell prompt will list file named 0xff (single char name | 370 | at shell prompt will list file named 0xff (single char name |
| 371 | with char value 255), not file named '?'. | 371 | with char value 255), not file named '?'. |
| 372 | |||
| 373 | choice | ||
| 374 | prompt "Use LOOP_CONFIGURE for losetup and loop mounts" | ||
| 375 | default TRY_LOOP_CONFIGURE | ||
| 376 | help | ||
| 377 | LOOP_CONFIGURE is added to Linux 5.8 | ||
| 378 | https://lwn.net/Articles/820408/ | ||
| 379 | This allows userspace to completely setup a loop device with a single | ||
| 380 | ioctl, removing the in-between state where the device can be partially | ||
| 381 | configured - eg the loop device has a backing file associated with it, | ||
| 382 | but is reading from the wrong offset. | ||
| 383 | |||
| 384 | config LOOP_CONFIGURE | ||
| 385 | bool "use LOOP_CONFIGURE, needs kernel >= 5.8" | ||
| 386 | |||
| 387 | config NO_LOOP_CONFIGURE | ||
| 388 | bool "use LOOP_SET_FD + LOOP_SET_STATUS" | ||
| 389 | |||
| 390 | config TRY_LOOP_CONFIGURE | ||
| 391 | bool "try LOOP_CONFIGURE, fall back to LOOP_SET_FD + LOOP_SET_STATUS" | ||
| 392 | |||
| 393 | endchoice | ||
diff --git a/libbb/lineedit.c b/libbb/lineedit.c index b4950688e..bee423553 100644 --- a/libbb/lineedit.c +++ b/libbb/lineedit.c | |||
| @@ -249,14 +249,6 @@ static void get_user_strings(void) | |||
| 249 | } | 249 | } |
| 250 | } | 250 | } |
| 251 | 251 | ||
| 252 | static const char *get_username_str(void) | ||
| 253 | { | ||
| 254 | if (!got_user_strings) | ||
| 255 | get_user_strings(); | ||
| 256 | return user_buf ? user_buf : ""; | ||
| 257 | /* btw, bash uses "I have no name!" string if uid has no entry */ | ||
| 258 | } | ||
| 259 | |||
| 260 | static NOINLINE const char *get_homedir_or_NULL(void) | 252 | static NOINLINE const char *get_homedir_or_NULL(void) |
| 261 | { | 253 | { |
| 262 | const char *home; | 254 | const char *home; |
| @@ -275,6 +267,16 @@ static NOINLINE const char *get_homedir_or_NULL(void) | |||
| 275 | } | 267 | } |
| 276 | #endif | 268 | #endif |
| 277 | 269 | ||
| 270 | #if ENABLE_FEATURE_EDITING_FANCY_PROMPT | ||
| 271 | static const char *get_username_str(void) | ||
| 272 | { | ||
| 273 | if (!got_user_strings) | ||
| 274 | get_user_strings(); | ||
| 275 | return user_buf ? user_buf : ""; | ||
| 276 | /* btw, bash uses "I have no name!" string if uid has no entry */ | ||
| 277 | } | ||
| 278 | #endif | ||
| 279 | |||
| 278 | #if ENABLE_UNICODE_SUPPORT | 280 | #if ENABLE_UNICODE_SUPPORT |
| 279 | static size_t load_string(const char *src) | 281 | static size_t load_string(const char *src) |
| 280 | { | 282 | { |
| @@ -2151,13 +2153,13 @@ static void parse_and_put_prompt(const char *prmt_ptr) | |||
| 2151 | case 'W': /* basename of cur dir */ | 2153 | case 'W': /* basename of cur dir */ |
| 2152 | if (!cwd_buf) { | 2154 | if (!cwd_buf) { |
| 2153 | const char *home; | 2155 | const char *home; |
| 2154 | #if ENABLE_SHELL_ASH | 2156 | # if EDITING_HAS_sh_get_var |
| 2155 | cwd_buf = state->sh_get_var | 2157 | cwd_buf = state->sh_get_var |
| 2156 | ? xstrdup(state->sh_get_var("PWD")) | 2158 | ? xstrdup(state->sh_get_var("PWD")) |
| 2157 | : xrealloc_getcwd_or_warn(NULL); | 2159 | : xrealloc_getcwd_or_warn(NULL); |
| 2158 | #else | 2160 | # else |
| 2159 | cwd_buf = xrealloc_getcwd_or_warn(NULL); | 2161 | cwd_buf = xrealloc_getcwd_or_warn(NULL); |
| 2160 | #endif | 2162 | # endif |
| 2161 | if (!cwd_buf) | 2163 | if (!cwd_buf) |
| 2162 | cwd_buf = (char *)bb_msg_unknown; | 2164 | cwd_buf = (char *)bb_msg_unknown; |
| 2163 | else if ((home = get_homedir_or_NULL()) != NULL && home[0]) { | 2165 | else if ((home = get_homedir_or_NULL()) != NULL && home[0]) { |
diff --git a/libbb/loop.c b/libbb/loop.c index cb8fa2442..a0c5d0259 100644 --- a/libbb/loop.c +++ b/libbb/loop.c | |||
| @@ -71,7 +71,7 @@ int FAST_FUNC del_loop(const char *device) | |||
| 71 | 71 | ||
| 72 | fd = open(device, O_RDONLY); | 72 | fd = open(device, O_RDONLY); |
| 73 | if (fd < 0) | 73 | if (fd < 0) |
| 74 | return 1; | 74 | return fd; /* -1 */ |
| 75 | rc = ioctl(fd, LOOP_CLR_FD, 0); | 75 | rc = ioctl(fd, LOOP_CLR_FD, 0); |
| 76 | close(fd); | 76 | close(fd); |
| 77 | 77 | ||
| @@ -96,6 +96,97 @@ int FAST_FUNC get_free_loop(void) | |||
| 96 | return loopdevno; /* can be -1 if error */ | 96 | return loopdevno; /* can be -1 if error */ |
| 97 | } | 97 | } |
| 98 | 98 | ||
| 99 | static int get_next_free_loop(char *dev, int id) | ||
| 100 | { | ||
| 101 | int loopdevno; | ||
| 102 | |||
| 103 | loopdevno = get_free_loop(); | ||
| 104 | if (loopdevno != -1) { | ||
| 105 | /* loopdevno is -2 (use id) or >= 0 (use id = loopdevno): */ | ||
| 106 | if (loopdevno >= 0) | ||
| 107 | id = loopdevno; | ||
| 108 | sprintf(dev, LOOP_FORMAT, id); | ||
| 109 | } | ||
| 110 | return loopdevno; | ||
| 111 | } | ||
| 112 | |||
| 113 | #if ENABLE_TRY_LOOP_CONFIGURE || ENABLE_LOOP_CONFIGURE | ||
| 114 | # define LOOP_CONFIGURE 0x4C0A | ||
| 115 | struct bb_loop_config { | ||
| 116 | uint32_t fd; | ||
| 117 | uint32_t block_size; | ||
| 118 | struct loop_info64 info; | ||
| 119 | uint64_t __reserved[8]; | ||
| 120 | }; | ||
| 121 | #endif | ||
| 122 | |||
| 123 | static int set_loopdev_params(int lfd, | ||
| 124 | int ffd, const char *file, | ||
| 125 | unsigned long long offset, | ||
| 126 | unsigned long long sizelimit, | ||
| 127 | unsigned flags) | ||
| 128 | { | ||
| 129 | int rc; | ||
| 130 | #if ENABLE_TRY_LOOP_CONFIGURE || ENABLE_LOOP_CONFIGURE | ||
| 131 | struct bb_loop_config lconfig; | ||
| 132 | # define loopinfo lconfig.info | ||
| 133 | #else | ||
| 134 | bb_loop_info loopinfo; | ||
| 135 | #endif | ||
| 136 | |||
| 137 | rc = ioctl(lfd, BB_LOOP_GET_STATUS, &loopinfo); | ||
| 138 | |||
| 139 | /* If device is free, try to claim it */ | ||
| 140 | if (rc && errno == ENXIO) { | ||
| 141 | #if ENABLE_TRY_LOOP_CONFIGURE || ENABLE_LOOP_CONFIGURE | ||
| 142 | memset(&lconfig, 0, sizeof(lconfig)); | ||
| 143 | #else | ||
| 144 | memset(&loopinfo, 0, sizeof(loopinfo)); | ||
| 145 | #endif | ||
| 146 | safe_strncpy((char *)loopinfo.lo_file_name, file, LO_NAME_SIZE); | ||
| 147 | loopinfo.lo_offset = offset; | ||
| 148 | loopinfo.lo_sizelimit = sizelimit; | ||
| 149 | /* | ||
| 150 | * LO_FLAGS_READ_ONLY is not set because RO is controlled | ||
| 151 | * by open type of the lfd. | ||
| 152 | */ | ||
| 153 | loopinfo.lo_flags = (flags & ~BB_LO_FLAGS_READ_ONLY); | ||
| 154 | |||
| 155 | #if ENABLE_TRY_LOOP_CONFIGURE || ENABLE_LOOP_CONFIGURE | ||
| 156 | lconfig.fd = ffd; | ||
| 157 | rc = ioctl(lfd, LOOP_CONFIGURE, &lconfig); | ||
| 158 | if (rc == 0) | ||
| 159 | return rc; /* SUCCESS! */ | ||
| 160 | # if ENABLE_TRY_LOOP_CONFIGURE | ||
| 161 | if (errno != EINVAL) | ||
| 162 | return rc; /* error other than old kernel */ | ||
| 163 | /* Old kernel, fall through into old way to do it: */ | ||
| 164 | # endif | ||
| 165 | #endif | ||
| 166 | #if ENABLE_TRY_LOOP_CONFIGURE || ENABLE_NO_LOOP_CONFIGURE | ||
| 167 | /* Associate free loop device with file */ | ||
| 168 | rc = ioctl(lfd, LOOP_SET_FD, ffd); | ||
| 169 | if (rc != 0) { | ||
| 170 | /* Ouch... race: the device already has a fd */ | ||
| 171 | return rc; | ||
| 172 | } | ||
| 173 | rc = ioctl(lfd, BB_LOOP_SET_STATUS, &loopinfo); | ||
| 174 | if (rc != 0 && (loopinfo.lo_flags & BB_LO_FLAGS_AUTOCLEAR)) { | ||
| 175 | /* Old kernel, does not support LO_FLAGS_AUTOCLEAR? */ | ||
| 176 | /* (this code path is not tested) */ | ||
| 177 | loopinfo.lo_flags -= BB_LO_FLAGS_AUTOCLEAR; | ||
| 178 | rc = ioctl(lfd, BB_LOOP_SET_STATUS, &loopinfo); | ||
| 179 | } | ||
| 180 | if (rc == 0) | ||
| 181 | return rc; /* SUCCESS! */ | ||
| 182 | /* failure, undo LOOP_SET_FD */ | ||
| 183 | ioctl(lfd, LOOP_CLR_FD, 0); // actually, 0 param is unnecessary | ||
| 184 | #endif | ||
| 185 | } | ||
| 186 | return -1; | ||
| 187 | #undef loopinfo | ||
| 188 | } | ||
| 189 | |||
| 99 | /* Returns opened fd to the loop device, <0 on error. | 190 | /* Returns opened fd to the loop device, <0 on error. |
| 100 | * *device is loop device to use, or if *device==NULL finds a loop device to | 191 | * *device is loop device to use, or if *device==NULL finds a loop device to |
| 101 | * mount it on and sets *device to a strdup of that loop device name. | 192 | * mount it on and sets *device to a strdup of that loop device name. |
| @@ -105,7 +196,6 @@ int FAST_FUNC set_loop(char **device, const char *file, unsigned long long offse | |||
| 105 | { | 196 | { |
| 106 | char dev[LOOP_NAMESIZE]; | 197 | char dev[LOOP_NAMESIZE]; |
| 107 | char *try; | 198 | char *try; |
| 108 | bb_loop_info loopinfo; | ||
| 109 | struct stat statbuf; | 199 | struct stat statbuf; |
| 110 | int i, lfd, ffd, mode, rc; | 200 | int i, lfd, ffd, mode, rc; |
| 111 | 201 | ||
| @@ -123,30 +213,27 @@ int FAST_FUNC set_loop(char **device, const char *file, unsigned long long offse | |||
| 123 | 213 | ||
| 124 | try = *device; | 214 | try = *device; |
| 125 | if (!try) { | 215 | if (!try) { |
| 126 | get_free_loopN: | ||
| 127 | i = get_free_loop(); | ||
| 128 | if (i == -1) { | ||
| 129 | close(ffd); | ||
| 130 | return -1; /* no free loop devices */ | ||
| 131 | } | ||
| 132 | if (i >= 0) { | ||
| 133 | try = xasprintf(LOOP_FORMAT, i); | ||
| 134 | goto open_lfd; | ||
| 135 | } | ||
| 136 | /* i == -2: no /dev/loop-control. Do an old-style search for a free device */ | ||
| 137 | try = dev; | 216 | try = dev; |
| 138 | } | 217 | } |
| 139 | 218 | ||
| 140 | /* Find a loop device */ | 219 | /* Find a loop device */ |
| 141 | /* 0xfffff is a max possible minor number in Linux circa 2010 */ | 220 | /* 0xfffff is a max possible minor number in Linux circa 2010 */ |
| 142 | for (i = 0; i <= 0xfffff; i++) { | 221 | for (i = 0; i <= 0xfffff; i++) { |
| 143 | sprintf(dev, LOOP_FORMAT, i); | 222 | if (!*device) { |
| 223 | rc = get_next_free_loop(dev, i); | ||
| 224 | if (rc == -1) | ||
| 225 | break; /* no free loop devices (or other error in LOOP_CTL_GET_FREE) */ | ||
| 226 | if (rc >= 0) | ||
| 227 | /* /dev/loop-control gave us the next free /dev/loopN */ | ||
| 228 | goto open_lfd; | ||
| 229 | /* else: sequential /dev/loopN, needs to be tested/maybe_created */ | ||
| 230 | } | ||
| 144 | 231 | ||
| 145 | IF_FEATURE_MOUNT_LOOP_CREATE(errno = 0;) | 232 | IF_FEATURE_MOUNT_LOOP_CREATE(errno = 0;) |
| 146 | if (stat(try, &statbuf) != 0 || !S_ISBLK(statbuf.st_mode)) { | 233 | if (stat(try, &statbuf) != 0 || !S_ISBLK(statbuf.st_mode)) { |
| 147 | if (ENABLE_FEATURE_MOUNT_LOOP_CREATE | 234 | if (ENABLE_FEATURE_MOUNT_LOOP_CREATE |
| 148 | && errno == ENOENT | 235 | && errno == ENOENT |
| 149 | && try == dev | 236 | && (!*device) |
| 150 | ) { | 237 | ) { |
| 151 | /* Node doesn't exist, try to create it */ | 238 | /* Node doesn't exist, try to create it */ |
| 152 | if (mknod(dev, S_IFBLK|0644, makedev(7, i)) == 0) | 239 | if (mknod(dev, S_IFBLK|0644, makedev(7, i)) == 0) |
| @@ -172,55 +259,19 @@ int FAST_FUNC set_loop(char **device, const char *file, unsigned long long offse | |||
| 172 | goto try_next_loopN; | 259 | goto try_next_loopN; |
| 173 | } | 260 | } |
| 174 | 261 | ||
| 175 | rc = ioctl(lfd, BB_LOOP_GET_STATUS, &loopinfo); | 262 | rc = set_loopdev_params(lfd, ffd, file, offset, sizelimit, flags); |
| 176 | 263 | if (rc == 0) { | |
| 177 | /* If device is free, try to claim it */ | 264 | /* SUCCESS! */ |
| 178 | if (rc && errno == ENXIO) { | 265 | if (!*device) |
| 179 | /* Associate free loop device with file */ | 266 | *device = xstrdup(dev); |
| 180 | if (ioctl(lfd, LOOP_SET_FD, ffd)) { | 267 | /* Note: mount asks for LO_FLAGS_AUTOCLEAR loopdev. |
| 181 | /* Ouch. Are we racing with other mount? */ | 268 | * Closing LO_FLAGS_AUTOCLEARed lfd before mount |
| 182 | if (!*device /* yes */ | 269 | * is wrong (would free the loop device!), |
| 183 | && try != dev /* tried a _kernel-offered_ loopN? */ | 270 | * this is why we return without closing it. |
| 184 | ) { | ||
| 185 | free(try); | ||
| 186 | close(lfd); | ||
| 187 | //TODO: add "if (--failcount != 0) ..."? | ||
| 188 | goto get_free_loopN; | ||
| 189 | } | ||
| 190 | goto close_and_try_next_loopN; | ||
| 191 | } | ||
| 192 | memset(&loopinfo, 0, sizeof(loopinfo)); | ||
| 193 | safe_strncpy((char *)loopinfo.lo_file_name, file, LO_NAME_SIZE); | ||
| 194 | loopinfo.lo_offset = offset; | ||
| 195 | loopinfo.lo_sizelimit = sizelimit; | ||
| 196 | /* | ||
| 197 | * Used by mount to set LO_FLAGS_AUTOCLEAR. | ||
| 198 | * LO_FLAGS_READ_ONLY is not set because RO is controlled by open type of the file. | ||
| 199 | * Note that closing LO_FLAGS_AUTOCLEARed lfd before mount | ||
| 200 | * is wrong (would free the loop device!) | ||
| 201 | */ | 271 | */ |
| 202 | loopinfo.lo_flags = (flags & ~BB_LO_FLAGS_READ_ONLY); | 272 | rc = lfd; /* return this */ |
| 203 | rc = ioctl(lfd, BB_LOOP_SET_STATUS, &loopinfo); | 273 | break; |
| 204 | if (rc != 0 && (loopinfo.lo_flags & BB_LO_FLAGS_AUTOCLEAR)) { | ||
| 205 | /* Old kernel, does not support LO_FLAGS_AUTOCLEAR? */ | ||
| 206 | /* (this code path is not tested) */ | ||
| 207 | loopinfo.lo_flags -= BB_LO_FLAGS_AUTOCLEAR; | ||
| 208 | rc = ioctl(lfd, BB_LOOP_SET_STATUS, &loopinfo); | ||
| 209 | } | ||
| 210 | if (rc == 0) { | ||
| 211 | /* SUCCESS! */ | ||
| 212 | if (try != dev) /* tried a kernel-offered free loopN? */ | ||
| 213 | *device = try; /* malloced */ | ||
| 214 | if (!*device) /* was looping in search of free "/dev/loopN"? */ | ||
| 215 | *device = xstrdup(dev); | ||
| 216 | rc = lfd; /* return this */ | ||
| 217 | break; | ||
| 218 | } | ||
| 219 | /* failure, undo LOOP_SET_FD */ | ||
| 220 | ioctl(lfd, LOOP_CLR_FD, 0); // actually, 0 param is unnecessary | ||
| 221 | } | 274 | } |
| 222 | /* else: device is not free (rc == 0) or error other than ENXIO */ | ||
| 223 | close_and_try_next_loopN: | ||
| 224 | close(lfd); | 275 | close(lfd); |
| 225 | try_next_loopN: | 276 | try_next_loopN: |
| 226 | rc = -1; | 277 | rc = -1; |
