-- Leo's gemini proxy

-- Connecting to shit.cx:1965...

-- Connected

-- Sending request

-- Meta line: 20 text/gemini;

        .     *  ⠈       +                ⠈
                   +  ──╕   ○    .   ⠈           ⠐
   ●     .           ╒═╕╞═╕ ╕ ╪═        *               .
                     ╘═╕│ │ │ │  .cx            +
           .     ....╘═╛╘ ╘ ╘ ╘═ ....:      ⠐        .
                 .               *                ⠐        .

Making a daemon from a shell script on OpenBSD: Why is it so hard?


2022-07-01T02:25


I've been becoming familiar with OpenBSD over the past few weeks. So far I've been liking it a lot. I'm getting so absorbed in it that it's getting into my dreams. That's not something that's happened since I was a kid getting into tech (or maybe it has something to do with the fever I've been fighting off). But today I ran into my first ordeal: running shell scripts through rcctl. It was way more fiddly than I was expecting.


I needed to publish the number of Gemini requests my vger daemon was serving over StatsD to InfluxDB. I looked for something I could take to do the job and only found statsdlog¹. A python app was more complicated than I wanted. I didn't want to deal with python and its dependencies.


I'd been thinking about setting up syslogd to send logs to netcat on localhost which would pipe it to awk to either drop or convert the log into a statsd message. Simple, right?


After a little mucking around, I had something working. It wasn't pretty and it has some unhandled edge-cases, but it's good enough for what I need.


#!/usr/bin/env bash
nc -k -l -u 50123 \
  | while read -d "<" LINE; do
      echo ${LINE} | grep -E "^\<[0-9]+\>" | sed 's/^/</'
    done \
  | awk '
      /vger: request gemini:\/\/shit\.cx\//            { print "gemini.requests,vhost=shit.cx:1|c"}
      { fflush(); }
    ' \
  | nc 127.0.0.1 8125

The first netcat listens to a stream of syslog messages. It's then delimited on `<` which is dodgy but good enough. Awk finds the interesting logs and increments a counter by 1 when found. It also runs fflush without which it buffers the output for some reason. The final netcat sends the statsd messages to the local statsd port.


Next, I needed to write an rc script to manage it and that's when the trouble began.


The first issue was making it kill the correct process. That was sorted out with `pexp`, but after doing that it wasn't killing the child processes. Netcat was still running even though the parent, bash, was gone. Netcat's ppid switched from bash's pid to 1. Not at all what I was expecting.


So I added some code to handle that. A trap that kills all processes with a ppid of itself.


But that still didn't work. It was like the pipeline wasn't leaving room bash to run its trap. So I ran the pipeline in the background and added a `wait` to prevent the script from completing.


That fixed it. I'm very surprised at how complicated this is. OpenBSD doesn't come with `daemon` like FreeBSD has so I avoided using that. Maybe there is a better way, I'm very new to OpenBSD so it's highly likely.


The script that I ended up with is this:


#!/usr/bin/env bash
PID=$$

_cleanup() {
  echo "cleaning up"
  kill $(pgrep -P ${PID})
}

trap '_cleanup' SIGINT SIGQUIT SIGKILL

nc -k -l -u 50123 \
  | while read -d "<" LINE; do
      echo ${LINE} | grep -E "^\<[0-9]+\>" | sed 's/^/</'
    done \
  | awk '
      /vger: request .*\_health.gmi/                   { next; }
      /vger: request gemini:\/\/shit\.cx\//            { print "gemini.requests,vhost=shit.cx:1|c"}
      /vger: request gemini:\/\/guardian\.shit\.cx\//  { print "gemini.requests,vhost=guardian.shit.cx:1|c"}
      { fflush(); }
    ' \
  | nc 127.0.0.1 8125 \
  &

pid=$!
wait $pid

And the rc script looks like this:


#!/bin/ksh

daemon="/usr/local/bin/log2statsd"

. /etc/rc.d/rc.subr

pexp='bash /usr/local/bin/log2statsd'
rc_stop_signal=QUIT

rc_start() {
        ${rcexec} "nohup ${daemon} ${daemon_flags} &"
}

rc_cmd $1


1. statsdlog



---


More Posts Like This

Return to Homepage


The content for this site is CC-BY-SA-4.0.

-- Response ended

-- Page fetched on Wed May 1 20:28:07 2024