# $NetBSD: rc.subr,v 1.18 2021/08/30 21:45:02 khorben Exp $ # # Copyright (c) 1997-2002 The NetBSD Foundation, Inc. # All rights reserved. # # This code is derived from software contributed to The NetBSD Foundation # by Luke Mewburn. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions # are met: # 1. Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # 2. Redistributions in binary form must reproduce the above copyright # notice, this list of conditions and the following disclaimer in the # documentation and/or other materials provided with the distribution. # # THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS # ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED # TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR # PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS # BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF # SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN # CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE # POSSIBILITY OF SUCH DAMAGE. # # rc.subr # functions used by various rc scripts # # global variables # ---------------- sysconfbase=@SYSCONFBASE@ _RCCMD_chown="/usr/sbin/chown" _RCCMD_chroot="/usr/sbin/chroot" _RCCMD_ci="/usr/bin/ci" _RCCMD_co="/usr/bin/co" _RCCMD_cp="/bin/cp" _RCCMD_echo="echo" # use sh builtin _RCCMD_kill="/bin/kill" _RCCMD_logger="/usr/bin/logger" _RCCMD_mount="/sbin/mount" _RCCMD_mv="/bin/mv" _RCCMD_nice="/usr/bin/nice" _RCCMD_ps="/bin/ps" _RCCMD_rcs="/usr/bin/rcs" _RCCMD_rm="/bin/rm" _RCCMD_sh="/bin/sh" _RCCMD_su="/usr/bin/su" _RCCMD_systrace="/bin/systrace" _RCCMD_whoami="/usr/bin/whoami" _RCARG_psformat="-o pid,command" _RCARG_ps="-ax" _RCARG_su="-m" _osname=$(uname -s) _osrelease=$(uname -r) case $_osname in Darwin) _RCCMD_echo="/bin/echo" ;; SunOS) _RCCMD_chown="/bin/chown" # _RCCMD_ci="/usr/bin/ci" # not in Solaris 9 # _RCCMD_co="/usr/bin/co" # not in Solaris 9 # _RCCMD_systrace="/bin/systrace" # not in Solaris 9 _RCARG_psformat="-o pid,comm" _RCARG_ps="-ef" _RCARG_su="" if [ "$_osrelease" = "5.11" ]; then bsd_echo () { if [ "$1" = "-n" ]; then shift; echo "$@\c" else echo "$@" fi } _RCCMD_echo="bsd_echo" else _RCCMD_echo="/usr/ucb/echo" # not in Solaris 11 _RCCMD_whoami="/usr/ucb/whoami" # not in Solaris 11 fi ;; Interix) bsd_echo () { if [ "$1" = "-n" ]; then shift; echo "$@\c" else echo "$@" fi } _RCCMD_chown="/usr/bin/chown" _RCCMD_ci="/usr/contrib/bin/ci" _RCCMD_co="/usr/contrib/bin/co" _RCCMD_echo="bsd_echo" _RCCMD_rcs="/usr/contrib/bin/rcs" _RCARG_psformat="-wwo pid,comm" ;; IRIX*) _RCCMD_chown="/sbin/chown" _RCCMD_ci="/usr/sbin/ci" _RCCMD_co="/usr/sbin/co" _RCCMD_cp="/sbin/cp" _RCCMD_kill="kill" # use sh builtin # _RCCMD_logger="/usr/bin/logger" # not in IRIX _RCCMD_mv="/sbin/mv" _RCCMD_nice="/sbin/nice" _RCCMD_ps="/sbin/ps" _RCCMD_rcs="/usr/sbin/rcs" _RCCMD_rm="/sbin/rm" _RCCMD_sh="/sbin/sh" _RCCMD_su="/sbin/su" # _RCCMD_systrace="/bin/systrace" # not in IRIX _RCCMD_whoami="/bin/whoami" _RCARG_psformat="-o pid,comm=12345678901234567890" # widen column to try to get full command-name _RCARG_ps="-ef" _RCARG_su="" ;; Linux) _RCCMD_chown="/bin/chown" # _RCCMD_ci="/usr/bin/ci" # not in Slackware 8.1 # _RCCMD_co="/usr/bin/co" # not in Slackware 8.1 if [ ! -f /etc/arch-release ] ; then # which not in Arch _RCCMD_nice=$(which nice) fi # _RCCMD_rcs="/usr/bin/rcs" # not in Slackware 8.1 # _RCCMD_systrace="/bin/systrace" # not in Slackware 8.1 _RCARG_ps="ax" if [ -e /etc/redhat-release ]; then _RCCMD_su="/bin/su" # for CentOS/RHEL fi ;; QNX) _RCCMD_chown="/bin/chown" # _RCCMD_ci="/usr/bin/ci" # not in QNX # _RCCMD_co="/usr/bin/co" # not in QNX # _RCCMD_systrace="/bin/systrace" # not in QNX _RCCMD_whoami="/usr/bin/id -un" _RCARG_psformat="-o pid,comm" _RCARG_ps="-ef" _RCARG_su="" ;; esac # # functions # --------- # # checkyesno var # Test $1 variable, and warn if not set to YES or NO. # Return 0 if it's "yes" (et al), nonzero otherwise. # checkyesno() { eval _value=\$${1} case $_value in # "yes", "true", "on", or "1" [Yy][Ee][Ss]|[Tt][Rr][Uu][Ee]|[Oo][Nn]|1) return 0 ;; # "no", "false", "off", or "0" [Nn][Oo]|[Ff][Aa][Ll][Ss][Ee]|[Oo][Ff][Ff]|0) return 1 ;; *) warn "\$${1} is not set properly - see rc.conf(5)." return 1 ;; esac } # reverse_list list # print the list in reverse order # reverse_list() { _revlist= for _revfile; do _revlist="$_revfile $_revlist" done ${_RCCMD_echo} $_revlist } # # mount_critical_filesystems type # Go through the list of critical filesystems as provided in # the rc.conf(5) variable $critical_filesystems_${type}, checking # each one to see if it is mounted, and if it is not, mounting it. # mount_critical_filesystems() { eval _fslist=\$critical_filesystems_${1} for _fs in $_fslist; do ${_RCCMD_mount} | ( _ismounted=false while read what _on on _type type; do if [ $on = $_fs ]; then _ismounted=true fi done if $_ismounted; then : else ${_RCCMD_mount} $_fs >/dev/null 2>&1 fi ) done } # # check_pidfile pidfile procname [interpreter] # Parses the first line of pidfile for a PID, and ensures # that the process is running and matches procname. # Prints the matching PID upon success, nothing otherwise. # interpreter is optional; see _find_processes() for details. # check_pidfile() { _pidfile=$1 _procname=$2 _interpreter=$3 if [ -z "$_pidfile" -o -z "$_procname" ]; then err 3 'USAGE: check_pidfile pidfile procname [interpreter]' fi if [ ! -f $_pidfile ]; then return fi read _pid _junk < $_pidfile if [ -z "$_pid" ]; then return fi _find_processes $_procname ${_interpreter:-.} '-p '"$_pid" } # # check_process procname [interpreter] # Ensures that a process (or processes) named procname is running. # Prints a list of matching PIDs. # interpreter is optional; see _find_processes() for details. # check_process() { _procname=$1 _interpreter=$2 if [ -z "$_procname" ]; then err 3 'USAGE: check_process procname [interpreter]' fi _find_processes $_procname ${_interpreter:-.} ${_RCARG_ps} } # # _find_processes procname interpreter psargs # Search for procname in the output of ps generated by psargs. # Prints the PIDs of any matching processes, space separated. # # If interpreter == ".", check the following variations of procname # against the first word of each command: # procname # `basename procname` # `basename procname` + ":" # "(" + `basename procname` + ")" # # If interpreter != ".", read the first line of procname, remove the # leading #!, normalise whitespace, append procname, and attempt to # match that against each command, either as is, or with extra words # at the end. # _find_processes() { if [ $# -ne 3 ]; then err 3 'USAGE: _find_processes procname interpreter psargs' fi _procname=$1 _interpreter=$2 _psargs=$3 _pref= if [ $_interpreter != "." ]; then # an interpreted script read _interp < $_procname # read interpreter name _interp=${_interp#\#!} # strip #! set -- $_interp if [ $_interpreter != $1 ]; then warn "\$command_interpreter $_interpreter != $1" fi _interp="$* $_procname" # cleanup spaces, add _procname _fp_args='_argv' _fp_match='case "$_argv" in ${_interp}|"${_interp} "*)' else # a normal daemon _procnamebn=${_procname##*/} _fp_args='_arg0 _argv' _fp_match='case "$_arg0" in $_procname|$_procnamebn|${_procnamebn}:|"(${_procnamebn})"|"[${_procnamebn}]")' fi _proccheck=' ${_RCCMD_ps} ${_RCARG_psformat} '"$_psargs"' | while read _npid '"$_fp_args"'; do case "$_npid" in PID) continue ;; esac ; '"$_fp_match"' ${_RCCMD_echo} -n "$_pref$_npid" ; _pref=" " ;; esac done' eval $_proccheck } # # wait_for_pids pid [pid ...] # spins until none of the pids exist # wait_for_pids() { _list="$@" if [ -z "$_list" ]; then return fi _prefix= while true; do _nlist=""; for _j in $_list; do if ${_RCCMD_kill} -0 $_j 2>/dev/null; then _nlist="${_nlist}${_nlist:+ }$_j" fi done if [ -z "$_nlist" ]; then break fi _list=$_nlist ${_RCCMD_echo} -n ${_prefix:-"Waiting for PIDS: "}$_list _prefix=", " sleep 2 done if [ -n "$_prefix" ]; then ${_RCCMD_echo} "." fi } # # run_rc_command argument # Search for argument in the list of supported commands, which is: # "start stop restart rcvar status poll ${extra_commands}" # If there's a match, run ${argument}_cmd or the default method # (see below). # # If argument has a given prefix, then change the operation as follows: # Prefix Operation # ------ --------- # fast Skip the pid check, and set rc_fast=yes # force Set ${rcvar} to YES, and set rc_force=yes # # The following globals are used: # # Name Needed Purpose # ---- ------ ------- # name y Name of script. # # command n Full path to command. # Not needed if ${rc_arg}_cmd is set for # each keyword. # # command_args n Optional args/shell directives for command. # # command_interpreter n If not empty, command is interpreted, so # call check_{pidfile,process}() appropriately. # # extra_commands n List of extra commands supported. # # pidfile n If set, use check_pidfile $pidfile $command, # otherwise use check_process $command. # In either case, only check if $command is set. # # procname n Process name to check for instead of $command. # # rcvar n This is checked with checkyesno to determine # if the action should be run. # # ${name}_chroot n Directory to chroot to before running ${command} # Requires /usr to be mounted. # # ${name}_chdir n Directory to cd to before running ${command} # (if not using ${name}_chroot). # # ${name}_flags n Arguments to call ${command} with. # NOTE: $flags from the parent environment # can be used to override this. # # ${name}_nice n Nice level to run ${command} at. # # ${name}_user n User to run ${command} as, using su(1) if not # using ${name}_chroot. # Requires /usr to be mounted. # # ${name}_group n Group to run chrooted ${command} as. # Requires /usr to be mounted. # # ${name}_groups n Comma separated list of supplementary groups # to run the chrooted ${command} with. # Requires /usr to be mounted. # # ${name}_systrace n Flags passed to systrace(1) if it is used. # Setting this variable enables systracing # of the given program. The use of "-a" is # recommended so that the boot process is not # stalled. In order to pass no flags to # systrace, set this variable to "--". # # ${rc_arg}_cmd n If set, use this as the method when invoked; # Otherwise, use default command (see below) # # ${rc_arg}_precmd n If set, run just before performing the # ${rc_arg}_cmd method in the default # operation (i.e, after checking for required # bits and process (non)existence). # If this completes with a non-zero exit code, # don't run ${rc_arg}_cmd. # # ${rc_arg}_postcmd n If set, run just after performing the # ${rc_arg}_cmd method, if that method # returned a zero exit code. # # required_dirs n If set, check for the existence of the given # directories before running the default # (re)start command. # # required_files n If set, check for the readability of the given # files before running the default (re)start # command. # # required_vars n If set, perform checkyesno on each of the # listed variables before running the default # (re)start command. # # Default behaviour for a given argument, if no override method is # provided: # # Argument Default behaviour # -------- ----------------- # start if !running && checkyesno ${rcvar} # ${command} # # stop if ${pidfile} # rc_pid=$(check_pidfile $pidfile $command) # else # rc_pid=$(check_process $command) # kill $sig_stop $rc_pid # wait_for_pids $rc_pid # ($sig_stop defaults to TERM.) # # reload Similar to stop, except use $sig_reload instead, # and doesn't wait_for_pids. # $sig_reload defaults to HUP. # # restart Run `stop' then `start'. # # status Show if ${command} is running, etc. # # poll Wait for ${command} to exit. # # rcvar Display what rc.conf variable is used (if any). # # Variables available to methods, and after run_rc_command() has # completed: # # Variable Purpose # -------- ------- # rc_arg Argument to command, after fast/force processing # performed # # rc_flags Flags to start the default command with. # Defaults to ${name}_flags, unless overridden # by $flags from the environment. # This variable may be changed by the precmd method. # # rc_pid PID of command (if appropriate) # # rc_fast Not empty if "fast" was provided (q.v.) # # rc_force Not empty if "force" was provided (q.v.) # # run_rc_command() { rc_arg=$1 if [ -z "$name" ]; then err 3 'run_rc_command: $name is not set.' fi case "$rc_arg" in fast*) # "fast" prefix; don't check pid rc_arg=${rc_arg#fast} rc_fast=yes ;; force*) # "force prefix; always start rc_arg=${rc_arg#force} rc_force=yes if [ -n "${rcvar}" ]; then eval ${rcvar}=YES fi ;; esac _keywords="start stop restart rcvar $extra_commands" rc_pid= _pidcmd= _procname=${procname:-${command}} # setup pid check command if not fast if [ -z "$rc_fast" -a -n "$_procname" ]; then if [ -n "$pidfile" ]; then _pidcmd='rc_pid=$(check_pidfile '"$pidfile $_procname $command_interpreter"')' else _pidcmd='rc_pid=$(check_process '"$_procname $command_interpreter"')' fi if [ -n "$_pidcmd" ]; then _keywords="${_keywords} status poll" fi fi if [ -z "$rc_arg" ]; then rc_usage "$_keywords" fi if [ -n "$flags" ]; then # allow override from environment rc_flags=$flags else eval rc_flags=\$${name}_flags fi eval _chdir=\$${name}_chdir _chroot=\$${name}_chroot \ _nice=\$${name}_nice _user=\$${name}_user \ _group=\$${name}_group _groups=\$${name}_groups \ _systrace=\$${name}_systrace if [ -n "$_user" ]; then # unset $_user if running as that user if [ "$_user" = "$($_RCCMD_whoami)" ]; then unset _user fi fi # if ${rcvar} is set, and $1 is not # "rcvar", then run # checkyesno ${rcvar} # and return if that failed # if [ -n "${rcvar}" -a "$rc_arg" != "rcvar" ]; then if ! checkyesno ${rcvar}; then return 0 fi fi eval $_pidcmd # determine the pid if necessary for _elem in $_keywords; do if [ "$_elem" != "$rc_arg" ]; then continue fi # if there's a custom ${XXX_cmd}, # run that instead of the default # eval _cmd=\$${rc_arg}_cmd _precmd=\$${rc_arg}_precmd \ _postcmd=\$${rc_arg}_postcmd if [ -n "$_cmd" ]; then # if the precmd failed and force # isn't set, exit # if ! eval $_precmd && [ -z "$rc_force" ]; then return 1 fi if ! eval $_cmd && [ -z "$rc_force" ]; then return 1 fi eval $_postcmd return 0 fi case "$rc_arg" in # default operations... status) if [ -n "$rc_pid" ]; then ${_RCCMD_echo} \ "${name} is running as pid $rc_pid." else ${_RCCMD_echo} "${name} is not running." return 1 fi ;; start) if [ -n "$rc_pid" ]; then ${_RCCMD_echo} \ "${name} already running? (pid=$rc_pid)." exit 1 fi if [ ! -x ${_chroot}${command} ]; then return 0 fi # check for required variables, # directories, and files # for _f in $required_vars; do if ! checkyesno $_f; then warn "\$${_f} is not set." if [ -z "$rc_force" ]; then return 1 fi fi done for _f in $required_dirs; do if [ ! -d "${_f}/." ]; then warn "${_f} is not a directory." if [ -z "$rc_force" ]; then return 1 fi fi done for _f in $required_files; do if [ ! -r "${_f}" ]; then warn "${_f} is not readable." if [ -z "$rc_force" ]; then return 1 fi fi done # if the precmd failed and force # isn't set, exit # if ! eval $_precmd && [ -z "$rc_force" ]; then return 1 fi # setup the command to run, and run it # ${_RCCMD_echo} "Starting ${name}." if [ -n "$_chroot" ]; then if [ "$_osname" = "SunOS" ]; then _doit="\ ${_nice:+${_RCCMD_nice} -n $_nice }\ ${_RCCMD_chroot} $_chroot" if [ -n "$_user" ]; then _doit="\ $_doit ${_RCCMD_su} ${_RCARG_su} $_user \ -c '${_RCCMD_sh} -c'" fi _doit="\ $_doit $command $rc_flags $command_args" else _doit="\ ${_nice:+${_RCCMD_nice} -n $_nice }\ ${_systrace:+${_RCCMD_systrace} $_systrace }\ ${_RCCMD_chroot} ${_user:+-u $_user }${_group:+-g $_group }\ ${_groups:+-G $_groups } $_chroot $command $rc_flags $command_args" fi else _doit="\ ${_chdir:+cd $_chdir; }\ ${_nice:+${_RCCMD_nice} -n $_nice }\ ${_systrace:+${_RCCMD_systrace} $_systrace }\ $command $rc_flags $command_args" if [ -n "$_user" ]; then _doit="${_RCCMD_su} ${_RCARG_su} $_user \ -c '${_RCCMD_sh} -c \"$_doit\"'" fi fi # if the cmd failed and force # isn't set, exit # if ! eval $_doit && [ -z "$rc_force" ]; then return 1 fi # finally, run postcmd # eval $_postcmd ;; stop) if [ -z "$rc_pid" ]; then if [ -n "$pidfile" ]; then ${_RCCMD_echo} \ "${name} not running? (check $pidfile)." else ${_RCCMD_echo} "${name} not running?" fi exit 1 fi # if the precmd failed and force # isn't set, exit # if ! eval $_precmd && [ -z "$rc_force" ]; then return 1 fi # send the signal to stop # ${_RCCMD_echo} "Stopping ${name}." _doit="${_RCCMD_kill} -${sig_stop:-TERM} $rc_pid" if [ -n "$_user" ]; then _doit="${_RCCMD_su} ${_RCARG_su} $_user \ -c '${_RCCMD_sh} -c \"$_doit\"'" fi # if the stop cmd failed and force # isn't set, exit # if ! eval $_doit && [ -z "$rc_force" ]; then return 1 fi # wait for the command to exit, # and run postcmd. wait_for_pids $rc_pid eval $_postcmd ;; reload) if [ -z "$rc_pid" ]; then if [ -n "$pidfile" ]; then ${_RCCMD_echo} \ "${name} not running? (check $pidfile)." else ${_RCCMD_echo} "${name} not running?" fi exit 1 fi ${_RCCMD_echo} "Reloading ${name} config files." if ! eval $_precmd && [ -z "$rc_force" ]; then return 1 fi _doit="${_RCCMD_kill} -${sig_reload:-HUP} $rc_pid" if [ -n "$_user" ]; then _doit="${_RCCMD_su} ${_RCARG_su} $_user -c '${_RCCMD_sh} -c \"$_doit\"'" fi if ! eval $_doit && [ -z "$rc_force" ]; then return 1 fi eval $_postcmd ;; restart) if ! eval $_precmd && [ -z "$rc_force" ]; then return 1 fi # prevent restart being called more # than once by any given script # if ${_rc_restart_done:-false}; then return 0 fi _rc_restart_done=true ( $0 ${rc_force:+force}stop ) $0 ${rc_force:+force}start eval $_postcmd ;; poll) if [ -n "$rc_pid" ]; then wait_for_pids $rc_pid fi ;; rcvar) ${_RCCMD_echo} "# $name" if [ -n "$rcvar" ]; then if checkyesno ${rcvar}; then ${_RCCMD_echo} "\$${rcvar}=YES" else ${_RCCMD_echo} "\$${rcvar}=NO" fi fi ;; *) rc_usage "$_keywords" ;; esac return 0 done ${_RCCMD_echo} 1>&2 "$0: unknown directive '$rc_arg'." rc_usage "$_keywords" exit 1 } # # run_rc_script file arg # Start the script `file' with `arg', and correctly handle the # return value from the script. If `file' ends with `.sh', it's # sourced into the current environment. If `file' appears to be # a backup or scratch file, ignore it. Otherwise if it's # executable run as a child process. # run_rc_script() { _file=$1 _arg=$2 if [ -z "$_file" -o -z "$_arg" ]; then err 3 'USAGE: run_rc_script file arg' fi unset name command command_args command_interpreter \ extra_commands pidfile procname \ rcvar required_dirs required_files required_vars eval unset ${_arg}_cmd ${_arg}_precmd ${_arg}_postcmd case "$_file" in *.sh) # run in current shell set $_arg ; . $_file ;; *[~#]|*.OLD|*.orig) # scratch file; skip warn "Ignoring scratch file $_file" ;; *) # run in subshell if [ -x $_file ]; then if [ -n "$rc_fast_and_loose" ]; then set $_arg ; . $_file else ( set $_arg ; . $_file ) fi fi ;; esac } # # load_rc_config # Source in the configuration file for a given command. # load_rc_config() { _command=$1 if [ -z "$_command" ]; then err 3 'USAGE: load_rc_config command' fi if ${_rc_conf_loaded:-false}; then : else . ${sysconfbase}/rc.conf _rc_conf_loaded=true fi if [ "$_osname" = "OpenBSD" ] && [ -f ${sysconfbase}/rc.conf.local ]; then . ${sysconfbase}/rc.conf.local fi if [ -f ${sysconfbase}/rc.conf.d/"$_command" ]; then . ${sysconfbase}/rc.conf.d/"$_command" fi } # # load_rc_config_var cmd var # Read the rc.conf(5) var for cmd and set in the # current shell, using load_rc_config in a subshell to prevent # unwanted side effects from other variable assignments. # load_rc_config_var() { if [ $# -ne 2 ]; then err 3 'USAGE: load_rc_config_var cmd var' fi eval $(eval '( load_rc_config '$1' >/dev/null; if [ -n "${'$2'}" ] || [ "${'$2'-UNSET}" != "UNSET" ]; then echo '$2'=\'\''${'$2'}\'\''; fi )' ) } # # rc_usage commands # Print a usage string for $0, with `commands' being a list of # valid commands. # rc_usage() { ${_RCCMD_echo} -n 1>&2 "Usage: $0 [fast|force](" _sep= for _elem; do ${_RCCMD_echo} -n 1>&2 "$_sep$_elem" _sep="|" done ${_RCCMD_echo} 1>&2 ")" exit 1 } # # err exitval message # Display message to stderr and log to the syslog, and exit with exitval. # err() { exitval=$1 shift if [ -x ${_RCCMD_logger} ]; then ${_RCCMD_logger} "$0: ERROR: $*" fi ${_RCCMD_echo} 1>&2 "$0: ERROR: $*" exit $exitval } # # warn message # Display message to stderr and log to the syslog. # warn() { if [ -x ${_RCCMD_logger} ]; then ${_RCCMD_logger} "$0: WARNING: $*" fi ${_RCCMD_echo} 1>&2 "$0: WARNING: $*" } # # backup_file action file cur backup # Make a backup copy of `file' into `cur', and save the previous # version of `cur' as `backup' or use rcs for archiving. # # This routine checks the value of the backup_uses_rcs variable, # which can be either YES or NO. # # The `action' keyword can be one of the following: # # add `file' is now being backed up (and is possibly # being reentered into the backups system). `cur' # is created and RCS files, if necessary, are # created as well. # # update `file' has changed and needs to be backed up. # If `cur' exists, it is copied to to `back' or # checked into RCS (if the repository file is old), # and then `file' is copied to `cur'. Another RCS # check in done here if RCS is being used. # # remove `file' is no longer being tracked by the backups # system. If RCS is not being used, `cur' is moved # to `back', otherwise an empty file is checked in, # and then `cur' is removed. # # backup_file() { _action=$1 _file=$2 _cur=$3 _back=$4 if checkyesno backup_uses_rcs; then _msg0="backup archive" _msg1="update" # ensure that history file is not locked if [ -f $_cur,v ]; then ${_RCCMD_rcs} -q -u -U -M $_cur fi # ensure after switching to rcs that the # current backup is not lost if [ -f $_cur ]; then # no archive, or current newer than archive if [ ! -f $_cur,v -o $_cur -nt $_cur,v ]; then ${_RCCMD_ci} -q -f -u -t-"$_msg0" \ -m"$_msg1" $_cur ${_RCCMD_rcs} -q -kb -U $_cur ${_RCCMD_co} -q -f -u $_cur fi fi case $_action in add|update) ${_RCCMD_cp} -p $_file $_cur ${_RCCMD_ci} -q -f -u -t-"$_msg0" -m"$_msg1" $_cur ${_RCCMD_rcs} -q -kb -U $_cur ${_RCCMD_co} -q -f -u $_cur ${_RCCMD_chown} root:wheel $_cur $_cur,v ;; remove) ${_RCCMD_cp} /dev/null $_cur ${_RCCMD_ci} -q -f -u -t-"$_msg0" -m"$_msg1" $_cur ${_RCCMD_rcs} -q -kb -U $_cur ${_RCCMD_chown} root:wheel $_cur $_cur,v ${_RCCMD_rm} $_cur ;; esac else case $_action in add|update) if [ -f $_cur ]; then ${_RCCMD_cp} -p $_cur $_back fi ${_RCCMD_cp} -p $_file $_cur ${_RCCMD_chown} root:wheel $_cur ;; remove) ${_RCCMD_mv} -f $_cur $_back ;; esac fi }