2 9ddaf4ab 2023-04-08 benni * Copyright (c) 2023 Benjamin Stürz <benni@stuerz.xyz>
4 9ddaf4ab 2023-04-08 benni * Permission to use, copy, modify, and distribute this software for any
5 9ddaf4ab 2023-04-08 benni * purpose with or without fee is hereby granted, provided that the above
6 9ddaf4ab 2023-04-08 benni * copyright notice and this permission notice appear in all copies.
8 9ddaf4ab 2023-04-08 benni * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 9ddaf4ab 2023-04-08 benni * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 9ddaf4ab 2023-04-08 benni * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11 9ddaf4ab 2023-04-08 benni * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 9ddaf4ab 2023-04-08 benni * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13 9ddaf4ab 2023-04-08 benni * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14 9ddaf4ab 2023-04-08 benni * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16 33bf1ca4 2023-04-08 benni #define _XOPEN_SOURCE 700
17 33bf1ca4 2023-04-08 benni #define _BSD_SOURCE 1
18 33bf1ca4 2023-04-08 benni #define DKTYPENAMES
19 7c38b724 2023-05-15 benni #define WSDEBUG 0
20 33bf1ca4 2023-04-08 benni #include <stddef.h>
21 b0a1b420 2023-05-15 benni #include <dev/biovar.h>
22 9c5d8ecc 2023-05-02 benni #include <sys/cdefs.h>
23 33bf1ca4 2023-04-08 benni #include <sys/types.h>
24 33bf1ca4 2023-04-08 benni #include <sys/disklabel.h>
25 33bf1ca4 2023-04-08 benni #include <sys/sysctl.h>
26 33bf1ca4 2023-04-08 benni #include <sys/ioctl.h>
27 33bf1ca4 2023-04-08 benni #include <sys/mount.h>
28 33bf1ca4 2023-04-08 benni #include <sys/dkio.h>
29 33bf1ca4 2023-04-08 benni #include <inttypes.h>
30 8380cc51 2023-05-01 benni #include <stdbool.h>
31 33bf1ca4 2023-04-08 benni #include <string.h>
32 33bf1ca4 2023-04-08 benni #include <stdarg.h>
33 33bf1ca4 2023-04-08 benni #include <stdint.h>
34 33bf1ca4 2023-04-08 benni #include <stdlib.h>
35 33bf1ca4 2023-04-08 benni #include <unistd.h>
36 5691dc7b 2023-05-05 benni #include <libgen.h>
37 33bf1ca4 2023-04-08 benni #include <stdio.h>
38 33bf1ca4 2023-04-08 benni #include <fcntl.h>
39 185836d0 2023-05-15 benni #include <ctype.h>
40 33bf1ca4 2023-04-08 benni #include <errno.h>
41 0c422a5b 2023-05-05 benni #include <util.h>
42 44121ddf 2023-05-05 benni #include <err.h>
44 da455e16 2023-09-01 benni #define PREFIX0_ASCII "|-"
45 da455e16 2023-09-01 benni #define PREFIX0_UNICODE "├─"
46 da455e16 2023-09-01 benni #define PREFIX1_ASCII "`-"
47 da455e16 2023-09-01 benni #define PREFIX1_UNICODE "└─"
48 da455e16 2023-09-01 benni #define PREFIX2_ASCII "| `-"
49 da455e16 2023-09-01 benni #define PREFIX2_UNICODE "│ └─"
51 da455e16 2023-09-01 benni static const char *prefix0, *prefix1, *prefix2;
53 33bf1ca4 2023-04-08 benni static int diskcount (void)
55 33bf1ca4 2023-04-08 benni const int mib[2] = { CTL_HW, HW_DISKCOUNT };
56 33bf1ca4 2023-04-08 benni int diskcount;
57 33bf1ca4 2023-04-08 benni size_t len = sizeof diskcount;
59 33bf1ca4 2023-04-08 benni if (sysctl (mib, 2, &diskcount, &len, NULL, 0) == -1)
60 44121ddf 2023-05-05 benni err (1, "sysctl(hw.diskcount)");
62 33bf1ca4 2023-04-08 benni return diskcount;
65 33bf1ca4 2023-04-08 benni static char *disknames (void)
67 33bf1ca4 2023-04-08 benni const int num = diskcount ();
68 33bf1ca4 2023-04-08 benni const int mib[2] = { CTL_HW, HW_DISKNAMES };
69 33bf1ca4 2023-04-08 benni size_t len = 32 * num;
70 33bf1ca4 2023-04-08 benni char *buffer = malloc (len);
72 33bf1ca4 2023-04-08 benni if (sysctl (mib, 2, buffer, &len, NULL, 0) == -1)
73 44121ddf 2023-05-05 benni err (1, "sysctl(hw.disknames)");
75 33bf1ca4 2023-04-08 benni return buffer;
78 9c5d8ecc 2023-05-02 benni static char *stripdisk (char *n)
80 9c5d8ecc 2023-05-02 benni const char sufx[] = " disk";
81 9c5d8ecc 2023-05-02 benni const size_t ln = strnlen (n, 16);
82 9c5d8ecc 2023-05-02 benni const size_t ls = sizeof sufx - 1;
84 2f06f21f 2023-06-08 benni if (memcmp (n + ln - ls, sufx, ls) == 0) {
85 9c5d8ecc 2023-05-02 benni n[ln - ls] = '\0';
91 9c5d8ecc 2023-05-02 benni static void print_size (uint64_t sz)
93 2f06f21f 2023-06-08 benni const struct unit {
95 33bf1ca4 2023-04-08 benni uint64_t factor;
96 2f06f21f 2023-06-08 benni } units[] = {
97 33bf1ca4 2023-04-08 benni { 'P', 1ull << 50 },
98 33bf1ca4 2023-04-08 benni { 'T', 1ull << 40 },
99 33bf1ca4 2023-04-08 benni { 'G', 1ull << 30 },
100 33bf1ca4 2023-04-08 benni { 'M', 1ull << 20 },
101 33bf1ca4 2023-04-08 benni { 'K', 1ull << 10 },
102 33bf1ca4 2023-04-08 benni { '0', 0 },
105 33bf1ca4 2023-04-08 benni char sym = 'B';
106 33bf1ca4 2023-04-08 benni uint64_t factor = 1;
108 33bf1ca4 2023-04-08 benni for (const struct unit *u = &units[0]; u->factor; ++u) {
109 33bf1ca4 2023-04-08 benni if (sz >= (u->factor * 9 / 10)) {
110 33bf1ca4 2023-04-08 benni sym = u->sym;
111 33bf1ca4 2023-04-08 benni factor = u->factor;
116 33bf1ca4 2023-04-08 benni const unsigned scaled10 = sz * 10 / factor;
117 33bf1ca4 2023-04-08 benni const unsigned scaled = sz / factor;
118 33bf1ca4 2023-04-08 benni if (scaled10 >= 1000) {
119 8a374bef 2023-04-08 benni printf ("%u", scaled);
120 33bf1ca4 2023-04-08 benni } else if (scaled10 >= 100) {
121 8a374bef 2023-04-08 benni printf (" %u", scaled);
123 8a374bef 2023-04-08 benni printf ("%u.%u", scaled, scaled10 % 10);
126 33bf1ca4 2023-04-08 benni putchar (sym);
127 9c5d8ecc 2023-05-02 benni putchar (' ');
131 0c961f7d 2023-05-04 benni FIELD_NAME = 0x01,
132 1115ad3a 2023-05-05 benni FIELD_DUID = 0x02,
133 1115ad3a 2023-05-05 benni FIELD_SIZE = 0x04,
134 1115ad3a 2023-05-05 benni FIELD_USED = 0x08,
135 1115ad3a 2023-05-05 benni FIELD_FREE = 0x10,
136 1115ad3a 2023-05-05 benni FIELD_TYPE = 0x20,
137 1678d261 2023-05-15 benni FIELD_COMMENT = 0x40,
139 1678d261 2023-05-15 benni FIELD_DEFAULT = FIELD_NAME | FIELD_SIZE | FIELD_TYPE | FIELD_COMMENT,
143 0c961f7d 2023-05-04 benni OPT_NOHEADER = 0x01,
144 da455e16 2023-09-01 benni OPT_NOBIO = 0x02,
147 b0a1b420 2023-05-15 benni struct my_diskinfo;
149 9c5d8ecc 2023-05-02 benni struct my_partinfo {
150 1115ad3a 2023-05-05 benni char letter;
151 9c5d8ecc 2023-05-02 benni uint64_t size;
152 9c5d8ecc 2023-05-02 benni uint64_t fssize;
153 9c5d8ecc 2023-05-02 benni uint64_t free;
154 9c5d8ecc 2023-05-02 benni const char *fstype;
155 9c5d8ecc 2023-05-02 benni const char *mount;
156 1678d261 2023-05-15 benni const struct my_diskinfo *sub; // If this is part of a RAID
157 1678d261 2023-05-15 benni const char *raidstatus; // Only available if (sub != NULL)
160 9c5d8ecc 2023-05-02 benni struct my_diskinfo {
161 9c5d8ecc 2023-05-02 benni char type[16];
162 9c5d8ecc 2023-05-02 benni char label[16];
163 69c9c7b9 2023-05-15 benni char name[8];
164 9c5d8ecc 2023-05-02 benni uint64_t size;
165 9c5d8ecc 2023-05-02 benni uint64_t used;
166 1115ad3a 2023-05-05 benni u_char duid[8];
167 b0a1b420 2023-05-15 benni uint8_t num_parts;
168 9c5d8ecc 2023-05-02 benni struct my_partinfo parts[MAXPARTITIONS];
169 1678d261 2023-05-15 benni const char *raidstatus; // If this is a RAID device
172 7c38b724 2023-05-15 benni struct padding {
174 7c38b724 2023-05-15 benni /* duid = 8 */
175 7c38b724 2023-05-15 benni /* size = 4 */
176 7c38b724 2023-05-15 benni /* used = 4 */
177 7c38b724 2023-05-15 benni /* free = 4 */
179 7c38b724 2023-05-15 benni int comment;
182 7c38b724 2023-05-15 benni static void print_header (int fields, const struct padding *p)
184 9c5d8ecc 2023-05-02 benni if (fields & FIELD_NAME)
185 7c38b724 2023-05-15 benni printf ("%-*s ", p->name, "NAME");
187 1115ad3a 2023-05-05 benni if (fields & FIELD_DUID)
188 1115ad3a 2023-05-05 benni printf ("%-18s ", "DUID");
190 9c5d8ecc 2023-05-02 benni if (fields & FIELD_SIZE)
191 9c5d8ecc 2023-05-02 benni printf ("%-4s ", "SIZE");
193 9c5d8ecc 2023-05-02 benni if (fields & FIELD_USED)
194 9c5d8ecc 2023-05-02 benni printf ("%-4s ", "USED");
196 9c5d8ecc 2023-05-02 benni if (fields & FIELD_FREE)
197 9c5d8ecc 2023-05-02 benni printf ("%-4s ", "FREE");
199 9c5d8ecc 2023-05-02 benni if (fields & FIELD_TYPE)
200 7c38b724 2023-05-15 benni printf ("%-*s ", p->type, "TYPE");
202 1678d261 2023-05-15 benni if (fields & FIELD_COMMENT)
203 7c38b724 2023-05-15 benni printf ("%-*s ", p->comment, "COMMENT");
205 7c38b724 2023-05-15 benni #if WSDEBUG
206 7c38b724 2023-05-15 benni putchar ('X');
209 9c5d8ecc 2023-05-02 benni putchar ('\n');
212 1115ad3a 2023-05-05 benni static void print_duid (const u_char *duid)
214 1115ad3a 2023-05-05 benni for (size_t i = 0; i < 8; ++i) {
215 1115ad3a 2023-05-05 benni printf ("%02x", duid[i]);
219 7c38b724 2023-05-15 benni static void print_disk (const struct my_diskinfo *, int, int, const char *, const struct padding *);
220 1115ad3a 2023-05-05 benni static void print_part (
221 1115ad3a 2023-05-05 benni const struct my_diskinfo *disk,
222 1115ad3a 2023-05-05 benni const struct my_partinfo *part,
223 1115ad3a 2023-05-05 benni int fields,
224 1115ad3a 2023-05-05 benni int options,
225 7c38b724 2023-05-15 benni bool last,
226 7c38b724 2023-05-15 benni const struct padding *p
228 0c961f7d 2023-05-04 benni if (fields & FIELD_NAME) {
229 da455e16 2023-09-01 benni const char *prefix = last ? prefix1 : prefix0;
231 7c38b724 2023-05-15 benni "%s%s%c%-*s ",
233 7c38b724 2023-05-15 benni disk->name,
234 7c38b724 2023-05-15 benni part->letter,
235 7c38b724 2023-05-15 benni p->name - 2 - (int)strlen (disk->name) - 1,
240 1115ad3a 2023-05-05 benni if (fields & FIELD_DUID) {
241 1115ad3a 2023-05-05 benni print_duid (disk->duid);
242 1115ad3a 2023-05-05 benni printf (".%c ", part->letter);
245 9c5d8ecc 2023-05-02 benni if (fields & FIELD_SIZE)
246 9c5d8ecc 2023-05-02 benni print_size (part->size);
248 9c5d8ecc 2023-05-02 benni if (fields & FIELD_USED) {
249 9c5d8ecc 2023-05-02 benni if (part->fssize) {
250 9c5d8ecc 2023-05-02 benni print_size (part->fssize - part->free);
252 9c5d8ecc 2023-05-02 benni printf (" N/A ");
256 9c5d8ecc 2023-05-02 benni if (fields & FIELD_FREE) {
257 9c5d8ecc 2023-05-02 benni if (part->fssize) {
258 9c5d8ecc 2023-05-02 benni print_size (part->free);
260 9c5d8ecc 2023-05-02 benni printf (" N/A ");
264 9c5d8ecc 2023-05-02 benni if (fields & FIELD_TYPE)
265 7c38b724 2023-05-15 benni printf ("%-*s ", p->type, part->fstype);
267 7c38b724 2023-05-15 benni if (fields & FIELD_COMMENT)
268 7c38b724 2023-05-15 benni printf ("%-*s ", p->comment, part->mount ? part->mount : "");
270 7c38b724 2023-05-15 benni #if WSDEBUG
271 7c38b724 2023-05-15 benni putchar ('X');
274 9c5d8ecc 2023-05-02 benni putchar ('\n');
276 b0a1b420 2023-05-15 benni if (part->sub) {
277 7c38b724 2023-05-15 benni print_disk (part->sub, fields, options, part->raidstatus, p);
281 7c38b724 2023-05-15 benni static void print_disk (
282 7c38b724 2023-05-15 benni const struct my_diskinfo *disk,
283 7c38b724 2023-05-15 benni int fields,
284 7c38b724 2023-05-15 benni int options,
285 7c38b724 2023-05-15 benni const char *raidstatus,
286 7c38b724 2023-05-15 benni const struct padding *p
288 b0a1b420 2023-05-15 benni if (fields & FIELD_NAME) {
289 da455e16 2023-09-01 benni const char *prefix = raidstatus ? prefix2 : "";
292 7c38b724 2023-05-15 benni "%s%-*s ",
294 7e6c6845 2023-05-15 benni p->name - (raidstatus ? 4 : 0),
295 7c38b724 2023-05-15 benni disk->name
299 1115ad3a 2023-05-05 benni if (fields & FIELD_DUID) {
300 1115ad3a 2023-05-05 benni print_duid (disk->duid);
301 1115ad3a 2023-05-05 benni printf (" ");
304 9c5d8ecc 2023-05-02 benni if (fields & FIELD_SIZE)
305 9c5d8ecc 2023-05-02 benni print_size (disk->size);
307 9c5d8ecc 2023-05-02 benni if (fields & FIELD_USED)
308 9c5d8ecc 2023-05-02 benni print_size (disk->used);
310 9c5d8ecc 2023-05-02 benni if (fields & FIELD_FREE)
311 9c5d8ecc 2023-05-02 benni print_size (disk->size - disk->used);
313 9c5d8ecc 2023-05-02 benni if (fields & FIELD_TYPE)
314 7c38b724 2023-05-15 benni printf ("%-*.16s ", p->type, disk->type);
316 1678d261 2023-05-15 benni if (fields & FIELD_COMMENT) {
317 1678d261 2023-05-15 benni if (raidstatus) {
318 7c38b724 2023-05-15 benni printf ("%-*s ", p->comment, raidstatus);
319 1678d261 2023-05-15 benni } else if (disk->raidstatus) {
321 7c38b724 2023-05-15 benni "%.16s (%s)%*s ",
322 7c38b724 2023-05-15 benni disk->label,
323 7c38b724 2023-05-15 benni disk->raidstatus,
324 7c38b724 2023-05-15 benni p->comment - (int)strnlen (disk->label, sizeof disk->label) - (int)strlen (disk->raidstatus) - 3,
328 7c38b724 2023-05-15 benni printf ("%-*.16s ", p->comment, disk->label);
332 7c38b724 2023-05-15 benni #if WSDEBUG
333 7c38b724 2023-05-15 benni putchar ('X');
336 9c5d8ecc 2023-05-02 benni putchar ('\n');
338 1678d261 2023-05-15 benni if (!raidstatus) {
339 b0a1b420 2023-05-15 benni for (uint8_t i = 0; i < disk->num_parts; ++i)
340 7c38b724 2023-05-15 benni print_part (disk, &disk->parts[i], fields, options, i == (disk->num_parts - 1), p);
344 9c5d8ecc 2023-05-02 benni static const struct statfs *find_mount (const char *dev)
346 9c5d8ecc 2023-05-02 benni static struct statfs *mounts = NULL;
347 9c5d8ecc 2023-05-02 benni static int n_mounts;
349 9c5d8ecc 2023-05-02 benni if (!mounts) {
350 9c5d8ecc 2023-05-02 benni n_mounts = getmntinfo (&mounts, MNT_NOWAIT);
351 9c5d8ecc 2023-05-02 benni if (n_mounts == 0)
352 44121ddf 2023-05-05 benni err (1, "getmntinfo()");
355 9c5d8ecc 2023-05-02 benni for (int i = 0; i < n_mounts; ++i) {
356 9c5d8ecc 2023-05-02 benni if (!strcmp (dev, mounts[i].f_mntfromname))
357 9c5d8ecc 2023-05-02 benni return &mounts[i];
360 9c5d8ecc 2023-05-02 benni return NULL;
363 a88ae11e 2023-05-30 benni static int read_disk (const char *name, struct my_diskinfo *disk)
365 9c5d8ecc 2023-05-02 benni struct disklabel label;
366 0c422a5b 2023-05-05 benni char *ppath, *letter;
368 f977c8f4 2023-05-30 benni memset (disk, 0, sizeof *disk);
370 9c5d8ecc 2023-05-02 benni { // Read disklabel.
371 0c422a5b 2023-05-05 benni size_t len;
374 0c422a5b 2023-05-05 benni fd = opendev (name, O_RDONLY, OPENDEV_PART | OPENDEV_BLCK, &ppath);
375 a88ae11e 2023-05-30 benni if (fd < 0) {
376 a88ae11e 2023-05-30 benni warn ("read_disk(): opendev(%s)", name);
377 a88ae11e 2023-05-30 benni return -1;
380 a88ae11e 2023-05-30 benni if (ioctl (fd, DIOCGDINFO, &label) < 0) {
381 a88ae11e 2023-05-30 benni warn ("read_disk(): ioctl(%s, DIOCGDINFO)", name);
382 a88ae11e 2023-05-30 benni close (fd);
383 a88ae11e 2023-05-30 benni return -1;
385 9c5d8ecc 2023-05-02 benni close (fd);
387 0c422a5b 2023-05-05 benni len = strlen (ppath);
388 0c422a5b 2023-05-05 benni letter = ppath + len - 1;
391 a88ae11e 2023-05-30 benni strlcpy (disk->name, name, sizeof disk->name);
392 a88ae11e 2023-05-30 benni disk->size = DL_GETDSIZE (&label) * label.d_secsize;
393 a88ae11e 2023-05-30 benni memcpy (disk->type, label.d_typename, sizeof disk->type);
394 a88ae11e 2023-05-30 benni stripdisk (disk->type);
395 a88ae11e 2023-05-30 benni memcpy (disk->label, label.d_packname, sizeof disk->label);
396 a88ae11e 2023-05-30 benni memcpy (disk->duid, label.d_uid, sizeof disk->duid);
397 a88ae11e 2023-05-30 benni disk->num_parts = 0;
399 9c5d8ecc 2023-05-02 benni for (uint16_t i = 0; i < label.d_npartitions; ++i) {
400 9c5d8ecc 2023-05-02 benni const struct partition *p = &label.d_partitions[i];
401 9c5d8ecc 2023-05-02 benni const struct statfs *mnt;
402 9c5d8ecc 2023-05-02 benni struct my_partinfo part;
404 f977c8f4 2023-05-30 benni memset (&part, 0, sizeof part);
406 9c5d8ecc 2023-05-02 benni part.size = DL_GETPSIZE (p) * label.d_secsize;
408 9c5d8ecc 2023-05-02 benni if (!part.size)
411 1115ad3a 2023-05-05 benni part.letter = 'a' + i;
412 0c422a5b 2023-05-05 benni *letter = part.letter;
413 0c422a5b 2023-05-05 benni mnt = find_mount (ppath);
415 9c5d8ecc 2023-05-02 benni if (mnt) {
416 9c5d8ecc 2023-05-02 benni const uint64_t bs = mnt->f_bsize;
417 9c5d8ecc 2023-05-02 benni part.mount = mnt->f_mntonname;
418 9c5d8ecc 2023-05-02 benni part.fssize = mnt->f_blocks * bs;
419 9c5d8ecc 2023-05-02 benni part.free = mnt->f_bfree * bs;
422 9c5d8ecc 2023-05-02 benni part.fstype = fstypenames[p->p_fstype];
423 9c5d8ecc 2023-05-02 benni if (i != 2)
424 a88ae11e 2023-05-30 benni disk->used += part.size;
425 a88ae11e 2023-05-30 benni disk->parts[disk->num_parts++] = part;
431 1678d261 2023-05-15 benni static const char *bd_statusstr (int status) {
432 1678d261 2023-05-15 benni switch (status) {
433 1678d261 2023-05-15 benni case BIOC_SDONLINE: return BIOC_SDONLINE_S;
434 1678d261 2023-05-15 benni case BIOC_SDOFFLINE: return BIOC_SDOFFLINE_S;
435 1678d261 2023-05-15 benni case BIOC_SDFAILED: return BIOC_SDFAILED_S;
436 1678d261 2023-05-15 benni case BIOC_SDREBUILD: return BIOC_SDREBUILD_S;
437 1678d261 2023-05-15 benni case BIOC_SDHOTSPARE: return BIOC_SDHOTSPARE_S;
438 1678d261 2023-05-15 benni case BIOC_SDUNUSED: return BIOC_SDUNUSED_S;
439 1678d261 2023-05-15 benni case BIOC_SDSCRUB: return BIOC_SDSCRUB_S;
440 1678d261 2023-05-15 benni case BIOC_SDINVALID: return BIOC_SDINVALID_S;
441 1678d261 2023-05-15 benni default: return "Unknown";
445 1678d261 2023-05-15 benni static const char *bv_statusstr (int status) {
446 1678d261 2023-05-15 benni switch (status) {
447 1678d261 2023-05-15 benni case BIOC_SVONLINE: return BIOC_SVONLINE_S;
448 1678d261 2023-05-15 benni case BIOC_SVOFFLINE: return BIOC_SVOFFLINE_S;
449 1678d261 2023-05-15 benni case BIOC_SVDEGRADED: return BIOC_SVDEGRADED_S;
450 1678d261 2023-05-15 benni case BIOC_SVBUILDING: return BIOC_SVBUILDING_S;
451 1678d261 2023-05-15 benni case BIOC_SVSCRUB: return BIOC_SVSCRUB_S;
452 1678d261 2023-05-15 benni case BIOC_SVREBUILD: return BIOC_SVREBUILD_S;
453 1678d261 2023-05-15 benni case BIOC_SVINVALID: return BIOC_SVINVALID_S;
454 1678d261 2023-05-15 benni default: return "Unknown";
458 b0a1b420 2023-05-15 benni static void read_raid (
459 1678d261 2023-05-15 benni struct my_diskinfo *disk,
460 b0a1b420 2023-05-15 benni struct my_diskinfo *disks,
461 b0a1b420 2023-05-15 benni size_t num_disks
463 b0a1b420 2023-05-15 benni struct bioc_inq bi;
466 b0a1b420 2023-05-15 benni fd = opendev (disk->name, O_RDONLY, OPENDEV_PART | OPENDEV_BLCK, NULL);
467 b0a1b420 2023-05-15 benni if (fd < 0) {
468 b0a1b420 2023-05-15 benni warn ("read_raid(): opendev(%s)", disk->name);
472 f977c8f4 2023-05-30 benni memset (&bi, 0, sizeof bi);
474 b0a1b420 2023-05-15 benni if (ioctl (fd, BIOCINQ, &bi) == -1)
477 1678d261 2023-05-15 benni for (int i = 0; i < bi.bi_novol; ++i) {
478 1678d261 2023-05-15 benni struct bioc_vol bv;
480 f977c8f4 2023-05-30 benni memset (&bv, 0, sizeof bv);
481 1678d261 2023-05-15 benni memcpy (&bv.bv_bio, &bi.bi_bio, sizeof bi.bi_bio);
482 1678d261 2023-05-15 benni bv.bv_volid = i;
484 1678d261 2023-05-15 benni if (ioctl (fd, BIOCVOL, &bv) == -1) {
485 1678d261 2023-05-15 benni warn ("read_raid(%s): BIOCVOL(%d)", disk->name, i);
489 1678d261 2023-05-15 benni if (strcmp (disk->name, bv.bv_dev) != 0)
492 1678d261 2023-05-15 benni disk->raidstatus = bv_statusstr (bv.bv_status);
494 1678d261 2023-05-15 benni for (int j = 0; j < bv.bv_nodisk; ++j) {
495 1678d261 2023-05-15 benni struct bioc_disk bd;
496 1678d261 2023-05-15 benni size_t len_vendor;
497 1678d261 2023-05-15 benni char letter;
499 f977c8f4 2023-05-30 benni memset (&bd, 0, sizeof bd);
500 1678d261 2023-05-15 benni memcpy (&bd.bd_bio, &bi.bi_bio, sizeof bi.bi_bio);
501 1678d261 2023-05-15 benni bd.bd_volid = i;
502 1678d261 2023-05-15 benni bd.bd_diskid = j;
504 1678d261 2023-05-15 benni if (ioctl (fd, BIOCDISK, &bd) == -1) {
505 1678d261 2023-05-15 benni warn ("read_raid(%s): BIOCDISK(%d, %d)", disk->name, i, j);
509 1678d261 2023-05-15 benni len_vendor = strlen (bd.bd_vendor);
510 185836d0 2023-05-15 benni if (len_vendor < 4 || len_vendor > 8) {
511 1678d261 2023-05-15 benni warnx ("read_raid(%s): unexpected vendor string: %.32s", disk->name, bd.bd_vendor);
514 1678d261 2023-05-15 benni letter = bd.bd_vendor[len_vendor - 1];
516 1678d261 2023-05-15 benni for (size_t k = 0; k < num_disks; ++k) {
517 1678d261 2023-05-15 benni if (!memcmp (bd.bd_vendor, disks[k].name, 3)) {
518 1678d261 2023-05-15 benni for (size_t l = 0; l < disks[k].num_parts; ++l) {
519 1678d261 2023-05-15 benni if (letter == disks[k].parts[l].letter) {
520 1678d261 2023-05-15 benni disks[k].parts[l].sub = disk;
521 1678d261 2023-05-15 benni disks[k].parts[l].raidstatus = bd_statusstr(bd.bd_status);
522 1678d261 2023-05-15 benni goto found;
531 b0a1b420 2023-05-15 benni close (fd);
534 9c5d8ecc 2023-05-02 benni static int usage (void)
536 1678d261 2023-05-15 benni fputs ("Usage: lsblk [-abinUuV] [disk...]\n", stderr);
540 7c38b724 2023-05-15 benni static void pad_update (int *pad, int newval)
542 7c38b724 2023-05-15 benni if (newval > *pad)
543 7c38b724 2023-05-15 benni *pad = newval;
546 7c38b724 2023-05-15 benni static void pad_disk (struct padding *p, const struct my_diskinfo *disk)
548 7c38b724 2023-05-15 benni size_t len_disk;
549 7c38b724 2023-05-15 benni int comment;
551 7c38b724 2023-05-15 benni len_disk = strnlen (disk->name, sizeof disk->name);
552 7c38b724 2023-05-15 benni comment = strnlen (disk->label, sizeof disk->label);
553 7c38b724 2023-05-15 benni if (disk->raidstatus)
554 7c38b724 2023-05-15 benni comment += strlen (disk->raidstatus) + 3;
556 7c38b724 2023-05-15 benni pad_update (&p->name, len_disk);
557 7c38b724 2023-05-15 benni pad_update (&p->type, strnlen (disk->type, sizeof disk->type));
558 7c38b724 2023-05-15 benni pad_update (&p->comment, comment);
560 7c38b724 2023-05-15 benni for (int i = 0; i < disk->num_parts; ++i) {
561 7c38b724 2023-05-15 benni const struct my_partinfo *part = &disk->parts[i];
563 7c38b724 2023-05-15 benni pad_update (&p->name, len_disk + 3);
564 7c38b724 2023-05-15 benni pad_update (&p->type, strlen (part->fstype));
566 7c38b724 2023-05-15 benni if (part->sub) {
567 7c38b724 2023-05-15 benni pad_update (&p->name, strnlen (part->sub->name, sizeof part->sub->name) + 4);
568 7c38b724 2023-05-15 benni pad_update (&p->comment, strlen (part->raidstatus));
569 7c38b724 2023-05-15 benni } else if (part->mount) {
570 7c38b724 2023-05-15 benni pad_update (&p->comment, strlen (part->mount));
576 4d8e470c 2023-05-15 benni static int compare_disk (const void *p1, const void *p2)
578 4d8e470c 2023-05-15 benni const struct my_diskinfo *d1 = p1;
579 4d8e470c 2023-05-15 benni const struct my_diskinfo *d2 = p2;
581 4d8e470c 2023-05-15 benni return strcmp (d1->name, d2->name);
584 33bf1ca4 2023-04-08 benni int main (int argc, char *argv[])
586 8380cc51 2023-05-01 benni int option;
587 9c5d8ecc 2023-05-02 benni int fields = FIELD_DEFAULT;
588 0c961f7d 2023-05-04 benni int options = 0;
589 14fd8749 2023-05-30 benni int ret = 0;
590 da455e16 2023-09-01 benni bool ascii = false;
592 aff15c23 2023-04-30 benni if (unveil ("/dev", "r") == -1)
593 44121ddf 2023-05-05 benni err (1, "unveil(/dev)");
595 aff15c23 2023-04-30 benni if (unveil (NULL, NULL) == -1)
596 44121ddf 2023-05-05 benni err (1, "unveil()");
598 1678d261 2023-05-15 benni while ((option = getopt (argc, argv, ":abinUuV")) != -1) {
599 33bf1ca4 2023-04-08 benni switch (option) {
601 bf0e6461 2023-05-02 benni fields = -1;
604 1678d261 2023-05-15 benni options |= OPT_NOBIO;
607 da455e16 2023-09-01 benni ascii = true;
610 0c961f7d 2023-05-04 benni options |= OPT_NOHEADER;
613 1115ad3a 2023-05-05 benni fields |= FIELD_DUID;
616 9c5d8ecc 2023-05-02 benni fields |= FIELD_USED | FIELD_FREE;
619 1115ad3a 2023-05-05 benni puts ("lsblk-" VERSION);
622 33bf1ca4 2023-04-08 benni return usage ();
626 5691dc7b 2023-05-05 benni argv += optind;
627 5691dc7b 2023-05-05 benni argc -= optind;
629 5691dc7b 2023-05-05 benni char *names = argc == 0 ? disknames () : NULL;
631 33bf1ca4 2023-04-08 benni if (pledge ("stdio rpath disklabel", NULL) == -1)
632 44121ddf 2023-05-05 benni err (1, "pledge()");
634 da455e16 2023-09-01 benni prefix0 = ascii ? PREFIX0_ASCII : PREFIX0_UNICODE;
635 da455e16 2023-09-01 benni prefix1 = ascii ? PREFIX1_ASCII : PREFIX1_UNICODE;
636 da455e16 2023-09-01 benni prefix2 = ascii ? PREFIX2_ASCII : PREFIX2_UNICODE;
638 5691dc7b 2023-05-05 benni size_t cap_disks;
639 5691dc7b 2023-05-05 benni if (argc == 0) {
640 5691dc7b 2023-05-05 benni const char *s = names;
641 56e08374 2023-06-08 benni cap_disks = 1;
642 5691dc7b 2023-05-05 benni while ((s = strchr (s, ',')) != NULL)
643 5691dc7b 2023-05-05 benni ++cap_disks, ++s;
645 5691dc7b 2023-05-05 benni cap_disks = argc;
648 9c5d8ecc 2023-05-02 benni struct my_diskinfo *disks = calloc (cap_disks, sizeof (struct my_diskinfo));
649 5691dc7b 2023-05-05 benni size_t num_disks = 0;
651 5691dc7b 2023-05-05 benni if (argc == 0) {
652 a88ae11e 2023-05-30 benni for (char *name; (name = strsep (&names, ",")) != NULL; ) {
653 a88ae11e 2023-05-30 benni char *colon = strchr (name, ':');
654 a88ae11e 2023-05-30 benni struct my_diskinfo disk;
656 5691dc7b 2023-05-05 benni if (colon)
657 5691dc7b 2023-05-05 benni *colon = '\0';
658 a88ae11e 2023-05-30 benni if (read_disk (name, &disk) == 0) {
659 a88ae11e 2023-05-30 benni disks[num_disks++] = disk;
664 5691dc7b 2023-05-05 benni if (colon)
665 5691dc7b 2023-05-05 benni *colon = ':';
668 5691dc7b 2023-05-05 benni for (int i = 0; i < argc; ++i) {
669 a88ae11e 2023-05-30 benni char *name = basename (argv[i]);
670 a88ae11e 2023-05-30 benni char *last = name + strlen (name) - 1;
671 a88ae11e 2023-05-30 benni struct my_diskinfo disk;
673 185836d0 2023-05-15 benni if (isalpha (*last)) {
674 a88ae11e 2023-05-30 benni warnx ("%s: specifying a partition is not supported, using the drive.", name);
675 185836d0 2023-05-15 benni *last = '\0';
677 a88ae11e 2023-05-30 benni if (read_disk (name, &disk) == 0) {
678 a88ae11e 2023-05-30 benni disks[num_disks++] = disk;
685 33bf1ca4 2023-04-08 benni free (names);
687 14fd8749 2023-05-30 benni if (num_disks == 0)
688 14fd8749 2023-05-30 benni return ret;
690 4d8e470c 2023-05-15 benni mergesort (disks, num_disks, sizeof *disks, compare_disk);
692 1678d261 2023-05-15 benni if (!(options & OPT_NOBIO)) {
693 1678d261 2023-05-15 benni for (size_t i = 0; i < num_disks; ++i) {
694 1678d261 2023-05-15 benni read_raid (&disks[i], disks, num_disks);
698 7c38b724 2023-05-15 benni struct padding p = {
699 7c38b724 2023-05-15 benni .name = strlen ("NAME"),
700 7c38b724 2023-05-15 benni .type = strlen ("TYPE"),
701 7c38b724 2023-05-15 benni .comment = strlen ("COMMENT"),
704 7c38b724 2023-05-15 benni for (size_t i = 0; i < num_disks; ++i)
705 7c38b724 2023-05-15 benni pad_disk (&p, &disks[i]);
707 0c961f7d 2023-05-04 benni if (!(options & OPT_NOHEADER))
708 7c38b724 2023-05-15 benni print_header (fields, &p);
710 9c5d8ecc 2023-05-02 benni for (size_t i = 0; i < num_disks; ++i) {
711 7c38b724 2023-05-15 benni print_disk (&disks[i], fields, options, NULL, &p);
714 14fd8749 2023-05-30 benni return ret;
717 da455e16 2023-09-01 benni /* vim: set tabstop=4 shiftwidth=4 expandtab: */