commit 1678d261f49117252b51dacb99182e9f99322b83 from: Benjamin Stürz date: Mon May 15 20:18:47 2023 UTC Improved RAID support - Changed "LABEL/MOUNT" to "COMMENT" - Show status of RAID disk in "COMMENT" - Show status of RAID volume in "COMMENT" - Fix RAID support if multiple volumes exist - Added -b option to disable scanning for RAID devices commit - b0a1b4203e231ca2b6ec3ab5a88efda868349631 commit + 1678d261f49117252b51dacb99182e9f99322b83 blob - 4eb647aabbd55b501e8ff215a50ac233388b669c blob + 21907b7b862acc36432e04968bc6798b2a865704 --- ChangeLog.md +++ ChangeLog.md @@ -9,13 +9,15 @@ and this project adheres to [Semantic Versioning](http ### Added - Accept "disk" arguments. - Show RAID disks + - Show status of RAID disk in "COMMENT" +- Show status of RAID volume in "COMMENT" - Options: - `-a` print all fields - `-i` don't print fancy unicode characters - `-U` print the DUID ### Changed -- Merge "LABEL" and "MOUNT" fields into "LABEL/MOUNT" +- Merge "LABEL" and "MOUNT" fields into "COMMENT" because disks can't be mounted but partitions can, and disks can have a label but partitions don't (at least through the disklabel interface). blob - 1ec4f487a9b69ba4bd77d67fff959873d6511dfe blob + 2a5244779f7c4299c46fa3ac1a55dc5930ebefbb --- README.md +++ README.md @@ -22,5 +22,6 @@ doas make unroot - [ ] `lsblk sd0a` - [ ] `lsblk -f duid,size` - [ ] Add an option to make the output script-friendly (like -c for CSV). -- [ ] Maybe: Display the child device of a RAID partition +- [x] Maybe: Display the child device of a RAID partition - [x] Show the DUID +- [ ] Explain the exact meaning of every field in lsblk.8 blob - 5522b5feb7c45bc31c82dc06e8a5d292b28b637a blob + 24e2ce488861a53567d572c5cfcafe75002df2f0 --- lsblk.8 +++ lsblk.8 @@ -16,7 +16,7 @@ lsblk \- list block devices .SH SYNOPSIS .B lsblk -[\fB-ainUuV\fR] +[\fB-abinUuV\fR] [\fIdisk ...\fR] .SH DESCRIPTION The @@ -34,6 +34,10 @@ prints version information to stdout, then exit. .B \-a print all fields. .TP +.B \-b +don't scan for RAID volumes using +.BR bio (4) . +.TP .B \-i don't print fancy unicode characters, only print ASCII. .TP @@ -70,8 +74,13 @@ The following line lists all fields of sd0: .RS 5 lsblk -a sd0 +.SH FIELDS +.B TODO +Explain the exact meaning of every field. + .SH SEE ALSO .BR disklabel (8) , +.BR bio (4) , .BR df (1) .SH HISTORY blob - 9c892b22b21731c19c377f1438944009c056a939 blob + 0b44817852780b41c6aeaf88eb235a5eee5b675c --- lsblk.c +++ lsblk.c @@ -125,14 +125,15 @@ enum { FIELD_USED = 0x08, FIELD_FREE = 0x10, FIELD_TYPE = 0x20, - FIELD_LMNT = 0x40, + FIELD_COMMENT = 0x40, - FIELD_DEFAULT = FIELD_NAME | FIELD_SIZE | FIELD_TYPE | FIELD_LMNT, + FIELD_DEFAULT = FIELD_NAME | FIELD_SIZE | FIELD_TYPE | FIELD_COMMENT, }; enum { OPT_NOHEADER = 0x01, OPT_NOUNICODE = 0x02, + OPT_NOBIO = 0x04, }; struct my_diskinfo; @@ -144,7 +145,8 @@ struct my_partinfo { uint64_t free; const char *fstype; const char *mount; - const struct my_diskinfo *sub; + const struct my_diskinfo *sub; // If this is part of a RAID + const char *raidstatus; // Only available if (sub != NULL) }; struct my_diskinfo { @@ -156,6 +158,7 @@ struct my_diskinfo { u_char duid[8]; uint8_t num_parts; struct my_partinfo parts[MAXPARTITIONS]; + const char *raidstatus; // If this is a RAID device }; static void print_header (int fields) @@ -178,8 +181,8 @@ static void print_header (int fields) if (fields & FIELD_TYPE) printf ("%-8s ", "TYPE"); - if (fields & FIELD_LMNT) - printf ("LABEL/MOUNT "); + if (fields & FIELD_COMMENT) + printf ("COMMENT "); putchar ('\n'); } @@ -191,7 +194,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_disk (const struct my_diskinfo *disk, int fields, int options, const char *raidstatus); static void print_part ( const struct my_diskinfo *disk, const struct my_partinfo *part, @@ -231,22 +234,22 @@ static void print_part ( if (fields & FIELD_TYPE) printf ("%-8.16s ", part->fstype); - if (fields & FIELD_LMNT && part->mount) + if (fields & FIELD_COMMENT && part->mount) printf ("%s ", part->mount); putchar ('\n'); if (part->sub) { printf ("│ └─"); - print_disk (part->sub, fields, options, true); + print_disk (part->sub, fields, options, part->raidstatus); } } -static void print_disk (const struct my_diskinfo *disk, int fields, int options, bool sub) +static void print_disk (const struct my_diskinfo *disk, int fields, int options, const char *raidstatus) { if (fields & FIELD_NAME) { printf ("%s ", disk->name); - if (!sub) + if (!raidstatus) printf (" "); } @@ -268,12 +271,19 @@ static void print_disk (const struct my_diskinfo *disk if (fields & FIELD_TYPE) printf ("%-8.16s ", disk->type); - if (fields & FIELD_LMNT) - printf ("%.16s ", disk->label); + if (fields & FIELD_COMMENT) { + if (raidstatus) { + printf ("%s ", raidstatus); + } else if (disk->raidstatus) { + printf ("%.16s (%s) ", disk->label, disk->raidstatus); + } else { + printf ("%.16s ", disk->label); + } + } putchar ('\n'); - if (!sub) { + if (!raidstatus) { for (uint8_t i = 0; i < disk->num_parts; ++i) print_part (disk, &disk->parts[i], fields, options, i == (disk->num_parts - 1)); } @@ -363,8 +373,35 @@ static struct my_diskinfo read_disk (const char *name) return disk; } +static const char *bd_statusstr (int status) { + switch (status) { + case BIOC_SDONLINE: return BIOC_SDONLINE_S; + case BIOC_SDOFFLINE: return BIOC_SDOFFLINE_S; + case BIOC_SDFAILED: return BIOC_SDFAILED_S; + case BIOC_SDREBUILD: return BIOC_SDREBUILD_S; + case BIOC_SDHOTSPARE: return BIOC_SDHOTSPARE_S; + case BIOC_SDUNUSED: return BIOC_SDUNUSED_S; + case BIOC_SDSCRUB: return BIOC_SDSCRUB_S; + case BIOC_SDINVALID: return BIOC_SDINVALID_S; + default: return "Unknown"; + } +} + +static const char *bv_statusstr (int status) { + switch (status) { + case BIOC_SVONLINE: return BIOC_SVONLINE_S; + case BIOC_SVOFFLINE: return BIOC_SVOFFLINE_S; + case BIOC_SVDEGRADED: return BIOC_SVDEGRADED_S; + case BIOC_SVBUILDING: return BIOC_SVBUILDING_S; + case BIOC_SVSCRUB: return BIOC_SVSCRUB_S; + case BIOC_SVREBUILD: return BIOC_SVREBUILD_S; + case BIOC_SVINVALID: return BIOC_SVINVALID_S; + default: return "Unknown"; + } +} + static void read_raid ( - const struct my_diskinfo *disk, + struct my_diskinfo *disk, struct my_diskinfo *disks, size_t num_disks ) { @@ -382,50 +419,66 @@ static void read_raid ( 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; + for (int i = 0; i < bi.bi_novol; ++i) { + struct bioc_vol bv; - if (ioctl (fd, BIOCDISK, &bd) == -1) { - warn ("read_raid(%s): BIOCDISK(%d)", disk->name, i); + bzero (&bv, sizeof bv); + memcpy (&bv.bv_bio, &bi.bi_bio, sizeof bi.bi_bio); + bv.bv_volid = i; + + if (ioctl (fd, BIOCVOL, &bv) == -1) { + warn ("read_raid(%s): BIOCVOL(%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); + if (strcmp (disk->name, bv.bv_dev) != 0) 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; + disk->raidstatus = bv_statusstr (bv.bv_status); + + for (int j = 0; j < bv.bv_nodisk; ++j) { + struct bioc_disk bd; + size_t len_vendor; + char letter; + + bzero (&bd, sizeof bd); + memcpy (&bd.bd_bio, &bi.bi_bio, sizeof bi.bi_bio); + bd.bd_volid = i; + bd.bd_diskid = j; + + if (ioctl (fd, BIOCDISK, &bd) == -1) { + warn ("read_raid(%s): BIOCDISK(%d, %d)", disk->name, i, j); + continue; + } + + len_vendor = strlen (bd.bd_vendor); + if (len_vendor != 4) { + warnx ("read_raid(%s): unexpected vendor string: %.32s", disk->name, bd.bd_vendor); + continue; + } + letter = bd.bd_vendor[len_vendor - 1]; + + for (size_t k = 0; k < num_disks; ++k) { + if (!memcmp (bd.bd_vendor, disks[k].name, 3)) { + for (size_t l = 0; l < disks[k].num_parts; ++l) { + if (letter == disks[k].parts[l].letter) { + disks[k].parts[l].sub = disk; + disks[k].parts[l].raidstatus = bd_statusstr(bd.bd_status); + goto found; + } } } } + found:; } - found:; } - ret: close (fd); } static int usage (void) { - fputs ("Usage: lsblk [-ainUuV] [disk...]\n", stderr); + fputs ("Usage: lsblk [-abinUuV] [disk...]\n", stderr); return 1; } @@ -441,11 +494,14 @@ int main (int argc, char *argv[]) if (unveil (NULL, NULL) == -1) err (1, "unveil()"); - while ((option = getopt (argc, argv, ":ainUuV")) != -1) { + while ((option = getopt (argc, argv, ":abinUuV")) != -1) { switch (option) { case 'a': fields = -1; break; + case 'b': + options |= OPT_NOBIO; + break; case 'i': options |= OPT_NOUNICODE; break; @@ -505,8 +561,10 @@ 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_NOBIO)) { + for (size_t i = 0; i < num_disks; ++i) { + read_raid (&disks[i], disks, num_disks); + } } if (!(options & OPT_NOHEADER))