[RndTbl] Scripting question

Adam Thompson athompso at athompso.net
Tue Jan 30 15:39:58 CST 2007


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 at athompso.net

-------------- next part --------------
An HTML attachment was scrubbed...
URL: http://www.muug.mb.ca/pipermail/roundtable/attachments/20070130/ab9e0d76/attachment.html


More information about the Roundtable mailing list