alexkarle.com

Source for alexkarle.com
git clone git://git.alexkarle.com/alexkarle.com.git
Log | Files | Refs | README | LICENSE

commit 1d677530fbf909c75b248f9f891d2be8ede058aa (patch)
parent f9181c89c1897f2eac7d417ea3d67ea65324d508
Author: Alex Karle <alex@alexkarle.com>
Date:   Wed,  8 Sep 2021 00:25:58 -0400

text: Goodbye kiosk and gengopher, hello text.alexkarle.com

I'll never feel fully comfortable rolling out kiosk(1) via SSH,
and gengopher was always a hack (with the setting of mtimes and
all that). Yet, I've always wanted my site to be available not
just as HTML but in a more man(1)-y format.

After reading text.causal.agency, I knew that a ascii dump was
the way to go. It took me quite a while to get it all working in
a gmake and OpenBSD-make way, but I'm really happy with the
results!

Diffstat:
M.gitignore | 11++++++++---
MMakefile | 101++++++++++++++++++++++++++++++++++++++++++++++++++++++++-----------------------
AORDER | 14++++++++++++++
Mbin/genatom.sh | 8+++++---
Dbin/gengopher.sh | 35-----------------------------------
Mbin/genpost.sh | 3+++
Dsrc/kiosk.c | 119-------------------------------------------------------------------------------
Awelcome.txt | 16++++++++++++++++
8 files changed, 118 insertions(+), 189 deletions(-)

