Kevin McGregor wrote:
I have this script:
#!/bin/bash

if [ -e /var/run/pgsql.pipe ]; then
        while [ -e /var/run/pgsql.pipe ]
        do
                psql -q -h padsysdb -U sysloguser syslog </var/run/pgsql.pipe
        done
fi

...running on a Ubuntu Linux server. It's clearly very simple; it just keeps checking the named pipe /var/run/pgsql.pipe and sending the contents to the psql command, which interprets the input as a SQL command and executes it accordingly.

My question is, given that I want this loop to execute (a) from server startup (b) indefinitely and without interruption, how do I reasonably ensure (a) and (b)?

More specifically, where do I stick this (or an equivalent) in the startup scripts on Ubuntu, and is there a good automated way to make sure it keeps going? I really don't want to lose any of my database input. It's a fairly critical system, and I'd like to make this pretty robust.
  

Regardless of distribution, you can always just call a command from /etc/rc.local (or something very close to that)...

However, to ensure it stays running you can take advantage of init(8)'s functionality and put a line in /etc/inittab(5):

    km:2345:respawn:/usr/local/bin/mypgsqlscript.sh arg1 arg2 argN

...and of course, mypgsqlscript.sh can do anything a shell script can.  Keep in mind that init exec(2)'s everything as root, so if you need to run as a different user you'll need two scripts, where the first script is a two-liner that looks like:

    #!/bin/bash
    exec /bin/su --login --command="/usr/local/bin/my_unprivliged_script.sh $@" some_unprivilged_username

(Psql doesn't usually care who it gets run as, the username is provided on the command-line... see the one-liner, following:)

This technique is (almost) distro-independent; the exception being anything that uses a BSD-style startup sequence where init(8) doesn't exist... all the major (and all the minor (and almost all of the niche)) Linux distributions use SysV-style init so this will be available to you.

The other option I would recommend is to look at the "daemontools" or "mon" packages.  They should be available for Ubuntu...

The last resort would be to have a script that actually does all the housekeeping necessary to monitor a daemon-like process and ensure that it restarts if it dies... but why go to that effort when init(8) does it for you?

Bottom line:  you can do this all in one line with inittab(5):

    km:2345:respawn:/usr/bin/psql --dbname syslog --file /var/run/pgsql.pipe --hostname padsysdb --output /var/log/pgsql_pipe.out --quiet --username sysloguser

since according to fifo(4) the reading process will block until a writer connects to the FIFO (aka Named Pipe).  Testing reveals that when the writer close(2)s the FIFO, the reader gets an EOF.  The psql utility's --file option implies that the program will terminate upon reaching EOF in that file.  Then init(8) will restart psql (because of "respawn") whereupon it will sit and wait for the next (set of) command(s) to arrive.

The big thing to watch out for here is timing.  Regardless of which way it's done, psql probably isn't written to process asynchronous input and so will probably sit and do nothing until EOF occurs.  So if you have a process writing commands once in a while to the FIFO, you need to ensure the file descriptor gets closed periodically so that psql can actually parse the SQL and run it.

Also, why would the FIFO vanish?  If there's a real danger of that happening, wrap the psql command in a shell script and put a mkfifo or mknod call first

    #!/bin/bash
    [[ -p /var/run/pgsql.pipe ]] || /bin/mknod /var/run/pgsql.pipe p
    exec
/usr/bin/psql --dbname syslog --file /var/run/pgsql.pipe --hostname padsysdb --output /var/log/pgsql_pipe.out --quiet --username sysloguser

and call that script from inittab instead of psql directly.  You probably only need/want to account for the possibility of the pipe vanishing on on end or the other - but you could always create a cron job that runs that one-liner (/bin/bash -c "exec </dev/null 2>&1 >/dev/null; [[ -p /var/run/pgsql.pipe]] || mkfifo /var/run/pgsql.pipe") every 5 minutes.  Or put that into inittab, too, if you only care about it at system startup:

    pp:2345:sysinit:/bin/mknod /var/run/pgsql.pipe p

N.B.  "/bin/mknod X p" is exactly equivalent to "/bin/mkfifo X".  Not sure why the coreutils team decided to duplicate that functionality... probably because HP/UX or something had a mkfifo command once upon a time.  The joy of backward compatability...

-Adam Thompson
 athompso-muug@athompso.net