From c19ac8729d304cf5af000f05ef1a048781f7ba6a Mon Sep 17 00:00:00 2001 From: Justine Tunney Date: Tue, 11 Oct 2022 09:54:49 -0700 Subject: [PATCH] Reinvent the classic unix wall command --- examples/wall.c | 148 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 148 insertions(+) create mode 100644 examples/wall.c diff --git a/examples/wall.c b/examples/wall.c new file mode 100644 index 000000000..1e115960b --- /dev/null +++ b/examples/wall.c @@ -0,0 +1,148 @@ +#if 0 +/*─────────────────────────────────────────────────────────────────╗ +│ To the extent possible under law, Justine Tunney has waived │ +│ all copyright and related or neighboring rights to this file, │ +│ as it is written in the following disclaimers: │ +│ • http://unlicense.org/ │ +│ • http://creativecommons.org/publicdomain/zero/1.0/ │ +╚─────────────────────────────────────────────────────────────────*/ +#endif +#include "libc/calls/calls.h" +#include "libc/calls/struct/timespec.h" +#include "libc/calls/termios.h" +#include "libc/errno.h" +#include "libc/fmt/fmt.h" +#include "libc/runtime/runtime.h" +#include "libc/stdio/append.h" +#include "libc/stdio/stdio.h" +#include "libc/str/str.h" +#include "libc/sysv/consts/o.h" +#include "libc/time/struct/tm.h" +#include "third_party/getopt/getopt.h" +#include "third_party/musl/passwd.h" + +/** + * @fileoverview program for broadcasting message to all terminals, e.g. + * + * o//examples/wall.com hello friends + * + * Will place some bold text into the top left corners of all terminals: + * + * Broadcast message from jart@host (pts/4) (Tue Oct 11 03:52:24 2022): + * hello friends + * + * It's useful for having one terminal tab notify your other ones when + * something like a long running job completes. In the old days back + * when unix systems had multiple users, the wall command provided the + * ultimate lulz especially if it's a setuid binary with root privs. + */ + +#define GETOPTS "v" +#define USAGE \ + "\ +Usage: wall.com [-v] [TEXTMSG] [pw_name, + GetHost()); + if (isatty(0) && (s = ttyname(0))) appendf(&msg, " (%s)", s); + appendf(&msg, " (%s):\r\n", GetTime()); + appends(&msg, "\e[K"); + + // append broadcast message + if (optind < argc) { + // use cli arguments as message if they exist + for (int i = 0; optind + i < argc; ++i) { + if (i) appends(&msg, " "); + for (s = argv[optind + i]; *s; ++s) { + if (*s == '\n') { + appends(&msg, "\r\n\e[K"); + } else { + appendw(&msg, *s & 255); + } + } + } + } else { + // otherwise use stdin as message + ssize_t i, rc; + char buf[512]; + while ((rc = read(0, buf, sizeof(buf))) > 0) { + for (i = 0; i < rc; ++i) { + if (buf[i] == '\n') { + appends(&msg, "\r\n\e[K"); // clear line forward + } else { + appendw(&msg, buf[i] & 255); + } + } + } + } + appends(&msg, "\r\n\e[K\e[0m\e8"); // restore + + // try to send message to all pseudoteletypewriters + for (int i = 0;; ++i) { + int fd; + char pts[32]; + snprintf(pts, sizeof(pts), "/dev/pts/%d", i); + if ((fd = open(pts, O_WRONLY | O_NOCTTY)) == -1) { + if (errno == ENOENT) break; + if (g_verbose) perror(pts); + } + write(fd, msg, appendz(msg).i); + close(fd); + } + + return 0; +}