Blame


1 9ddaf4ab 2023-04-08 benni /*
2 9ddaf4ab 2023-04-08 benni * Copyright (c) 2023 Benjamin Stürz <benni@stuerz.xyz>
3 9ddaf4ab 2023-04-08 benni *
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.
7 9ddaf4ab 2023-04-08 benni *
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.
15 9ddaf4ab 2023-04-08 benni */
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 33bf1ca4 2023-04-08 benni #include <stddef.h>
20 b0a1b420 2023-05-15 benni #include <dev/biovar.h>
21 9c5d8ecc 2023-05-02 benni #include <sys/cdefs.h>
22 33bf1ca4 2023-04-08 benni #include <sys/types.h>
23 33bf1ca4 2023-04-08 benni #include <sys/disklabel.h>
24 33bf1ca4 2023-04-08 benni #include <sys/sysctl.h>
25 33bf1ca4 2023-04-08 benni #include <sys/ioctl.h>
26 33bf1ca4 2023-04-08 benni #include <sys/mount.h>
27 33bf1ca4 2023-04-08 benni #include <sys/dkio.h>
28 33bf1ca4 2023-04-08 benni #include <inttypes.h>
29 8380cc51 2023-05-01 benni #include <stdbool.h>
30 33bf1ca4 2023-04-08 benni #include <string.h>
31 33bf1ca4 2023-04-08 benni #include <stdarg.h>
32 33bf1ca4 2023-04-08 benni #include <stdint.h>
33 33bf1ca4 2023-04-08 benni #include <stdlib.h>
34 33bf1ca4 2023-04-08 benni #include <unistd.h>
35 5691dc7b 2023-05-05 benni #include <libgen.h>
36 33bf1ca4 2023-04-08 benni #include <stdio.h>
37 33bf1ca4 2023-04-08 benni #include <fcntl.h>
38 33bf1ca4 2023-04-08 benni #include <errno.h>
39 0c422a5b 2023-05-05 benni #include <util.h>
40 44121ddf 2023-05-05 benni #include <err.h>
41 33bf1ca4 2023-04-08 benni
42 33bf1ca4 2023-04-08 benni static int diskcount (void)
43 33bf1ca4 2023-04-08 benni {
44 33bf1ca4 2023-04-08 benni const int mib[2] = { CTL_HW, HW_DISKCOUNT };
45 33bf1ca4 2023-04-08 benni int diskcount;
46 33bf1ca4 2023-04-08 benni size_t len = sizeof diskcount;
47 33bf1ca4 2023-04-08 benni
48 33bf1ca4 2023-04-08 benni if (sysctl (mib, 2, &diskcount, &len, NULL, 0) == -1)
49 44121ddf 2023-05-05 benni err (1, "sysctl(hw.diskcount)");
50 33bf1ca4 2023-04-08 benni
51 33bf1ca4 2023-04-08 benni return diskcount;
52 33bf1ca4 2023-04-08 benni }
53 33bf1ca4 2023-04-08 benni
54 33bf1ca4 2023-04-08 benni static char *disknames (void)
55 33bf1ca4 2023-04-08 benni {
56 33bf1ca4 2023-04-08 benni const int num = diskcount ();
57 33bf1ca4 2023-04-08 benni const int mib[2] = { CTL_HW, HW_DISKNAMES };
58 33bf1ca4 2023-04-08 benni size_t len = 32 * num;
59 33bf1ca4 2023-04-08 benni char *buffer = malloc (len);
60 33bf1ca4 2023-04-08 benni
61 33bf1ca4 2023-04-08 benni if (sysctl (mib, 2, buffer, &len, NULL, 0) == -1)
62 44121ddf 2023-05-05 benni err (1, "sysctl(hw.disknames)");
63 33bf1ca4 2023-04-08 benni
64 33bf1ca4 2023-04-08 benni return buffer;
65 33bf1ca4 2023-04-08 benni }
66 33bf1ca4 2023-04-08 benni
67 9c5d8ecc 2023-05-02 benni static char *stripdisk (char *n)
68 33bf1ca4 2023-04-08 benni {
69 9c5d8ecc 2023-05-02 benni const char sufx[] = " disk";
70 9c5d8ecc 2023-05-02 benni const size_t ln = strnlen (n, 16);
71 9c5d8ecc 2023-05-02 benni const size_t ls = sizeof sufx - 1;
72 9c5d8ecc 2023-05-02 benni
73 9c5d8ecc 2023-05-02 benni if (!memcmp (n + ln - ls, sufx, ls)) {
74 9c5d8ecc 2023-05-02 benni n[ln - ls] = '\0';
75 9c5d8ecc 2023-05-02 benni }
76 9c5d8ecc 2023-05-02 benni
77 9c5d8ecc 2023-05-02 benni return n;
78 9c5d8ecc 2023-05-02 benni }
79 9c5d8ecc 2023-05-02 benni
80 9c5d8ecc 2023-05-02 benni static void print_size (uint64_t sz)
81 9c5d8ecc 2023-05-02 benni {
82 33bf1ca4 2023-04-08 benni struct unit {
83 33bf1ca4 2023-04-08 benni char sym;
84 33bf1ca4 2023-04-08 benni uint64_t factor;
85 33bf1ca4 2023-04-08 benni };
86 33bf1ca4 2023-04-08 benni
87 33bf1ca4 2023-04-08 benni const struct unit 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 },
94 33bf1ca4 2023-04-08 benni };
95 33bf1ca4 2023-04-08 benni
96 33bf1ca4 2023-04-08 benni char sym = 'B';
97 33bf1ca4 2023-04-08 benni uint64_t factor = 1;
98 33bf1ca4 2023-04-08 benni
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;
103 33bf1ca4 2023-04-08 benni break;
104 33bf1ca4 2023-04-08 benni }
105 33bf1ca4 2023-04-08 benni }
106 33bf1ca4 2023-04-08 benni
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);
113 33bf1ca4 2023-04-08 benni } else {
114 8a374bef 2023-04-08 benni printf ("%u.%u", scaled, scaled10 % 10);
115 33bf1ca4 2023-04-08 benni }
116 33bf1ca4 2023-04-08 benni
117 33bf1ca4 2023-04-08 benni putchar (sym);
118 9c5d8ecc 2023-05-02 benni putchar (' ');
119 33bf1ca4 2023-04-08 benni }
120 33bf1ca4 2023-04-08 benni
121 9c5d8ecc 2023-05-02 benni enum {
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,
129 9c5d8ecc 2023-05-02 benni
130 1678d261 2023-05-15 benni FIELD_DEFAULT = FIELD_NAME | FIELD_SIZE | FIELD_TYPE | FIELD_COMMENT,
131 9c5d8ecc 2023-05-02 benni };
132 9c5d8ecc 2023-05-02 benni
133 0c961f7d 2023-05-04 benni enum {
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,
137 0c961f7d 2023-05-04 benni };
138 0c961f7d 2023-05-04 benni
139 b0a1b420 2023-05-15 benni struct my_diskinfo;
140 b0a1b420 2023-05-15 benni
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)
150 9c5d8ecc 2023-05-02 benni };
151 9c5d8ecc 2023-05-02 benni
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 9c5d8ecc 2023-05-02 benni char name[4];
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
162 9c5d8ecc 2023-05-02 benni };
163 9c5d8ecc 2023-05-02 benni
164 9c5d8ecc 2023-05-02 benni static void print_header (int fields)
165 33bf1ca4 2023-04-08 benni {
166 9c5d8ecc 2023-05-02 benni if (fields & FIELD_NAME)
167 b0a1b420 2023-05-15 benni printf ("%-7s ", "NAME");
168 9c5d8ecc 2023-05-02 benni
169 1115ad3a 2023-05-05 benni if (fields & FIELD_DUID)
170 1115ad3a 2023-05-05 benni printf ("%-18s ", "DUID");
171 1115ad3a 2023-05-05 benni
172 9c5d8ecc 2023-05-02 benni if (fields & FIELD_SIZE)
173 9c5d8ecc 2023-05-02 benni printf ("%-4s ", "SIZE");
174 9c5d8ecc 2023-05-02 benni
175 9c5d8ecc 2023-05-02 benni if (fields & FIELD_USED)
176 9c5d8ecc 2023-05-02 benni printf ("%-4s ", "USED");
177 9c5d8ecc 2023-05-02 benni
178 9c5d8ecc 2023-05-02 benni if (fields & FIELD_FREE)
179 9c5d8ecc 2023-05-02 benni printf ("%-4s ", "FREE");
180 9c5d8ecc 2023-05-02 benni
181 9c5d8ecc 2023-05-02 benni if (fields & FIELD_TYPE)
182 9c5d8ecc 2023-05-02 benni printf ("%-8s ", "TYPE");
183 9c5d8ecc 2023-05-02 benni
184 1678d261 2023-05-15 benni if (fields & FIELD_COMMENT)
185 1678d261 2023-05-15 benni printf ("COMMENT ");
186 9c5d8ecc 2023-05-02 benni
187 9c5d8ecc 2023-05-02 benni putchar ('\n');
188 33bf1ca4 2023-04-08 benni }
189 33bf1ca4 2023-04-08 benni
190 1115ad3a 2023-05-05 benni static void print_duid (const u_char *duid)
191 3103dec4 2023-05-01 benni {
192 1115ad3a 2023-05-05 benni for (size_t i = 0; i < 8; ++i) {
193 1115ad3a 2023-05-05 benni printf ("%02x", duid[i]);
194 1115ad3a 2023-05-05 benni }
195 1115ad3a 2023-05-05 benni }
196 1115ad3a 2023-05-05 benni
197 1678d261 2023-05-15 benni static void print_disk (const struct my_diskinfo *disk, int fields, int options, const char *raidstatus);
198 1115ad3a 2023-05-05 benni static void print_part (
199 1115ad3a 2023-05-05 benni const struct my_diskinfo *disk,
200 1115ad3a 2023-05-05 benni const struct my_partinfo *part,
201 1115ad3a 2023-05-05 benni int fields,
202 1115ad3a 2023-05-05 benni int options,
203 1115ad3a 2023-05-05 benni bool last
204 1115ad3a 2023-05-05 benni ) {
205 0c961f7d 2023-05-04 benni if (fields & FIELD_NAME) {
206 0c961f7d 2023-05-04 benni const char *prefix = (options & OPT_NOUNICODE) ? " " : (last ? "└─" : "├─");
207 b0a1b420 2023-05-15 benni printf ("%s%s%c ", prefix, disk->name, part->letter);
208 0c961f7d 2023-05-04 benni }
209 3103dec4 2023-05-01 benni
210 1115ad3a 2023-05-05 benni if (fields & FIELD_DUID) {
211 1115ad3a 2023-05-05 benni print_duid (disk->duid);
212 1115ad3a 2023-05-05 benni printf (".%c ", part->letter);
213 1115ad3a 2023-05-05 benni }
214 1115ad3a 2023-05-05 benni
215 9c5d8ecc 2023-05-02 benni if (fields & FIELD_SIZE)
216 9c5d8ecc 2023-05-02 benni print_size (part->size);
217 9c5d8ecc 2023-05-02 benni
218 9c5d8ecc 2023-05-02 benni if (fields & FIELD_USED) {
219 9c5d8ecc 2023-05-02 benni if (part->fssize) {
220 9c5d8ecc 2023-05-02 benni print_size (part->fssize - part->free);
221 9c5d8ecc 2023-05-02 benni } else {
222 9c5d8ecc 2023-05-02 benni printf (" N/A ");
223 9c5d8ecc 2023-05-02 benni }
224 3103dec4 2023-05-01 benni }
225 3103dec4 2023-05-01 benni
226 9c5d8ecc 2023-05-02 benni if (fields & FIELD_FREE) {
227 9c5d8ecc 2023-05-02 benni if (part->fssize) {
228 9c5d8ecc 2023-05-02 benni print_size (part->free);
229 9c5d8ecc 2023-05-02 benni } else {
230 9c5d8ecc 2023-05-02 benni printf (" N/A ");
231 9c5d8ecc 2023-05-02 benni }
232 9c5d8ecc 2023-05-02 benni }
233 9c5d8ecc 2023-05-02 benni
234 9c5d8ecc 2023-05-02 benni if (fields & FIELD_TYPE)
235 9c5d8ecc 2023-05-02 benni printf ("%-8.16s ", part->fstype);
236 9c5d8ecc 2023-05-02 benni
237 1678d261 2023-05-15 benni if (fields & FIELD_COMMENT && part->mount)
238 9c5d8ecc 2023-05-02 benni printf ("%s ", part->mount);
239 9c5d8ecc 2023-05-02 benni
240 9c5d8ecc 2023-05-02 benni putchar ('\n');
241 b0a1b420 2023-05-15 benni
242 b0a1b420 2023-05-15 benni if (part->sub) {
243 b0a1b420 2023-05-15 benni printf ("│ └─");
244 1678d261 2023-05-15 benni print_disk (part->sub, fields, options, part->raidstatus);
245 b0a1b420 2023-05-15 benni }
246 9c5d8ecc 2023-05-02 benni }
247 9c5d8ecc 2023-05-02 benni
248 1678d261 2023-05-15 benni static void print_disk (const struct my_diskinfo *disk, int fields, int options, const char *raidstatus)
249 9c5d8ecc 2023-05-02 benni {
250 b0a1b420 2023-05-15 benni if (fields & FIELD_NAME) {
251 b0a1b420 2023-05-15 benni printf ("%s ", disk->name);
252 1678d261 2023-05-15 benni if (!raidstatus)
253 b0a1b420 2023-05-15 benni printf (" ");
254 b0a1b420 2023-05-15 benni }
255 9c5d8ecc 2023-05-02 benni
256 1115ad3a 2023-05-05 benni if (fields & FIELD_DUID) {
257 1115ad3a 2023-05-05 benni print_duid (disk->duid);
258 1115ad3a 2023-05-05 benni printf (" ");
259 1115ad3a 2023-05-05 benni }
260 1115ad3a 2023-05-05 benni
261 9c5d8ecc 2023-05-02 benni if (fields & FIELD_SIZE)
262 9c5d8ecc 2023-05-02 benni print_size (disk->size);
263 9c5d8ecc 2023-05-02 benni
264 9c5d8ecc 2023-05-02 benni if (fields & FIELD_USED)
265 9c5d8ecc 2023-05-02 benni print_size (disk->used);
266 9c5d8ecc 2023-05-02 benni
267 9c5d8ecc 2023-05-02 benni if (fields & FIELD_FREE)
268 9c5d8ecc 2023-05-02 benni print_size (disk->size - disk->used);
269 9c5d8ecc 2023-05-02 benni
270 9c5d8ecc 2023-05-02 benni // Pad only upto 8 characters because most disk types are <=8 bytes long.
271 9c5d8ecc 2023-05-02 benni if (fields & FIELD_TYPE)
272 9c5d8ecc 2023-05-02 benni printf ("%-8.16s ", disk->type);
273 9c5d8ecc 2023-05-02 benni
274 1678d261 2023-05-15 benni if (fields & FIELD_COMMENT) {
275 1678d261 2023-05-15 benni if (raidstatus) {
276 1678d261 2023-05-15 benni printf ("%s ", raidstatus);
277 1678d261 2023-05-15 benni } else if (disk->raidstatus) {
278 1678d261 2023-05-15 benni printf ("%.16s (%s) ", disk->label, disk->raidstatus);
279 1678d261 2023-05-15 benni } else {
280 1678d261 2023-05-15 benni printf ("%.16s ", disk->label);
281 1678d261 2023-05-15 benni }
282 1678d261 2023-05-15 benni }
283 9c5d8ecc 2023-05-02 benni
284 9c5d8ecc 2023-05-02 benni putchar ('\n');
285 9c5d8ecc 2023-05-02 benni
286 1678d261 2023-05-15 benni if (!raidstatus) {
287 b0a1b420 2023-05-15 benni for (uint8_t i = 0; i < disk->num_parts; ++i)
288 b0a1b420 2023-05-15 benni print_part (disk, &disk->parts[i], fields, options, i == (disk->num_parts - 1));
289 b0a1b420 2023-05-15 benni }
290 9c5d8ecc 2023-05-02 benni }
291 9c5d8ecc 2023-05-02 benni
292 9c5d8ecc 2023-05-02 benni static const struct statfs *find_mount (const char *dev)
293 9c5d8ecc 2023-05-02 benni {
294 9c5d8ecc 2023-05-02 benni static struct statfs *mounts = NULL;
295 9c5d8ecc 2023-05-02 benni static int n_mounts;
296 9c5d8ecc 2023-05-02 benni
297 9c5d8ecc 2023-05-02 benni if (!mounts) {
298 9c5d8ecc 2023-05-02 benni n_mounts = getmntinfo (&mounts, MNT_NOWAIT);
299 9c5d8ecc 2023-05-02 benni if (n_mounts == 0)
300 44121ddf 2023-05-05 benni err (1, "getmntinfo()");
301 9c5d8ecc 2023-05-02 benni }
302 9c5d8ecc 2023-05-02 benni
303 9c5d8ecc 2023-05-02 benni for (int i = 0; i < n_mounts; ++i) {
304 9c5d8ecc 2023-05-02 benni if (!strcmp (dev, mounts[i].f_mntfromname))
305 9c5d8ecc 2023-05-02 benni return &mounts[i];
306 9c5d8ecc 2023-05-02 benni }
307 9c5d8ecc 2023-05-02 benni
308 9c5d8ecc 2023-05-02 benni return NULL;
309 3103dec4 2023-05-01 benni }
310 3103dec4 2023-05-01 benni
311 9c5d8ecc 2023-05-02 benni static struct my_diskinfo read_disk (const char *name)
312 9c5d8ecc 2023-05-02 benni {
313 9c5d8ecc 2023-05-02 benni struct my_diskinfo disk;
314 9c5d8ecc 2023-05-02 benni struct disklabel label;
315 0c422a5b 2023-05-05 benni char *ppath, *letter;
316 9c5d8ecc 2023-05-02 benni
317 9c5d8ecc 2023-05-02 benni bzero (&disk, sizeof disk);
318 9c5d8ecc 2023-05-02 benni
319 9c5d8ecc 2023-05-02 benni { // Read disklabel.
320 0c422a5b 2023-05-05 benni size_t len;
321 9c5d8ecc 2023-05-02 benni int fd;
322 9c5d8ecc 2023-05-02 benni
323 0c422a5b 2023-05-05 benni fd = opendev (name, O_RDONLY, OPENDEV_PART | OPENDEV_BLCK, &ppath);
324 9c5d8ecc 2023-05-02 benni if (fd < 0)
325 44121ddf 2023-05-05 benni err (1, "opendev(%s)", name);
326 0c422a5b 2023-05-05 benni
327 9c5d8ecc 2023-05-02 benni if (ioctl (fd, DIOCGDINFO, &label) < 0)
328 44121ddf 2023-05-05 benni err (1, "ioctl(%s, DIOCGDINFO)", name);
329 9c5d8ecc 2023-05-02 benni close (fd);
330 9c5d8ecc 2023-05-02 benni
331 0c422a5b 2023-05-05 benni len = strlen (ppath);
332 0c422a5b 2023-05-05 benni letter = ppath + len - 1;
333 0c422a5b 2023-05-05 benni }
334 5691dc7b 2023-05-05 benni
335 9c5d8ecc 2023-05-02 benni memcpy (disk.name, name, 3);
336 9c5d8ecc 2023-05-02 benni disk.name[3] = '\0';
337 9c5d8ecc 2023-05-02 benni disk.size = DL_GETDSIZE (&label) * label.d_secsize;
338 9c5d8ecc 2023-05-02 benni memcpy (disk.type, label.d_typename, 16);
339 9c5d8ecc 2023-05-02 benni stripdisk (disk.type);
340 9c5d8ecc 2023-05-02 benni memcpy (disk.label, label.d_packname, 16);
341 1115ad3a 2023-05-05 benni memcpy (disk.duid, label.d_uid, sizeof disk.duid);
342 9c5d8ecc 2023-05-02 benni disk.num_parts = 0;
343 9c5d8ecc 2023-05-02 benni
344 9c5d8ecc 2023-05-02 benni for (uint16_t i = 0; i < label.d_npartitions; ++i) {
345 9c5d8ecc 2023-05-02 benni const struct partition *p = &label.d_partitions[i];
346 9c5d8ecc 2023-05-02 benni const struct statfs *mnt;
347 9c5d8ecc 2023-05-02 benni struct my_partinfo part;
348 9c5d8ecc 2023-05-02 benni
349 9c5d8ecc 2023-05-02 benni bzero (&part, sizeof part);
350 9c5d8ecc 2023-05-02 benni
351 9c5d8ecc 2023-05-02 benni part.size = DL_GETPSIZE (p) * label.d_secsize;
352 9c5d8ecc 2023-05-02 benni
353 9c5d8ecc 2023-05-02 benni if (!part.size)
354 9c5d8ecc 2023-05-02 benni continue;
355 9c5d8ecc 2023-05-02 benni
356 1115ad3a 2023-05-05 benni part.letter = 'a' + i;
357 0c422a5b 2023-05-05 benni *letter = part.letter;
358 0c422a5b 2023-05-05 benni mnt = find_mount (ppath);
359 9c5d8ecc 2023-05-02 benni
360 9c5d8ecc 2023-05-02 benni if (mnt) {
361 9c5d8ecc 2023-05-02 benni const uint64_t bs = mnt->f_bsize;
362 9c5d8ecc 2023-05-02 benni part.mount = mnt->f_mntonname;
363 9c5d8ecc 2023-05-02 benni part.fssize = mnt->f_blocks * bs;
364 9c5d8ecc 2023-05-02 benni part.free = mnt->f_bfree * bs;
365 9c5d8ecc 2023-05-02 benni }
366 9c5d8ecc 2023-05-02 benni
367 9c5d8ecc 2023-05-02 benni part.fstype = fstypenames[p->p_fstype];
368 9c5d8ecc 2023-05-02 benni if (i != 2)
369 9c5d8ecc 2023-05-02 benni disk.used += part.size;
370 9c5d8ecc 2023-05-02 benni disk.parts[disk.num_parts++] = part;
371 9c5d8ecc 2023-05-02 benni }
372 9c5d8ecc 2023-05-02 benni
373 9c5d8ecc 2023-05-02 benni return disk;
374 9c5d8ecc 2023-05-02 benni }
375 9c5d8ecc 2023-05-02 benni
376 1678d261 2023-05-15 benni static const char *bd_statusstr (int status) {
377 1678d261 2023-05-15 benni switch (status) {
378 1678d261 2023-05-15 benni case BIOC_SDONLINE: return BIOC_SDONLINE_S;
379 1678d261 2023-05-15 benni case BIOC_SDOFFLINE: return BIOC_SDOFFLINE_S;
380 1678d261 2023-05-15 benni case BIOC_SDFAILED: return BIOC_SDFAILED_S;
381 1678d261 2023-05-15 benni case BIOC_SDREBUILD: return BIOC_SDREBUILD_S;
382 1678d261 2023-05-15 benni case BIOC_SDHOTSPARE: return BIOC_SDHOTSPARE_S;
383 1678d261 2023-05-15 benni case BIOC_SDUNUSED: return BIOC_SDUNUSED_S;
384 1678d261 2023-05-15 benni case BIOC_SDSCRUB: return BIOC_SDSCRUB_S;
385 1678d261 2023-05-15 benni case BIOC_SDINVALID: return BIOC_SDINVALID_S;
386 1678d261 2023-05-15 benni default: return "Unknown";
387 1678d261 2023-05-15 benni }
388 1678d261 2023-05-15 benni }
389 1678d261 2023-05-15 benni
390 1678d261 2023-05-15 benni static const char *bv_statusstr (int status) {
391 1678d261 2023-05-15 benni switch (status) {
392 1678d261 2023-05-15 benni case BIOC_SVONLINE: return BIOC_SVONLINE_S;
393 1678d261 2023-05-15 benni case BIOC_SVOFFLINE: return BIOC_SVOFFLINE_S;
394 1678d261 2023-05-15 benni case BIOC_SVDEGRADED: return BIOC_SVDEGRADED_S;
395 1678d261 2023-05-15 benni case BIOC_SVBUILDING: return BIOC_SVBUILDING_S;
396 1678d261 2023-05-15 benni case BIOC_SVSCRUB: return BIOC_SVSCRUB_S;
397 1678d261 2023-05-15 benni case BIOC_SVREBUILD: return BIOC_SVREBUILD_S;
398 1678d261 2023-05-15 benni case BIOC_SVINVALID: return BIOC_SVINVALID_S;
399 1678d261 2023-05-15 benni default: return "Unknown";
400 1678d261 2023-05-15 benni }
401 1678d261 2023-05-15 benni }
402 1678d261 2023-05-15 benni
403 b0a1b420 2023-05-15 benni static void read_raid (
404 1678d261 2023-05-15 benni struct my_diskinfo *disk,
405 b0a1b420 2023-05-15 benni struct my_diskinfo *disks,
406 b0a1b420 2023-05-15 benni size_t num_disks
407 b0a1b420 2023-05-15 benni ) {
408 b0a1b420 2023-05-15 benni struct bioc_inq bi;
409 b0a1b420 2023-05-15 benni int fd;
410 b0a1b420 2023-05-15 benni
411 b0a1b420 2023-05-15 benni fd = opendev (disk->name, O_RDONLY, OPENDEV_PART | OPENDEV_BLCK, NULL);
412 b0a1b420 2023-05-15 benni if (fd < 0) {
413 b0a1b420 2023-05-15 benni warn ("read_raid(): opendev(%s)", disk->name);
414 b0a1b420 2023-05-15 benni return;
415 b0a1b420 2023-05-15 benni }
416 b0a1b420 2023-05-15 benni
417 b0a1b420 2023-05-15 benni bzero (&bi, sizeof bi);
418 b0a1b420 2023-05-15 benni
419 b0a1b420 2023-05-15 benni if (ioctl (fd, BIOCINQ, &bi) == -1)
420 b0a1b420 2023-05-15 benni goto ret;
421 b0a1b420 2023-05-15 benni
422 1678d261 2023-05-15 benni for (int i = 0; i < bi.bi_novol; ++i) {
423 1678d261 2023-05-15 benni struct bioc_vol bv;
424 b0a1b420 2023-05-15 benni
425 1678d261 2023-05-15 benni bzero (&bv, sizeof bv);
426 1678d261 2023-05-15 benni memcpy (&bv.bv_bio, &bi.bi_bio, sizeof bi.bi_bio);
427 1678d261 2023-05-15 benni bv.bv_volid = i;
428 1678d261 2023-05-15 benni
429 1678d261 2023-05-15 benni if (ioctl (fd, BIOCVOL, &bv) == -1) {
430 1678d261 2023-05-15 benni warn ("read_raid(%s): BIOCVOL(%d)", disk->name, i);
431 b0a1b420 2023-05-15 benni continue;
432 b0a1b420 2023-05-15 benni }
433 b0a1b420 2023-05-15 benni
434 1678d261 2023-05-15 benni if (strcmp (disk->name, bv.bv_dev) != 0)
435 b0a1b420 2023-05-15 benni continue;
436 b0a1b420 2023-05-15 benni
437 1678d261 2023-05-15 benni disk->raidstatus = bv_statusstr (bv.bv_status);
438 1678d261 2023-05-15 benni
439 1678d261 2023-05-15 benni for (int j = 0; j < bv.bv_nodisk; ++j) {
440 1678d261 2023-05-15 benni struct bioc_disk bd;
441 1678d261 2023-05-15 benni size_t len_vendor;
442 1678d261 2023-05-15 benni char letter;
443 1678d261 2023-05-15 benni
444 1678d261 2023-05-15 benni bzero (&bd, sizeof bd);
445 1678d261 2023-05-15 benni memcpy (&bd.bd_bio, &bi.bi_bio, sizeof bi.bi_bio);
446 1678d261 2023-05-15 benni bd.bd_volid = i;
447 1678d261 2023-05-15 benni bd.bd_diskid = j;
448 1678d261 2023-05-15 benni
449 1678d261 2023-05-15 benni if (ioctl (fd, BIOCDISK, &bd) == -1) {
450 1678d261 2023-05-15 benni warn ("read_raid(%s): BIOCDISK(%d, %d)", disk->name, i, j);
451 1678d261 2023-05-15 benni continue;
452 1678d261 2023-05-15 benni }
453 1678d261 2023-05-15 benni
454 1678d261 2023-05-15 benni len_vendor = strlen (bd.bd_vendor);
455 1678d261 2023-05-15 benni if (len_vendor != 4) {
456 1678d261 2023-05-15 benni warnx ("read_raid(%s): unexpected vendor string: %.32s", disk->name, bd.bd_vendor);
457 1678d261 2023-05-15 benni continue;
458 1678d261 2023-05-15 benni }
459 1678d261 2023-05-15 benni letter = bd.bd_vendor[len_vendor - 1];
460 1678d261 2023-05-15 benni
461 1678d261 2023-05-15 benni for (size_t k = 0; k < num_disks; ++k) {
462 1678d261 2023-05-15 benni if (!memcmp (bd.bd_vendor, disks[k].name, 3)) {
463 1678d261 2023-05-15 benni for (size_t l = 0; l < disks[k].num_parts; ++l) {
464 1678d261 2023-05-15 benni if (letter == disks[k].parts[l].letter) {
465 1678d261 2023-05-15 benni disks[k].parts[l].sub = disk;
466 1678d261 2023-05-15 benni disks[k].parts[l].raidstatus = bd_statusstr(bd.bd_status);
467 1678d261 2023-05-15 benni goto found;
468 1678d261 2023-05-15 benni }
469 b0a1b420 2023-05-15 benni }
470 b0a1b420 2023-05-15 benni }
471 b0a1b420 2023-05-15 benni }
472 1678d261 2023-05-15 benni found:;
473 b0a1b420 2023-05-15 benni }
474 b0a1b420 2023-05-15 benni }
475 b0a1b420 2023-05-15 benni ret:
476 b0a1b420 2023-05-15 benni close (fd);
477 b0a1b420 2023-05-15 benni }
478 b0a1b420 2023-05-15 benni
479 9c5d8ecc 2023-05-02 benni static int usage (void)
480 9c5d8ecc 2023-05-02 benni {
481 1678d261 2023-05-15 benni fputs ("Usage: lsblk [-abinUuV] [disk...]\n", stderr);
482 9c5d8ecc 2023-05-02 benni return 1;
483 9c5d8ecc 2023-05-02 benni }
484 9c5d8ecc 2023-05-02 benni
485 33bf1ca4 2023-04-08 benni int main (int argc, char *argv[])
486 33bf1ca4 2023-04-08 benni {
487 8380cc51 2023-05-01 benni int option;
488 9c5d8ecc 2023-05-02 benni int fields = FIELD_DEFAULT;
489 0c961f7d 2023-05-04 benni int options = 0;
490 8380cc51 2023-05-01 benni
491 aff15c23 2023-04-30 benni if (unveil ("/dev", "r") == -1)
492 44121ddf 2023-05-05 benni err (1, "unveil(/dev)");
493 aff15c23 2023-04-30 benni
494 aff15c23 2023-04-30 benni if (unveil (NULL, NULL) == -1)
495 44121ddf 2023-05-05 benni err (1, "unveil()");
496 aff15c23 2023-04-30 benni
497 1678d261 2023-05-15 benni while ((option = getopt (argc, argv, ":abinUuV")) != -1) {
498 33bf1ca4 2023-04-08 benni switch (option) {
499 bf0e6461 2023-05-02 benni case 'a':
500 bf0e6461 2023-05-02 benni fields = -1;
501 8380cc51 2023-05-01 benni break;
502 1678d261 2023-05-15 benni case 'b':
503 1678d261 2023-05-15 benni options |= OPT_NOBIO;
504 1678d261 2023-05-15 benni break;
505 0c961f7d 2023-05-04 benni case 'i':
506 0c961f7d 2023-05-04 benni options |= OPT_NOUNICODE;
507 0c961f7d 2023-05-04 benni break;
508 bf0e6461 2023-05-02 benni case 'n':
509 0c961f7d 2023-05-04 benni options |= OPT_NOHEADER;
510 bf0e6461 2023-05-02 benni break;
511 1115ad3a 2023-05-05 benni case 'U':
512 1115ad3a 2023-05-05 benni fields |= FIELD_DUID;
513 1115ad3a 2023-05-05 benni break;
514 9c5d8ecc 2023-05-02 benni case 'u':
515 9c5d8ecc 2023-05-02 benni fields |= FIELD_USED | FIELD_FREE;
516 9c5d8ecc 2023-05-02 benni break;
517 1115ad3a 2023-05-05 benni case 'V':
518 1115ad3a 2023-05-05 benni puts ("lsblk-" VERSION);
519 1115ad3a 2023-05-05 benni return 0;
520 33bf1ca4 2023-04-08 benni default:
521 33bf1ca4 2023-04-08 benni return usage ();
522 33bf1ca4 2023-04-08 benni }
523 33bf1ca4 2023-04-08 benni }
524 33bf1ca4 2023-04-08 benni
525 5691dc7b 2023-05-05 benni argv += optind;
526 5691dc7b 2023-05-05 benni argc -= optind;
527 33bf1ca4 2023-04-08 benni
528 5691dc7b 2023-05-05 benni char *names = argc == 0 ? disknames () : NULL;
529 33bf1ca4 2023-04-08 benni
530 33bf1ca4 2023-04-08 benni if (pledge ("stdio rpath disklabel", NULL) == -1)
531 44121ddf 2023-05-05 benni err (1, "pledge()");
532 33bf1ca4 2023-04-08 benni
533 5691dc7b 2023-05-05 benni size_t cap_disks;
534 5691dc7b 2023-05-05 benni if (argc == 0) {
535 5691dc7b 2023-05-05 benni const char *s = names;
536 5691dc7b 2023-05-05 benni cap_disks = 0;
537 5691dc7b 2023-05-05 benni while ((s = strchr (s, ',')) != NULL)
538 5691dc7b 2023-05-05 benni ++cap_disks, ++s;
539 5691dc7b 2023-05-05 benni } else {
540 5691dc7b 2023-05-05 benni cap_disks = argc;
541 5691dc7b 2023-05-05 benni }
542 5691dc7b 2023-05-05 benni
543 9c5d8ecc 2023-05-02 benni struct my_diskinfo *disks = calloc (cap_disks, sizeof (struct my_diskinfo));
544 5691dc7b 2023-05-05 benni size_t num_disks = 0;
545 8380cc51 2023-05-01 benni
546 5691dc7b 2023-05-05 benni if (argc == 0) {
547 5691dc7b 2023-05-05 benni for (char *disk; (disk = strsep (&names, ",")) != NULL; ) {
548 5691dc7b 2023-05-05 benni char *colon = strchr (disk, ':');
549 5691dc7b 2023-05-05 benni if (colon)
550 5691dc7b 2023-05-05 benni *colon = '\0';
551 5691dc7b 2023-05-05 benni disks[num_disks++] = read_disk (disk);
552 5691dc7b 2023-05-05 benni if (colon)
553 5691dc7b 2023-05-05 benni *colon = ':';
554 33bf1ca4 2023-04-08 benni }
555 5691dc7b 2023-05-05 benni } else {
556 5691dc7b 2023-05-05 benni for (int i = 0; i < argc; ++i) {
557 5691dc7b 2023-05-05 benni char *disk = basename (argv[i]);
558 5691dc7b 2023-05-05 benni disks[num_disks++] = read_disk (disk);
559 5691dc7b 2023-05-05 benni }
560 33bf1ca4 2023-04-08 benni }
561 33bf1ca4 2023-04-08 benni
562 33bf1ca4 2023-04-08 benni free (names);
563 9c5d8ecc 2023-05-02 benni
564 1678d261 2023-05-15 benni if (!(options & OPT_NOBIO)) {
565 1678d261 2023-05-15 benni for (size_t i = 0; i < num_disks; ++i) {
566 1678d261 2023-05-15 benni read_raid (&disks[i], disks, num_disks);
567 1678d261 2023-05-15 benni }
568 b0a1b420 2023-05-15 benni }
569 b0a1b420 2023-05-15 benni
570 0c961f7d 2023-05-04 benni if (!(options & OPT_NOHEADER))
571 9c5d8ecc 2023-05-02 benni print_header (fields);
572 9c5d8ecc 2023-05-02 benni
573 9c5d8ecc 2023-05-02 benni for (size_t i = 0; i < num_disks; ++i) {
574 b0a1b420 2023-05-15 benni print_disk (&disks[i], fields, options, false);
575 9c5d8ecc 2023-05-02 benni }
576 5691dc7b 2023-05-05 benni
577 33bf1ca4 2023-04-08 benni return 0;
578 33bf1ca4 2023-04-08 benni }