From 240504f287c0945aedcf1f7c6fe956c81f5a0f45 Mon Sep 17 00:00:00 2001 From: Librebooter Date: Mon, 16 Mar 2026 02:41:26 -0500 Subject: [PATCH] initial commit --- Makefile | 16 +++ README | 59 ++++++++++ beastie | Bin 0 -> 17744 bytes beastie.c | 336 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ config.h | 54 +++++++++ config.mk | 7 ++ 6 files changed, 472 insertions(+) create mode 100644 Makefile create mode 100644 README create mode 100755 beastie create mode 100644 beastie.c create mode 100644 config.h create mode 100644 config.mk diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..2c619a9 --- /dev/null +++ b/Makefile @@ -0,0 +1,16 @@ +# beastie - minimal system info +include config.mk + +beastie: beastie.c config.h + ${CC} ${CFLAGS} -o $@ beastie.c ${LDFLAGS} + +install: beastie + install -m 755 beastie ${DESTDIR}${PREFIX}/bin/beastie + +uninstall: + rm -f ${DESTDIR}${PREFIX}/bin/beastie + +clean: + rm -f beastie + +.PHONY: install uninstall clean diff --git a/README b/README new file mode 100644 index 0000000..17ca90c --- /dev/null +++ b/README @@ -0,0 +1,59 @@ +beastie - minimal system fetch +================================ + +Minimal system info tool for BSD. Displays info side-by-side with +ASCII art. Named after the BSD daemon mascot. + +Reads hardware/OS info via sysctlbyname(3). +WM detection uses xdpyinfo(1) at runtime if MOD_WM is enabled. + + +EXAMPLE OUTPUT +-------------- + + %@ realdaemon@daemon-box + %# @## + %#@ @%%%%%%@%%##@ os FreeBSD 15.0-RELEASE-p4 + @%%##@%%%%%@######%## kernel MinKern + %%%###%%%%# @@ @# cpu Intel(R) Core(TM) i7-4910MQ CPU @ 2.90GHz + %%%%%%%%## @ @#@ uptime 3h 45m + @%%%%%## @@#@@# mem 2689M / 16237M + %%%%#### @@##### shell sh + %%%%%%#####%##@## *: term st + @%%%#@######%#@ : :@ wm dwm (on XLibre) + %%%%%%###@ @# @:@ @: + %%###### %#@ + @%%@##@###@%%##@ + %%%##%####@%@@ + @%%%%%%%%%@ + @%@::%@@%##@ + @%:@%%%####@ + @%%%@@%@:@%:# + @%%%%%@ @+ :-:@@:::@@@ + %##@@ %::::::# . @ + %%@ %@ @ @ + @@%#### + + +CONFIGURATION +------------- +Edit config.h and recompile. Configurable: + + COLOR_ART ANSI color for the ASCII art + COLOR_USER ANSI color for the user@host header + COLOR_LABEL ANSI color for info labels + ART_W Visual width of the widest art line (must be accurate) + ART[] The ASCII art, one line per string + + +BUILD AND INSTALL +----------------- + make + doas make install + +Installs to /usr/local/bin/beastie. Override PREFIX to change. + + +REQUIREMENTS +------------ + BSD: base system, optionally xdpyinfo(1) for wm vendor detection diff --git a/beastie b/beastie new file mode 100755 index 0000000000000000000000000000000000000000..2e6f4a85814a4e1e8117242c13490c26e67a6101 GIT binary patch literal 17744 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 F{XZ7+T_FGf literal 0 HcmV?d00001 diff --git a/beastie.c b/beastie.c new file mode 100644 index 0000000..746e19c --- /dev/null +++ b/beastie.c @@ -0,0 +1,336 @@ +/* beastie - minimal system info */ +#define VERSION "dev" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* module IDs - reference these in config.h modules[] */ +enum module { + MOD_SEP, /* blank separator line */ + MOD_USERATHOST, /* user@hostname */ + MOD_OS, /* os name + release */ + MOD_KERNEL, /* kern.ident */ + MOD_CPU, /* hw.model */ + MOD_UPTIME, /* uptime */ + MOD_MEM, /* used / total memory */ + MOD_SHELL, /* $SHELL basename */ + MOD_TERM, /* $TERM */ + MOD_WM, /* wm (via xdpyinfo) */ + MOD_DISK, /* used / total on / */ + MOD_PKGS, /* pkg count */ + MOD_RES, /* screen resolution */ + MOD_COLORS, /* 16-color palette */ +}; + +#include "config.h" + +#define ART_H (int)(sizeof(ART)/sizeof(ART[0])) +#define NMOD (int)(sizeof(modules)/sizeof(modules[0])) +#define MAX_INFO 32 + +/* format uptime as Xd Xh Xm from boot time */ +static void +uptime_str(char *buf, size_t len) +{ + long up = 0; + struct timeval bt; + size_t sz = sizeof(bt); + if (sysctlbyname("kern.boottime", &bt, &sz, NULL, 0) == 0) + up = (long)(time(NULL) - bt.tv_sec); + if (!up) { snprintf(buf, len, "unknown"); return; } + long d = up / 86400, h = (up % 86400) / 3600, m = (up % 3600) / 60; + if (d) snprintf(buf, len, "%ldd %ldh %ldm", d, h, m); + else if (h) snprintf(buf, len, "%ldh %ldm", h, m); + else snprintf(buf, len, "%ldm", m); +} + +/* format memory as used / total in MB */ +static void +mem_str(char *buf, size_t len) +{ + unsigned long total_mb = 0, used_mb = 0; + unsigned long physmem; + unsigned int free_c = 0, inactive_c = 0; + int pgsz = 0; + size_t sz; + sz = sizeof(physmem); + if (sysctlbyname("hw.physmem", &physmem, &sz, NULL, 0) == -1) { + snprintf(buf, len, "unknown"); return; + } + /* available = free + inactive pages */ + sz = sizeof(free_c); sysctlbyname("vm.stats.vm.v_free_count", &free_c, &sz, NULL, 0); + sz = sizeof(inactive_c); sysctlbyname("vm.stats.vm.v_inactive_count", &inactive_c, &sz, NULL, 0); + sz = sizeof(pgsz); sysctlbyname("hw.pagesize", &pgsz, &sz, NULL, 0); + unsigned long avail = (unsigned long)(free_c + inactive_c) * pgsz; + total_mb = physmem >> 20; + used_mb = (physmem - avail) >> 20; + if (!total_mb) { snprintf(buf, len, "unknown"); return; } + snprintf(buf, len, "%luM / %luM", used_mb, total_mb); +} + +/* read cpu model string */ +static void +cpu_str(char *buf, size_t len) +{ + size_t sz = len; + if (sysctlbyname("hw.model", buf, &sz, NULL, 0) == 0) return; + snprintf(buf, len, "unknown"); +} + +/* disk usage on / in GB used / total */ +static void +disk_str(char *buf, size_t len) +{ + struct statvfs s; + if (statvfs("/", &s) == -1) { snprintf(buf, len, "unknown"); return; } + unsigned long long total = (unsigned long long)s.f_blocks * s.f_frsize; + unsigned long long avail = (unsigned long long)s.f_bavail * s.f_frsize; + unsigned long long used = total - avail; + snprintf(buf, len, "%.1fG / %.1fG", + (double)used / (1024*1024*1024), + (double)total / (1024*1024*1024)); +} + +/* installed pkg count via pkg info */ +static void +pkgs_str(char *buf, size_t len) +{ + FILE *f = popen("pkg info 2>/dev/null | wc -l", "r"); + if (f) { + int n = 0; + fscanf(f, "%d", &n); + pclose(f); + if (n > 0) { snprintf(buf, len, "%d (pkg)", n); return; } + } + snprintf(buf, len, "unknown"); +} + +/* screen resolution via xdpyinfo */ +static void +res_str(char *buf, size_t len) +{ + FILE *f = popen("xdpyinfo 2>/dev/null | grep dimensions | awk '{print $2}'", "r"); + if (f) { + char res[32] = {0}; + fgets(res, sizeof(res), f); + pclose(f); + size_t rl = strlen(res); + if (rl && res[rl-1] == '\n') res[rl-1] = '\0'; + if (res[0]) { snprintf(buf, len, "%s", res); return; } + } + snprintf(buf, len, "unknown"); +} + +/* read custom kernel name via kern.ident sysctl */ +static void +kernel_ident(char *buf, size_t len) +{ + size_t sz = len; + if (sysctlbyname("kern.ident", buf, &sz, NULL, 0) == 0) return; + snprintf(buf, len, "unknown"); +} + +int +main(int argc, char *argv[]) +{ + if (argc == 2 && strcmp(argv[1], "--version") == 0) { + printf("Beastie version " VERSION "\n"); + printf("Beastie is a minimal fetch tool for BSD systems.\n"); + printf("Compiled with " +#if defined(__clang__) + "clang " __clang_version__ +#elif defined(__GNUC__) + "gcc " __VERSION__ +#else + "unknown compiler" +#endif + "\n"); + return 0; + } + struct utsname uts; + char cpu[256] = {0}; + char kid[64] = {0}; + char upt[64] = {0}; + char mem[64] = {0}; + char dsk[64] = {0}; + char pkg[64] = {0}; + char res[64] = {0}; + + uname(&uts); + + /* prefer $USER env, fall back to passwd db */ + const char *user = getenv("USER"); + if (!user) { + struct passwd *pw = getpwuid(getuid()); + user = pw ? pw->pw_name : "?"; + } + + cpu_str(cpu, sizeof(cpu)); + kernel_ident(kid, sizeof(kid)); + uptime_str(upt, sizeof(upt)); + mem_str(mem, sizeof(mem)); + disk_str(dsk, sizeof(dsk)); + pkgs_str(pkg, sizeof(pkg)); + res_str(res, sizeof(res)); + + /* strip path prefix from $SHELL */ + const char *shell = getenv("SHELL"); + if (shell) { const char *s = strrchr(shell, '/'); if (s) shell = s + 1; } + else shell = "unknown"; + + /* normalize $TERM - strip -256color/-color suffix, map xterm generically */ + char termbuf[64] = "unknown"; + const char *termenv = getenv("TERM"); + if (termenv) { + if (strncmp(termenv, "xterm", 5) == 0) + snprintf(termbuf, sizeof(termbuf), "generic terminal emulator"); + else { + char *p; + snprintf(termbuf, sizeof(termbuf), "%s", termenv); + if ((p = strstr(termbuf, "-256color"))) *p = '\0'; + else if ((p = strstr(termbuf, "-color"))) *p = '\0'; + } + } + const char *term = termbuf; + + /* detect x server vendor via xdpyinfo to avoid linking against libX11 */ + char wmbuf[64] = "none"; + if (getenv("DISPLAY")) { + FILE *xdpy = popen("xdpyinfo 2>/dev/null | grep 'vendor string' | awk '{print $3}'", "r"); + if (xdpy) { + char vendor[64] = {0}; + fgets(vendor, sizeof(vendor), xdpy); + pclose(xdpy); + size_t vl = strlen(vendor); + if (vl && vendor[vl-1] == '\n') vendor[vl-1] = '\0'; + if (vendor[0]) + snprintf(wmbuf, sizeof(wmbuf), "dwm (on %s)", vendor); + else + snprintf(wmbuf, sizeof(wmbuf), "dwm"); + } else { + snprintf(wmbuf, sizeof(wmbuf), "dwm"); + } + } + const char *wm = wmbuf; + + /* build info lines from modules[] */ + char ibufs[MAX_INFO][512]; + const char *ilines[MAX_INFO]; + int ni = 0; + + for (int j = 0; j < NMOD && ni < MAX_INFO; j++) { + switch (modules[j]) { + case MOD_SEP: + ilines[ni++] = ""; + break; + case MOD_USERATHOST: + snprintf(ibufs[ni], sizeof(ibufs[0]), + COLOR_BOLD COLOR_USER "%s" COLOR_RESET + "@" + COLOR_BOLD COLOR_USER "%s" COLOR_RESET, + user, uts.nodename); + ilines[ni] = ibufs[ni]; ni++; + break; + case MOD_OS: + snprintf(ibufs[ni], sizeof(ibufs[0]), + COLOR_LABEL "os " COLOR_RESET " %s %s", + uts.sysname, uts.release); + ilines[ni] = ibufs[ni]; ni++; + break; + case MOD_KERNEL: + snprintf(ibufs[ni], sizeof(ibufs[0]), + COLOR_LABEL "kernel" COLOR_RESET " %s", kid); + ilines[ni] = ibufs[ni]; ni++; + break; + case MOD_CPU: + snprintf(ibufs[ni], sizeof(ibufs[0]), + COLOR_LABEL "cpu " COLOR_RESET " %s", cpu); + ilines[ni] = ibufs[ni]; ni++; + break; + case MOD_UPTIME: + snprintf(ibufs[ni], sizeof(ibufs[0]), + COLOR_LABEL "uptime" COLOR_RESET " %s", upt); + ilines[ni] = ibufs[ni]; ni++; + break; + case MOD_MEM: + snprintf(ibufs[ni], sizeof(ibufs[0]), + COLOR_LABEL "mem " COLOR_RESET " %s", mem); + ilines[ni] = ibufs[ni]; ni++; + break; + case MOD_SHELL: + snprintf(ibufs[ni], sizeof(ibufs[0]), + COLOR_LABEL "shell " COLOR_RESET " %s", shell); + ilines[ni] = ibufs[ni]; ni++; + break; + case MOD_TERM: + snprintf(ibufs[ni], sizeof(ibufs[0]), + COLOR_LABEL "term " COLOR_RESET " %s", term); + ilines[ni] = ibufs[ni]; ni++; + break; + case MOD_WM: + snprintf(ibufs[ni], sizeof(ibufs[0]), + COLOR_LABEL "wm " COLOR_RESET " %s", wm); + ilines[ni] = ibufs[ni]; ni++; + break; + case MOD_DISK: + snprintf(ibufs[ni], sizeof(ibufs[0]), + COLOR_LABEL "disk " COLOR_RESET " %s", dsk); + ilines[ni] = ibufs[ni]; ni++; + break; + case MOD_PKGS: + snprintf(ibufs[ni], sizeof(ibufs[0]), + COLOR_LABEL "pkgs " COLOR_RESET " %s", pkg); + ilines[ni] = ibufs[ni]; ni++; + break; + case MOD_RES: + snprintf(ibufs[ni], sizeof(ibufs[0]), + COLOR_LABEL "res " COLOR_RESET " %s", res); + ilines[ni] = ibufs[ni]; ni++; + break; + case MOD_COLORS: { + /* render two rows of 8 color swatches each */ + char *p = ibufs[ni]; + size_t rem = sizeof(ibufs[0]); + int n; + for (int k = 0; k < 8; k++) { + n = snprintf(p, rem, "\033[4%dm ", k); + p += n; rem -= n; + } + n = snprintf(p, rem, COLOR_RESET " "); + p += n; rem -= n; + for (int k = 8; k < 16; k++) { + n = snprintf(p, rem, "\033[48;5;%dm ", k); + p += n; rem -= n; + } + snprintf(p, rem, COLOR_RESET); + ilines[ni] = ibufs[ni]; ni++; + break; + } + } + } + + /* print art + info side by side, padding whichever is shorter */ + int total = ni > ART_H ? ni : ART_H; + + printf("\n"); + for (int i = 0; i < total; i++) { + printf(" "); + if (i < ART_H) + printf(COLOR_ART "%s" COLOR_RESET, ART[i]); + else + printf("%*s", ART_W, ""); + printf(" "); + if (i < ni) + printf("%s", ilines[i]); + printf("\n"); + } + + return 0; +} diff --git a/config.h b/config.h new file mode 100644 index 0000000..139eab2 --- /dev/null +++ b/config.h @@ -0,0 +1,54 @@ +/* beastie - configuration, edit and recompile */ + +/* colors */ +#define COLOR_RESET "\033[0m" +#define COLOR_BOLD "\033[1m" +#define COLOR_ART "\033[1;31m" /* bold red - art */ +#define COLOR_USER "\033[1;34m" /* bold blue - user@host */ +#define COLOR_LABEL "\033[1;35m" /* bold magenta - info labels */ + +/* modules to display, in order - comment out or reorder to taste */ +static const enum module modules[] = { + MOD_USERATHOST, + MOD_SEP, + MOD_OS, + MOD_KERNEL, + MOD_CPU, + MOD_UPTIME, + MOD_MEM, + MOD_SHELL, + MOD_TERM, + MOD_WM, + MOD_DISK, + MOD_PKGS, + MOD_RES, + MOD_SEP, + /* MOD_COLORS, */ +}; + +/* ascii art - ART_W must equal the visual width of the longest line */ +#define ART_W 38 +static const char *ART[] = { + " %@ ", + " %# @## ", + " %#@ @%%%%%%@%%##@ ", + " @%%##@%%%%%@######%## ", + " %%%###%%%%# @@ @# ", + " %%%%%%%%## @ @#@ ", + " @%%%%%## @@#@@# ", + " %%%%#### @@##### ", + " %%%%%%#####%##@## *: ", + " @%%%#@######%#@ : :@ ", + " %%%%%%###@ @# @:@ @: ", + " %%###### %#@ ", + " @%%@##@###@%%##@ ", + " %%%##%####@%@@ ", + " @%%%%%%%%%@ ", + " @%@::%@@%##@ ", + " @%:@%%%####@ ", + " @%%%@@%@:@%:# ", + " @%%%%%@ @+ :-:@@:::@@@ ", + " %##@@ %::::::# . @ ", + "%%@ %@ @ @ ", + " @@%#### ", +}; diff --git a/config.mk b/config.mk new file mode 100644 index 0000000..b9296f0 --- /dev/null +++ b/config.mk @@ -0,0 +1,7 @@ +# beastie - build configuration, edit and recompile + +PREFIX = /usr/local + +CC = cc +CFLAGS = -O2 -Wall -Wextra -std=c99 -pedantic +LDFLAGS =