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

_______________________________________________
busybox mailing list
[email protected]
https://lists.busybox.net/mailman/listinfo/busybox

Reply via email to