--- /dev/null
+#include <sys/stat.h>
+#include <sys/sysctl.h>
+#include <sys/types.h>
+
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <err.h>
+#include <kvm.h>
+
+typedef enum {
+ NO_CONV,
+ KB_CONV,
+ MB_CONV,
+ GB_CONV,
+ TB_CONV,
+ PB_CONV,
+ HU_CONV
+} ConvFlags;
+
+static kvm_t *kd;
+static long pgsz;
+static char sbuff[32];
+
+void
+usage(void)
+{
+ fprintf(stderr, "usage: %s [-bghkmpt]\n", getprogname());
+ exit(2);
+}
+
+long long
+getphysmem(int unused)
+{
+ (void)unused;
+
+ long long physcnt;
+ size_t len = sizeof(physcnt);
+
+ if (sysctlbyname("hw.physmem", &physcnt, &len, NULL, 0) < 0)
+ err(1, "hw.physmem");
+
+ return physcnt;
+}
+
+long long
+getavailmem(int flag)
+{
+ size_t len;
+ unsigned int freecnt, inactcnt;
+
+ len = sizeof(freecnt);
+ if (sysctlbyname("vm.stats.vm.v_free_count", &freecnt, &len, NULL, 0) < 0)
+ err(1, "vm.stats.vm.v_free_count");
+ if (sysctlbyname("vm.stats.vm.v_inactive_count", &inactcnt, &len, NULL, 0) < 0)
+ err(1, "vm.stats.vm.v_inactive_count");
+
+ if (flag == 1)
+ return (long long)(getphysmem(0) - (freecnt + inactcnt) * pgsz);
+ else if (flag == 2)
+ return (long long)(freecnt * pgsz);
+ else
+ return (long long)((freecnt + inactcnt) * pgsz);
+}
+
+long long
+getwiredmem(int unused)
+{
+ (void)unused;
+
+ size_t len;
+ unsigned int wirecnt;
+
+ len = sizeof(wirecnt);
+ if (sysctlbyname("vm.stats.vm.v_wire_count", &wirecnt, &len, NULL, 0) < 0)
+ err(1, "vm.stats.vm.v_wire_count");
+
+ return (long long)(wirecnt * pgsz);
+
+}
+
+long long
+getbufcachestats(int unused)
+{
+ (void)unused;
+
+ size_t len;
+ long bufspace, arcspace;
+ unsigned int cachecnt;
+
+ len = sizeof(bufspace);
+ if (sysctlbyname("vfs.bufspace", &bufspace, &len, NULL, 0) < 0)
+ err(1, "vfs.bufspace");
+ /* Ignore failure in case ZFS is not used */
+ (void)sysctlbyname("kstat.zfs.misc.arcstats.size", &arcspace, &len, NULL, 0);
+
+ len = sizeof(cachecnt);
+ if (sysctlbyname("vm.stats.vm.v_cache_count", &cachecnt, &len, NULL, 0) < 0)
+ err(1, "vm.stats.vm.v_inactive_count");
+
+ return (long long)(cachecnt * pgsz + bufspace + arcspace);
+}
+
+long long
+getswapstats(int flag)
+{
+ int nswap;
+ struct kvm_swap swap;
+
+ if ((nswap = kvm_getswapinfo(kd, &swap, 1, 0)) < 0)
+ errx(1, "kvm_getswapinfo: %s", kvm_geterr(kd));
+
+ if (flag == 0)
+ return (long long)(swap.ksw_total * pgsz);
+ else if (flag == 1)
+ return (long long)(swap.ksw_used * pgsz);
+ else
+ return (long long)((swap.ksw_total - swap.ksw_used) * pgsz);
+}
+
+int
+tohumansize(long long bytes, char **buff, ConvFlags flag)
+{
+ int i = 0;
+ double size = (double)bytes;
+ char units[] = {'\0', 'K', 'M', 'G', 'T', 'P'};
+
+ if (flag != HU_CONV)
+ memset(units, '\0', sizeof(units));
+ if (flag == NO_CONV)
+ return asprintf(buff, "%.0f", size);
+
+ while (i < (int)flag) {
+ if (size <= 1024 && flag == HU_CONV) break;
+ size /= 1024;
+ i++;
+ }
+
+ if (i == 0 || size < 0.1)
+ return asprintf(buff, "%.0f", size);
+ else if (size < 10)
+ return asprintf(buff, "%.1f%c", size, units[i]);
+ else
+ return asprintf(buff, "%.0f%c", size, units[i]);
+}
+
+void
+sprintfaligned(char *buff, size_t len)
+{
+ size_t blen;
+ char *ind;
+
+ blen = strlen(buff);
+ ind = sbuff + len - blen;
+ if (ind < sbuff) {
+ size_t t = sbuff - ind;
+ ind = sbuff;
+ *ind = '%';
+ ind++; buff += t;
+ blen = 30;
+ }
+ strlcpy(ind, buff, blen + 1);
+
+ return;
+}
+
+int
+main(int argc, char *argv[])
+{
+ int c, i;
+ char *buff;
+ size_t offset;
+ ConvFlags flags;
+ long long (*getmemstats[])(int) =
+ {getphysmem, getavailmem, getavailmem, getwiredmem, getbufcachestats, getavailmem};
+
+ flags = KB_CONV;
+ while ((c = getopt(argc, argv, "bghkmpt")) >= 0) {
+ switch(c) {
+ case 'b':
+ flags = NO_CONV; break;
+ case 'k':
+ flags = KB_CONV; break;
+ case 'm':
+ flags = MB_CONV; break;
+ case 'g':
+ flags = GB_CONV; break;
+ case 't':
+ flags = TB_CONV; break;
+ case 'p':
+ flags = PB_CONV; break;
+ case 'h':
+ flags = HU_CONV; break;
+ default:
+ usage();
+ }
+ }
+
+ pgsz = sysconf(_SC_PAGESIZE);
+
+ /* initializing kvm device for swap stats */
+ if (!(kd = kvm_open(NULL, "/dev/null", NULL, 0, "kvm_open")))
+ err(1, "kvm_open");
+
+ printf("%16s%12s%12s%12s%12s%12s\nMem:",
+ "total", "used", "free", "wired", "buff/cache", "available");
+
+ offset = 12;
+ for (i = 0; i < 6; i++) {
+ memset(sbuff, ' ', sizeof(sbuff));
+ tohumansize(getmemstats[i](i), &buff, flags);
+ sprintfaligned(buff, offset);
+ printf("%s", sbuff);
+ free(buff);
+ }
+
+ offset = 11;
+ printf("\nSwap:");
+ for (i = 0; i < 3; i++) {
+ memset(sbuff, ' ', sizeof(sbuff));
+ tohumansize(getswapstats(i), &buff, flags);
+ sprintfaligned(buff, offset);
+ printf("%s", sbuff);
+ free(buff);
+ offset = 12;
+ }
+ putc('\n', stdout);
+
+ return 0;
+}