Skip site navigation (1)Skip section navigation (2)

FreeBSD Manual Pages

  
 
  

home | help
perpetrate(5)		persistent process supervision		 perpetrate(5)

NAME
       perpetrate - conventions	for runscripts

DESCRIPTION
       perpd(8)	 operates  on  a  pair	of ``runscripts'' that are executed to
       start and reset a service and an	optional logger.

       The runscripts recognized by perpd(8) are:

       rc.log
	      Optional.	 Controls the logger for the main service.

       rc.main
	      Required.	 Controls the main service.

       The arguments, structure, and conventions for rc.log  and  rc.main  are
       identical.  The illustrations below will	usually	be shown with rc.main,
       but are equally applicable to rc.log unless noted otherwise.

       perpd(8)	will invoke service runscripts from within the service defini-
       tion directory.	For example, given some	service	definition directory

	      /etc/perp/foo

       perpd(8)	 will switch into foo before invoking a	runscript.  This means
       that foo	will be	the current working directory within the runscript en-
       vironment.

       Runscripts are normally implemented as executable shell	scripts,  pre-
       pared  and  installed by	the system administrator.  A runscript will be
       executed	at least twice during the life cycle of	a service:

	      	  to start the service

	      	  after	the service exits

       A runscript will	accordingly be structured to handle  either  of	 these
       events.

       Runscripts are invoked in the general form:

	      ./rc.main	target svname [	args...	 ]

       The  argument  target will be set to one	of two literal strings,	either
       ``start'' or ``reset'', depending on whether perpd(8)  is  starting  or
       resetting the service.  The svname argument will	be set to the basename
       of  the	service	 definition directory, such as ``foo'' for the service
       directory foo.  Any additional arguments	depend on the target.

       When using a ``start'' target, perpd(8) will invoke the runscript  like
       this:

	      ./rc.main	start svname

       This  follows  the  general form	with no	additional arguments.  Given a
       ``start'' target, a runscript process should  perform  any  initializa-
       tions  the  service  requires,  and then	proceed	to replace itself (its
       process ID) with	the desired service  running  in  the  foreground.   A
       Bourne-compatible script	such as	sh(1) will replace itself by using the
       exec  command  to  start	 the service.  This provides perpd(8) with the
       process ID it needs for the actual running service, so that the service
       may be properly monitored and controlled.

       Normally	the ``start'' target will result in a  persistent  process,  a
       long-running  program  that  starts  at system boot and continues until
       system shutdown.	 A runscript called with  a  ``start''	target	should
       generally  not return or	exit, unless some error	is encountered in ini-
       tializing or starting the service.

       As long-running as a service may	be, whenever it	 does  exit,  for  any
       reason, perpd(8)	will call the runscript	again with a ``reset'' target.
       A  ``reset'' target will	invoke the runscript with additional arguments
       in either one of	two forms, depending on	 whether  the  service	exited
       normally, or was	terminated by a	signal:

	      ./rc.main	reset svname exit exitcode
       or
	      ./rc.main	reset svname signal signum signame

       In  the	first case, where a service has	terminated normally, the addi-
       tional arguments	include	the literal string  ``exit'',  followed	 by  a
       string representation of	the numeric exit code returned by the process.

       In the second case, where a service was terminated by a signal, the ad-
       ditional	arguments include the literal string ``signal'', followed by a
       string  representation  of  the	signal number that killed the process,
       followed	by the symbolic	name for the signal, such as SIGTERM,  and  as
       may be found listed in signal(7).

       When  called  with  a ``reset'' target, a runscript may be used for any
       number of purposes:

	      	  post-service logging and cleanup

	      	  sysadmin notification

	      	  shutdown of dependent	services

       On the other hand, a runscript doesn't have to do anything with a ``re-
       set'' target at all.  There are no particular  conditions  or  require-
       ments  for  a  resetting	service, except	that the runscript should nor-
       mally return/exit as promptly as	possible.  A resetting runscript  will
       usually do its job quickly so that perpd(8) may start the service again
       as soon as possible.

