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