Succinct, idiomatic abort in execlineb scripts?

From: Saj Goonatilleke <saj_at_discourse.org>
Date: Tue, 06 Sep 2022 04:54:48 +1000

Hello,

Within the context of, say, an s6 run script that needs to do a little bit of
prep work before execing into a server, it is often helpful to abort early if
any of said prep work stumbles upon an unexpected problem.

Maybe the filesystem is R/O. Or full.
Maybe an operator has fat-fingered something we need.
Who knows! Production is full of surprises.

sh provides set -e, which is often satisfactory for simple prep scripts
(if one is aware of its footguns).

Is there a succinct, idiomatic set -e equivalent in the execline suite?

I have included an example s6 run script below, which demonstrates the closest I
have come so far. fgsigwait is my alternative take on foreground[1]. fgsigwait
behaviour differs in the following respects:

* fgsigwait exits[2] if prog1 exits with non-zero status.
  foreground, by comparison, sets the ? environment variable and continues.
  (fgsigwait -! reverts to foreground-ish behaviour.)

* fgsigwait forwards some trappable signals to its child. HUP, INT, etc.
  This is where its name comes from.
  (PID 1 is broken on some of our systems, which provided the initial motivation
  for this hack. fgsigwait always waits on prog1 after forwarding a signal.
  This, plus execline's execution model, gave me fine control over when stuff
  is forked -- and helped us avoid some Z process leaks. Anyhoo.)

fgsigwait otherwise aims to be a syntactic execlineb drop-in for foreground in
cases where these features are desired. Chaining stuff with fgsigwait emulates
sh set -e without needing to repeatedly and explicitly test the ? env var.

--- 8< ---
#!/usr/bin/env -S execlineb -WP

fdmove -c 2 1

# slow-deathroll is a simple wrapper around
# github.com/leahneukirchen/snooze
# extends the s6 one-second restart penalty if we crash too soon
fgsigwait { slow-deathroll }

# Here is a simple example of some prep work.
# We want to bail here if any of these things exit non-zero.
fgsigwait {
  execline-cd data
  if -t { test ! -e live } fgsigwait { mkdir -p empty } ln -s empty live
}

# maybe a smidge more prep here...

# all prep done. exec into our server.
nsd -d -c nsd.conf
--- >8 ---

This does work OK, but, every time I reach for my little program, I can't shake
the feeling that I am probably reinventing some wheel.

fgsigwait was implemented in Go, as is personal tradition when something need be
hacked up in a hurry on the clock. Spooling up the Go runtime eats a few extra
milliseconds of time, and a few megabytes of memory. While not practically
significant to us -- we don't deploy to tiny machines -- a small part of me was
sad to add bloat. It would be nice if I could get rid of it.

Is there a better way to abort?

I suppose I could just fork sh, but inlining is pleasant when the prep is short.

Thanks!


[1]: https://skarnet.org/software/execline/foreground.html
[2]: https://skarnet.org/software/execline/exitcodes.html
Received on Mon Sep 05 2022 - 20:54:48 CEST

This archive was generated by hypermail 2.4.0 : Mon Sep 05 2022 - 20:55:22 CEST