EXAMPLES
       Assume  that perpd(8) is	supervising some service defined in the	subdi-
       rectory foo.  The simplest barebones rc.main runscript will act only on
       the ``start'' target to exec into the foo service:

	      #!/bin/sh
	      if test ${1} = 'start' ; then
		exec /usr/bin/foo -f
	      fi

	      exit 0

       This example performs no	initializations, does not prepare for logging,
       and responds only to a ``start''	target.	  It  simply  execs  into  the
       /usr/bin/foo  program,  here called with	an -f argument,	presumably re-
       quired to run foo in the	foreground.  On	any other  target  other  than
       ``start'', this runscript will exit 0.

       Here  is	 another example of a simple foo service, this time with a bit
       of logging added:

	      #!/bin/sh
	      exec 2>&1

	      if test ${1} = 'start' ; then
		echo "starting ${2}..."
		exec /usr/bin/foo -f
	      fi

	      exit 0

       This runscript starts by	redirecting stderr to stdout, so that all out-
       put will	be captured by the associated logging service.	The  runscript
       also  emits  a  startup	message	 that will be picked up	by the logger,
       showing the use of the svname argument given as the second parameter to
       the runscript.

       A simple	rc.log runscript for this service might	look like this:

	      #!/bin/sh
	      if test ${1} = 'start' ; then
		exec tinylog -k	5 -t /var/log/${2}
	      fi

	      exit 0

       As with the rc.main runscript example, this runscript only responds  to
       a  ``start''  target.  It execs tinylog(8) to maintain a	set of up to 5
       rotated and timestamped log files in the	directory  /var/log/foo,  sup-
       plying  the final path element to the logging directory from the	svname
       given as	the second parameter to	the runscript.

       With a logger setup for the foo service,	some post-service logging  may
       now be added for	a ``reset'' target in rc.main:

	      #!/bin/sh
	      exec 2>&1

	      if test ${1} = 'start' ; then
		echo "starting ${2}..."
		exec /usr/bin/foo -f
	      fi

	      if test ${1} = 'reset' ; then
		case ${3} in
		  'exit')   echo "service ${2} exited with exitcode ${4}" ;;
		  'signal') echo "service ${2} terminated on signal ${5}" ;;
		esac
	      fi

	      exit 0

       Now  whenever this service exits, and the runscript is run with a ``re-
       set'' target, the logger	will pick up a timestamped record of the event
       as well as the cause/type of termination.

       Runscripts may use whatever branching idioms are	provided by the	script
       interpreter.  A couple of obvious possibilities in  sh(1)  include  the
       case and	eval statements.  Here is an example runscript using eval:

	      #!/bin/sh
	      exec 2>&1

	      TARGET=${1}
	      SVNAME=${2}

	      start() {
		echo "starting ${SVNAME}..."
		exec /usr/bin/foo -f
	      }

	      reset() {
		echo "resetting	${SVNAME}..."
		exit 0
	      }

	      eval ${TARGET} "$@"

       The  runscripts	shown above are	admittedly simplistic.	Runscripts may
       be, and often are, embellished considerably beyond the simple  examples
       shown here.  In particular, runtools(8) are often used in the exec com-
       mand  of	 a  runscript  ``start'' target	to implement resource control,
       privilege drops,	and other manipulations	of the service	process	 envi-
       ronment.

       Nevertheless,  it  is generally preferable to keep runscripts as	simple
       as possible, while still	starting  the  service	safely	and  reliably.
       Simpler	runscripts  run	 faster,  are easier to	maintain and diagnose,
       have fewer unexpected side effects, and	are  generally	more  portable
       among different host installations.

ENVIRONMENT
       In addition to the positional arguments supplied	to the runscript, cer-
       tain other variables are	also defined within the	runscript environment.

       The PERP_BASE variable is defined for both ``start'' and	``reset'' tar-
       gets.  This variable provides the base directory	of the service instal-
       lation,	normally /etc/perp, and	as described in	perpd(8).  The defini-
       tion of PERP_BASE permits the use of such perp utilities	 as  perpok(8)
       and  perpctl(8)	directly within	runscripts, where they may then	easily
       reference any other service definitions as necessary.

       The PERP_SVPID variable is defined for  both  ``start''	and  ``reset''
       targets.	  For the ``start'' target, PERP_SVPID gives the process ID of
       the service that	will be	started.  For the ``reset'' target, PERP_SVPID
       gives the process ID of the service that	 has  just  terminated.	  Run-
       scripts	may  choose  to	use the	PERP_SVPID variable to generate	output
       that cleanly brackets the complete life-cycle of	a service within  ser-
       vice logs, or for any other purpose of reporting	and notification.

       The  PERP_SVSECS	variable is defined only for the ``reset'' target.  It
       gives the total wallclock uptime, in seconds, of	the service  that  has
       just  terminated.   Runscripts  running	``reset''  may	choose	to use
       PERP_SVSECS for logging the uptime of a service,	or for any other  pur-
       pose of reporting and notification.

COMPATIBILITY
       For  users familiar with	the daemontools	package, the runscript conven-
       tions described here are	not directly interchangeable with those	of su-
       pervise(8).  The	main difference	is that	the run	scripts	of daemontools
       are designed to perform only on startup of a service, and will have  no
       facility	for properly handling a	``reset'' argument.

       Nevertheless,  it  is  trivial to provide compatibility to perpd(8) for
       any pre-existing	daemontools run	scripts.  Just install copies  of  the
       following rc.main into any daemontools service definition directory:

	      #!/bin/sh
	      if test ${1} = 'start' ; then
		exec ./run
	      fi

       Likewise, this rc.log:

	      #!/bin/sh
	      if test ${1} = 'start' ; then
		cd ./log && exec ./run
	      fi

HISTORY
       The perpd(8) daemon formerly used multiple instances of a perpetrate(8)
       executable,  running  one  instance for each service under supervision.
       Under that architecture,	the perpetrate(8) executable performed all the
       supervisory operations on the service definition	as described  in  this
       manual.

       Beginning  with	version	 2.0, the operations of	the perpetrate(8) exe-
       cutable were internally coalesced with perpd(8) itself,	and  the  need
       for perpetrate(8) was eliminated.  Meanwhile, all the runscript conven-
       tions  have  otherwise  remained	 the same, and the name	of this	manual
       page has	been retained to describe them.

AUTHOR
       Wayne Marshall, http://b0llix.net/perp/

SEE ALSO
       perp_intro(8),	perpboot(8),   perpctl(8),    perpd(8),	   perphup(8),
       perpls(8), perpok(8), perpstat(8), sissylog(8), tinylog(8)

perp-2.07			 January 2013			 perpetrate(5)

Want to link to this manual page? Use this URL:
<https://man.freebsd.org/cgi/man.cgi?query=perpetrate&sektion=5&manpath=FreeBSD+Ports+14.3.quarterly>

home | help