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 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>
43 33bf1ca4 2023-04-08 benni
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 "│ └─"
50 da455e16 2023-09-01 benni
51 da455e16 2023-09-01 benni static const char *prefix0, *prefix1, *prefix2;
52 da455e16 2023-09-01 benni
53 33bf1ca4 2023-04-08 benni static int diskcount (void)
54 33bf1ca4 2023-04-08 benni {
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;
58 33bf1ca4 2023-04-08 benni
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)");
61 33bf1ca4 2023-04-08 benni
62 33bf1ca4 2023-04-08 benni return diskcount;
63 33bf1ca4 2023-04-08 benni }
64 33bf1ca4 2023-04-08 benni
65 33bf1ca4 2023-04-08 benni static char *disknames (void)
66 33bf1ca4 2023-04-08 benni {
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);
71 33bf1ca4 2023-04-08 benni
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)");
74 33bf1ca4 2023-04-08 benni
75 33bf1ca4 2023-04-08 benni return buffer;
76 33bf1ca4 2023-04-08 benni }
77 33bf1ca4 2023-04-08 benni
78 9c5d8ecc 2023-05-02 benni static char *stripdisk (char *n)
79 33bf1ca4 2023-04-08 benni {
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;
83 9c5d8ecc 2023-05-02 benni
84 2f06f21f 2023-06-08 benni if (memcmp (n + ln - ls, sufx, ls) == 0) {
85 9c5d8ecc 2023-05-02 benni n[ln - ls] = '\0';
86 9c5d8ecc 2023-05-02 benni }
87 9c5d8ecc 2023-05-02 benni
88 9c5d8ecc 2023-05-02 benni return n;
89 9c5d8ecc 2023-05-02 benni }
90 9c5d8ecc 2023-05-02 benni
91 9c5d8ecc 2023-05-02 benni static void print_size (uint64_t sz)
92 9c5d8ecc 2023-05-02 benni {
93 2f06f21f 2023-06-08 benni const struct unit {
94 33bf1ca4 2023-04-08 benni char sym;
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 },
103 33bf1ca4 2023-04-08 benni };
104 33bf1ca4 2023-04-08 benni
105 33bf1ca4 2023-04-08 benni char sym = 'B';
106 33bf1ca4 2023-04-08 benni uint64_t factor = 1;
107 33bf1ca4 2023-04-08 benni
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;
112 33bf1ca4 2023-04-08 benni break;
113 33bf1ca4 2023-04-08 benni }
114 33bf1ca4 2023-04-08 benni }
115 33bf1ca4 2023-04-08 benni
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);
122 33bf1ca4 2023-04-08 benni } else {
123 8a374bef 2023-04-08 benni printf ("%u.%u", scaled, scaled10 % 10);
124 33bf1ca4 2023-04-08 benni }
125 33bf1ca4 2023-04-08 benni
126 33bf1ca4 2023-04-08 benni putchar (sym);
127 9c5d8ecc 2023-05-02 benni putchar (' ');
128 33bf1ca4 2023-04-08 benni }
129 33bf1ca4 2023-04-08 benni
130 9c5d8ecc 2023-05-02 benni enum {
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,
138 9c5d8ecc 2023-05-02 benni
139 1678d261 2023-05-15 benni FIELD_DEFAULT = FIELD_NAME | FIELD_SIZE | FIELD_TYPE | FIELD_COMMENT,
140 9c5d8ecc 2023-05-02 benni };
141 9c5d8ecc 2023-05-02 benni
142 0c961f7d 2023-05-04 benni enum {
143 0c961f7d 2023-05-04 benni OPT_NOHEADER = 0x01,
144 da455e16 2023-09-01 benni OPT_NOBIO = 0x02,
145 0c961f7d 2023-05-04 benni };
146 0c961f7d 2023-05-04 benni
147 b0a1b420 2023-05-15 benni struct my_diskinfo;
148 b0a1b420 2023-05-15 benni
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)
158 9c5d8ecc 2023-05-02 benni };
159 9c5d8ecc 2023-05-02 benni
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
170 9c5d8ecc 2023-05-02 benni };
171 9c5d8ecc 2023-05-02 benni
172 7c38b724 2023-05-15 benni struct padding {
173 7c38b724 2023-05-15 benni int name;
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 */
178 7c38b724 2023-05-15 benni int type;
179 7c38b724 2023-05-15 benni int comment;
180 7c38b724 2023-05-15 benni };
181 7c38b724 2023-05-15 benni
182 7c38b724 2023-05-15 benni static void print_header (int fields, const struct padding *p)
183 33bf1ca4 2023-04-08 benni {
184 9c5d8ecc 2023-05-02 benni if (fields & FIELD_NAME)
185 7c38b724 2023-05-15 benni printf ("%-*s ", p->name, "NAME");
186 9c5d8ecc 2023-05-02 benni
187 1115ad3a 2023-05-05 benni if (fields & FIELD_DUID)
188 1115ad3a 2023-05-05 benni printf ("%-18s ", "DUID");
189 1115ad3a 2023-05-05 benni
190 9c5d8ecc 2023-05-02 benni if (fields & FIELD_SIZE)
191 9c5d8ecc 2023-05-02 benni printf ("%-4s ", "SIZE");
192 9c5d8ecc 2023-05-02 benni
193 9c5d8ecc 2023-05-02 benni if (fields & FIELD_USED)
194 9c5d8ecc 2023-05-02 benni printf ("%-4s ", "USED");
195 9c5d8ecc 2023-05-02 benni
196 9c5d8ecc 2023-05-02 benni if (fields & FIELD_FREE)
197 9c5d8ecc 2023-05-02 benni printf ("%-4s ", "FREE");
198 9c5d8ecc 2023-05-02 benni
199 9c5d8ecc 2023-05-02 benni if (fields & FIELD_TYPE)
200 7c38b724 2023-05-15 benni printf ("%-*s ", p->type, "TYPE");
201 9c5d8ecc 2023-05-02 benni
202 1678d261 2023-05-15 benni if (fields & FIELD_COMMENT)
203 7c38b724 2023-05-15 benni printf ("%-*s ", p->comment, "COMMENT");
204 9c5d8ecc 2023-05-02 benni
205 7c38b724 2023-05-15 benni #if WSDEBUG
206 7c38b724 2023-05-15 benni putchar ('X');
207 7c38b724 2023-05-15 benni #endif
208 7c38b724 2023-05-15 benni
209 9c5d8ecc 2023-05-02 benni putchar ('\n');
210 33bf1ca4 2023-04-08 benni }
211 33bf1ca4 2023-04-08 benni
212 1115ad3a 2023-05-05 benni static void print_duid (const u_char *duid)
213 3103dec4 2023-05-01 benni {
214 1115ad3a 2023-05-05 benni for (size_t i = 0; i < 8; ++i) {
215 1115ad3a 2023-05-05 benni printf ("%02x", duid[i]);
216 1115ad3a 2023-05-05 benni }
217 1115ad3a 2023-05-05 benni }
218 1115ad3a 2023-05-05 benni
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
227 1115ad3a 2023-05-05 benni ) {
228 0c961f7d 2023-05-04 benni if (fields & FIELD_NAME) {
229 da455e16 2023-09-01 benni const char *prefix = last ? prefix1 : prefix0;
230 7c38b724 2023-05-15 benni printf (
231 7c38b724 2023-05-15 benni "%s%s%c%-*s ",
232 7c38b724 2023-05-15 benni prefix,
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,
236 7c38b724 2023-05-15 benni ""
237 7c38b724 2023-05-15 benni );
238 0c961f7d 2023-05-04 benni }
239 3103dec4 2023-05-01 benni
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);
243 1115ad3a 2023-05-05 benni }
244 1115ad3a 2023-05-05 benni
245 9c5d8ecc 2023-05-02 benni if (fields & FIELD_SIZE)
246 9c5d8ecc 2023-05-02 benni print_size (part->size);
247 9c5d8ecc 2023-05-02 benni
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);
251 9c5d8ecc 2023-05-02 benni } else {
252 9c5d8ecc 2023-05-02 benni printf (" N/A ");
253 9c5d8ecc 2023-05-02 benni }
254 3103dec4 2023-05-01 benni }
255 3103dec4 2023-05-01 benni
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);
259 9c5d8ecc 2023-05-02 benni } else {
260 9c5d8ecc 2023-05-02 benni printf (" N/A ");
261 9c5d8ecc 2023-05-02 benni }
262 9c5d8ecc 2023-05-02 benni }
263 9c5d8ecc 2023-05-02 benni
264 9c5d8ecc 2023-05-02 benni if (fields & FIELD_TYPE)
265 7c38b724 2023-05-15 benni printf ("%-*s ", p->type, part->fstype);
266 9c5d8ecc 2023-05-02 benni
267 7c38b724 2023-05-15 benni if (fields & FIELD_COMMENT)
268 7c38b724 2023-05-15 benni printf ("%-*s ", p->comment, part->mount ? part->mount : "");
269 9c5d8ecc 2023-05-02 benni
270 7c38b724 2023-05-15 benni #if WSDEBUG
271 7c38b724 2023-05-15 benni putchar ('X');
272 7c38b724 2023-05-15 benni #endif
273 7c38b724 2023-05-15 benni
274 9c5d8ecc 2023-05-02 benni putchar ('\n');
275 b0a1b420 2023-05-15 benni
276 b0a1b420 2023-05-15 benni if (part->sub) {
277 7c38b724 2023-05-15 benni print_disk (part->sub, fields, options, part->raidstatus, p);
278 b0a1b420 2023-05-15 benni }
279 9c5d8ecc 2023-05-02 benni }
280 9c5d8ecc 2023-05-02 benni
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
287 7c38b724 2023-05-15 benni ) {
288 b0a1b420 2023-05-15 benni if (fields & FIELD_NAME) {
289 da455e16 2023-09-01 benni const char *prefix = raidstatus ? prefix2 : "";
290 7c38b724 2023-05-15 benni
291 7c38b724 2023-05-15 benni printf (
292 7c38b724 2023-05-15 benni "%s%-*s ",
293 7c38b724 2023-05-15 benni prefix,
294 7e6c6845 2023-05-15 benni p->name - (raidstatus ? 4 : 0),
295 7c38b724 2023-05-15 benni disk->name
296 7c38b724 2023-05-15 benni );
297 b0a1b420 2023-05-15 benni }
298 9c5d8ecc 2023-05-02 benni
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 (" ");
302 1115ad3a 2023-05-05 benni }
303 1115ad3a 2023-05-05 benni
304 9c5d8ecc 2023-05-02 benni if (fields & FIELD_SIZE)
305 9c5d8ecc 2023-05-02 benni print_size (disk->size);
306 9c5d8ecc 2023-05-02 benni
307 9c5d8ecc 2023-05-02 benni if (fields & FIELD_USED)
308 9c5d8ecc 2023-05-02 benni print_size (disk->used);
309 9c5d8ecc 2023-05-02 benni
310 9c5d8ecc 2023-05-02 benni if (fields & FIELD_FREE)
311 9c5d8ecc 2023-05-02 benni print_size (disk->size - disk->used);
312 9c5d8ecc 2023-05-02 benni
313 9c5d8ecc 2023-05-02 benni if (fields & FIELD_TYPE)
314 7c38b724 2023-05-15 benni printf ("%-*.16s ", p->type, disk->type);
315 9c5d8ecc 2023-05-02 benni
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) {
320 7c38b724 2023-05-15 benni printf (
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,
325 7c38b724 2023-05-15 benni ""
326 7c38b724 2023-05-15 benni );
327 1678d261 2023-05-15 benni } else {
328 7c38b724 2023-05-15 benni printf ("%-*.16s ", p->comment, disk->label);
329 1678d261 2023-05-15 benni }
330 1678d261 2023-05-15 benni }
331 9c5d8ecc 2023-05-02 benni
332 7c38b724 2023-05-15 benni #if WSDEBUG
333 7c38b724 2023-05-15 benni putchar ('X');
334 7c38b724 2023-05-15 benni #endif
335 7c38b724 2023-05-15 benni
336 9c5d8ecc 2023-05-02 benni putchar ('\n');
337 9c5d8ecc 2023-05-02 benni
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);
341 b0a1b420 2023-05-15 benni }
342 9c5d8ecc 2023-05-02 benni }
343 9c5d8ecc 2023-05-02 benni
344 9c5d8ecc 2023-05-02 benni static const struct statfs *find_mount (const char *dev)
345 9c5d8ecc 2023-05-02 benni {
346 9c5d8ecc 2023-05-02 benni static struct statfs *mounts = NULL;
347 9c5d8ecc 2023-05-02 benni static int n_mounts;
348 9c5d8ecc 2023-05-02 benni
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()");
353 9c5d8ecc 2023-05-02 benni }
354 9c5d8ecc 2023-05-02 benni
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];
358 9c5d8ecc 2023-05-02 benni }
359 9c5d8ecc 2023-05-02 benni
360 9c5d8ecc 2023-05-02 benni return NULL;
361 3103dec4 2023-05-01 benni }
362 3103dec4 2023-05-01 benni
363 a88ae11e 2023-05-30 benni static int read_disk (const char *name, struct my_diskinfo *disk)
364 9c5d8ecc 2023-05-02 benni {
365 9c5d8ecc 2023-05-02 benni struct disklabel label;
366 0c422a5b 2023-05-05 benni char *ppath, *letter;
367 9c5d8ecc 2023-05-02 benni
368 f977c8f4 2023-05-30 benni memset (disk, 0, sizeof *disk);
369 9c5d8ecc 2023-05-02 benni
370 9c5d8ecc 2023-05-02 benni { // Read disklabel.
371 0c422a5b 2023-05-05 benni size_t len;
372 9c5d8ecc 2023-05-02 benni int fd;
373 9c5d8ecc 2023-05-02 benni
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;
378 a88ae11e 2023-05-30 benni }
379 0c422a5b 2023-05-05 benni
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;
384 a88ae11e 2023-05-30 benni }
385 9c5d8ecc 2023-05-02 benni close (fd);
386 9c5d8ecc 2023-05-02 benni
387 0c422a5b 2023-05-05 benni len = strlen (ppath);
388 0c422a5b 2023-05-05 benni letter = ppath + len - 1;
389 0c422a5b 2023-05-05 benni }
390 5691dc7b 2023-05-05 benni
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;
398 9c5d8ecc 2023-05-02 benni
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;
403 9c5d8ecc 2023-05-02 benni
404 f977c8f4 2023-05-30 benni memset (&part, 0, sizeof part);
405 9c5d8ecc 2023-05-02 benni
406 9c5d8ecc 2023-05-02 benni part.size = DL_GETPSIZE (p) * label.d_secsize;
407 9c5d8ecc 2023-05-02 benni
408 9c5d8ecc 2023-05-02 benni if (!part.size)
409 9c5d8ecc 2023-05-02 benni continue;
410 9c5d8ecc 2023-05-02 benni
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);
414 9c5d8ecc 2023-05-02 benni
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;
420 9c5d8ecc 2023-05-02 benni }
421 9c5d8ecc 2023-05-02 benni
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;
426 9c5d8ecc 2023-05-02 benni }
427 9c5d8ecc 2023-05-02 benni
428 a88ae11e 2023-05-30 benni return 0;
429 9c5d8ecc 2023-05-02 benni }
430 9c5d8ecc 2023-05-02 benni
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";
442 1678d261 2023-05-15 benni }
443 1678d261 2023-05-15 benni }
444 1678d261 2023-05-15 benni
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";
455 1678d261 2023-05-15 benni }
456 1678d261 2023-05-15 benni }
457 1678d261 2023-05-15 benni
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
462 b0a1b420 2023-05-15 benni ) {
463 b0a1b420 2023-05-15 benni struct bioc_inq bi;
464 b0a1b420 2023-05-15 benni int fd;
465 b0a1b420 2023-05-15 benni
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);
469 b0a1b420 2023-05-15 benni return;
470 b0a1b420 2023-05-15 benni }
471 b0a1b420 2023-05-15 benni
472 f977c8f4 2023-05-30 benni memset (&bi, 0, sizeof bi);
473 b0a1b420 2023-05-15 benni
474 b0a1b420 2023-05-15 benni if (ioctl (fd, BIOCINQ, &bi) == -1)
475 b0a1b420 2023-05-15 benni goto ret;
476 b0a1b420 2023-05-15 benni
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;
479 b0a1b420 2023-05-15 benni
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;
483 1678d261 2023-05-15 benni
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);
486 b0a1b420 2023-05-15 benni continue;
487 b0a1b420 2023-05-15 benni }
488 b0a1b420 2023-05-15 benni
489 1678d261 2023-05-15 benni if (strcmp (disk->name, bv.bv_dev) != 0)
490 b0a1b420 2023-05-15 benni continue;
491 b0a1b420 2023-05-15 benni
492 1678d261 2023-05-15 benni disk->raidstatus = bv_statusstr (bv.bv_status);
493 1678d261 2023-05-15 benni
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;
498 1678d261 2023-05-15 benni
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;
503 1678d261 2023-05-15 benni
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);
506 1678d261 2023-05-15 benni continue;
507 1678d261 2023-05-15 benni }
508 1678d261 2023-05-15 benni
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);
512 1678d261 2023-05-15 benni continue;
513 1678d261 2023-05-15 benni }
514 1678d261 2023-05-15 benni letter = bd.bd_vendor[len_vendor - 1];
515 1678d261 2023-05-15 benni
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;
523 1678d261 2023-05-15 benni }
524 b0a1b420 2023-05-15 benni }
525 b0a1b420 2023-05-15 benni }
526 b0a1b420 2023-05-15 benni }
527 1678d261 2023-05-15 benni found:;
528 b0a1b420 2023-05-15 benni }
529 b0a1b420 2023-05-15 benni }
530 b0a1b420 2023-05-15 benni ret:
531 b0a1b420 2023-05-15 benni close (fd);
532 b0a1b420 2023-05-15 benni }
533 b0a1b420 2023-05-15 benni
534 9c5d8ecc 2023-05-02 benni static int usage (void)
535 9c5d8ecc 2023-05-02 benni {
536 1678d261 2023-05-15 benni fputs ("Usage: lsblk [-abinUuV] [disk...]\n", stderr);
537 9c5d8ecc 2023-05-02 benni return 1;
538 4d8e470c 2023-05-15 benni }
539 4d8e470c 2023-05-15 benni
540 7c38b724 2023-05-15 benni static void pad_update (int *pad, int newval)
541 7c38b724 2023-05-15 benni {
542 7c38b724 2023-05-15 benni if (newval > *pad)
543 7c38b724 2023-05-15 benni *pad = newval;
544 7c38b724 2023-05-15 benni }
545 7c38b724 2023-05-15 benni
546 7c38b724 2023-05-15 benni static void pad_disk (struct padding *p, const struct my_diskinfo *disk)
547 7c38b724 2023-05-15 benni {
548 7c38b724 2023-05-15 benni size_t len_disk;
549 7c38b724 2023-05-15 benni int comment;
550 7c38b724 2023-05-15 benni
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;
555 7c38b724 2023-05-15 benni
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);
559 7c38b724 2023-05-15 benni
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];
562 7c38b724 2023-05-15 benni
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));
565 7c38b724 2023-05-15 benni
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));
571 7c38b724 2023-05-15 benni }
572 7c38b724 2023-05-15 benni }
573 7c38b724 2023-05-15 benni }
574 7c38b724 2023-05-15 benni
575 7c38b724 2023-05-15 benni
576 4d8e470c 2023-05-15 benni static int compare_disk (const void *p1, const void *p2)
577 4d8e470c 2023-05-15 benni {
578 4d8e470c 2023-05-15 benni const struct my_diskinfo *d1 = p1;
579 4d8e470c 2023-05-15 benni const struct my_diskinfo *d2 = p2;
580 4d8e470c 2023-05-15 benni
581 4d8e470c 2023-05-15 benni return strcmp (d1->name, d2->name);
582 9c5d8ecc 2023-05-02 benni }
583 9c5d8ecc 2023-05-02 benni
584 33bf1ca4 2023-04-08 benni int main (int argc, char *argv[])
585 33bf1ca4 2023-04-08 benni {
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;
591 8380cc51 2023-05-01 benni
592 aff15c23 2023-04-30 benni if (unveil ("/dev", "r") == -1)
593 44121ddf 2023-05-05 benni err (1, "unveil(/dev)");
594 aff15c23 2023-04-30 benni
595 aff15c23 2023-04-30 benni if (unveil (NULL, NULL) == -1)
596 44121ddf 2023-05-05 benni err (1, "unveil()");
597 aff15c23 2023-04-30 benni
598 1678d261 2023-05-15 benni while ((option = getopt (argc, argv, ":abinUuV")) != -1) {
599 33bf1ca4 2023-04-08 benni switch (option) {
600 bf0e6461 2023-05-02 benni case 'a':
601 bf0e6461 2023-05-02 benni fields = -1;
602 8380cc51 2023-05-01 benni break;
603 1678d261 2023-05-15 benni case 'b':
604 1678d261 2023-05-15 benni options |= OPT_NOBIO;
605 1678d261 2023-05-15 benni break;
606 0c961f7d 2023-05-04 benni case 'i':
607 da455e16 2023-09-01 benni ascii = true;
608 0c961f7d 2023-05-04 benni break;
609 bf0e6461 2023-05-02 benni case 'n':
610 0c961f7d 2023-05-04 benni options |= OPT_NOHEADER;
611 bf0e6461 2023-05-02 benni break;
612 1115ad3a 2023-05-05 benni case 'U':
613 1115ad3a 2023-05-05 benni fields |= FIELD_DUID;
614 1115ad3a 2023-05-05 benni break;
615 9c5d8ecc 2023-05-02 benni case 'u':
616 9c5d8ecc 2023-05-02 benni fields |= FIELD_USED | FIELD_FREE;
617 9c5d8ecc 2023-05-02 benni break;
618 1115ad3a 2023-05-05 benni case 'V':
619 1115ad3a 2023-05-05 benni puts ("lsblk-" VERSION);
620 1115ad3a 2023-05-05 benni return 0;
621 33bf1ca4 2023-04-08 benni default:
622 33bf1ca4 2023-04-08 benni return usage ();
623 33bf1ca4 2023-04-08 benni }
624 33bf1ca4 2023-04-08 benni }
625 33bf1ca4 2023-04-08 benni
626 5691dc7b 2023-05-05 benni argv += optind;
627 5691dc7b 2023-05-05 benni argc -= optind;
628 33bf1ca4 2023-04-08 benni
629 5691dc7b 2023-05-05 benni char *names = argc == 0 ? disknames () : NULL;
630 33bf1ca4 2023-04-08 benni
631 33bf1ca4 2023-04-08 benni if (pledge ("stdio rpath disklabel", NULL) == -1)
632 44121ddf 2023-05-05 benni err (1, "pledge()");
633 33bf1ca4 2023-04-08 benni
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;
637 da455e16 2023-09-01 benni
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;
644 5691dc7b 2023-05-05 benni } else {
645 5691dc7b 2023-05-05 benni cap_disks = argc;
646 5691dc7b 2023-05-05 benni }
647 5691dc7b 2023-05-05 benni
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;
650 8380cc51 2023-05-01 benni
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;
655 a88ae11e 2023-05-30 benni
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;
660 14fd8749 2023-05-30 benni } else {
661 14fd8749 2023-05-30 benni ret = 1;
662 a88ae11e 2023-05-30 benni }
663 a88ae11e 2023-05-30 benni
664 5691dc7b 2023-05-05 benni if (colon)
665 5691dc7b 2023-05-05 benni *colon = ':';
666 33bf1ca4 2023-04-08 benni }
667 5691dc7b 2023-05-05 benni } else {
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;
672 a88ae11e 2023-05-30 benni
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';
676 185836d0 2023-05-15 benni }
677 a88ae11e 2023-05-30 benni if (read_disk (name, &disk) == 0) {
678 a88ae11e 2023-05-30 benni disks[num_disks++] = disk;
679 14fd8749 2023-05-30 benni } else {
680 14fd8749 2023-05-30 benni ret = 1;
681 a88ae11e 2023-05-30 benni }
682 5691dc7b 2023-05-05 benni }
683 33bf1ca4 2023-04-08 benni }
684 33bf1ca4 2023-04-08 benni
685 33bf1ca4 2023-04-08 benni free (names);
686 9c5d8ecc 2023-05-02 benni
687 14fd8749 2023-05-30 benni if (num_disks == 0)
688 14fd8749 2023-05-30 benni return ret;
689 14fd8749 2023-05-30 benni
690 4d8e470c 2023-05-15 benni mergesort (disks, num_disks, sizeof *disks, compare_disk);
691 4d8e470c 2023-05-15 benni
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);
695 1678d261 2023-05-15 benni }
696 b0a1b420 2023-05-15 benni }
697 b0a1b420 2023-05-15 benni
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"),
702 7c38b724 2023-05-15 benni };
703 7c38b724 2023-05-15 benni
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]);
706 7c38b724 2023-05-15 benni
707 0c961f7d 2023-05-04 benni if (!(options & OPT_NOHEADER))
708 7c38b724 2023-05-15 benni print_header (fields, &p);
709 9c5d8ecc 2023-05-02 benni
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);
712 9c5d8ecc 2023-05-02 benni }
713 5691dc7b 2023-05-05 benni
714 14fd8749 2023-05-30 benni return ret;
715 33bf1ca4 2023-04-08 benni }
716 da455e16 2023-09-01 benni
717 da455e16 2023-09-01 benni /* vim: set tabstop=4 shiftwidth=4 expandtab: */