Commit Diff


commit - 0c422a5b7d0b4f4ddf3f70089c95d9ae2d2baf06
commit + b0a1b4203e231ca2b6ec3ab5a88efda868349631
blob - faadd5ac7957d4c3cc3487fa9e3610d40587a282
blob + 4eb647aabbd55b501e8ff215a50ac233388b669c
--- ChangeLog.md
+++ ChangeLog.md
@@ -8,6 +8,7 @@ and this project adheres to [Semantic Versioning](http
 ## [1.2] - TBD
 ### Added
 - Accept "disk" arguments.
+- Show RAID disks
 - Options:
   - `-a` print all fields
   - `-i` don't print fancy unicode characters
blob - 4141794cedcce65dbb0f62e3ccbddd8735e1e870
blob + 9c892b22b21731c19c377f1438944009c056a939
--- lsblk.c
+++ lsblk.c
@@ -17,6 +17,7 @@
 #define _BSD_SOURCE 1
 #define DKTYPENAMES
 #include <stddef.h>
+#include <dev/biovar.h>
 #include <sys/cdefs.h>
 #include <sys/types.h>
 #include <sys/disklabel.h>
@@ -134,6 +135,8 @@ enum {
     OPT_NOUNICODE   = 0x02,
 };
 
+struct my_diskinfo;
+
 struct my_partinfo {
     char letter;
     uint64_t size;
@@ -141,6 +144,7 @@ struct my_partinfo {
     uint64_t free;
     const char *fstype;
     const char *mount;
+    const struct my_diskinfo *sub;
 };
 
 struct my_diskinfo {
@@ -149,15 +153,15 @@ struct my_diskinfo {
     char name[4];
     uint64_t size;
     uint64_t used;
-    uint8_t num_parts;
     u_char duid[8];
+    uint8_t num_parts;
     struct my_partinfo parts[MAXPARTITIONS];
 };
 
 static void print_header (int fields)
 {
     if (fields & FIELD_NAME)
-        printf ("%-6s ", "NAME");
+        printf ("%-7s ", "NAME");
 
     if (fields & FIELD_DUID)
         printf ("%-18s ", "DUID");
@@ -187,6 +191,7 @@ static void print_duid (const u_char *duid)
     }
 }
 
+static void print_disk (const struct my_diskinfo *disk, int fields, int options, bool sub);
 static void print_part (
     const struct my_diskinfo *disk,
     const struct my_partinfo *part,
@@ -196,7 +201,7 @@ static void print_part (
 ) {
     if (fields & FIELD_NAME) {
         const char *prefix = (options & OPT_NOUNICODE) ? "  " : (last ? "└─" : "├─");
-        printf ("%s%s%c ", prefix, disk->name, part->letter);
+        printf ("%s%s%c  ", prefix, disk->name, part->letter);
     }
 
     if (fields & FIELD_DUID) {
@@ -230,12 +235,20 @@ static void print_part (
         printf ("%s ", part->mount);
 
     putchar ('\n');
+
+    if (part->sub) {
+        printf ("│ └─");
+        print_disk (part->sub, fields, options, true);
+    }
 }
 
-static void print_disk (const struct my_diskinfo *disk, int fields, int options)
+static void print_disk (const struct my_diskinfo *disk, int fields, int options, bool sub)
 {
-    if (fields & FIELD_NAME)
-        printf ("%s    ", disk->name);
+    if (fields & FIELD_NAME) {
+        printf ("%s ", disk->name);
+        if (!sub)
+            printf ("    ");
+    }
 
     if (fields & FIELD_DUID) {
         print_duid (disk->duid);
@@ -260,8 +273,10 @@ static void print_disk (const struct my_diskinfo *disk
 
     putchar ('\n');
 
-    for (uint8_t i = 0; i < disk->num_parts; ++i)
-        print_part (disk, &disk->parts[i], fields, options, i == (disk->num_parts - 1));
+    if (!sub) {
+        for (uint8_t i = 0; i < disk->num_parts; ++i)
+            print_part (disk, &disk->parts[i], fields, options, i == (disk->num_parts - 1));
+    }
 }
 
 static const struct statfs *find_mount (const char *dev)
@@ -348,6 +363,66 @@ static struct my_diskinfo read_disk (const char *name)
     return disk;
 }
 
+static void read_raid (
+    const struct my_diskinfo *disk,
+    struct my_diskinfo *disks,
+    size_t num_disks
+) {
+    struct bioc_inq bi;
+    int fd;
+
+    fd = opendev (disk->name, O_RDONLY, OPENDEV_PART | OPENDEV_BLCK, NULL);
+    if (fd < 0) {
+        warn ("read_raid(): opendev(%s)", disk->name);
+        return;
+    }
+
+    bzero (&bi, sizeof bi);
+
+    if (ioctl (fd, BIOCINQ, &bi) == -1)
+        goto ret;
+
+    for (int i = 0; i < bi.bi_nodisk; ++i) {
+        struct bioc_disk bd;
+        const char *vendor;
+        size_t len_vendor;
+        char letter;
+
+        bzero (&bd, sizeof bd);
+        memcpy (&bd.bd_bio, &bi.bi_bio, sizeof bi.bi_bio);
+        bd.bd_volid = 0;
+        bd.bd_diskid = i;
+
+        if (ioctl (fd, BIOCDISK, &bd) == -1) {
+            warn ("read_raid(%s): BIOCDISK(%d)", disk->name, i);
+            continue;
+        }
+
+        vendor = bd.bd_vendor;
+        len_vendor = strlen (vendor);
+        if (len_vendor != 4) {
+            warnx ("read_raid(%s): unexpected vendor string: '%.32s'", disk->name, vendor);
+            continue;
+        }
+        letter = vendor[len_vendor - 1];
+
+        for (size_t j = 0; j < num_disks; ++j) {
+            if (!memcmp (vendor, disks[j].name, 3)) {
+                for (size_t k = 0; k < disks[j].num_parts; ++k) {
+                    if (letter == disks[j].parts[k].letter) {
+                        disks[j].parts[k].sub = disk;
+                        goto found;
+                    }
+                }
+            }
+        }
+    found:;
+    }
+
+ret:
+    close (fd);
+}
+
 static int usage (void)
 {
     fputs ("Usage: lsblk [-ainUuV] [disk...]\n", stderr);
@@ -430,11 +505,15 @@ int main (int argc, char *argv[])
 
     free (names);
 
+    for (size_t i = 0; i < num_disks; ++i) {
+        read_raid (&disks[i], disks, num_disks);
+    }
+
     if (!(options & OPT_NOHEADER))
         print_header (fields);
 
     for (size_t i = 0; i < num_disks; ++i) {
-        print_disk (&disks[i], fields, options);
+        print_disk (&disks[i], fields, options, false);
     }
 
     return 0;