Lsb conforming init script

From PostgreSQL wiki

Revision as of 18:58, 19 May 2012 by Boshomi (Talk | contribs)

(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to: navigation, search

This is to show an LSB conforming script done using sh scripting, so that it can be used to identify desirable features to add to pg_ctl.

Script

#
 #! /bin/sh
 
 ### BEGIN INIT INFO
 # Provides: postgresql
 # Required-Start: $local_fs $network $syslog
 # Should-Start: $remote_fs $named $time
 # Required-Stop: $local_fs $network $syslog
 # Should-Stop: $remote_fs $named
 # Default-Start: 2 3 4 5
 # Default-Stop: 0 1 6
 # Short-Description: PostgreSQL RDBMS
 # Description: PostgreSQL RDBMS service.
 #              The world's most advanced open source database.
 #              See http://www.postgresql.org/ for more information.
 ### END INIT INFO
 
 # This is an example of a Linux LSB conforming init script.
 # See http://refspecs.freestandards.org/ for more information on LSB.
 
 # Original author:  Kevin Grittner
 
 # $PostgreSQL$
 
 #--------------------------------------------------------------------
 # The only edits needed should be in the INIT INFO block above
 # and between the lines of dashes below.  If any other
 # changes are needed, or you find a way to enhance the script,
 # consider posting to the PostgreSQL hackers list.
 #--------------------------------------------------------------------
 
 # Installation prefix
 prefix="/usr/local/pgsql"
 prefix="/usr/local/pgsql-8.5devel"
 
 # Data directory (Don't end with a slash.)
 PGDATA="/var/local/pgsql/data"
 PGDATA="/var/pgsql/data/test3"
 
 # Who to run the postmaster as, usually "postgres".  (NOT "root")
 PGUSER=postgres
 PGUSER=kgrittn
 
 # Where to keep a log file
 PGLOG="$PGDATA/serverlog"
 
 #--------------------------------------------------------------------
 
 # The path that is to be used for the script
 PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin
 
 # The LSB functions must be present.
 lsbf=/lib/lsb/init-functions
 test -r "$lsbf" || {
     echo "$0: not able to read $lsbf: script cannot run" 1>&2
     exit 5
   }
 
 # Source the functions.
 . "$lsbf"
 # Most output from the script should be through the LSB msg functions after this.
 # In particular, messages indicating success, failure, or warning must use the LSB functions.
 # Progress information may be output to stdout or stderr; although it should be understood
 # that it might not be shown to the user or written to any log or file.
 
 # Define usage string, used in more than one place.
 usage="Usage: $0 {start|stop|restart|try-restart|reload|force-reload|status}"
 
 # Check that we have one parameter: action
 if [ $# -ne 1 ] ; then
   if [ $# -lt 1 -o "$1" = "" ] ; then
     log_failure_msg "$0: action not specified"
   else
     log_failure_msg "$0: too many parameters"
   fi
   log_warning_msg "$usage"
   exit 2
 fi
 action="$1"
 
 # What to use to manipulate the postmaster.
 PGCTL="$prefix/bin/pg_ctl"
 
 # Only start if we can find the $PGCTL executable.
 test -x "$PGCTL" || {
     if [ "$action" = "stop" ] ; then
       log_warning_msg "$0: executable $PGCTL not found: $action request ignored"
       exit 0
     else
       log_failure_msg "$0: executable $PGCTL not found: $action request failed"
       exit 5
     fi
   }
 
 pidfile="$PGDATA/postmaster.pid"
 servicename=$( basename "$0" )
 
 ulimit -c unlimited
 
 # Assuming the first line of the pid file contains (at most) one pid, return it.
 pg_initd_pid () {
   head -1 "$pidfile" 2>/dev/null
 }
 
 # Count how many processes named postgres* are using the data directory.
 pg_initd_process_count () {
   lsof -a -c postgres | grep "$PGDATA/" | wc -l
 }
 
 # Count how many streams are open for connecting to the pid, TCP and UNIX sockets.
 pg_initd_socket_count () {
   pgpid=$( pg_initd_pid )
   if [ "$pgpid" = "" ] ; then
     echo "-1"
   else
     echo $(( $( lsof -at -p "$pgpid" -U | wc -l ) \
            + $( lsof -a -p "$pgpid" -itcp | grep LISTEN | wc -l ) ))
   fi
 }
 
 pg_initd_start () {
   echo -n "Starting $servicename: "
   su -c "'$PGCTL' -w -D '$PGDATA' -l '$PGLOG' start" - $PGUSER
   rc=$?
   if [ $rc -ne 0 ] ; then
     return
   fi
   # pg_ctl can be fooled by a competing postmaster which has already grabbed the port;
   # the test initiated by -w can indicate success, based on talking to the other process.
   # Check that the pid we just created matches an open server socket of some sort.
   if [ $( pg_initd_socket_count ) -gt 0 ] ; then
     return
   fi
   log_warning_msg "$servicename $action: a competing instance of PostgreSQL may be running"
   rc=1
 }
 
 pg_initd_stop () {
   # This will be called when the server is shutting down.
   # If this function never exits, the server hangs forever in a partially shut down state,
   # possibly requiring a hard reboot without shutting down other services.
   # If this function exits before PostgreSQL is completely shut down, any remaining
   # processes will probably be killed with -9 -- which is not recommended.
   # Try very hard to avoid either of the above.
   pgpid=$( pg_initd_pid )
   if [ "$pgpid" = "" ] ; then
     # If this happens, the process went away after the initial check.
     echo "$servicename: not running"
     rc=0
     return
   fi
   echo -n "Shutting down $servicename: "
   su -c "kill -s SIGINT '$pgpid'" - $PGUSER
   echo -n 'waiting for server to stop...'
   rc=1
   # Try "fast" shutdown for a while.
   for seconds in $( seq 50 ) ; do
     echo -n '.'
     if ! ps -o pid= -p "$pgpid" >/dev/null ; then
       rc=0
       break
     fi
     sleep 1
   done
   # Fast didn't do it; try immediate shutdown.
   if [ $rc -ne 0 ] ; then
     su -c "kill -s SIGQUIT '$pgpid'" - $PGUSER
     for seconds in $( seq 10 ) ; do
       echo -n '!'
       if ! ps -o pid= -p "$pgpid" >/dev/null ; then
         rc=0
         break
       fi
       sleep 1
     done
   fi
   ! ps -o pid= -p "$pgpid" >/dev/null
   rc=$?
   if [ "$rc" -eq 0 ] ; then
     echo ' done'
     rm -f "$pidfile"
   else
     echo ' failed'
   fi
 }
 
 pg_initd_reload () {
   su -c "$PGCTL reload -D '$PGDATA'" - $PGUSER
   rc=$?
 }
 
 pg_initd_status () {
   if [ ! -f "$pidfile" ] ; then
     if [ $( pg_initd_process_count ) -ne 0 ] ; then
       log_warning_msg "$servicename $action: orphaned postgres processes may exist"
       rc=4
     else
       rc=3
     fi
     return
   fi
   # pid file found
   pgpid=$( pg_initd_pid )
   if [ $( stat -c%U "$PGDATA" ) != "$PGUSER" ] ; then
     log_warning_msg "$servicename $action: data directory \"$PGDATA\" not owned by \"$PGUSER\""
     rc=4
     return
   fi
   su -c "$PGCTL status -D '$PGDATA'" - $PGUSER
   rc=$?
   if [ $rc -ne 0 ] ; then
     # pg_ctl doesn't return LSB conforming values; treat non-success as "unknown" failure.
     rc=4
   fi
 }
 
 pg_initd_exit () {
   if [ "$action" = "status" ] ; then
     case $rc in
       0)
         log_success_msg "$servicename $action: running"
         ;;
       1)
         log_failure_msg "$servicename $action: dead with existing pid file: $pidfile"
         ;;
       3)
         log_failure_msg "$servicename $action: not running"
         ;;
       *)
         log_failure_msg "$servicename $action: unknown ($rc)"
         ;;
     esac
   else
     case $rc in
       0)
         log_success_msg "$servicename $action: done"
         ;;
       1)
         log_failure_msg "$servicename $action: failed"
         ;;
       4)
         log_failure_msg "$servicename $action: insufficient privilege"
         ;;
       7)
         log_failure_msg "$servicename $action: not running"
         ;;
       *)
         log_failure_msg "$servicename $action: failed ($rc)"
         ;;
     esac
   fi
   exit $rc
 }
 
 # Actions other than status may use these return codes:
 #  1 - generic or unspecified error
 #  2 - invalid or excess argument(s)
 #  3 - unimplemented feature (for example, "reload")
 #  4 - user had insufficient privilege
 #  5 - program is not installed
 #  6 - program is not configured
 #  7 - program is not running
 # Some of these are tested before getting to this case statement.
 case "$action" in
   start)
     # Start the service.
     # If already running, return success without start attempt.
     pg_initd_status
     if [ $rc -eq 0 ] ; then
       log_warning_msg "$servicename $action: service already running; no action taken"
       pg_initd_exit
     fi
     pg_initd_start
     pg_initd_exit
     ;;
   stop)
     # Stop the service.
     # If not running, return success without stop attempt.
     pg_initd_status
     if [ $rc -eq 3 ] ; then
       log_warning_msg "$servicename $action: service not running; no action taken"
       rc=0
       pg_initd_exit
     fi
     if [ $rc -ne 0 ] ; then
       rc=1
       pg_initd_exit
     fi
     pg_initd_stop
     pg_initd_exit
     ;;
   restart)
     # Stop and restart the service if the service is already running,
     # otherwise start the service.
     pg_initd_status
     if [ $rc -eq 3 ] ; then
       log_warning_msg "$servicename $action: service not running; no attempt to stop"
     else
       pg_initd_stop
       if [ $rc -ne 0 ] ; then
         pg_initd_exit
       fi
     fi
     pg_initd_start
     pg_initd_exit
     ;;
   try-restart)
     # Restart the service if the service is already running.
     # If stopped, return success without stop attempt.
     pg_initd_status
     if [ $rc -eq 3 ] ; then
       log_warning_msg "$servicename $action: service not running; no action taken"
       rc=0
       pg_initd_exit
     fi
     if [ $rc -ne 0 ] ; then
       pg_initd_exit
     fi
     pg_initd_stop
     if [ $rc -ne 0 ] ; then
       pg_initd_exit
     fi
     pg_initd_start
     pg_initd_exit
     ;;
   reload|force-reload)
     # Cause the configuration of the service to be reloaded
     # without actually stopping and restarting the service.
     # (Since PostgreSQL supports reload, force-reload should use that.)
     pg_initd_status
     if [ $rc -eq 3 ] ; then
       rc=7
       pg_initd_exit
     fi
     pg_initd_reload
     pg_initd_exit
     ;;
   status)
     # Print the current status of the service.
     # Return codes differ from other actions:
     #  0 - program is running or service is OK
     #  1 - program is dead and /var/run pid file exists
     #  2 - program is dead and /var/lock lock file exists
     #  3 - program is not running
     #  4 - program or service status is unknown
     pg_initd_status
     pg_initd_exit
     ;;
   *)
     # If we don't recognize action, consider it an invalid argument.
     # If the standard adds actions we don't support, exit should be 3 for those.
     log_failure_msg "$0: action \"$action\" not recognized"
     log_warning_msg "$usage"
     exit 2
     ;;
 esac
Personal tools