The Missing Bit

Watching a file under OpenBSD

2024-04-27

I wanted to watch a file under OpenBSD to synchronize my PowerDNS database between two hosts.

First, I tried the entr tool, while it worked, it would usually die after a few days.

OpenBSD philosophy being that daemon should not be restarted on crash, there is no clean way to restart it if it crashes.

I ended up writing a simple shell script. But as I did, I found a few small gotcha and I think it can make it to the posterity.

Below a fully commented version:

#!/bin/sh

# This is the file I am observing
DB=/var/db/pdns/pdns.sqlite3

# This is the command I run if the file changes, simply rsync wrapper
SYNC=/etc/pdns/sync.sh

# This is this script, to let me invoke it recursively
SELF=$0

# If we are invoked with the watch argument, let's loop forever
if [ "$1" = "watch" ] ; then

  # Get the file modified time (OpenBSD format)
  TIME0=$(stat -f  %m $DB)

  while true
  do
    # Get the time again
    TIME1=$(stat -f  %m $DB)

    # If it changed simply run the command and save the time
    if [[ "$TIME0" != "$TIME1" ]]
    then
        $SYNC
        TIME0=$TIME1
    fi
    # This is the poll time, you can make it shorter, but 10 second is enough
    # This part is important, we fork the sleep call to the background, this
    # is to ensure that this script will exit immedialy when killed with
    # SIGTERM
    sleep 10 &
    wait $!
  done
fi

# If not invoked with the watch argument, invoke again with it in the background
# This acts as a start script
if [ "$1" != "watch" ] ; then
  $SELF watch &
  exit 0
fi
If you wish to comment or discuss this post, just mention me on Bluesky or email me.