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

FreeBSD Manual Pages


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

       perpetrate - conventions	for runscripts

       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:

	      Optional.	 Controls the logger for the main service.

	      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


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

       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:

	      o	  to start the service

	      o	  after	the service exits

       A  runscript  will  accordingly be structured to	handle either of these

       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

	      ./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
	      ./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:

	      o	  post-service logging and cleanup

	      o	  sysadmin notification

	      o	  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.

       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:

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

	      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:

	      exec 2>&1

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

	      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:

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

	      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:

	      exec 2>&1

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

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

	      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:

	      exec 2>&1


	      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-

       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.

       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.

       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:

	      if test ${1} = 'start' ; then
		exec ./run

       Likewise, this rc.log:

	      if test ${1} = 'start' ; then
		cd ./log && exec ./run

       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

       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.

       Wayne Marshall,

       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:

home | help