diff --git a/.gitignore b/.gitignore @@ -7,6 +7,11 @@ atom.xml # jam-tuesday hits generated by jam-tuesday/stats.sh jam-tuesday/greatest-hits -# kiosk binary and files -bin/kiosk -kiosk/ +# timestamp files +*.ts + +# text files (gopher, text.alexkarle.com) +text/ + +# obj directory on OpenBSD for out-of-tree builds +obj/ diff --git a/Makefile b/Makefile @@ -1,46 +1,89 @@ # alexkarle.com makefile +# +# a tale of two builds +# +# This Makefile builds both text.alexkarle.com (text-only) and +# alexkarle.com (html) from the same mdoc(7) by leveraging "timestamp" +# (*.ts) files which indicate when the two for each *.7 file were made. +# On OpenBSD, all artifacts are built into the obj/ dir (after make obj) +# for an out-of-tree build, but care was taken to maintain gmake +# compatibility. +# # targets: -# build [default] -- generates HTML in current dir -# clean -- deletes said HTML -HTML != echo index.html *.[1-9] | sed 's/\.[1-9]/.html/g' -SETS != find jam-tuesday -name '[0-9][0-9][0-9][0-9]-*' -JAMGEN = jam-tuesday/index.html jam-tuesday/greatest-hits +# build [default] -- generates html and text in obj (OpenBSD) or $PWD +# obj -- makes the obj/ directory for out-of-tree build on OpenBSD +# clean -- deletes html and text artifacts -# Running with HIDE="" shows the full build command instead -# of the abbreviated version (@ suppresses the command in make) -HIDE = @ +# gmake defines CURDIR, OpenBSD defines .CURDIR -- one should work +DIR = $(.CURDIR)$(CURDIR) -CC = cc -CFLAGS = -g -O2 -Wall -Wpedantic -Wextra +#---------------------------------------------------------- +# Variables to store timestamp and setlist dependencies +TS != echo $(DIR)/*.[1-9] | sed 's@$(DIR)/\([^\.]*\)\.[1-9]@\1.ts@g' +SETS != find $(DIR)/jam-tuesday -name '[0-9][0-9][0-9][0-9]-*' + +#---------------------------------------------------------- +# Top Level Targets .PHONY: build -build: $(HTML) atom.xml $(JAMGEN) bin/kiosk +build: $(TS) html/atom.xml jam-text.ts jam-html.ts \ + html/index.html html/style.css html/logo.png text/000-welcome.txt + +obj: + mkdir -p obj .PHONY: clean clean: - rm -f $(HTML) atom.xml $(JAMGEN) + rm -f *.ts + rm -rf text html obj + +#---------------------------------------------------------- +# jam-tuesday targets +jam-text.ts: $(SETS) bin/jam-stats.sh + @mkdir -p text/jam-tuesday + (date; echo; $(DIR)/bin/jam-stats.sh) > text/jam-tuesday/stats + @cp $(SETS) text/jam-tuesday + @echo 'cp $$SETS html/jam-tuesday' + @touch $@ + +jam-html.ts: $(SETS) bin/jam-index.sh bin/jam-stats.sh + @mkdir -p html/jam-tuesday + $(DIR)/bin/jam-index.sh > html/jam-tuesday/index.html + @cp $(SETS) html/jam-tuesday + @echo 'cp $$SETS html/jam-tuesday' + @touch $@ + + +#---------------------------------------------------------- +# Various files that just need to be copied into html/text +html/index.html: + cd html && ln -sf intro.html index.html -index.html: - ln -sf intro.html $@ +html/style.css: style.css + cp $(DIR)/style.css $@ -atom.xml: blog.7 bin/genatom.sh - ./bin/genatom.sh > $@ +html/logo.png: logo.png + cp $(DIR)/logo.png $@ -jam-tuesday/index.html: $(SETS) bin/jam-index.sh bin/jam-stats.sh - ./bin/jam-index.sh > $@ +html/atom.xml: blog.7 bin/genatom.sh + $(DIR)/bin/genatom.sh > $@ -jam-tuesday/greatest-hits: $(SETS) bin/jam-stats.sh - (date; echo; ./bin/jam-stats.sh) > $@ +text/000-welcome.txt: welcome.txt + cp $(DIR)/welcome.txt $@ -bin/kiosk: src/kiosk.c - $(CC) $(CFLAGS) -DMANDIR="\"`pwd`/kiosk\"" src/kiosk.c -o $@ -$(HTML): bin/genpost.sh +#---------------------------------------------------------------------- +# Finally, the actual meat -- generating *.html/*.txt from the mdoc(7) +# The most egregious hack here is the live renaming of the files via +# grepping through the ORDER file so that text.alexkarle.com presents +# the files in a reasonable order for viewing +$(TS): bin/genpost.sh -.SUFFIXES: .7 .html -.7.html: +.SUFFIXES: .7 .ts +.7.ts: @echo "mandoc $<" - $(HIDE)mandoc -Tlint -Werror $< - $(HIDE)./bin/genpost.sh < $< > $@ - $(HIDE)mkdir -p kiosk - $(HIDE)mandoc $< > kiosk/`basename $@ .html` + @mkdir -p text html + @mandoc -Tlint -Werror $< + @$(DIR)/bin/genpost.sh < $< > html/$$(basename $< .7).html + @mandoc -Tascii -Owidth=72 < $< | col -b > text/$$(grep $$(basename $< .7) $(DIR)/ORDER) + @touch $@ diff --git a/ORDER b/ORDER @@ -0,0 +1,14 @@ +# file order for the text.alexkarle.com site +001-intro.txt +002-license.txt +003-uses.txt +004-jam-tuesday.txt +101-blog.txt +102-a-new-hope.txt +103-domain-names.txt +104-BLM.txt +105-self-hosted.txt +106-on-writing.txt +107-my-old-man.txt +108-use-feeds.txt +109-creative-coding.txt diff --git a/bin/genatom.sh b/bin/genatom.sh @@ -2,10 +2,12 @@ # genatom.sh -- generate atom.xml set -e +REPO=$(dirname "$(dirname "$0")") + # All posts are a item (.It) in the list, and linked via .Xr -POSTS=$(sed '/SEE ALSO/q' blog.7 | grep -A1 '\.It' | grep '\.Xr' | sed 's/^\.Xr \([^ ]*\) 7/\1/') +POSTS=$(sed '/SEE ALSO/q' "$REPO/blog.7" | grep -A1 '\.It' | grep '\.Xr' | sed 's/^\.Xr \([^ ]*\) 7/\1/') # Assume dates are 1-1 -DATES=$(grep -o '[0-9]\{1,2\}/[0-9]\{1,2\}/[0-9]\{4\}' blog.7 \ +DATES=$(grep -o '[0-9]\{1,2\}/[0-9]\{1,2\}/[0-9]\{4\}' "$REPO/blog.7" \ | sed -e 's#\([0-9]\{2\}\)/\([0-9]\{2\}\)/\([0-9]\{4\}\)#\3-\1-\2#') cat <<HEADER @@ -36,7 +38,7 @@ for p in $POSTS; do <![CDATA[ ENTRY # Print fragment (no need for escapes -- in CDATA - mandoc -Thtml -O'fragment,man=%N.html;https://man.openbsd.org/%N.%S' $p.7 \ + mandoc -Thtml -O'fragment,man=%N.html;https://man.openbsd.org/%N.%S' "$REPO/$p.7" \ | sed '/<td class="head-vol">Miscellaneous Information Manual<\/td>/d' cat <<EOENTRY ]]> diff --git a/bin/gengopher.sh b/bin/gengopher.sh @@ -1,35 +0,0 @@ -#!/bin/sh -# generates my gopherhole based on the checkout of the files -# in the html area -set -e - -WWW=/var/www/htdocs/akcom -DEPLOY=/var/gopher -PHLOG=$DEPLOY/phlog - -# First generate the content -for f in $WWW/*.7; do - # col -b to strip backspace underlines, see mandoc(1) - mandoc -Tascii -Owidth=72 $f | col -b > $PHLOG/`basename $f .7`.txt -done - -# Copy over jam-tuesday -cp -a "$WWW/jam-tuesday" "$PHLOG" - -# Remove/move some non-phlog cruft -mv $PHLOG/intro.txt $DEPLOY/intro.txt -rm -f $PHLOG/template.txt - -# Set the mtimes so they show nicely in the directory listing -# by parsing the .Dd lines using grep(1) and date(1) -# TODO: create a real gophermap for this directory based on blog(7) -for f in $PHLOG/*.txt; do - grep '\.Dd' $WWW/`basename $f .txt`.7 \ - | grep -v Mdocdate \ - | sed "s#\.Dd #$f #" -done > /tmp/mtimes - -IFS=" " # tab to split file/date for read (see ksh(1)) -while read f d; do - touch -m -d `date -j -f "%b %d, %Y" "+%Y-%m-%dT%H:%M:%S" "$d"` "$f" -done < /tmp/mtimes diff --git a/bin/genpost.sh b/bin/genpost.sh @@ -1,6 +1,9 @@ #!/bin/sh # genpost.sh -- reads mdoc(7) from stdin, generates HTML to stdout +REPO=$(dirname "$(dirname "$0")") +# cd into $REPO so that the includes work! +cd $REPO # Command Explained # ----------------- diff --git a/src/kiosk.c b/src/kiosk.c @@ -1,119 +0,0 @@ -#include <dirent.h> -#include <err.h> -#include <limits.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <unistd.h> -#include <fcntl.h> - -int list(void) { - DIR *dirp = opendir(MANDIR); - struct dirent *dp; - int n = 0; - while ((dp = readdir(dirp)) != NULL) { - /* ignore hidden files (and, conveniently, . and ..) */ - if (dp->d_name[0] != '.') { - printf("%2d: %s(7)\n", ++n, dp->d_name); - } - } - closedir(dirp); - printf(" l: list\n"); - printf(" h: help\n"); - printf(" q: quit\n"); - return n; -} - -void help(void) { - printf( - "Welcome to alexkarle.com's SSH Kiosk!\n" - "\n" - "Here you'll find all the mdoc(7) contents of my blog, rendered\n" - "in their original form via mandoc(1).\n" - "\n" - "Currently, due to security concerns, only the blog posts are\n" - "browsable (and no shell access is given).\n" - "\n" - "If you think this is cool, I'd love to hear from you!\n" - "Drop me a line at alex@alexkarle.com!\n" - ); - -} - -/* TODO: have list() read into memory so we don't readdir each time! */ -void mandoc(int choice) { - DIR *dirp = opendir(MANDIR); - struct dirent *dp; - int i = 0; - while ((dp = readdir(dirp)) != NULL) { - if (dp->d_name[0] != '.' && ++i == choice) { - char path[PATH_MAX]; - sprintf(path, "%s/%s", MANDIR, dp->d_name); - FILE *fd = fopen(path, "r"); - if (fd == NULL) - err(1, "open"); - char c; - while ((c = getc(fd)) != EOF) { - putc(c, stdout); - } - fclose(fd); - break; - } - } - closedir(dirp); -} - -void prompt(int n) { - printf("kiosk> "); - fflush(stdout); - - /* NOTE: Read from /dev/tty instead of stdin to prevent - * simple DDOS via < /dev/random */ - - FILE *tty = fopen("/dev/tty", "r"); - if (tty == NULL) - errx(1, "unable to open tty"); - char *line = NULL; - size_t line_len; - ssize_t nread = getline(&line, &line_len, tty); - if (nread == -1 || strcmp(line, "q\n") == 0) { - printf("Goodbye!\n"); - exit(0); - } - fclose(tty); - - int choice; - if (strcmp(line, "l\n") == 0) { - list(); - } else if (strcmp(line, "h\n") == 0) { - help(); - } else if (nread == 1) { - /* must be blank line... no-op */ - } else if (sscanf(line, "%d\n", &choice) == 0) { - printf("Bad input: %s", line); - } else if (choice > n || choice <= 0) { - printf("Choice %d out of bounds\n", choice); - } else { - mandoc(choice); - } - - free(line); -} - -int main(void) { -#ifdef __OpenBSD__ - /* All unveils for this proc only (not for less) */ - if (unveil(MANDIR, "r") == -1) - err(1, "unveil"); - if (unveil("/dev/tty", "r") == -1) - err(1, "unveil"); - /* no more unveil's past here! requires pledge*/ - if (pledge("stdio rpath", NULL) == -1) - err(1, "pledge"); -#endif - int n = list(); - setenv("LESSSECURE", "1", 1); - for(;;) - prompt(n); - return 0; -} diff --git a/welcome.txt b/welcome.txt @@ -0,0 +1,16 @@ +Welcome to text.alexkarle.com! + +This is an experimental version of my main site (alexkarle.com) +in text-only format. For maximum retro effect, I serve up this +directory over HTTP, HTTPS, and Gopher. + +I've been serving txt versions of my mdoc(7) for a while over +Gopher, but decided to formalize the subtree generation and serve +it over HTTP after reading text.causal.agency, which you should +totally check out. (aside: I'd like to state that I've been doing +the whole mdoc(7) thing before I knew about causal.agency and am +not a complete copycat (much respect, great minds think alike and +all that) :) ) + +I hope you enjoy your stay! If you think this is cool, don't +hesitate to reach out: text@alexkarle.com