commit - b0a1b4203e231ca2b6ec3ab5a88efda868349631
commit + 1678d261f49117252b51dacb99182e9f99322b83
blob - 4eb647aabbd55b501e8ff215a50ac233388b669c
blob + 21907b7b862acc36432e04968bc6798b2a865704
--- ChangeLog.md
+++ ChangeLog.md
### 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
- [ ] `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
lsblk \- list block devices
.SH SYNOPSIS
.B lsblk
-[\fB-ainUuV\fR]
+[\fB-abinUuV\fR]
[\fIdisk ...\fR]
.SH DESCRIPTION
The
.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
.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
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;
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 {
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)
if (fields & FIELD_TYPE)
printf ("%-8s ", "TYPE");
- if (fields & FIELD_LMNT)
- printf ("LABEL/MOUNT ");
+ if (fields & FIELD_COMMENT)
+ printf ("COMMENT ");
putchar ('\n');
}
}
}
-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,
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 (" ");
}
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));
}
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
) {
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;
}
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;
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))