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 33bf1ca4 2023-04-08 benni #include <sys/types.h>
21 33bf1ca4 2023-04-08 benni #include <sys/disklabel.h>
22 33bf1ca4 2023-04-08 benni #include <sys/sysctl.h>
23 33bf1ca4 2023-04-08 benni #include <sys/ioctl.h>
24 33bf1ca4 2023-04-08 benni #include <sys/mount.h>
25 33bf1ca4 2023-04-08 benni #include <sys/dkio.h>
26 33bf1ca4 2023-04-08 benni #include <inttypes.h>
27 33bf1ca4 2023-04-08 benni #include <string.h>
28 33bf1ca4 2023-04-08 benni #include <stdarg.h>
29 33bf1ca4 2023-04-08 benni #include <stdint.h>
30 33bf1ca4 2023-04-08 benni #include <stdlib.h>
31 33bf1ca4 2023-04-08 benni #include <unistd.h>
32 33bf1ca4 2023-04-08 benni #include <stdio.h>
33 33bf1ca4 2023-04-08 benni #include <fcntl.h>
34 33bf1ca4 2023-04-08 benni #include <errno.h>
35 33bf1ca4 2023-04-08 benni
36 33bf1ca4 2023-04-08 benni static void die (const char *fmt, ...)
37 33bf1ca4 2023-04-08 benni {
38 33bf1ca4 2023-04-08 benni va_list ap;
39 33bf1ca4 2023-04-08 benni
40 33bf1ca4 2023-04-08 benni va_start (ap, fmt);
41 33bf1ca4 2023-04-08 benni fputs ("Error: ", stderr);
42 33bf1ca4 2023-04-08 benni vfprintf (stderr, fmt, ap);
43 33bf1ca4 2023-04-08 benni
44 33bf1ca4 2023-04-08 benni if (errno != 0) {
45 33bf1ca4 2023-04-08 benni fprintf (stderr, ": %s\n", strerror (errno));
46 33bf1ca4 2023-04-08 benni } else {
47 33bf1ca4 2023-04-08 benni fputc ('\n', stderr);
48 33bf1ca4 2023-04-08 benni }
49 33bf1ca4 2023-04-08 benni
50 33bf1ca4 2023-04-08 benni exit (1);
51 33bf1ca4 2023-04-08 benni }
52 33bf1ca4 2023-04-08 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 33bf1ca4 2023-04-08 benni die ("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 33bf1ca4 2023-04-08 benni die ("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 33bf1ca4 2023-04-08 benni static void printsize (uint64_t sz)
79 33bf1ca4 2023-04-08 benni {
80 33bf1ca4 2023-04-08 benni struct unit {
81 33bf1ca4 2023-04-08 benni char sym;
82 33bf1ca4 2023-04-08 benni uint64_t factor;
83 33bf1ca4 2023-04-08 benni };
84 33bf1ca4 2023-04-08 benni
85 33bf1ca4 2023-04-08 benni const struct unit units[] = {
86 33bf1ca4 2023-04-08 benni { 'P', 1ull << 50 },
87 33bf1ca4 2023-04-08 benni { 'T', 1ull << 40 },
88 33bf1ca4 2023-04-08 benni { 'G', 1ull << 30 },
89 33bf1ca4 2023-04-08 benni { 'M', 1ull << 20 },
90 33bf1ca4 2023-04-08 benni { 'K', 1ull << 10 },
91 33bf1ca4 2023-04-08 benni { '0', 0 },
92 33bf1ca4 2023-04-08 benni };
93 33bf1ca4 2023-04-08 benni
94 33bf1ca4 2023-04-08 benni char sym = 'B';
95 33bf1ca4 2023-04-08 benni uint64_t factor = 1;
96 33bf1ca4 2023-04-08 benni
97 33bf1ca4 2023-04-08 benni for (const struct unit *u = &units[0]; u->factor; ++u) {
98 33bf1ca4 2023-04-08 benni if (sz >= (u->factor * 9 / 10)) {
99 33bf1ca4 2023-04-08 benni sym = u->sym;
100 33bf1ca4 2023-04-08 benni factor = u->factor;
101 33bf1ca4 2023-04-08 benni break;
102 33bf1ca4 2023-04-08 benni }
103 33bf1ca4 2023-04-08 benni }
104 33bf1ca4 2023-04-08 benni
105 33bf1ca4 2023-04-08 benni const unsigned scaled10 = sz * 10 / factor;
106 33bf1ca4 2023-04-08 benni const unsigned scaled = sz / factor;
107 33bf1ca4 2023-04-08 benni if (scaled10 >= 1000) {
108 33bf1ca4 2023-04-08 benni printf (" %u", scaled);
109 33bf1ca4 2023-04-08 benni } else if (scaled10 >= 100) {
110 33bf1ca4 2023-04-08 benni printf ("%u.%u", scaled, scaled10 % 10);
111 33bf1ca4 2023-04-08 benni } else {
112 33bf1ca4 2023-04-08 benni printf (" %u.%u", scaled, scaled10 % 10);
113 33bf1ca4 2023-04-08 benni }
114 33bf1ca4 2023-04-08 benni
115 33bf1ca4 2023-04-08 benni putchar (sym);
116 33bf1ca4 2023-04-08 benni }
117 33bf1ca4 2023-04-08 benni
118 33bf1ca4 2023-04-08 benni static int usage (void)
119 33bf1ca4 2023-04-08 benni {
120 33bf1ca4 2023-04-08 benni fputs ("Usage: lsblk [-V]\n", stderr);
121 33bf1ca4 2023-04-08 benni return 1;
122 33bf1ca4 2023-04-08 benni }
123 33bf1ca4 2023-04-08 benni
124 33bf1ca4 2023-04-08 benni int main (int argc, char *argv[])
125 33bf1ca4 2023-04-08 benni {
126 33bf1ca4 2023-04-08 benni int option;
127 33bf1ca4 2023-04-08 benni while ((option = getopt (argc, argv, ":V")) != -1) {
128 33bf1ca4 2023-04-08 benni switch (option) {
129 33bf1ca4 2023-04-08 benni case 'V':
130 33bf1ca4 2023-04-08 benni puts ("lsblk-" VERSION);
131 33bf1ca4 2023-04-08 benni return 0;
132 33bf1ca4 2023-04-08 benni default:
133 33bf1ca4 2023-04-08 benni return usage ();
134 33bf1ca4 2023-04-08 benni }
135 33bf1ca4 2023-04-08 benni }
136 33bf1ca4 2023-04-08 benni
137 33bf1ca4 2023-04-08 benni if (argc != optind)
138 33bf1ca4 2023-04-08 benni return usage ();
139 33bf1ca4 2023-04-08 benni
140 33bf1ca4 2023-04-08 benni struct statfs *mounts;
141 33bf1ca4 2023-04-08 benni char *names = disknames ();
142 33bf1ca4 2023-04-08 benni
143 33bf1ca4 2023-04-08 benni if (pledge ("stdio rpath disklabel", NULL) == -1)
144 33bf1ca4 2023-04-08 benni die ("pledge()");
145 33bf1ca4 2023-04-08 benni
146 33bf1ca4 2023-04-08 benni const int n_mounts = getmntinfo (&mounts, MNT_NOWAIT);
147 33bf1ca4 2023-04-08 benni if (n_mounts == 0)
148 33bf1ca4 2023-04-08 benni die ("getmntinfo()");
149 33bf1ca4 2023-04-08 benni
150 33bf1ca4 2023-04-08 benni for (char *disk; (disk = strsep (&names, ",")) != NULL;) {
151 33bf1ca4 2023-04-08 benni struct disklabel label;
152 33bf1ca4 2023-04-08 benni char *colon, *name = NULL;
153 33bf1ca4 2023-04-08 benni int fd;
154 33bf1ca4 2023-04-08 benni
155 33bf1ca4 2023-04-08 benni colon = strchr (disk, ':');
156 33bf1ca4 2023-04-08 benni if (colon)
157 33bf1ca4 2023-04-08 benni *colon = '\0';
158 33bf1ca4 2023-04-08 benni
159 33bf1ca4 2023-04-08 benni asprintf (&name, "/dev/%sc", disk);
160 33bf1ca4 2023-04-08 benni
161 33bf1ca4 2023-04-08 benni fd = open (name, O_RDONLY);
162 33bf1ca4 2023-04-08 benni if (fd < 0)
163 33bf1ca4 2023-04-08 benni die ("open(%s)", name);
164 33bf1ca4 2023-04-08 benni
165 33bf1ca4 2023-04-08 benni if (ioctl (fd, DIOCGDINFO, &label) < 0)
166 33bf1ca4 2023-04-08 benni die ("ioctl(%s, IOCGDINFO)", name);
167 33bf1ca4 2023-04-08 benni
168 33bf1ca4 2023-04-08 benni close (fd);
169 33bf1ca4 2023-04-08 benni
170 33bf1ca4 2023-04-08 benni const uint32_t ss = label.d_secsize;
171 33bf1ca4 2023-04-08 benni
172 33bf1ca4 2023-04-08 benni char *letter = name + strlen (name) - 1;
173 33bf1ca4 2023-04-08 benni
174 33bf1ca4 2023-04-08 benni printf ("%s ", disk);
175 bb3f9866 2023-04-08 benni printsize ((((uint64_t)label.d_secperunith << 32) | label.d_secperunit) * ss);
176 33bf1ca4 2023-04-08 benni printf (" %s\n", label.d_typename);
177 33bf1ca4 2023-04-08 benni for (uint16_t i = 0; i < label.d_npartitions; ++i) {
178 33bf1ca4 2023-04-08 benni const struct partition *p = &label.d_partitions[i];
179 33bf1ca4 2023-04-08 benni const uint64_t size = (((uint64_t)p->p_sizeh << 32) | p->p_size) * ss;
180 33bf1ca4 2023-04-08 benni if (size == 0)
181 33bf1ca4 2023-04-08 benni continue;
182 33bf1ca4 2023-04-08 benni
183 33bf1ca4 2023-04-08 benni *letter = i + 'a';
184 33bf1ca4 2023-04-08 benni const char *mp = "";
185 33bf1ca4 2023-04-08 benni for (int i = 0; i < n_mounts; ++i) {
186 33bf1ca4 2023-04-08 benni const struct statfs *m = &mounts[i];
187 33bf1ca4 2023-04-08 benni if (!strcmp (name, m->f_mntfromname)) {
188 33bf1ca4 2023-04-08 benni mp = m->f_mntonname;
189 33bf1ca4 2023-04-08 benni break;
190 33bf1ca4 2023-04-08 benni }
191 33bf1ca4 2023-04-08 benni }
192 33bf1ca4 2023-04-08 benni
193 33bf1ca4 2023-04-08 benni printf (" %s%c ", disk, *letter);
194 33bf1ca4 2023-04-08 benni printsize (size);
195 33bf1ca4 2023-04-08 benni printf (" %s %s\n", fstypenames[p->p_fstype], mp);
196 33bf1ca4 2023-04-08 benni }
197 33bf1ca4 2023-04-08 benni }
198 33bf1ca4 2023-04-08 benni
199 33bf1ca4 2023-04-08 benni free (names);
200 33bf1ca4 2023-04-08 benni return 0;
201 33bf1ca4 2023-04-08 benni }