Commit Diff


commit - /dev/null
commit + 33bf1ca46df95a50bcf92dfa97e36620311e21ac
blob - /dev/null
blob + ccf77bad06d032847934382eb88a4ddc54e3fdd8 (mode 644)
--- /dev/null
+++ .gitignore
@@ -0,0 +1 @@
+/lsblk
blob - /dev/null
blob + d54c0cb5093a50eb504667e6181c5362270784aa (mode 644)
--- /dev/null
+++ Makefile
@@ -0,0 +1,23 @@
+.POSIX:
+
+VERSION = 0.1
+PREFIX = /usr/local
+MANPREFIX = ${PREFIX}/man
+CFLAGS = -pipe -O2 -Wall -Werror
+
+all: lsblk
+
+lsblk: lsblk.c
+	${CC} -o $@ $< ${CFLAGS} -DVERSION=\"${VERSION}\"
+
+clean:
+	rm -f lsblk
+
+install: lsblk
+	mkdir -p ${DESTDIR}${PREFIX}/bin ${DESTDIR}${MANPREFIX}
+	cp -f lsblk ${DESTDIR}${PREFIX}/bin
+	chmod 755 ${DESTDIR}${PREFIX}/bin/lsblk
+	cp -f lsblk.8 ${DESTDIR}${MANPREFIX}
+
+uninstall:
+	rm -f $(DESTDIR)$(PREFIX)/bin/lsblk
blob - /dev/null
blob + 59ddb42ff6b0e6953d2fec72ba514b0870f5a383 (mode 644)
--- /dev/null
+++ README.md
@@ -0,0 +1,9 @@
+# lsblk for OpenBSD
+This project aims to implement a clone of lsblk for OpenBSD.
+
+## Quirks
+- It requires root privileges
+
+## TODO
+- Header
+- Padding/Spacing
blob - /dev/null
blob + ed0f461bdabb97eed90436858d7766557bca988b (mode 644)
--- /dev/null
+++ lsblk.8
@@ -0,0 +1,11 @@
+.TH LSBLK 8 lsblk-0.1 2023-04-08
+.SH NAME
+lsblk \- list block devices
+.SH SYNOPSIS
+.B lsblk
+.SH DESCRIPTION
+The
+.B lsblk
+utilit can be used to examine the attached block devices on the system.
+.SH SEE ALSO
+.BR disklabel (8)
blob - /dev/null
blob + 78a36646696a653ace47134ea73902f38067ba6e (mode 644)
--- /dev/null
+++ lsblk.c
@@ -0,0 +1,186 @@
+#define _XOPEN_SOURCE 700
+#define _BSD_SOURCE 1
+#define DKTYPENAMES
+#include <stddef.h>
+#include <sys/types.h>
+#include <sys/disklabel.h>
+#include <sys/sysctl.h>
+#include <sys/ioctl.h>
+#include <sys/mount.h>
+#include <sys/dkio.h>
+#include <inttypes.h>
+#include <string.h>
+#include <stdarg.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <errno.h>
+
+static void die (const char *fmt, ...)
+{
+    va_list ap;
+
+    va_start (ap, fmt);
+    fputs ("Error: ", stderr);
+    vfprintf (stderr, fmt, ap);
+
+    if (errno != 0) {
+        fprintf (stderr, ": %s\n", strerror (errno));
+    } else {
+        fputc ('\n', stderr);
+    }
+
+    exit (1);
+}
+
+static int diskcount (void)
+{
+    const int mib[2] = { CTL_HW, HW_DISKCOUNT };
+    int diskcount;
+    size_t len = sizeof diskcount;
+
+    if (sysctl (mib, 2, &diskcount, &len, NULL, 0) == -1)
+        die ("sysctl(hw.diskcount)");
+
+    return diskcount;
+}
+
+static char *disknames (void)
+{
+    const int num = diskcount ();
+    const int mib[2] = { CTL_HW, HW_DISKNAMES };
+    size_t len = 32 * num;
+    char *buffer = malloc (len);
+
+    if (sysctl (mib, 2, buffer, &len, NULL, 0) == -1)
+        die ("sysctl(hw.disknames)");
+
+    return buffer;
+}
+
+static void printsize (uint64_t sz)
+{
+    struct unit {
+        char sym;
+        uint64_t factor;
+    };
+
+    const struct unit units[] = {
+        { 'P', 1ull << 50 },
+        { 'T', 1ull << 40 },
+        { 'G', 1ull << 30 },
+        { 'M', 1ull << 20 },
+        { 'K', 1ull << 10 },
+        { '0', 0 },
+    };
+
+    char sym = 'B';
+    uint64_t factor = 1;
+
+    for (const struct unit *u = &units[0]; u->factor; ++u) {
+        if (sz >= (u->factor * 9 / 10)) {
+            sym = u->sym;
+            factor = u->factor;
+            break;
+        }
+    }
+
+    const unsigned scaled10 = sz * 10 / factor;
+    const unsigned scaled = sz / factor;
+    if (scaled10 >= 1000) {
+        printf (" %u", scaled);
+    } else if (scaled10 >= 100) {
+        printf ("%u.%u", scaled, scaled10 % 10);
+    } else {
+        printf (" %u.%u", scaled, scaled10 % 10);
+    }
+
+    putchar (sym);
+}
+
+static int usage (void)
+{
+    fputs ("Usage: lsblk [-V]\n", stderr);
+    return 1;
+}
+
+int main (int argc, char *argv[])
+{
+    int option;
+    while ((option = getopt (argc, argv, ":V")) != -1) {
+        switch (option) {
+        case 'V':
+            puts ("lsblk-" VERSION);
+            return 0;
+        default:
+            return usage ();
+        }
+    }
+
+    if (argc != optind)
+        return usage ();
+
+    struct statfs *mounts;
+    char *names = disknames ();
+
+    if (pledge ("stdio rpath disklabel", NULL) == -1)
+        die ("pledge()");
+
+    const int n_mounts = getmntinfo (&mounts, MNT_NOWAIT);
+    if (n_mounts == 0)
+        die ("getmntinfo()");
+
+    for (char *disk; (disk = strsep (&names, ",")) != NULL;) {
+        struct disklabel label;
+        char *colon, *name = NULL;
+        int fd;
+
+        colon = strchr (disk, ':');
+        if (colon)
+            *colon = '\0';
+
+        asprintf (&name, "/dev/%sc", disk);
+
+        fd = open (name, O_RDONLY);
+        if (fd < 0)
+            die ("open(%s)", name);
+
+        if (ioctl (fd, DIOCGDINFO, &label) < 0)
+            die ("ioctl(%s, IOCGDINFO)", name);
+
+        close (fd);
+
+        const uint32_t ss = label.d_secsize;
+
+        char *letter = name + strlen (name) - 1;
+
+        printf ("%s    ", disk);
+        printsize ((uint64_t)label.d_nsectors * ss);
+        printf (" %s\n", label.d_typename);
+        for (uint16_t i = 0; i < label.d_npartitions; ++i) {
+            const struct partition *p = &label.d_partitions[i];
+            const uint64_t size = (((uint64_t)p->p_sizeh << 32) | p->p_size) * ss;
+            if (size == 0)
+                continue;
+
+            *letter = i + 'a';
+            const char *mp = "";
+            for (int i = 0; i < n_mounts; ++i) {
+                const struct statfs *m = &mounts[i];
+                if (!strcmp (name, m->f_mntfromname)) {
+                    mp = m->f_mntonname;
+                    break;
+                }
+            }
+
+            printf ("  %s%c ", disk, *letter);
+            printsize (size);
+            printf (" %s %s\n", fstypenames[p->p_fstype], mp);
+        }
+    }
+
+    free (names);
+    return 0;
+}