On Thu, Dec 04, 2025 at 10:08:46PM +0100, Osama Abdelkader wrote: > Add a simple lsblk utility that lists information about block devices. > Reads from /sys/block to enumerate devices and displays their size, > type, and mount point. > > Features: > - Lists all block devices or specific devices > - Shows device size in human-readable format (B, K, M, G, T, P) > - Shows device type (disk, loop, rom, etc.) > - Shows mount point if device is mounted > - Sorts devices alphabetically > - Minimal implementation (~2.5 kb) > - NOFORK applet for efficiency > > Signed-off-by: Osama Abdelkader <[email protected]> > --- > util-linux/lsblk.c | 219 +++++++++++++++++++++++++++++++++++++++++++++ > 1 file changed, 219 insertions(+) > create mode 100644 util-linux/lsblk.c > > diff --git a/util-linux/lsblk.c b/util-linux/lsblk.c > new file mode 100644 > index 000000000..47f217fb8 > --- /dev/null > +++ b/util-linux/lsblk.c > @@ -0,0 +1,219 @@ > +/* vi: set sw=4 ts=4: */ > +/* > + * Mini lsblk implementation for busybox > + * > + * Licensed under GPLv2 or later, see file LICENSE in this source tree. > + */ > +//config:config LSBLK > +//config: bool "lsblk (2.5 kb)" > +//config: default y > +//config: help > +//config: List information about all available or specified block devices. > + > +//applet:IF_LSBLK(APPLET_NOFORK(lsblk, lsblk, BB_DIR_USR_BIN, BB_SUID_DROP, > lsblk)) > + > +//kbuild:lib-$(CONFIG_LSBLK) += lsblk.o > + > +//usage:#define lsblk_trivial_usage > +//usage: "[BLOCKDEVICE...]" > +//usage:#define lsblk_full_usage "\n\n" > +//usage: "List information about all available or specified block > devices" > + > +#include "libbb.h" > +#include <mntent.h> > + > +/* This is a NOFORK applet. Be very careful! */ > + > +struct blockdev_info { > + char *name; > + unsigned long long size; > + char *type; > + char *mountpoint; > +}; > + > +static unsigned long long read_size_from_sysfs(const char *devname) > +{ > + char path[256]; > + char buf[64]; > + ssize_t len; > + unsigned long long size = 0; > + > + snprintf(path, sizeof(path), "/sys/block/%s/size", devname); > + len = open_read_close(path, buf, sizeof(buf) - 1); > + if (len > 0) { > + buf[len] = '\0'; > + /* Remove trailing newline if present */ > + if (buf[len - 1] == '\n') > + buf[len - 1] = '\0'; > + size = bb_strtoull(buf, NULL, 10); > + /* size is in 512-byte sectors, convert to bytes */ > + size *= 512; > + } > + return size; > +} > + > +static char *get_device_type(const char *devname) > +{ > + char path[256]; > + char *buf, *type = NULL; > + size_t len; > + > + /* Try to read from uevent */ > + snprintf(path, sizeof(path), "/sys/block/%s/uevent", devname); > + buf = xmalloc_open_read_close(path, &len); > + if (buf) { > + char *p = buf; > + while (*p) { > + if (strncmp(p, "DEVTYPE=", 8) == 0) { > + char *end; > + type = xstrdup(p + 8); > + /* Remove newline */ > + end = strchr(type, '\n'); > + if (end) *end = '\0'; > + break; > + } > + p = strchr(p, '\n'); > + if (!p) break; > + p++; > + } > + free(buf); > + } > + > + /* Fallback: guess from device name */ > + if (!type) { > + if (strncmp(devname, "loop", 4) == 0) > + type = xstrdup("loop"); > + else if (strncmp(devname, "ram", 3) == 0) > + type = xstrdup("ram"); > + else if (strncmp(devname, "nvme", 4) == 0 || strncmp(devname, > "sd", 2) == 0 || > + strncmp(devname, "hd", 2) == 0 || strncmp(devname, > "vd", 2) == 0) > + type = xstrdup("disk"); > + else > + type = xstrdup("disk"); > + } > + > + return type; > +} > + > +static char *get_mountpoint(const char *devname) > +{ > + char devpath[256]; > + struct mntent *mnt; > + FILE *mtab; > + char *mountpoint = NULL; > + > + snprintf(devpath, sizeof(devpath), "/dev/%s", devname); > + mtab = setmntent(bb_path_mtab_file, "r"); > + if (mtab) { > + while ((mnt = getmntent(mtab)) != NULL) { > + if (strcmp(mnt->mnt_fsname, devpath) == 0) { > + mountpoint = xstrdup(mnt->mnt_dir); > + break; > + } > + } > + endmntent(mtab); > + } > + > + return mountpoint; > +} > + > +static void print_size(unsigned long long size) > +{ > + const char *units[] = {"B", "K", "M", "G", "T", "P"}; > + int unit_idx = 0; > + double dsize = size; > + > + while (dsize >= 1024.0 && unit_idx < 5) { > + dsize /= 1024.0; > + unit_idx++; > + } > + > + if (unit_idx == 0) > + printf("%llu", size); > + else > + printf("%.1f%c", dsize, units[unit_idx][0]); > +} > + > +static int compare_devices(const void *a, const void *b) > +{ > + const struct blockdev_info *da = (const struct blockdev_info *)a; > + const struct blockdev_info *db = (const struct blockdev_info *)b; > + return strcmp(da->name, db->name); > +} > + > +int lsblk_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; > +int lsblk_main(int argc UNUSED_PARAM, char **argv) > +{ > + DIR *dir; > + struct dirent *entry; > + struct blockdev_info *devices = NULL; > + int count = 0; > + int i; > + unsigned opt; > + > + opt = getopt32(argv, ""); > + argv += optind; > + > + /* If specific devices are requested, process them */ > + if (*argv) { > + while (*argv) { > + char *devname = *argv; > + /* Remove /dev/ prefix if present */ > + if (strncmp(devname, "/dev/", 5) == 0) > + devname += 5; > + > + devices = xrealloc_vector(devices, 4, count); > + devices[count].name = xstrdup(devname); > + devices[count].size = read_size_from_sysfs(devname); > + devices[count].type = get_device_type(devname); > + devices[count].mountpoint = get_mountpoint(devname); > + count++; > + argv++; > + } > + } else { > + /* Read all devices from /sys/block */ > + dir = opendir("/sys/block"); > + if (!dir) > + bb_simple_perror_msg_and_die("/sys/block"); > + > + while ((entry = readdir(dir)) != NULL) { > + if (DOT_OR_DOTDOT(entry->d_name)) > + continue; > + > + devices = xrealloc_vector(devices, 4, count); > + devices[count].name = xstrdup(entry->d_name); > + devices[count].size = > read_size_from_sysfs(entry->d_name); > + devices[count].type = get_device_type(entry->d_name); > + devices[count].mountpoint = > get_mountpoint(entry->d_name); > + count++; > + } > + closedir(dir); > + } > + > + /* Sort devices by name */ > + qsort(devices, count, sizeof(struct blockdev_info), compare_devices); > + > + /* Print header */ > + printf("%-15s %8s %-6s %s\n", "NAME", "SIZE", "TYPE", "MOUNTPOINT"); > + > + /* Print devices */ > + for (i = 0; i < count; i++) { > + printf("%-15s ", devices[i].name); > + print_size(devices[i].size); > + printf(" %-6s ", devices[i].type); > + if (devices[i].mountpoint) > + printf("%s", devices[i].mountpoint); > + printf("\n"); > + > + free(devices[i].name); > + free(devices[i].type); > + if (devices[i].mountpoint) > + free(devices[i].mountpoint); > + } > + > + if (devices) > + free(devices); > + > + return fflush_all(); > +} > + > -- > 2.43.0 >
ping. _______________________________________________ busybox mailing list [email protected] https://lists.busybox.net/mailman/listinfo/busybox
