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 9c5d8ecc 2023-05-02 benni #include <sys/cdefs.h>
21 33bf1ca4 2023-04-08 benni #include <sys/types.h>
22 33bf1ca4 2023-04-08 benni #include <sys/disklabel.h>
23 33bf1ca4 2023-04-08 benni #include <sys/sysctl.h>
24 33bf1ca4 2023-04-08 benni #include <sys/ioctl.h>
25 33bf1ca4 2023-04-08 benni #include <sys/mount.h>
26 33bf1ca4 2023-04-08 benni #include <sys/dkio.h>
27 33bf1ca4 2023-04-08 benni #include <inttypes.h>
28 8380cc51 2023-05-01 benni #include <stdbool.h>
29 33bf1ca4 2023-04-08 benni #include <string.h>
30 33bf1ca4 2023-04-08 benni #include <stdarg.h>
31 33bf1ca4 2023-04-08 benni #include <stdint.h>
32 33bf1ca4 2023-04-08 benni #include <stdlib.h>
33 33bf1ca4 2023-04-08 benni #include <unistd.h>
34 5691dc7b 2023-05-05 benni #include <libgen.h>
35 33bf1ca4 2023-04-08 benni #include <stdio.h>
36 33bf1ca4 2023-04-08 benni #include <fcntl.h>
37 33bf1ca4 2023-04-08 benni #include <errno.h>
38 33bf1ca4 2023-04-08 benni
39 9c5d8ecc 2023-05-02 benni static __dead void die (const char *fmt, ...)
40 33bf1ca4 2023-04-08 benni {
41 33bf1ca4 2023-04-08 benni va_list ap;
42 33bf1ca4 2023-04-08 benni
43 33bf1ca4 2023-04-08 benni va_start (ap, fmt);
44 33bf1ca4 2023-04-08 benni fputs ("Error: ", stderr);
45 33bf1ca4 2023-04-08 benni vfprintf (stderr, fmt, ap);
46 33bf1ca4 2023-04-08 benni
47 33bf1ca4 2023-04-08 benni if (errno != 0) {
48 33bf1ca4 2023-04-08 benni fprintf (stderr, ": %s\n", strerror (errno));
49 33bf1ca4 2023-04-08 benni } else {
50 33bf1ca4 2023-04-08 benni fputc ('\n', stderr);
51 33bf1ca4 2023-04-08 benni }
52 33bf1ca4 2023-04-08 benni
53 33bf1ca4 2023-04-08 benni exit (1);
54 33bf1ca4 2023-04-08 benni }
55 33bf1ca4 2023-04-08 benni
56 33bf1ca4 2023-04-08 benni static int diskcount (void)
57 33bf1ca4 2023-04-08 benni {
58 33bf1ca4 2023-04-08 benni const int mib[2] = { CTL_HW, HW_DISKCOUNT };
59 33bf1ca4 2023-04-08 benni int diskcount;
60 33bf1ca4 2023-04-08 benni size_t len = sizeof diskcount;
61 33bf1ca4 2023-04-08 benni
62 33bf1ca4 2023-04-08 benni if (sysctl (mib, 2, &diskcount, &len, NULL, 0) == -1)
63 33bf1ca4 2023-04-08 benni die ("sysctl(hw.diskcount)");
64 33bf1ca4 2023-04-08 benni
65 33bf1ca4 2023-04-08 benni return diskcount;
66 33bf1ca4 2023-04-08 benni }
67 33bf1ca4 2023-04-08 benni
68 33bf1ca4 2023-04-08 benni static char *disknames (void)
69 33bf1ca4 2023-04-08 benni {
70 33bf1ca4 2023-04-08 benni const int num = diskcount ();
71 33bf1ca4 2023-04-08 benni const int mib[2] = { CTL_HW, HW_DISKNAMES };
72 33bf1ca4 2023-04-08 benni size_t len = 32 * num;
73 33bf1ca4 2023-04-08 benni char *buffer = malloc (len);
74 33bf1ca4 2023-04-08 benni
75 33bf1ca4 2023-04-08 benni if (sysctl (mib, 2, buffer, &len, NULL, 0) == -1)
76 33bf1ca4 2023-04-08 benni die ("sysctl(hw.disknames)");
77 33bf1ca4 2023-04-08 benni
78 33bf1ca4 2023-04-08 benni return buffer;
79 33bf1ca4 2023-04-08 benni }
80 33bf1ca4 2023-04-08 benni
81 9c5d8ecc 2023-05-02 benni static char *stripdisk (char *n)
82 33bf1ca4 2023-04-08 benni {
83 9c5d8ecc 2023-05-02 benni const char sufx[] = " disk";
84 9c5d8ecc 2023-05-02 benni const size_t ln = strnlen (n, 16);
85 9c5d8ecc 2023-05-02 benni const size_t ls = sizeof sufx - 1;
86 9c5d8ecc 2023-05-02 benni
87 9c5d8ecc 2023-05-02 benni if (!memcmp (n + ln - ls, sufx, ls)) {
88 9c5d8ecc 2023-05-02 benni n[ln - ls] = '\0';
89 9c5d8ecc 2023-05-02 benni }
90 9c5d8ecc 2023-05-02 benni
91 9c5d8ecc 2023-05-02 benni return n;
92 9c5d8ecc 2023-05-02 benni }
93 9c5d8ecc 2023-05-02 benni
94 9c5d8ecc 2023-05-02 benni static void print_size (uint64_t sz)
95 9c5d8ecc 2023-05-02 benni {
96 33bf1ca4 2023-04-08 benni struct unit {
97 33bf1ca4 2023-04-08 benni char sym;
98 33bf1ca4 2023-04-08 benni uint64_t factor;
99 33bf1ca4 2023-04-08 benni };
100 33bf1ca4 2023-04-08 benni
101 33bf1ca4 2023-04-08 benni const struct unit units[] = {
102 33bf1ca4 2023-04-08 benni { 'P', 1ull << 50 },
103 33bf1ca4 2023-04-08 benni { 'T', 1ull << 40 },
104 33bf1ca4 2023-04-08 benni { 'G', 1ull << 30 },
105 33bf1ca4 2023-04-08 benni { 'M', 1ull << 20 },
106 33bf1ca4 2023-04-08 benni { 'K', 1ull << 10 },
107 33bf1ca4 2023-04-08 benni { '0', 0 },
108 33bf1ca4 2023-04-08 benni };
109 33bf1ca4 2023-04-08 benni
110 33bf1ca4 2023-04-08 benni char sym = 'B';
111 33bf1ca4 2023-04-08 benni uint64_t factor = 1;
112 33bf1ca4 2023-04-08 benni
113 33bf1ca4 2023-04-08 benni for (const struct unit *u = &units[0]; u->factor; ++u) {
114 33bf1ca4 2023-04-08 benni if (sz >= (u->factor * 9 / 10)) {
115 33bf1ca4 2023-04-08 benni sym = u->sym;
116 33bf1ca4 2023-04-08 benni factor = u->factor;
117 33bf1ca4 2023-04-08 benni break;
118 33bf1ca4 2023-04-08 benni }
119 33bf1ca4 2023-04-08 benni }
120 33bf1ca4 2023-04-08 benni
121 33bf1ca4 2023-04-08 benni const unsigned scaled10 = sz * 10 / factor;
122 33bf1ca4 2023-04-08 benni const unsigned scaled = sz / factor;
123 33bf1ca4 2023-04-08 benni if (scaled10 >= 1000) {
124 8a374bef 2023-04-08 benni printf ("%u", scaled);
125 33bf1ca4 2023-04-08 benni } else if (scaled10 >= 100) {
126 8a374bef 2023-04-08 benni printf (" %u", scaled);
127 33bf1ca4 2023-04-08 benni } else {
128 8a374bef 2023-04-08 benni printf ("%u.%u", scaled, scaled10 % 10);
129 33bf1ca4 2023-04-08 benni }
130 33bf1ca4 2023-04-08 benni
131 33bf1ca4 2023-04-08 benni putchar (sym);
132 9c5d8ecc 2023-05-02 benni putchar (' ');
133 33bf1ca4 2023-04-08 benni }
134 33bf1ca4 2023-04-08 benni
135 9c5d8ecc 2023-05-02 benni enum {
136 0c961f7d 2023-05-04 benni FIELD_NAME = 0x01,
137 0c961f7d 2023-05-04 benni FIELD_SIZE = 0x02,
138 0c961f7d 2023-05-04 benni FIELD_USED = 0x04,
139 0c961f7d 2023-05-04 benni FIELD_FREE = 0x08,
140 0c961f7d 2023-05-04 benni FIELD_TYPE = 0x10,
141 0c961f7d 2023-05-04 benni FIELD_LMNT = 0x20,
142 9c5d8ecc 2023-05-02 benni
143 2b650bba 2023-05-04 benni FIELD_DEFAULT = FIELD_NAME | FIELD_SIZE | FIELD_TYPE | FIELD_LMNT,
144 9c5d8ecc 2023-05-02 benni };
145 9c5d8ecc 2023-05-02 benni
146 0c961f7d 2023-05-04 benni enum {
147 0c961f7d 2023-05-04 benni OPT_NOHEADER = 0x01,
148 0c961f7d 2023-05-04 benni OPT_NOUNICODE = 0x02,
149 0c961f7d 2023-05-04 benni };
150 0c961f7d 2023-05-04 benni
151 9c5d8ecc 2023-05-02 benni struct my_partinfo {
152 9c5d8ecc 2023-05-02 benni char name[5];
153 9c5d8ecc 2023-05-02 benni uint64_t size;
154 9c5d8ecc 2023-05-02 benni uint64_t fssize;
155 9c5d8ecc 2023-05-02 benni uint64_t free;
156 9c5d8ecc 2023-05-02 benni const char *fstype;
157 9c5d8ecc 2023-05-02 benni const char *mount;
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 9c5d8ecc 2023-05-02 benni char name[4];
164 9c5d8ecc 2023-05-02 benni uint64_t size;
165 9c5d8ecc 2023-05-02 benni uint64_t used;
166 9c5d8ecc 2023-05-02 benni uint8_t num_parts;
167 9c5d8ecc 2023-05-02 benni struct my_partinfo parts[MAXPARTITIONS];
168 9c5d8ecc 2023-05-02 benni };
169 9c5d8ecc 2023-05-02 benni
170 9c5d8ecc 2023-05-02 benni static void print_header (int fields)
171 33bf1ca4 2023-04-08 benni {
172 9c5d8ecc 2023-05-02 benni if (fields & FIELD_NAME)
173 9c5d8ecc 2023-05-02 benni printf ("%-6s ", "NAME");
174 9c5d8ecc 2023-05-02 benni
175 9c5d8ecc 2023-05-02 benni if (fields & FIELD_SIZE)
176 9c5d8ecc 2023-05-02 benni printf ("%-4s ", "SIZE");
177 9c5d8ecc 2023-05-02 benni
178 9c5d8ecc 2023-05-02 benni if (fields & FIELD_USED)
179 9c5d8ecc 2023-05-02 benni printf ("%-4s ", "USED");
180 9c5d8ecc 2023-05-02 benni
181 9c5d8ecc 2023-05-02 benni if (fields & FIELD_FREE)
182 9c5d8ecc 2023-05-02 benni printf ("%-4s ", "FREE");
183 9c5d8ecc 2023-05-02 benni
184 9c5d8ecc 2023-05-02 benni if (fields & FIELD_TYPE)
185 9c5d8ecc 2023-05-02 benni printf ("%-8s ", "TYPE");
186 9c5d8ecc 2023-05-02 benni
187 2b650bba 2023-05-04 benni if (fields & FIELD_LMNT)
188 2b650bba 2023-05-04 benni printf ("LABEL/MOUNT ");
189 9c5d8ecc 2023-05-02 benni
190 9c5d8ecc 2023-05-02 benni putchar ('\n');
191 33bf1ca4 2023-04-08 benni }
192 33bf1ca4 2023-04-08 benni
193 0c961f7d 2023-05-04 benni static void print_part (const struct my_partinfo *part, int fields, int options, bool last)
194 3103dec4 2023-05-01 benni {
195 0c961f7d 2023-05-04 benni if (fields & FIELD_NAME) {
196 0c961f7d 2023-05-04 benni const char *prefix = (options & OPT_NOUNICODE) ? " " : (last ? "└─" : "├─");
197 0c961f7d 2023-05-04 benni printf ("%s%s ", prefix, part->name);
198 0c961f7d 2023-05-04 benni }
199 3103dec4 2023-05-01 benni
200 9c5d8ecc 2023-05-02 benni if (fields & FIELD_SIZE)
201 9c5d8ecc 2023-05-02 benni print_size (part->size);
202 9c5d8ecc 2023-05-02 benni
203 9c5d8ecc 2023-05-02 benni if (fields & FIELD_USED) {
204 9c5d8ecc 2023-05-02 benni if (part->fssize) {
205 9c5d8ecc 2023-05-02 benni print_size (part->fssize - part->free);
206 9c5d8ecc 2023-05-02 benni } else {
207 9c5d8ecc 2023-05-02 benni printf (" N/A ");
208 9c5d8ecc 2023-05-02 benni }
209 3103dec4 2023-05-01 benni }
210 3103dec4 2023-05-01 benni
211 9c5d8ecc 2023-05-02 benni if (fields & FIELD_FREE) {
212 9c5d8ecc 2023-05-02 benni if (part->fssize) {
213 9c5d8ecc 2023-05-02 benni print_size (part->free);
214 9c5d8ecc 2023-05-02 benni } else {
215 9c5d8ecc 2023-05-02 benni printf (" N/A ");
216 9c5d8ecc 2023-05-02 benni }
217 9c5d8ecc 2023-05-02 benni }
218 9c5d8ecc 2023-05-02 benni
219 9c5d8ecc 2023-05-02 benni if (fields & FIELD_TYPE)
220 9c5d8ecc 2023-05-02 benni printf ("%-8.16s ", part->fstype);
221 9c5d8ecc 2023-05-02 benni
222 2b650bba 2023-05-04 benni if (fields & FIELD_LMNT && part->mount)
223 9c5d8ecc 2023-05-02 benni printf ("%s ", part->mount);
224 9c5d8ecc 2023-05-02 benni
225 9c5d8ecc 2023-05-02 benni putchar ('\n');
226 9c5d8ecc 2023-05-02 benni }
227 9c5d8ecc 2023-05-02 benni
228 0c961f7d 2023-05-04 benni static void print_disk (const struct my_diskinfo *disk, int fields, int options)
229 9c5d8ecc 2023-05-02 benni {
230 9c5d8ecc 2023-05-02 benni if (fields & FIELD_NAME)
231 9c5d8ecc 2023-05-02 benni printf ("%s ", disk->name);
232 9c5d8ecc 2023-05-02 benni
233 9c5d8ecc 2023-05-02 benni if (fields & FIELD_SIZE)
234 9c5d8ecc 2023-05-02 benni print_size (disk->size);
235 9c5d8ecc 2023-05-02 benni
236 9c5d8ecc 2023-05-02 benni if (fields & FIELD_USED)
237 9c5d8ecc 2023-05-02 benni print_size (disk->used);
238 9c5d8ecc 2023-05-02 benni
239 9c5d8ecc 2023-05-02 benni if (fields & FIELD_FREE)
240 9c5d8ecc 2023-05-02 benni print_size (disk->size - disk->used);
241 9c5d8ecc 2023-05-02 benni
242 9c5d8ecc 2023-05-02 benni // Pad only upto 8 characters because most disk types are <=8 bytes long.
243 9c5d8ecc 2023-05-02 benni if (fields & FIELD_TYPE)
244 9c5d8ecc 2023-05-02 benni printf ("%-8.16s ", disk->type);
245 9c5d8ecc 2023-05-02 benni
246 2b650bba 2023-05-04 benni if (fields & FIELD_LMNT)
247 2b650bba 2023-05-04 benni printf ("%.16s ", disk->label);
248 9c5d8ecc 2023-05-02 benni
249 9c5d8ecc 2023-05-02 benni putchar ('\n');
250 9c5d8ecc 2023-05-02 benni
251 9c5d8ecc 2023-05-02 benni for (uint8_t i = 0; i < disk->num_parts; ++i)
252 0c961f7d 2023-05-04 benni print_part (&disk->parts[i], fields, options, i == (disk->num_parts - 1));
253 9c5d8ecc 2023-05-02 benni }
254 9c5d8ecc 2023-05-02 benni
255 9c5d8ecc 2023-05-02 benni static const struct statfs *find_mount (const char *dev)
256 9c5d8ecc 2023-05-02 benni {
257 9c5d8ecc 2023-05-02 benni static struct statfs *mounts = NULL;
258 9c5d8ecc 2023-05-02 benni static int n_mounts;
259 9c5d8ecc 2023-05-02 benni
260 9c5d8ecc 2023-05-02 benni if (!mounts) {
261 9c5d8ecc 2023-05-02 benni n_mounts = getmntinfo (&mounts, MNT_NOWAIT);
262 9c5d8ecc 2023-05-02 benni if (n_mounts == 0)
263 9c5d8ecc 2023-05-02 benni die ("getmntinfo()");
264 9c5d8ecc 2023-05-02 benni }
265 9c5d8ecc 2023-05-02 benni
266 9c5d8ecc 2023-05-02 benni for (int i = 0; i < n_mounts; ++i) {
267 9c5d8ecc 2023-05-02 benni if (!strcmp (dev, mounts[i].f_mntfromname))
268 9c5d8ecc 2023-05-02 benni return &mounts[i];
269 9c5d8ecc 2023-05-02 benni }
270 9c5d8ecc 2023-05-02 benni
271 9c5d8ecc 2023-05-02 benni return NULL;
272 3103dec4 2023-05-01 benni }
273 3103dec4 2023-05-01 benni
274 9c5d8ecc 2023-05-02 benni static struct my_diskinfo read_disk (const char *name)
275 9c5d8ecc 2023-05-02 benni {
276 9c5d8ecc 2023-05-02 benni struct my_diskinfo disk;
277 9c5d8ecc 2023-05-02 benni struct disklabel label;
278 9c5d8ecc 2023-05-02 benni
279 9c5d8ecc 2023-05-02 benni bzero (&disk, sizeof disk);
280 9c5d8ecc 2023-05-02 benni
281 9c5d8ecc 2023-05-02 benni { // Read disklabel.
282 5691dc7b 2023-05-05 benni char *path = NULL;
283 9c5d8ecc 2023-05-02 benni int fd;
284 9c5d8ecc 2023-05-02 benni
285 5691dc7b 2023-05-05 benni asprintf (&path, "/dev/%sc", name);
286 9c5d8ecc 2023-05-02 benni fd = open (path, O_RDONLY);
287 9c5d8ecc 2023-05-02 benni if (fd < 0)
288 9c5d8ecc 2023-05-02 benni die ("open(%s)", path);
289 9c5d8ecc 2023-05-02 benni if (ioctl (fd, DIOCGDINFO, &label) < 0)
290 9c5d8ecc 2023-05-02 benni die ("ioctl(%s, DIOCGDINFO)", path);
291 9c5d8ecc 2023-05-02 benni close (fd);
292 5691dc7b 2023-05-05 benni free (path);
293 9c5d8ecc 2023-05-02 benni }
294 9c5d8ecc 2023-05-02 benni
295 5691dc7b 2023-05-05 benni
296 9c5d8ecc 2023-05-02 benni memcpy (disk.name, name, 3);
297 9c5d8ecc 2023-05-02 benni disk.name[3] = '\0';
298 9c5d8ecc 2023-05-02 benni disk.size = DL_GETDSIZE (&label) * label.d_secsize;
299 9c5d8ecc 2023-05-02 benni memcpy (disk.type, label.d_typename, 16);
300 9c5d8ecc 2023-05-02 benni stripdisk (disk.type);
301 9c5d8ecc 2023-05-02 benni memcpy (disk.label, label.d_packname, 16);
302 9c5d8ecc 2023-05-02 benni disk.num_parts = 0;
303 9c5d8ecc 2023-05-02 benni
304 9c5d8ecc 2023-05-02 benni for (uint16_t i = 0; i < label.d_npartitions; ++i) {
305 9c5d8ecc 2023-05-02 benni const struct partition *p = &label.d_partitions[i];
306 9c5d8ecc 2023-05-02 benni const struct statfs *mnt;
307 9c5d8ecc 2023-05-02 benni struct my_partinfo part;
308 9c5d8ecc 2023-05-02 benni char path[5 + 4 + 1];
309 9c5d8ecc 2023-05-02 benni
310 9c5d8ecc 2023-05-02 benni bzero (&part, sizeof part);
311 9c5d8ecc 2023-05-02 benni
312 9c5d8ecc 2023-05-02 benni part.size = DL_GETPSIZE (p) * label.d_secsize;
313 9c5d8ecc 2023-05-02 benni
314 9c5d8ecc 2023-05-02 benni if (!part.size)
315 9c5d8ecc 2023-05-02 benni continue;
316 9c5d8ecc 2023-05-02 benni
317 9c5d8ecc 2023-05-02 benni memcpy (part.name, disk.name, 3);
318 9c5d8ecc 2023-05-02 benni part.name[3] = 'a' + i;
319 9c5d8ecc 2023-05-02 benni part.name[4] = '\0';
320 9c5d8ecc 2023-05-02 benni
321 9c5d8ecc 2023-05-02 benni snprintf (path, sizeof path, "/dev/%s", part.name);
322 9c5d8ecc 2023-05-02 benni mnt = find_mount (path);
323 9c5d8ecc 2023-05-02 benni
324 9c5d8ecc 2023-05-02 benni if (mnt) {
325 9c5d8ecc 2023-05-02 benni const uint64_t bs = mnt->f_bsize;
326 9c5d8ecc 2023-05-02 benni part.mount = mnt->f_mntonname;
327 9c5d8ecc 2023-05-02 benni part.fssize = mnt->f_blocks * bs;
328 9c5d8ecc 2023-05-02 benni part.free = mnt->f_bfree * bs;
329 9c5d8ecc 2023-05-02 benni }
330 9c5d8ecc 2023-05-02 benni
331 9c5d8ecc 2023-05-02 benni part.fstype = fstypenames[p->p_fstype];
332 9c5d8ecc 2023-05-02 benni if (i != 2)
333 9c5d8ecc 2023-05-02 benni disk.used += part.size;
334 9c5d8ecc 2023-05-02 benni disk.parts[disk.num_parts++] = part;
335 9c5d8ecc 2023-05-02 benni }
336 9c5d8ecc 2023-05-02 benni
337 9c5d8ecc 2023-05-02 benni return disk;
338 9c5d8ecc 2023-05-02 benni }
339 9c5d8ecc 2023-05-02 benni
340 9c5d8ecc 2023-05-02 benni static int usage (void)
341 9c5d8ecc 2023-05-02 benni {
342 5691dc7b 2023-05-05 benni fputs ("Usage: lsblk [-Vainu] [disk...]\n", stderr);
343 9c5d8ecc 2023-05-02 benni return 1;
344 9c5d8ecc 2023-05-02 benni }
345 9c5d8ecc 2023-05-02 benni
346 33bf1ca4 2023-04-08 benni int main (int argc, char *argv[])
347 33bf1ca4 2023-04-08 benni {
348 8380cc51 2023-05-01 benni int option;
349 9c5d8ecc 2023-05-02 benni int fields = FIELD_DEFAULT;
350 0c961f7d 2023-05-04 benni int options = 0;
351 8380cc51 2023-05-01 benni
352 aff15c23 2023-04-30 benni if (unveil ("/dev", "r") == -1)
353 aff15c23 2023-04-30 benni die ("unveil(/dev)");
354 aff15c23 2023-04-30 benni
355 aff15c23 2023-04-30 benni if (unveil (NULL, NULL) == -1)
356 aff15c23 2023-04-30 benni die ("unveil()");
357 aff15c23 2023-04-30 benni
358 0c961f7d 2023-05-04 benni while ((option = getopt (argc, argv, ":Vainu")) != -1) {
359 33bf1ca4 2023-04-08 benni switch (option) {
360 33bf1ca4 2023-04-08 benni case 'V':
361 33bf1ca4 2023-04-08 benni puts ("lsblk-" VERSION);
362 33bf1ca4 2023-04-08 benni return 0;
363 bf0e6461 2023-05-02 benni case 'a':
364 bf0e6461 2023-05-02 benni fields = -1;
365 8380cc51 2023-05-01 benni break;
366 0c961f7d 2023-05-04 benni case 'i':
367 0c961f7d 2023-05-04 benni options |= OPT_NOUNICODE;
368 0c961f7d 2023-05-04 benni break;
369 bf0e6461 2023-05-02 benni case 'n':
370 0c961f7d 2023-05-04 benni options |= OPT_NOHEADER;
371 bf0e6461 2023-05-02 benni break;
372 9c5d8ecc 2023-05-02 benni case 'u':
373 9c5d8ecc 2023-05-02 benni fields |= FIELD_USED | FIELD_FREE;
374 9c5d8ecc 2023-05-02 benni break;
375 33bf1ca4 2023-04-08 benni default:
376 33bf1ca4 2023-04-08 benni return usage ();
377 33bf1ca4 2023-04-08 benni }
378 33bf1ca4 2023-04-08 benni }
379 33bf1ca4 2023-04-08 benni
380 5691dc7b 2023-05-05 benni argv += optind;
381 5691dc7b 2023-05-05 benni argc -= optind;
382 33bf1ca4 2023-04-08 benni
383 5691dc7b 2023-05-05 benni char *names = argc == 0 ? disknames () : NULL;
384 33bf1ca4 2023-04-08 benni
385 33bf1ca4 2023-04-08 benni if (pledge ("stdio rpath disklabel", NULL) == -1)
386 33bf1ca4 2023-04-08 benni die ("pledge()");
387 33bf1ca4 2023-04-08 benni
388 5691dc7b 2023-05-05 benni size_t cap_disks;
389 5691dc7b 2023-05-05 benni if (argc == 0) {
390 5691dc7b 2023-05-05 benni const char *s = names;
391 5691dc7b 2023-05-05 benni cap_disks = 0;
392 5691dc7b 2023-05-05 benni while ((s = strchr (s, ',')) != NULL)
393 5691dc7b 2023-05-05 benni ++cap_disks, ++s;
394 5691dc7b 2023-05-05 benni } else {
395 5691dc7b 2023-05-05 benni cap_disks = argc;
396 5691dc7b 2023-05-05 benni }
397 5691dc7b 2023-05-05 benni
398 9c5d8ecc 2023-05-02 benni struct my_diskinfo *disks = calloc (cap_disks, sizeof (struct my_diskinfo));
399 5691dc7b 2023-05-05 benni size_t num_disks = 0;
400 8380cc51 2023-05-01 benni
401 5691dc7b 2023-05-05 benni if (argc == 0) {
402 5691dc7b 2023-05-05 benni for (char *disk; (disk = strsep (&names, ",")) != NULL; ) {
403 5691dc7b 2023-05-05 benni char *colon = strchr (disk, ':');
404 5691dc7b 2023-05-05 benni if (colon)
405 5691dc7b 2023-05-05 benni *colon = '\0';
406 5691dc7b 2023-05-05 benni disks[num_disks++] = read_disk (disk);
407 5691dc7b 2023-05-05 benni if (colon)
408 5691dc7b 2023-05-05 benni *colon = ':';
409 33bf1ca4 2023-04-08 benni }
410 5691dc7b 2023-05-05 benni } else {
411 5691dc7b 2023-05-05 benni for (int i = 0; i < argc; ++i) {
412 5691dc7b 2023-05-05 benni char *disk = basename (argv[i]);
413 5691dc7b 2023-05-05 benni disks[num_disks++] = read_disk (disk);
414 5691dc7b 2023-05-05 benni }
415 33bf1ca4 2023-04-08 benni }
416 33bf1ca4 2023-04-08 benni
417 33bf1ca4 2023-04-08 benni free (names);
418 9c5d8ecc 2023-05-02 benni
419 0c961f7d 2023-05-04 benni if (!(options & OPT_NOHEADER))
420 9c5d8ecc 2023-05-02 benni print_header (fields);
421 9c5d8ecc 2023-05-02 benni
422 9c5d8ecc 2023-05-02 benni for (size_t i = 0; i < num_disks; ++i) {
423 0c961f7d 2023-05-04 benni print_disk (&disks[i], fields, options);
424 9c5d8ecc 2023-05-02 benni }
425 5691dc7b 2023-05-05 benni
426 33bf1ca4 2023-04-08 benni return 0;
427 33bf1ca4 2023-04-08 benni }