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 33bf1ca4 2023-04-08 benni static int diskcount (void)
46 33bf1ca4 2023-04-08 benni const int mib[2] = { CTL_HW, HW_DISKCOUNT };
47 33bf1ca4 2023-04-08 benni int diskcount;
48 33bf1ca4 2023-04-08 benni size_t len = sizeof diskcount;
50 33bf1ca4 2023-04-08 benni if (sysctl (mib, 2, &diskcount, &len, NULL, 0) == -1)
51 44121ddf 2023-05-05 benni err (1, "sysctl(hw.diskcount)");
53 33bf1ca4 2023-04-08 benni return diskcount;
56 33bf1ca4 2023-04-08 benni static char *disknames (void)
58 33bf1ca4 2023-04-08 benni const int num = diskcount ();
59 33bf1ca4 2023-04-08 benni const int mib[2] = { CTL_HW, HW_DISKNAMES };
60 33bf1ca4 2023-04-08 benni size_t len = 32 * num;
61 33bf1ca4 2023-04-08 benni char *buffer = malloc (len);
63 33bf1ca4 2023-04-08 benni if (sysctl (mib, 2, buffer, &len, NULL, 0) == -1)
64 44121ddf 2023-05-05 benni err (1, "sysctl(hw.disknames)");
66 33bf1ca4 2023-04-08 benni return buffer;
69 9c5d8ecc 2023-05-02 benni static char *stripdisk (char *n)
71 9c5d8ecc 2023-05-02 benni const char sufx[] = " disk";
72 9c5d8ecc 2023-05-02 benni const size_t ln = strnlen (n, 16);
73 9c5d8ecc 2023-05-02 benni const size_t ls = sizeof sufx - 1;
75 2f06f21f 2023-06-08 benni if (memcmp (n + ln - ls, sufx, ls) == 0) {
76 9c5d8ecc 2023-05-02 benni n[ln - ls] = '\0';
82 9c5d8ecc 2023-05-02 benni static void print_size (uint64_t sz)
84 2f06f21f 2023-06-08 benni const struct unit {
86 33bf1ca4 2023-04-08 benni uint64_t factor;
87 2f06f21f 2023-06-08 benni } units[] = {
88 33bf1ca4 2023-04-08 benni { 'P', 1ull << 50 },
89 33bf1ca4 2023-04-08 benni { 'T', 1ull << 40 },
90 33bf1ca4 2023-04-08 benni { 'G', 1ull << 30 },
91 33bf1ca4 2023-04-08 benni { 'M', 1ull << 20 },
92 33bf1ca4 2023-04-08 benni { 'K', 1ull << 10 },
93 33bf1ca4 2023-04-08 benni { '0', 0 },
96 33bf1ca4 2023-04-08 benni char sym = 'B';
97 33bf1ca4 2023-04-08 benni uint64_t factor = 1;
99 33bf1ca4 2023-04-08 benni for (const struct unit *u = &units[0]; u->factor; ++u) {
100 33bf1ca4 2023-04-08 benni if (sz >= (u->factor * 9 / 10)) {
101 33bf1ca4 2023-04-08 benni sym = u->sym;
102 33bf1ca4 2023-04-08 benni factor = u->factor;
107 33bf1ca4 2023-04-08 benni const unsigned scaled10 = sz * 10 / factor;
108 33bf1ca4 2023-04-08 benni const unsigned scaled = sz / factor;
109 33bf1ca4 2023-04-08 benni if (scaled10 >= 1000) {
110 8a374bef 2023-04-08 benni printf ("%u", scaled);
111 33bf1ca4 2023-04-08 benni } else if (scaled10 >= 100) {
112 8a374bef 2023-04-08 benni printf (" %u", scaled);
114 8a374bef 2023-04-08 benni printf ("%u.%u", scaled, scaled10 % 10);
117 33bf1ca4 2023-04-08 benni putchar (sym);
118 9c5d8ecc 2023-05-02 benni putchar (' ');
122 0c961f7d 2023-05-04 benni FIELD_NAME = 0x01,
123 1115ad3a 2023-05-05 benni FIELD_DUID = 0x02,
124 1115ad3a 2023-05-05 benni FIELD_SIZE = 0x04,
125 1115ad3a 2023-05-05 benni FIELD_USED = 0x08,
126 1115ad3a 2023-05-05 benni FIELD_FREE = 0x10,
127 1115ad3a 2023-05-05 benni FIELD_TYPE = 0x20,
128 1678d261 2023-05-15 benni FIELD_COMMENT = 0x40,
130 1678d261 2023-05-15 benni FIELD_DEFAULT = FIELD_NAME | FIELD_SIZE | FIELD_TYPE | FIELD_COMMENT,
134 0c961f7d 2023-05-04 benni OPT_NOHEADER = 0x01,
135 0c961f7d 2023-05-04 benni OPT_NOUNICODE = 0x02,
136 1678d261 2023-05-15 benni OPT_NOBIO = 0x04,
139 b0a1b420 2023-05-15 benni struct my_diskinfo;
141 9c5d8ecc 2023-05-02 benni struct my_partinfo {
142 1115ad3a 2023-05-05 benni char letter;
143 9c5d8ecc 2023-05-02 benni uint64_t size;
144 9c5d8ecc 2023-05-02 benni uint64_t fssize;
145 9c5d8ecc 2023-05-02 benni uint64_t free;
146 9c5d8ecc 2023-05-02 benni const char *fstype;
147 9c5d8ecc 2023-05-02 benni const char *mount;
148 1678d261 2023-05-15 benni const struct my_diskinfo *sub; // If this is part of a RAID
149 1678d261 2023-05-15 benni const char *raidstatus; // Only available if (sub != NULL)
152 9c5d8ecc 2023-05-02 benni struct my_diskinfo {
153 9c5d8ecc 2023-05-02 benni char type[16];
154 9c5d8ecc 2023-05-02 benni char label[16];
155 69c9c7b9 2023-05-15 benni char name[8];
156 9c5d8ecc 2023-05-02 benni uint64_t size;
157 9c5d8ecc 2023-05-02 benni uint64_t used;
158 1115ad3a 2023-05-05 benni u_char duid[8];
159 b0a1b420 2023-05-15 benni uint8_t num_parts;
160 9c5d8ecc 2023-05-02 benni struct my_partinfo parts[MAXPARTITIONS];
161 1678d261 2023-05-15 benni const char *raidstatus; // If this is a RAID device
164 7c38b724 2023-05-15 benni struct padding {
166 7c38b724 2023-05-15 benni /* duid = 8 */
167 7c38b724 2023-05-15 benni /* size = 4 */
168 7c38b724 2023-05-15 benni /* used = 4 */
169 7c38b724 2023-05-15 benni /* free = 4 */
171 7c38b724 2023-05-15 benni int comment;
174 7c38b724 2023-05-15 benni static void print_header (int fields, const struct padding *p)
176 9c5d8ecc 2023-05-02 benni if (fields & FIELD_NAME)
177 7c38b724 2023-05-15 benni printf ("%-*s ", p->name, "NAME");
179 1115ad3a 2023-05-05 benni if (fields & FIELD_DUID)
180 1115ad3a 2023-05-05 benni printf ("%-18s ", "DUID");
182 9c5d8ecc 2023-05-02 benni if (fields & FIELD_SIZE)
183 9c5d8ecc 2023-05-02 benni printf ("%-4s ", "SIZE");
185 9c5d8ecc 2023-05-02 benni if (fields & FIELD_USED)
186 9c5d8ecc 2023-05-02 benni printf ("%-4s ", "USED");
188 9c5d8ecc 2023-05-02 benni if (fields & FIELD_FREE)
189 9c5d8ecc 2023-05-02 benni printf ("%-4s ", "FREE");
191 9c5d8ecc 2023-05-02 benni if (fields & FIELD_TYPE)
192 7c38b724 2023-05-15 benni printf ("%-*s ", p->type, "TYPE");
194 1678d261 2023-05-15 benni if (fields & FIELD_COMMENT)
195 7c38b724 2023-05-15 benni printf ("%-*s ", p->comment, "COMMENT");
197 7c38b724 2023-05-15 benni #if WSDEBUG
198 7c38b724 2023-05-15 benni putchar ('X');
201 9c5d8ecc 2023-05-02 benni putchar ('\n');
204 1115ad3a 2023-05-05 benni static void print_duid (const u_char *duid)
206 1115ad3a 2023-05-05 benni for (size_t i = 0; i < 8; ++i) {
207 1115ad3a 2023-05-05 benni printf ("%02x", duid[i]);
211 7c38b724 2023-05-15 benni static void print_disk (const struct my_diskinfo *, int, int, const char *, const struct padding *);
212 1115ad3a 2023-05-05 benni static void print_part (
213 1115ad3a 2023-05-05 benni const struct my_diskinfo *disk,
214 1115ad3a 2023-05-05 benni const struct my_partinfo *part,
215 1115ad3a 2023-05-05 benni int fields,
216 1115ad3a 2023-05-05 benni int options,
217 7c38b724 2023-05-15 benni bool last,
218 7c38b724 2023-05-15 benni const struct padding *p
220 0c961f7d 2023-05-04 benni if (fields & FIELD_NAME) {
221 0c961f7d 2023-05-04 benni const char *prefix = (options & OPT_NOUNICODE) ? " " : (last ? "└─" : "├─");
223 7c38b724 2023-05-15 benni "%s%s%c%-*s ",
225 7c38b724 2023-05-15 benni disk->name,
226 7c38b724 2023-05-15 benni part->letter,
227 7c38b724 2023-05-15 benni p->name - 2 - (int)strlen (disk->name) - 1,
232 1115ad3a 2023-05-05 benni if (fields & FIELD_DUID) {
233 1115ad3a 2023-05-05 benni print_duid (disk->duid);
234 1115ad3a 2023-05-05 benni printf (".%c ", part->letter);
237 9c5d8ecc 2023-05-02 benni if (fields & FIELD_SIZE)
238 9c5d8ecc 2023-05-02 benni print_size (part->size);
240 9c5d8ecc 2023-05-02 benni if (fields & FIELD_USED) {
241 9c5d8ecc 2023-05-02 benni if (part->fssize) {
242 9c5d8ecc 2023-05-02 benni print_size (part->fssize - part->free);
244 9c5d8ecc 2023-05-02 benni printf (" N/A ");
248 9c5d8ecc 2023-05-02 benni if (fields & FIELD_FREE) {
249 9c5d8ecc 2023-05-02 benni if (part->fssize) {
250 9c5d8ecc 2023-05-02 benni print_size (part->free);
252 9c5d8ecc 2023-05-02 benni printf (" N/A ");
256 9c5d8ecc 2023-05-02 benni if (fields & FIELD_TYPE)
257 7c38b724 2023-05-15 benni printf ("%-*s ", p->type, part->fstype);
259 7c38b724 2023-05-15 benni if (fields & FIELD_COMMENT)
260 7c38b724 2023-05-15 benni printf ("%-*s ", p->comment, part->mount ? part->mount : "");
262 7c38b724 2023-05-15 benni #if WSDEBUG
263 7c38b724 2023-05-15 benni putchar ('X');
266 9c5d8ecc 2023-05-02 benni putchar ('\n');
268 b0a1b420 2023-05-15 benni if (part->sub) {
269 7c38b724 2023-05-15 benni print_disk (part->sub, fields, options, part->raidstatus, p);
273 7c38b724 2023-05-15 benni static void print_disk (
274 7c38b724 2023-05-15 benni const struct my_diskinfo *disk,
275 7c38b724 2023-05-15 benni int fields,
276 7c38b724 2023-05-15 benni int options,
277 7c38b724 2023-05-15 benni const char *raidstatus,
278 7c38b724 2023-05-15 benni const struct padding *p
280 b0a1b420 2023-05-15 benni if (fields & FIELD_NAME) {
281 7e6c6845 2023-05-15 benni const char *prefix = raidstatus ? (options & OPT_NOUNICODE ? " " : "│ └─") : "";
284 7c38b724 2023-05-15 benni "%s%-*s ",
286 7e6c6845 2023-05-15 benni p->name - (raidstatus ? 4 : 0),
287 7c38b724 2023-05-15 benni disk->name
291 1115ad3a 2023-05-05 benni if (fields & FIELD_DUID) {
292 1115ad3a 2023-05-05 benni print_duid (disk->duid);
293 1115ad3a 2023-05-05 benni printf (" ");
296 9c5d8ecc 2023-05-02 benni if (fields & FIELD_SIZE)
297 9c5d8ecc 2023-05-02 benni print_size (disk->size);
299 9c5d8ecc 2023-05-02 benni if (fields & FIELD_USED)
300 9c5d8ecc 2023-05-02 benni print_size (disk->used);
302 9c5d8ecc 2023-05-02 benni if (fields & FIELD_FREE)
303 9c5d8ecc 2023-05-02 benni print_size (disk->size - disk->used);
305 9c5d8ecc 2023-05-02 benni if (fields & FIELD_TYPE)
306 7c38b724 2023-05-15 benni printf ("%-*.16s ", p->type, disk->type);
308 1678d261 2023-05-15 benni if (fields & FIELD_COMMENT) {
309 1678d261 2023-05-15 benni if (raidstatus) {
310 7c38b724 2023-05-15 benni printf ("%-*s ", p->comment, raidstatus);
311 1678d261 2023-05-15 benni } else if (disk->raidstatus) {
313 7c38b724 2023-05-15 benni "%.16s (%s)%*s ",
314 7c38b724 2023-05-15 benni disk->label,
315 7c38b724 2023-05-15 benni disk->raidstatus,
316 7c38b724 2023-05-15 benni p->comment - (int)strnlen (disk->label, sizeof disk->label) - (int)strlen (disk->raidstatus) - 3,
320 7c38b724 2023-05-15 benni printf ("%-*.16s ", p->comment, disk->label);
324 7c38b724 2023-05-15 benni #if WSDEBUG
325 7c38b724 2023-05-15 benni putchar ('X');
328 9c5d8ecc 2023-05-02 benni putchar ('\n');
330 1678d261 2023-05-15 benni if (!raidstatus) {
331 b0a1b420 2023-05-15 benni for (uint8_t i = 0; i < disk->num_parts; ++i)
332 7c38b724 2023-05-15 benni print_part (disk, &disk->parts[i], fields, options, i == (disk->num_parts - 1), p);
336 9c5d8ecc 2023-05-02 benni static const struct statfs *find_mount (const char *dev)
338 9c5d8ecc 2023-05-02 benni static struct statfs *mounts = NULL;
339 9c5d8ecc 2023-05-02 benni static int n_mounts;
341 9c5d8ecc 2023-05-02 benni if (!mounts) {
342 9c5d8ecc 2023-05-02 benni n_mounts = getmntinfo (&mounts, MNT_NOWAIT);
343 9c5d8ecc 2023-05-02 benni if (n_mounts == 0)
344 44121ddf 2023-05-05 benni err (1, "getmntinfo()");
347 9c5d8ecc 2023-05-02 benni for (int i = 0; i < n_mounts; ++i) {
348 9c5d8ecc 2023-05-02 benni if (!strcmp (dev, mounts[i].f_mntfromname))
349 9c5d8ecc 2023-05-02 benni return &mounts[i];
352 9c5d8ecc 2023-05-02 benni return NULL;
355 a88ae11e 2023-05-30 benni static int read_disk (const char *name, struct my_diskinfo *disk)
357 9c5d8ecc 2023-05-02 benni struct disklabel label;
358 0c422a5b 2023-05-05 benni char *ppath, *letter;
360 f977c8f4 2023-05-30 benni memset (disk, 0, sizeof *disk);
362 9c5d8ecc 2023-05-02 benni { // Read disklabel.
363 0c422a5b 2023-05-05 benni size_t len;
366 0c422a5b 2023-05-05 benni fd = opendev (name, O_RDONLY, OPENDEV_PART | OPENDEV_BLCK, &ppath);
367 a88ae11e 2023-05-30 benni if (fd < 0) {
368 a88ae11e 2023-05-30 benni warn ("read_disk(): opendev(%s)", name);
369 a88ae11e 2023-05-30 benni return -1;
372 a88ae11e 2023-05-30 benni if (ioctl (fd, DIOCGDINFO, &label) < 0) {
373 a88ae11e 2023-05-30 benni warn ("read_disk(): ioctl(%s, DIOCGDINFO)", name);
374 a88ae11e 2023-05-30 benni close (fd);
375 a88ae11e 2023-05-30 benni return -1;
377 9c5d8ecc 2023-05-02 benni close (fd);
379 0c422a5b 2023-05-05 benni len = strlen (ppath);
380 0c422a5b 2023-05-05 benni letter = ppath + len - 1;
383 a88ae11e 2023-05-30 benni strlcpy (disk->name, name, sizeof disk->name);
384 a88ae11e 2023-05-30 benni disk->size = DL_GETDSIZE (&label) * label.d_secsize;
385 a88ae11e 2023-05-30 benni memcpy (disk->type, label.d_typename, sizeof disk->type);
386 a88ae11e 2023-05-30 benni stripdisk (disk->type);
387 a88ae11e 2023-05-30 benni memcpy (disk->label, label.d_packname, sizeof disk->label);
388 a88ae11e 2023-05-30 benni memcpy (disk->duid, label.d_uid, sizeof disk->duid);
389 a88ae11e 2023-05-30 benni disk->num_parts = 0;
391 9c5d8ecc 2023-05-02 benni for (uint16_t i = 0; i < label.d_npartitions; ++i) {
392 9c5d8ecc 2023-05-02 benni const struct partition *p = &label.d_partitions[i];
393 9c5d8ecc 2023-05-02 benni const struct statfs *mnt;
394 9c5d8ecc 2023-05-02 benni struct my_partinfo part;
396 f977c8f4 2023-05-30 benni memset (&part, 0, sizeof part);
398 9c5d8ecc 2023-05-02 benni part.size = DL_GETPSIZE (p) * label.d_secsize;
400 9c5d8ecc 2023-05-02 benni if (!part.size)
403 1115ad3a 2023-05-05 benni part.letter = 'a' + i;
404 0c422a5b 2023-05-05 benni *letter = part.letter;
405 0c422a5b 2023-05-05 benni mnt = find_mount (ppath);
407 9c5d8ecc 2023-05-02 benni if (mnt) {
408 9c5d8ecc 2023-05-02 benni const uint64_t bs = mnt->f_bsize;
409 9c5d8ecc 2023-05-02 benni part.mount = mnt->f_mntonname;
410 9c5d8ecc 2023-05-02 benni part.fssize = mnt->f_blocks * bs;
411 9c5d8ecc 2023-05-02 benni part.free = mnt->f_bfree * bs;
414 9c5d8ecc 2023-05-02 benni part.fstype = fstypenames[p->p_fstype];
415 9c5d8ecc 2023-05-02 benni if (i != 2)
416 a88ae11e 2023-05-30 benni disk->used += part.size;
417 a88ae11e 2023-05-30 benni disk->parts[disk->num_parts++] = part;
423 1678d261 2023-05-15 benni static const char *bd_statusstr (int status) {
424 1678d261 2023-05-15 benni switch (status) {
425 1678d261 2023-05-15 benni case BIOC_SDONLINE: return BIOC_SDONLINE_S;
426 1678d261 2023-05-15 benni case BIOC_SDOFFLINE: return BIOC_SDOFFLINE_S;
427 1678d261 2023-05-15 benni case BIOC_SDFAILED: return BIOC_SDFAILED_S;
428 1678d261 2023-05-15 benni case BIOC_SDREBUILD: return BIOC_SDREBUILD_S;
429 1678d261 2023-05-15 benni case BIOC_SDHOTSPARE: return BIOC_SDHOTSPARE_S;
430 1678d261 2023-05-15 benni case BIOC_SDUNUSED: return BIOC_SDUNUSED_S;
431 1678d261 2023-05-15 benni case BIOC_SDSCRUB: return BIOC_SDSCRUB_S;
432 1678d261 2023-05-15 benni case BIOC_SDINVALID: return BIOC_SDINVALID_S;
433 1678d261 2023-05-15 benni default: return "Unknown";
437 1678d261 2023-05-15 benni static const char *bv_statusstr (int status) {
438 1678d261 2023-05-15 benni switch (status) {
439 1678d261 2023-05-15 benni case BIOC_SVONLINE: return BIOC_SVONLINE_S;
440 1678d261 2023-05-15 benni case BIOC_SVOFFLINE: return BIOC_SVOFFLINE_S;
441 1678d261 2023-05-15 benni case BIOC_SVDEGRADED: return BIOC_SVDEGRADED_S;
442 1678d261 2023-05-15 benni case BIOC_SVBUILDING: return BIOC_SVBUILDING_S;
443 1678d261 2023-05-15 benni case BIOC_SVSCRUB: return BIOC_SVSCRUB_S;
444 1678d261 2023-05-15 benni case BIOC_SVREBUILD: return BIOC_SVREBUILD_S;
445 1678d261 2023-05-15 benni case BIOC_SVINVALID: return BIOC_SVINVALID_S;
446 1678d261 2023-05-15 benni default: return "Unknown";
450 b0a1b420 2023-05-15 benni static void read_raid (
451 1678d261 2023-05-15 benni struct my_diskinfo *disk,
452 b0a1b420 2023-05-15 benni struct my_diskinfo *disks,
453 b0a1b420 2023-05-15 benni size_t num_disks
455 b0a1b420 2023-05-15 benni struct bioc_inq bi;
458 b0a1b420 2023-05-15 benni fd = opendev (disk->name, O_RDONLY, OPENDEV_PART | OPENDEV_BLCK, NULL);
459 b0a1b420 2023-05-15 benni if (fd < 0) {
460 b0a1b420 2023-05-15 benni warn ("read_raid(): opendev(%s)", disk->name);
464 f977c8f4 2023-05-30 benni memset (&bi, 0, sizeof bi);
466 b0a1b420 2023-05-15 benni if (ioctl (fd, BIOCINQ, &bi) == -1)
469 1678d261 2023-05-15 benni for (int i = 0; i < bi.bi_novol; ++i) {
470 1678d261 2023-05-15 benni struct bioc_vol bv;
472 f977c8f4 2023-05-30 benni memset (&bv, 0, sizeof bv);
473 1678d261 2023-05-15 benni memcpy (&bv.bv_bio, &bi.bi_bio, sizeof bi.bi_bio);
474 1678d261 2023-05-15 benni bv.bv_volid = i;
476 1678d261 2023-05-15 benni if (ioctl (fd, BIOCVOL, &bv) == -1) {
477 1678d261 2023-05-15 benni warn ("read_raid(%s): BIOCVOL(%d)", disk->name, i);
481 1678d261 2023-05-15 benni if (strcmp (disk->name, bv.bv_dev) != 0)
484 1678d261 2023-05-15 benni disk->raidstatus = bv_statusstr (bv.bv_status);
486 1678d261 2023-05-15 benni for (int j = 0; j < bv.bv_nodisk; ++j) {
487 1678d261 2023-05-15 benni struct bioc_disk bd;
488 1678d261 2023-05-15 benni size_t len_vendor;
489 1678d261 2023-05-15 benni char letter;
491 f977c8f4 2023-05-30 benni memset (&bd, 0, sizeof bd);
492 1678d261 2023-05-15 benni memcpy (&bd.bd_bio, &bi.bi_bio, sizeof bi.bi_bio);
493 1678d261 2023-05-15 benni bd.bd_volid = i;
494 1678d261 2023-05-15 benni bd.bd_diskid = j;
496 1678d261 2023-05-15 benni if (ioctl (fd, BIOCDISK, &bd) == -1) {
497 1678d261 2023-05-15 benni warn ("read_raid(%s): BIOCDISK(%d, %d)", disk->name, i, j);
501 1678d261 2023-05-15 benni len_vendor = strlen (bd.bd_vendor);
502 185836d0 2023-05-15 benni if (len_vendor < 4 || len_vendor > 8) {
503 1678d261 2023-05-15 benni warnx ("read_raid(%s): unexpected vendor string: %.32s", disk->name, bd.bd_vendor);
506 1678d261 2023-05-15 benni letter = bd.bd_vendor[len_vendor - 1];
508 1678d261 2023-05-15 benni for (size_t k = 0; k < num_disks; ++k) {
509 1678d261 2023-05-15 benni if (!memcmp (bd.bd_vendor, disks[k].name, 3)) {
510 1678d261 2023-05-15 benni for (size_t l = 0; l < disks[k].num_parts; ++l) {
511 1678d261 2023-05-15 benni if (letter == disks[k].parts[l].letter) {
512 1678d261 2023-05-15 benni disks[k].parts[l].sub = disk;
513 1678d261 2023-05-15 benni disks[k].parts[l].raidstatus = bd_statusstr(bd.bd_status);
514 1678d261 2023-05-15 benni goto found;
523 b0a1b420 2023-05-15 benni close (fd);
526 9c5d8ecc 2023-05-02 benni static int usage (void)
528 1678d261 2023-05-15 benni fputs ("Usage: lsblk [-abinUuV] [disk...]\n", stderr);
532 7c38b724 2023-05-15 benni static void pad_update (int *pad, int newval)
534 7c38b724 2023-05-15 benni if (newval > *pad)
535 7c38b724 2023-05-15 benni *pad = newval;
538 7c38b724 2023-05-15 benni static void pad_disk (struct padding *p, const struct my_diskinfo *disk)
540 7c38b724 2023-05-15 benni size_t len_disk;
541 7c38b724 2023-05-15 benni int comment;
543 7c38b724 2023-05-15 benni len_disk = strnlen (disk->name, sizeof disk->name);
544 7c38b724 2023-05-15 benni comment = strnlen (disk->label, sizeof disk->label);
545 7c38b724 2023-05-15 benni if (disk->raidstatus)
546 7c38b724 2023-05-15 benni comment += strlen (disk->raidstatus) + 3;
548 7c38b724 2023-05-15 benni pad_update (&p->name, len_disk);
549 7c38b724 2023-05-15 benni pad_update (&p->type, strnlen (disk->type, sizeof disk->type));
550 7c38b724 2023-05-15 benni pad_update (&p->comment, comment);
552 7c38b724 2023-05-15 benni for (int i = 0; i < disk->num_parts; ++i) {
553 7c38b724 2023-05-15 benni const struct my_partinfo *part = &disk->parts[i];
555 7c38b724 2023-05-15 benni pad_update (&p->name, len_disk + 3);
556 7c38b724 2023-05-15 benni pad_update (&p->type, strlen (part->fstype));
558 7c38b724 2023-05-15 benni if (part->sub) {
559 7c38b724 2023-05-15 benni pad_update (&p->name, strnlen (part->sub->name, sizeof part->sub->name) + 4);
560 7c38b724 2023-05-15 benni pad_update (&p->comment, strlen (part->raidstatus));
561 7c38b724 2023-05-15 benni } else if (part->mount) {
562 7c38b724 2023-05-15 benni pad_update (&p->comment, strlen (part->mount));
568 4d8e470c 2023-05-15 benni static int compare_disk (const void *p1, const void *p2)
570 4d8e470c 2023-05-15 benni const struct my_diskinfo *d1 = p1;
571 4d8e470c 2023-05-15 benni const struct my_diskinfo *d2 = p2;
573 4d8e470c 2023-05-15 benni return strcmp (d1->name, d2->name);
576 33bf1ca4 2023-04-08 benni int main (int argc, char *argv[])
578 8380cc51 2023-05-01 benni int option;
579 9c5d8ecc 2023-05-02 benni int fields = FIELD_DEFAULT;
580 0c961f7d 2023-05-04 benni int options = 0;
581 14fd8749 2023-05-30 benni int ret = 0;
583 aff15c23 2023-04-30 benni if (unveil ("/dev", "r") == -1)
584 44121ddf 2023-05-05 benni err (1, "unveil(/dev)");
586 aff15c23 2023-04-30 benni if (unveil (NULL, NULL) == -1)
587 44121ddf 2023-05-05 benni err (1, "unveil()");
589 1678d261 2023-05-15 benni while ((option = getopt (argc, argv, ":abinUuV")) != -1) {
590 33bf1ca4 2023-04-08 benni switch (option) {
592 bf0e6461 2023-05-02 benni fields = -1;
595 1678d261 2023-05-15 benni options |= OPT_NOBIO;
598 0c961f7d 2023-05-04 benni options |= OPT_NOUNICODE;
601 0c961f7d 2023-05-04 benni options |= OPT_NOHEADER;
604 1115ad3a 2023-05-05 benni fields |= FIELD_DUID;
607 9c5d8ecc 2023-05-02 benni fields |= FIELD_USED | FIELD_FREE;
610 1115ad3a 2023-05-05 benni puts ("lsblk-" VERSION);
613 33bf1ca4 2023-04-08 benni return usage ();
617 5691dc7b 2023-05-05 benni argv += optind;
618 5691dc7b 2023-05-05 benni argc -= optind;
620 5691dc7b 2023-05-05 benni char *names = argc == 0 ? disknames () : NULL;
622 33bf1ca4 2023-04-08 benni if (pledge ("stdio rpath disklabel", NULL) == -1)
623 44121ddf 2023-05-05 benni err (1, "pledge()");
625 5691dc7b 2023-05-05 benni size_t cap_disks;
626 5691dc7b 2023-05-05 benni if (argc == 0) {
627 5691dc7b 2023-05-05 benni const char *s = names;
628 56e08374 2023-06-08 benni cap_disks = 1;
629 5691dc7b 2023-05-05 benni while ((s = strchr (s, ',')) != NULL)
630 5691dc7b 2023-05-05 benni ++cap_disks, ++s;
632 5691dc7b 2023-05-05 benni cap_disks = argc;
635 9c5d8ecc 2023-05-02 benni struct my_diskinfo *disks = calloc (cap_disks, sizeof (struct my_diskinfo));
636 5691dc7b 2023-05-05 benni size_t num_disks = 0;
638 5691dc7b 2023-05-05 benni if (argc == 0) {
639 a88ae11e 2023-05-30 benni for (char *name; (name = strsep (&names, ",")) != NULL; ) {
640 a88ae11e 2023-05-30 benni char *colon = strchr (name, ':');
641 a88ae11e 2023-05-30 benni struct my_diskinfo disk;
643 5691dc7b 2023-05-05 benni if (colon)
644 5691dc7b 2023-05-05 benni *colon = '\0';
645 a88ae11e 2023-05-30 benni if (read_disk (name, &disk) == 0) {
646 a88ae11e 2023-05-30 benni disks[num_disks++] = disk;
651 5691dc7b 2023-05-05 benni if (colon)
652 5691dc7b 2023-05-05 benni *colon = ':';
655 5691dc7b 2023-05-05 benni for (int i = 0; i < argc; ++i) {
656 a88ae11e 2023-05-30 benni char *name = basename (argv[i]);
657 a88ae11e 2023-05-30 benni char *last = name + strlen (name) - 1;
658 a88ae11e 2023-05-30 benni struct my_diskinfo disk;
660 185836d0 2023-05-15 benni if (isalpha (*last)) {
661 a88ae11e 2023-05-30 benni warnx ("%s: specifying a partition is not supported, using the drive.", name);
662 185836d0 2023-05-15 benni *last = '\0';
664 a88ae11e 2023-05-30 benni if (read_disk (name, &disk) == 0) {
665 a88ae11e 2023-05-30 benni disks[num_disks++] = disk;
672 33bf1ca4 2023-04-08 benni free (names);
674 14fd8749 2023-05-30 benni if (num_disks == 0)
675 14fd8749 2023-05-30 benni return ret;
677 4d8e470c 2023-05-15 benni mergesort (disks, num_disks, sizeof *disks, compare_disk);
679 1678d261 2023-05-15 benni if (!(options & OPT_NOBIO)) {
680 1678d261 2023-05-15 benni for (size_t i = 0; i < num_disks; ++i) {
681 1678d261 2023-05-15 benni read_raid (&disks[i], disks, num_disks);
685 7c38b724 2023-05-15 benni struct padding p = {
686 7c38b724 2023-05-15 benni .name = strlen ("NAME"),
687 7c38b724 2023-05-15 benni .type = strlen ("TYPE"),
688 7c38b724 2023-05-15 benni .comment = strlen ("COMMENT"),
691 7c38b724 2023-05-15 benni for (size_t i = 0; i < num_disks; ++i)
692 7c38b724 2023-05-15 benni pad_disk (&p, &disks[i]);
694 0c961f7d 2023-05-04 benni if (!(options & OPT_NOHEADER))
695 7c38b724 2023-05-15 benni print_header (fields, &p);
697 9c5d8ecc 2023-05-02 benni for (size_t i = 0; i < num_disks; ++i) {
698 7c38b724 2023-05-15 benni print_disk (&disks[i], fields, options, NULL, &p);
701 14fd8749 2023-05-30 benni return ret;