diff options
| author | Denys Vlasenko <vda.linux@googlemail.com> | 2026-01-30 20:05:18 +0100 |
|---|---|---|
| committer | Denys Vlasenko <vda.linux@googlemail.com> | 2026-01-30 20:16:59 +0100 |
| commit | 8463ce06ca9aabc08909f34356b8b0342e5fb8ed (patch) | |
| tree | c16fc4856d1d1db53783326e005bec8100c00cbc | |
| parent | 8a347fd31aa2095be8eb683ad4f7627e525229f1 (diff) | |
| download | busybox-w32-8463ce06ca9aabc08909f34356b8b0342e5fb8ed.tar.gz busybox-w32-8463ce06ca9aabc08909f34356b8b0342e5fb8ed.tar.bz2 busybox-w32-8463ce06ca9aabc08909f34356b8b0342e5fb8ed.zip | |
lsblk: add error messages and exit code when non-blockdevs are given
function old new delta
process__sys_block_NAME - 461 +461
lsblk_main 511 550 +39
.rodata 106960 106977 +17
process_SYS_BLOCK_entry 460 - -460
------------------------------------------------------------------------------
(add/remove: 1/1 grow/shrink: 2/0 up/down: 517/-460) Total: 57 bytes
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
| -rw-r--r-- | util-linux/lsblk.c | 56 |
1 files changed, 39 insertions, 17 deletions
diff --git a/util-linux/lsblk.c b/util-linux/lsblk.c index 3063d8ae9..560ccbaf8 100644 --- a/util-linux/lsblk.c +++ b/util-linux/lsblk.c | |||
| @@ -71,8 +71,9 @@ struct blockdev_info { | |||
| 71 | }; | 71 | }; |
| 72 | 72 | ||
| 73 | struct globals { | 73 | struct globals { |
| 74 | unsigned count; | ||
| 75 | struct blockdev_info *list; | 74 | struct blockdev_info *list; |
| 75 | unsigned count; | ||
| 76 | unsigned exitcode; | ||
| 76 | }; | 77 | }; |
| 77 | #define G (*ptr_to_globals) | 78 | #define G (*ptr_to_globals) |
| 78 | #define INIT_G() do { \ | 79 | #define INIT_G() do { \ |
| @@ -124,6 +125,8 @@ static char *get_majmin_from_stat(const char *filename) | |||
| 124 | (unsigned)minor(st.st_rdev) | 125 | (unsigned)minor(st.st_rdev) |
| 125 | ); | 126 | ); |
| 126 | } | 127 | } |
| 128 | bb_error_msg("%s: not a block device", filename); | ||
| 129 | G.exitcode |= 64; /* util-linux compat */ | ||
| 127 | return NULL; | 130 | return NULL; |
| 128 | } | 131 | } |
| 129 | 132 | ||
| @@ -159,9 +162,7 @@ static char *read_str(const char *path, const char *name) | |||
| 159 | 162 | ||
| 160 | filename = concat_path_file(path, name); | 163 | filename = concat_path_file(path, name); |
| 161 | res = xmalloc_open_read_close(filename, NULL); | 164 | res = xmalloc_open_read_close(filename, NULL); |
| 162 | #if 0 | 165 | //bb_error_msg("open_read_close('%s'):'%s'", filename, res); |
| 163 | bb_error_msg("open_read_close('%s'):'%s'", filename, res); | ||
| 164 | #endif | ||
| 165 | free(filename); | 166 | free(filename); |
| 166 | 167 | ||
| 167 | if (res) | 168 | if (res) |
| @@ -184,10 +185,10 @@ bb_error_msg("open_read_close('%s'):'%s'", filename, res); | |||
| 184 | * MAJMIN1=open("/sys/block/DEV/PART/dev")+read | 185 | * MAJMIN1=open("/sys/block/DEV/PART/dev")+read |
| 185 | * recurse into handling MAJMIN1 for this partition | 186 | * recurse into handling MAJMIN1 for this partition |
| 186 | */ | 187 | */ |
| 187 | static void process_SYS_BLOCK_entry(const char *path, const char *devname); | 188 | static void process__sys_block_NAME(const char *path, const char *devname); |
| 188 | 189 | ||
| 189 | /* Note: consumes malloc'ed majmin */ | 190 | /* Note: consumes malloc'ed majmin */ |
| 190 | static void process_SYS_DEV_BLOCK_entry(const char *path, char *majmin, const char *devname) | 191 | static void process__sys_dev_block_MAJMIN(const char *path, char *majmin, const char *devname) |
| 191 | { | 192 | { |
| 192 | DIR *dir; | 193 | DIR *dir; |
| 193 | struct dirent *entry; | 194 | struct dirent *entry; |
| @@ -215,22 +216,24 @@ static void process_SYS_DEV_BLOCK_entry(const char *path, char *majmin, const ch | |||
| 215 | while ((entry = readdir(dir)) != NULL) { | 216 | while ((entry = readdir(dir)) != NULL) { |
| 216 | if (is_prefixed_with(entry->d_name, devname)) { | 217 | if (is_prefixed_with(entry->d_name, devname)) { |
| 217 | char *part = xasprintf("/sys/block/%s/%s", devname, entry->d_name); | 218 | char *part = xasprintf("/sys/block/%s/%s", devname, entry->d_name); |
| 218 | process_SYS_BLOCK_entry(part, entry->d_name); | 219 | process__sys_block_NAME(part, entry->d_name); |
| 219 | free(part); | 220 | free(part); |
| 220 | } | 221 | } |
| 221 | } | 222 | } |
| 222 | closedir(dir); | 223 | closedir(dir); |
| 223 | } | 224 | } |
| 224 | static void process_SYS_BLOCK_entry(const char *path, const char *devname) | 225 | static void process__sys_block_NAME(const char *path, const char *devname) |
| 225 | { | 226 | { |
| 226 | char *majmin = read_str(path, "dev"); | 227 | char *majmin = read_str(path, "dev"); |
| 228 | //bb_error_msg("%s/dev:'%s'", path, majmin); | ||
| 227 | if (majmin /*&& majmin[0]*/) { | 229 | if (majmin /*&& majmin[0]*/) { |
| 228 | char *sys_dev_block_MAJMIN = concat_path_file("/sys/dev/block", majmin); | 230 | char *sys_dev_block_MAJMIN = concat_path_file("/sys/dev/block", majmin); |
| 229 | process_SYS_DEV_BLOCK_entry(sys_dev_block_MAJMIN, majmin, devname); | 231 | process__sys_dev_block_MAJMIN(sys_dev_block_MAJMIN, majmin, devname); |
| 230 | /* ^^^ consumes malloc'ed majmin */ | 232 | /* ^^^ consumes malloc'ed majmin */ |
| 231 | free(sys_dev_block_MAJMIN); | 233 | free(sys_dev_block_MAJMIN); |
| 232 | } | 234 | } |
| 233 | /* WRONG: free(majmin); */ | 235 | /* WRONG: free(majmin); */ |
| 236 | // return !majmin; /* 1 if no PATH/dev was seen */ | ||
| 234 | } | 237 | } |
| 235 | 238 | ||
| 236 | static int compare_devices(const void *a, const void *b) | 239 | static int compare_devices(const void *a, const void *b) |
| @@ -254,7 +257,6 @@ int lsblk_main(int argc UNUSED_PARAM, char **argv) | |||
| 254 | /* If specific devices are requested, process them */ | 257 | /* If specific devices are requested, process them */ |
| 255 | if (*argv) { | 258 | if (*argv) { |
| 256 | while (*argv) { | 259 | while (*argv) { |
| 257 | char *devname = *argv++; | ||
| 258 | char *majmin; | 260 | char *majmin; |
| 259 | char *sys_dev_block_MAJMIN; | 261 | char *sys_dev_block_MAJMIN; |
| 260 | char *target; | 262 | char *target; |
| @@ -264,19 +266,36 @@ int lsblk_main(int argc UNUSED_PARAM, char **argv) | |||
| 264 | * cp -a /dev/DISK /tmp/bogusname; lsblk /tmp/bogusname | 266 | * cp -a /dev/DISK /tmp/bogusname; lsblk /tmp/bogusname |
| 265 | * ^^^^ should still show "DISK" as the name of blockdev, and show its partitions if any | 267 | * ^^^^ should still show "DISK" as the name of blockdev, and show its partitions if any |
| 266 | */ | 268 | */ |
| 267 | majmin = get_majmin_from_stat(devname); | 269 | majmin = get_majmin_from_stat(*argv++); |
| 270 | //bb_error_msg("get_majmin_from_stat('%s'):'%s'", argv[-1], majmin); | ||
| 268 | if (!majmin) | 271 | if (!majmin) |
| 269 | continue; | 272 | continue; |
| 270 | 273 | ||
| 271 | sys_dev_block_MAJMIN = concat_path_file("/sys/dev/block", majmin); | 274 | sys_dev_block_MAJMIN = concat_path_file("/sys/dev/block", majmin); |
| 272 | /* util-linux 2.41.1 gets the "real name" from the symlink's last component */ | 275 | /* util-linux 2.41.1 gets the "real name" from the symlink's last component */ |
| 273 | target = xmalloc_readlink(sys_dev_block_MAJMIN); | 276 | target = xmalloc_readlink(sys_dev_block_MAJMIN); |
| 277 | //bb_error_msg("target:'%s'", target); | ||
| 274 | if (target) { | 278 | if (target) { |
| 275 | name = strrchr(target, '/'); | 279 | name = strrchr(target, '/'); |
| 276 | if (name && name[1]) { | 280 | if (name && *++name) { |
| 277 | char *sys_block_NAME = concat_path_file("/sys/block", ++name); | 281 | char *sys_block_NAME; |
| 278 | process_SYS_BLOCK_entry(sys_block_NAME, name); | 282 | // Maybe there's a reason why util-linux tries /sys/block/NAME first. |
| 279 | free(sys_block_NAME); | 283 | // In which case uncomment this, and explain. |
| 284 | // int err; | ||
| 285 | // | ||
| 286 | // sys_block_NAME = concat_path_file("/sys/block", name); | ||
| 287 | // err = process__sys_block_NAME(sys_block_NAME, name); | ||
| 288 | // free(sys_block_NAME); | ||
| 289 | // /* "/sys/block/NAME/dev" wasn't found? (Happens for "lsblk /dev/PARTITION") */ | ||
| 290 | // if (err) { | ||
| 291 | /* util-linux seems to test for existence of /sys/dev/block/MAJMIN/partition, | ||
| 292 | * if that exists, it *guesses* parent disk name (!!!). | ||
| 293 | * We just try /sys/class/block/NAME, which exists for partitions too. | ||
| 294 | */ | ||
| 295 | sys_block_NAME = concat_path_file("/sys/class/block", name); | ||
| 296 | process__sys_block_NAME(sys_block_NAME, name); | ||
| 297 | free(sys_block_NAME); | ||
| 298 | // } | ||
| 280 | } | 299 | } |
| 281 | free(target); | 300 | free(target); |
| 282 | } | 301 | } |
| @@ -294,12 +313,15 @@ int lsblk_main(int argc UNUSED_PARAM, char **argv) | |||
| 294 | if (DOT_OR_DOTDOT(entry->d_name)) | 313 | if (DOT_OR_DOTDOT(entry->d_name)) |
| 295 | continue; | 314 | continue; |
| 296 | sys_block_NAME = concat_path_file("/sys/block", entry->d_name); | 315 | sys_block_NAME = concat_path_file("/sys/block", entry->d_name); |
| 297 | process_SYS_BLOCK_entry(sys_block_NAME, entry->d_name); | 316 | process__sys_block_NAME(sys_block_NAME, entry->d_name); |
| 298 | free(sys_block_NAME); | 317 | free(sys_block_NAME); |
| 299 | } | 318 | } |
| 300 | closedir(dir); | 319 | closedir(dir); |
| 301 | } | 320 | } |
| 302 | 321 | ||
| 322 | if (G.count == 0) | ||
| 323 | return 32; /* try "lsblk /dev/null DOES_NOT_EXIST" */ | ||
| 324 | |||
| 303 | /* Sort devices by name */ | 325 | /* Sort devices by name */ |
| 304 | qsort(G.list, G.count, sizeof(G.list[0]), compare_devices); | 326 | qsort(G.list, G.count, sizeof(G.list[0]), compare_devices); |
| 305 | 327 | ||
| @@ -321,5 +343,5 @@ int lsblk_main(int argc UNUSED_PARAM, char **argv) | |||
| 321 | ); | 343 | ); |
| 322 | } | 344 | } |
| 323 | 345 | ||
| 324 | fflush_stdout_and_exit_SUCCESS(); | 346 | fflush_stdout_and_exit(G.exitcode); |
| 325 | } | 347 | } |
