diff options
| author | Denys Vlasenko <vda.linux@googlemail.com> | 2026-01-30 21:16:30 +0100 |
|---|---|---|
| committer | Denys Vlasenko <vda.linux@googlemail.com> | 2026-01-30 21:16:30 +0100 |
| commit | 2bfe3753d9f02ac01bf245610b4c39da727e2489 (patch) | |
| tree | c8650b463099d571fa0407e7def9eb0e33eb12f2 | |
| parent | 8463ce06ca9aabc08909f34356b8b0342e5fb8ed (diff) | |
| download | busybox-w32-2bfe3753d9f02ac01bf245610b4c39da727e2489.tar.gz busybox-w32-2bfe3753d9f02ac01bf245610b4c39da727e2489.tar.bz2 busybox-w32-2bfe3753d9f02ac01bf245610b4c39da727e2489.zip | |
lkblk: list multiple MOUNTPOINTS
function old new delta
lsblk_main 550 869 +319
.rodata 106977 107010 +33
process__sys_block_NAME 461 356 -105
------------------------------------------------------------------------------
(add/remove: 0/0 grow/shrink: 2/1 up/down: 352/-105) Total: 247 bytes
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
| -rw-r--r-- | util-linux/lsblk.c | 80 |
1 files changed, 58 insertions, 22 deletions
diff --git a/util-linux/lsblk.c b/util-linux/lsblk.c index 560ccbaf8..a482bfbbc 100644 --- a/util-linux/lsblk.c +++ b/util-linux/lsblk.c | |||
| @@ -67,11 +67,12 @@ struct blockdev_info { | |||
| 67 | unsigned long long size; | 67 | unsigned long long size; |
| 68 | const char *type; | 68 | const char *type; |
| 69 | const char *majmin; | 69 | const char *majmin; |
| 70 | const char *mountpoint; | 70 | //const char *mountpoint; |
| 71 | }; | 71 | }; |
| 72 | 72 | ||
| 73 | struct globals { | 73 | struct globals { |
| 74 | struct blockdev_info *list; | 74 | struct blockdev_info *list; |
| 75 | char *mountinfo; | ||
| 75 | unsigned count; | 76 | unsigned count; |
| 76 | unsigned exitcode; | 77 | unsigned exitcode; |
| 77 | }; | 78 | }; |
| @@ -93,27 +94,47 @@ static struct blockdev_info *get_or_create_info(const char *devname) | |||
| 93 | return &G.list[G.count++]; | 94 | return &G.list[G.count++]; |
| 94 | } | 95 | } |
| 95 | 96 | ||
| 96 | static char *get_mountpoint(const char *devname) | 97 | static char *get_mountpoints(const char *majmin) |
| 97 | { | 98 | { |
| 98 | char devpath[256]; | 99 | unsigned len; |
| 99 | struct mntent *mnt; | 100 | char *p, *mountpoints; |
| 100 | FILE *mtab; | 101 | |
| 101 | char *mountpoint = NULL; | 102 | mountpoints = NULL; |
| 102 | 103 | len = strlen(majmin); | |
| 103 | snprintf(devpath, sizeof(devpath), "/dev/%s", devname); | 104 | p = G.mountinfo; // "/proc/self/mountinfo" |
| 104 | //TODO: use /proc/self/mountinfo instead, it has MAJ:MIN column which is unambiguous | 105 | /* lines a-la "63 1 259:3 / /MNTPOINT per-mount_options - ext4 /dev/NAME per-superblock_options" */ |
| 105 | mtab = setmntent(bb_path_mtab_file, "r"); | 106 | while (*p) { |
| 106 | if (mtab) { | 107 | char *e, *f; |
| 107 | while ((mnt = getmntent(mtab)) != NULL) { | 108 | |
| 108 | if (strcmp(mnt->mnt_fsname, devpath) == 0) { | 109 | p = skip_non_whitespace(p); |
| 109 | mountpoint = xstrdup(mnt->mnt_dir); | 110 | if (*p != ' ') break; |
| 111 | // at " 1 259:3" | ||
| 112 | p = skip_non_whitespace(p + 1); | ||
| 113 | if (*p != ' ') break; | ||
| 114 | p++; | ||
| 115 | // at "259:3 / /MNTPOINT" | ||
| 116 | if (strncmp(p, majmin, len) != 0 || (p+=len)[0] != ' ') { | ||
| 117 | p = strchr(p, '\n'); | ||
| 118 | if (!p) | ||
| 110 | break; | 119 | break; |
| 111 | } | 120 | p++; |
| 121 | continue; | ||
| 112 | } | 122 | } |
| 113 | endmntent(mtab); | 123 | // at " / /MNTPOINT" |
| 124 | p = skip_non_whitespace(p + 1); | ||
| 125 | if (*p != ' ') break; | ||
| 126 | |||
| 127 | // at " /MNTPOINT" | ||
| 128 | e = skip_non_whitespace(p + 1); | ||
| 129 | // e is at the end of " /MNTPOINT" | ||
| 130 | f = mountpoints; | ||
| 131 | // NO. We return " /MNT1 /MNT2 /MNT3" _with_ leading space! | ||
| 132 | // if (!f) | ||
| 133 | // p++; | ||
| 134 | mountpoints = xasprintf("%s%.*s", f ? f : "", (int)(e - p), p); | ||
| 135 | free(f); | ||
| 114 | } | 136 | } |
| 115 | 137 | return mountpoints; | |
| 116 | return mountpoint; | ||
| 117 | } | 138 | } |
| 118 | 139 | ||
| 119 | static char *get_majmin_from_stat(const char *filename) | 140 | static char *get_majmin_from_stat(const char *filename) |
| @@ -209,7 +230,7 @@ static void process__sys_dev_block_MAJMIN(const char *path, char *majmin, const | |||
| 209 | info->majmin = majmin; | 230 | info->majmin = majmin; |
| 210 | //info->rm = ...; | 231 | //info->rm = ...; |
| 211 | //info->ro = ...; | 232 | //info->ro = ...; |
| 212 | info->mountpoint = get_mountpoint(devname); | 233 | //info->mountpoint = get_mountpoint(majmin); |
| 213 | 234 | ||
| 214 | /* Scan for partititons */ | 235 | /* Scan for partititons */ |
| 215 | dir = xopendir(path); | 236 | dir = xopendir(path); |
| @@ -254,6 +275,8 @@ int lsblk_main(int argc UNUSED_PARAM, char **argv) | |||
| 254 | getopt32(argv, "a"); | 275 | getopt32(argv, "a"); |
| 255 | argv += optind; | 276 | argv += optind; |
| 256 | 277 | ||
| 278 | G.mountinfo = xmalloc_xopen_read_close("/proc/self/mountinfo", NULL); | ||
| 279 | |||
| 257 | /* If specific devices are requested, process them */ | 280 | /* If specific devices are requested, process them */ |
| 258 | if (*argv) { | 281 | if (*argv) { |
| 259 | while (*argv) { | 282 | while (*argv) { |
| @@ -326,21 +349,34 @@ int lsblk_main(int argc UNUSED_PARAM, char **argv) | |||
| 326 | qsort(G.list, G.count, sizeof(G.list[0]), compare_devices); | 349 | qsort(G.list, G.count, sizeof(G.list[0]), compare_devices); |
| 327 | 350 | ||
| 328 | /* Print header */ | 351 | /* Print header */ |
| 329 | printf("%-15s MAJ:MIN SIZE TYPE MOUNTPOINT\n", "NAME"); | 352 | printf("%-15s MAJ:MIN SIZE TYPE MOUNTPOINTS\n", "NAME"); |
| 330 | //util-linux 2.41.1 default set of fields: | 353 | //util-linux 2.41.1 default set of fields: |
| 331 | //"NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINTS" | 354 | //"NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINTS" |
| 332 | 355 | ||
| 333 | /* Print devices */ | 356 | /* Print devices */ |
| 334 | for (i = 0; i < G.count; i++) { | 357 | for (i = 0; i < G.count; i++) { |
| 335 | char buf6[6]; | 358 | char buf6[6]; |
| 359 | char *mnt, *e; | ||
| 360 | |||
| 361 | mnt = (get_mountpoints(G.list[i].majmin) ? : (char*)""); | ||
| 362 | e = strchrnul(mnt[0] ? mnt + 1 : "", ' '); | ||
| 336 | smart_ulltoa5(G.list[i].size * 512, buf6, " KMGTPEZY"); | 363 | smart_ulltoa5(G.list[i].size * 512, buf6, " KMGTPEZY"); |
| 337 | printf("%-15s %-7s %.5s %4s %s\n", | 364 | printf("%-15s %-7s %.5s %4s%.*s\n", |
| 338 | G.list[i].name, | 365 | G.list[i].name, |
| 339 | G.list[i].majmin, | 366 | G.list[i].majmin, |
| 340 | buf6, | 367 | buf6, |
| 341 | G.list[i].type, | 368 | G.list[i].type, |
| 342 | (G.list[i].mountpoint ? G.list[i].mountpoint : "") | 369 | (int)(e - mnt), mnt |
| 343 | ); | 370 | ); |
| 371 | while (*mnt == ' ') { | ||
| 372 | //util-linux prints multiple mountpoints on separate lines: | ||
| 373 | //DEVNAME 259:3 0 475.4G 0 part /MNT1 | ||
| 374 | // /MNT2 | ||
| 375 | mnt = skip_non_whitespace(mnt + 1); | ||
| 376 | if (!mnt[0]) break; | ||
| 377 | e = strchrnul(mnt + 1, ' '); | ||
| 378 | printf("%34s%.*s\n", "", (int)(e - mnt), mnt); | ||
| 379 | } | ||
| 344 | } | 380 | } |
| 345 | 381 | ||
| 346 | fflush_stdout_and_exit(G.exitcode); | 382 | fflush_stdout_and_exit(G.exitcode); |
