2 * Copyright (c) 2023 Benjamin Stürz <benni@stuerz.xyz>
4 * Permission to use, copy, modify, and distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16 #define _XOPEN_SOURCE 700
20 #include <sys/types.h>
21 #include <sys/disklabel.h>
22 #include <sys/sysctl.h>
23 #include <sys/ioctl.h>
24 #include <sys/mount.h>
36 static void die (const char *fmt, ...)
41 fputs ("Error: ", stderr);
42 vfprintf (stderr, fmt, ap);
45 fprintf (stderr, ": %s\n", strerror (errno));
53 static int diskcount (void)
55 const int mib[2] = { CTL_HW, HW_DISKCOUNT };
57 size_t len = sizeof diskcount;
59 if (sysctl (mib, 2, &diskcount, &len, NULL, 0) == -1)
60 die ("sysctl(hw.diskcount)");
65 static char *disknames (void)
67 const int num = diskcount ();
68 const int mib[2] = { CTL_HW, HW_DISKNAMES };
69 size_t len = 32 * num;
70 char *buffer = malloc (len);
72 if (sysctl (mib, 2, buffer, &len, NULL, 0) == -1)
73 die ("sysctl(hw.disknames)");
78 static void printsize (uint64_t sz)
85 const struct unit units[] = {
97 for (const struct unit *u = &units[0]; u->factor; ++u) {
98 if (sz >= (u->factor * 9 / 10)) {
105 const unsigned scaled10 = sz * 10 / factor;
106 const unsigned scaled = sz / factor;
107 if (scaled10 >= 1000) {
108 printf (" %u", scaled);
109 } else if (scaled10 >= 100) {
110 printf ("%u.%u", scaled, scaled10 % 10);
112 printf (" %u.%u", scaled, scaled10 % 10);
118 static int usage (void)
120 fputs ("Usage: lsblk [-V]\n", stderr);
124 int main (int argc, char *argv[])
127 while ((option = getopt (argc, argv, ":V")) != -1) {
130 puts ("lsblk-" VERSION);
140 struct statfs *mounts;
141 char *names = disknames ();
143 if (pledge ("stdio rpath disklabel", NULL) == -1)
146 const int n_mounts = getmntinfo (&mounts, MNT_NOWAIT);
148 die ("getmntinfo()");
150 for (char *disk; (disk = strsep (&names, ",")) != NULL;) {
151 struct disklabel label;
152 char *colon, *name = NULL;
155 colon = strchr (disk, ':');
159 asprintf (&name, "/dev/%sc", disk);
161 fd = open (name, O_RDONLY);
163 die ("open(%s)", name);
165 if (ioctl (fd, DIOCGDINFO, &label) < 0)
166 die ("ioctl(%s, IOCGDINFO)", name);
170 const uint32_t ss = label.d_secsize;
172 char *letter = name + strlen (name) - 1;
174 printf ("%s ", disk);
175 printsize ((((uint64_t)label.d_secperunith << 32) | label.d_secperunit) * ss);
176 printf (" %s\n", label.d_typename);
177 for (uint16_t i = 0; i < label.d_npartitions; ++i) {
178 const struct partition *p = &label.d_partitions[i];
179 const uint64_t size = (((uint64_t)p->p_sizeh << 32) | p->p_size) * ss;
185 for (int i = 0; i < n_mounts; ++i) {
186 const struct statfs *m = &mounts[i];
187 if (!strcmp (name, m->f_mntfromname)) {
193 printf (" %s%c ", disk, *letter);
195 printf (" %s %s\n", fstypenames[p->p_fstype], mp);