1*f42f89fdSandvar# $NetBSD: rc.subr,v 1.111 2022/05/22 11:27:33 andvar Exp $ 26096ea59Slukem# 375350585Sapb# Copyright (c) 1997-2011 The NetBSD Foundation, Inc. 46096ea59Slukem# All rights reserved. 56096ea59Slukem# 66096ea59Slukem# This code is derived from software contributed to The NetBSD Foundation 76096ea59Slukem# by Luke Mewburn. 86096ea59Slukem# 96096ea59Slukem# Redistribution and use in source and binary forms, with or without 106096ea59Slukem# modification, are permitted provided that the following conditions 116096ea59Slukem# are met: 126096ea59Slukem# 1. Redistributions of source code must retain the above copyright 136096ea59Slukem# notice, this list of conditions and the following disclaimer. 146096ea59Slukem# 2. Redistributions in binary form must reproduce the above copyright 156096ea59Slukem# notice, this list of conditions and the following disclaimer in the 166096ea59Slukem# documentation and/or other materials provided with the distribution. 176096ea59Slukem# 186096ea59Slukem# THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 196096ea59Slukem# ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 206096ea59Slukem# TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 216096ea59Slukem# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 226096ea59Slukem# BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 236096ea59Slukem# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 246096ea59Slukem# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 256096ea59Slukem# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 266096ea59Slukem# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 276096ea59Slukem# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 286096ea59Slukem# POSSIBILITY OF SUCH DAMAGE. 296096ea59Slukem# 306096ea59Slukem# rc.subr 31c3b0e18dScjs# functions used by various rc scripts 326096ea59Slukem# 33c3b0e18dScjs 343c8a1444Sjmmv: ${rcvar_manpage:='rc.conf(5)'} 3531edfc6fSapb: ${RC_PID:=$$} ; export RC_PID 3689fd5357Sapbnl=' 3789fd5357Sapb' # a literal newline 383c8a1444Sjmmv 39bda2cfe4Schristos# RC variables to clear on start. 40bda2cfe4Schristos_env_clear_rc_vars=" 41bda2cfe4SchristosRC_PID= 42bda2cfe4Schristos_rc_pid= 43bda2cfe4Schristos_rc_original_stdout_fd= 44bda2cfe4Schristos_rc_original_stderr_fd= 45bda2cfe4Schristos_rc_postprocessor_fd= 463dd07195Schristos_rc_kill_ntries= 47bda2cfe4Schristos" 48bda2cfe4Schristos 490a50b87eSchristosexport PATH=/sbin:/bin:/usr/sbin:/usr/bin 5077eeaedfSlukem# 516096ea59Slukem# functions 526096ea59Slukem# --------- 536096ea59Slukem 5477eeaedfSlukem# 556096ea59Slukem# checkyesno var 5656e4b525Sroy# Test $1 variable. 5756e4b525Sroy# Return 0 if it's "yes" (et al), 1 if it's "no" (et al), 2 otherwise. 586096ea59Slukem# 5956e4b525Sroycheckyesnox() 606096ea59Slukem{ 616096ea59Slukem eval _value=\$${1} 626096ea59Slukem case $_value in 6379201de0Slukem 6479201de0Slukem # "yes", "true", "on", or "1" 6579201de0Slukem [Yy][Ee][Ss]|[Tt][Rr][Uu][Ee]|[Oo][Nn]|1) 6679201de0Slukem return 0 676b18196fSlukem ;; 6879201de0Slukem 6979201de0Slukem # "no", "false", "off", or "0" 7079201de0Slukem [Nn][Oo]|[Ff][Aa][Ll][Ss][Ee]|[Oo][Ff][Ff]|0) 7179201de0Slukem return 1 726b18196fSlukem ;; 736b18196fSlukem *) 7456e4b525Sroy return 2 756b18196fSlukem ;; 766b18196fSlukem esac 77c3b0e18dScjs} 7885726955Smellon 793c81b28aSlukem# 8056e4b525Sroy# checkyesno var 8156e4b525Sroy# Test $1 variable, and warn if not set to YES or NO. 8256e4b525Sroy# Return 0 if it's "yes" (et al), nonzero otherwise. 8356e4b525Sroy# 8456e4b525Sroycheckyesno() 8556e4b525Sroy{ 8656e4b525Sroy local var 8756e4b525Sroy 8856e4b525Sroy checkyesnox $1 8956e4b525Sroy var=$? 90e063fa5fSkre case "${var}" in 91e063fa5fSkre ( 0 | 1 ) return $var;; 92e063fa5fSkre esac 9356e4b525Sroy warn "\$${1} is not set properly - see ${rcvar_manpage}." 9456e4b525Sroy return 1 9556e4b525Sroy} 9656e4b525Sroy 9756e4b525Sroy# 9889fd5357Sapb# yesno_to_truefalse var 9989fd5357Sapb# Convert the value of a variable from any of the values 10089fd5357Sapb# understood by checkyesno() to "true" or "false". 10189fd5357Sapb# 10289fd5357Sapbyesno_to_truefalse() 10389fd5357Sapb{ 10489fd5357Sapb local var=$1 10589fd5357Sapb if checkyesno $var; then 10689fd5357Sapb eval $var=true 10789fd5357Sapb return 0 10889fd5357Sapb else 10989fd5357Sapb eval $var=false 11089fd5357Sapb return 1 11189fd5357Sapb fi 11289fd5357Sapb} 11389fd5357Sapb 11489fd5357Sapb# 11550b7dbcbSlukem# reverse_list list 11650b7dbcbSlukem# print the list in reverse order 11750b7dbcbSlukem# 11850b7dbcbSlukemreverse_list() 11950b7dbcbSlukem{ 12050b7dbcbSlukem _revlist= 121b224530cSchristos for _revfile; do 12250b7dbcbSlukem _revlist="$_revfile $_revlist" 12350b7dbcbSlukem done 12450b7dbcbSlukem echo $_revlist 12550b7dbcbSlukem} 12650b7dbcbSlukem 12785726955Smellon# 12831edfc6fSapb# If booting directly to multiuser, send SIGTERM to 12931edfc6fSapb# the parent (/etc/rc) to abort the boot. 13031edfc6fSapb# Otherwise just exit. 13131edfc6fSapb# 13231edfc6fSapbstop_boot() 13331edfc6fSapb{ 13431edfc6fSapb if [ "$autoboot" = yes ]; then 13531edfc6fSapb echo "ERROR: ABORTING BOOT (sending SIGTERM to parent)!" 13631edfc6fSapb kill -TERM ${RC_PID} 13731edfc6fSapb fi 13831edfc6fSapb exit 1 13931edfc6fSapb} 14031edfc6fSapb 14131edfc6fSapb# 1425ee7ac88Slukem# mount_critical_filesystems type 1435ee7ac88Slukem# Go through the list of critical file systems as provided in 1445ee7ac88Slukem# the rc.conf(5) variable $critical_filesystems_${type}, checking 1455ee7ac88Slukem# each one to see if it is mounted, and if it is not, mounting it. 14670472a48Sapb# It's not an error if file systems prefixed with "OPTIONAL:" 14770472a48Sapb# are not mentioned in /etc/fstab. 14885726955Smellon# 1496096ea59Slukemmount_critical_filesystems() 1506096ea59Slukem{ 1515ee7ac88Slukem eval _fslist=\$critical_filesystems_${1} 15270472a48Sapb _mountcrit_es=0 153c8ddd612Slukem for _fs in $_fslist; do 15470472a48Sapb _optional=false 15570472a48Sapb case "$_fs" in 15670472a48Sapb OPTIONAL:*) 15770472a48Sapb _optional=true 15870472a48Sapb _fs="${_fs#*:}" 15970472a48Sapb ;; 16070472a48Sapb esac 16115388316Slukem _ismounted=false 16270472a48Sapb # look for a line like "${fs} on * type *" 16370472a48Sapb # or "* on ${fs} type *" in the output from mount. 16470472a48Sapb case "${nl}$( mount )${nl}" in 16570472a48Sapb *" on ${_fs} type "*) 16615388316Slukem _ismounted=true 16770472a48Sapb ;; 16870472a48Sapb *"${nl}${_fs} on "*) 16970472a48Sapb _ismounted=true 17070472a48Sapb ;; 17170472a48Sapb esac 17215388316Slukem if $_ismounted; then 17370472a48Sapb print_rc_metadata \ 17470472a48Sapb "note:File system ${_fs} was already mounted" 175ef98b9ddSlukem else 17670472a48Sapb _mount_output=$( mount $_fs 2>&1 ) 17770472a48Sapb _mount_es=$? 17870472a48Sapb case "$_mount_output" in 17970472a48Sapb *"${nl}"*) 18070472a48Sapb # multiple lines can't be good, 18170472a48Sapb # not even if $_optional is true 18270472a48Sapb ;; 183f932526aSapb *[uU]'nknown special file or file system'*) 18470472a48Sapb if $_optional; then 18570472a48Sapb # ignore this error 18670472a48Sapb print_rc_metadata \ 18770472a48Sapb "note:Optional file system ${_fs} is not present" 18870472a48Sapb _mount_es=0 18970472a48Sapb _mount_output="" 19085726955Smellon fi 19170472a48Sapb ;; 19270472a48Sapb esac 19370472a48Sapb if [ -n "$_mount_output" ]; then 19470472a48Sapb printf >&2 "%s\n" "$_mount_output" 19570472a48Sapb fi 19670472a48Sapb if [ "$_mount_es" != 0 ]; then 19770472a48Sapb _mountcrit_es="$_mount_es" 19870472a48Sapb fi 19970472a48Sapb fi 20085726955Smellon done 20170472a48Sapb return $_mountcrit_es 20285726955Smellon} 203668efbbcScjs 2046096ea59Slukem# 205ae342f47Salnsn# mount_critical_filesystems_zfs 206ae342f47Salnsn# Go through the list of critical ZFS mountpoints as provided in 207ae342f47Salnsn# the rc.conf(5) variable $critical_filesystems_zfs, checking 208ae342f47Salnsn# each one to see if it is mounted, and if it is not, mounting it. 209ae342f47Salnsn# It's not an error if file systems prefixed with "OPTIONAL:" 210082b9a1eSalnsn# aren't ZFS mountpoints. 211ae342f47Salnsnmount_critical_filesystems_zfs() 212ae342f47Salnsn{ 213082b9a1eSalnsn _fslist=$critical_filesystems_zfs 214ae342f47Salnsn _tab=" " 215ae342f47Salnsn _mountcrit_es=0 216ae342f47Salnsn for _fs in $_fslist; do 217ae342f47Salnsn _optional=false 218ae342f47Salnsn case "$_fs" in 219ae342f47Salnsn OPTIONAL:*) 220ae342f47Salnsn _optional=true 221ae342f47Salnsn _fs="${_fs#*:}" 222ae342f47Salnsn ;; 223ae342f47Salnsn esac 224ae342f47Salnsn 225082b9a1eSalnsn _dataset=$( 226ae342f47Salnsn zfs list -H -o mountpoint,name | 227ae342f47Salnsn while read _line ; do 228ae342f47Salnsn _dataset='' 229ae342f47Salnsn case "$_line" in 230ae342f47Salnsn "${_fs}${_tab}"*) 231ae342f47Salnsn _dataset="${_line#*${_tab}}" 232ae342f47Salnsn ;; 233ae342f47Salnsn esac 234ae342f47Salnsn if [ -n "$_dataset" ]; then 235ae342f47Salnsn case "$( zfs get -H -o value canmount $_dataset )" in 236ae342f47Salnsn on) 237ae342f47Salnsn echo -n "$_dataset" 238ae342f47Salnsn break ;; 239ae342f47Salnsn *) # noauto|off - dataset isn't supposed to be mounted 240ae342f47Salnsn ;; 241ae342f47Salnsn esac 242ae342f47Salnsn fi 243082b9a1eSalnsn done) 244ae342f47Salnsn 245ae342f47Salnsn if [ -z "$_dataset" ]; then 246ae342f47Salnsn if $_optional; then 247ae342f47Salnsn # ignore this error 248ae342f47Salnsn print_rc_metadata \ 249ae342f47Salnsn "note:Optional file system $_fs is not present" 250ae342f47Salnsn else 251ae342f47Salnsn printf >&2 "%s\n" "No suitable ZFS dataset found for mountpoint $_fs" 252ae342f47Salnsn _mountcrit_es=1 253ae342f47Salnsn fi 254ae342f47Salnsn else 255ae342f47Salnsn _mount_es= 256ae342f47Salnsn case "$( zfs get -H -o value mounted $_dataset )" in 257ae342f47Salnsn yes) 258ae342f47Salnsn _mount_es=1 259ae342f47Salnsn print_rc_metadata \ 260ae342f47Salnsn "note:File system $_fs was already mounted" 261ae342f47Salnsn ;; 262082b9a1eSalnsn *) # no 263ae342f47Salnsn zfs mount "$_dataset" >/dev/null 264ae342f47Salnsn _mount_es=$? 265082b9a1eSalnsn ;; 266082b9a1eSalnsn esac 267ae342f47Salnsn 268082b9a1eSalnsn if [ $_mount_es -ne 0 ]; then 269ae342f47Salnsn _mountcrit_es="$_mount_es" 270ae342f47Salnsn fi 271ae342f47Salnsn fi 272ae342f47Salnsn done 273ae342f47Salnsn return $_mountcrit_es 274ae342f47Salnsn} 275ae342f47Salnsn 276ae342f47Salnsn# 277d40d6757Slukem# check_pidfile pidfile procname [interpreter] 278d40d6757Slukem# Parses the first line of pidfile for a PID, and ensures 2796096ea59Slukem# that the process is running and matches procname. 280d40d6757Slukem# Prints the matching PID upon success, nothing otherwise. 281d40d6757Slukem# interpreter is optional; see _find_processes() for details. 2826096ea59Slukem# 2836096ea59Slukemcheck_pidfile() 2846096ea59Slukem{ 2856096ea59Slukem _pidfile=$1 2866096ea59Slukem _procname=$2 287d40d6757Slukem _interpreter=$3 288e063fa5fSkre if [ -z "$_pidfile" ] || [ -z "$_procname" ]; then 289d40d6757Slukem err 3 'USAGE: check_pidfile pidfile procname [interpreter]' 290668efbbcScjs fi 2916096ea59Slukem if [ ! -f $_pidfile ]; then 2926096ea59Slukem return 2936096ea59Slukem fi 2946096ea59Slukem read _pid _junk < $_pidfile 2956096ea59Slukem if [ -z "$_pid" ]; then 2966096ea59Slukem return 2976096ea59Slukem fi 298d40d6757Slukem _find_processes $_procname ${_interpreter:-.} '-p '"$_pid" 2996096ea59Slukem} 3006096ea59Slukem 3016096ea59Slukem# 302d40d6757Slukem# check_process procname [interpreter] 3036096ea59Slukem# Ensures that a process (or processes) named procname is running. 304d40d6757Slukem# Prints a list of matching PIDs. 305d40d6757Slukem# interpreter is optional; see _find_processes() for details. 3066096ea59Slukem# 3076096ea59Slukemcheck_process() 3086096ea59Slukem{ 3096096ea59Slukem _procname=$1 310d40d6757Slukem _interpreter=$2 3116096ea59Slukem if [ -z "$_procname" ]; then 312d40d6757Slukem err 3 'USAGE: check_process procname [interpreter]' 3136096ea59Slukem fi 3147d5ae540Skre _find_processes $_procname ${_interpreter:-.} '-A' 315d40d6757Slukem} 316d40d6757Slukem 317d40d6757Slukem# 318d40d6757Slukem# _find_processes procname interpreter psargs 319d40d6757Slukem# Search for procname in the output of ps generated by psargs. 320d40d6757Slukem# Prints the PIDs of any matching processes, space separated. 321d40d6757Slukem# 322d40d6757Slukem# If interpreter == ".", check the following variations of procname 323d40d6757Slukem# against the first word of each command: 324d40d6757Slukem# procname 325d40d6757Slukem# `basename procname` 326d40d6757Slukem# `basename procname` + ":" 327d40d6757Slukem# "(" + `basename procname` + ")" 328d40d6757Slukem# 329d40d6757Slukem# If interpreter != ".", read the first line of procname, remove the 330d40d6757Slukem# leading #!, normalise whitespace, append procname, and attempt to 331d40d6757Slukem# match that against each command, either as is, or with extra words 332dbdaee06Sdholland# at the end. As an alternative, to deal with interpreted daemons 3335e1904ecShe# using perl, the basename of the interpreter plus a colon is also 3345e1904ecShe# tried as the prefix to procname. 335d40d6757Slukem# 336d40d6757Slukem_find_processes() 337d40d6757Slukem{ 338d40d6757Slukem if [ $# -ne 3 ]; then 339d40d6757Slukem err 3 'USAGE: _find_processes procname interpreter psargs' 340d40d6757Slukem fi 341d40d6757Slukem _procname=$1 342d40d6757Slukem _interpreter=$2 343d40d6757Slukem _psargs=$3 344d40d6757Slukem 3456096ea59Slukem _pref= 34678b99d68Shubertf _procnamebn=${_procname##*/} 347d40d6757Slukem if [ $_interpreter != "." ]; then # an interpreted script 348fa3f94a4Selad read _interp < ${_chroot:-}/$_procname # read interpreter name 349d40d6757Slukem _interp=${_interp#\#!} # strip #! 350d40d6757Slukem set -- $_interp 3513a128b33Schristos if [ $1 = "/usr/bin/env" ]; then 3523a128b33Schristos shift 3533a128b33Schristos set -- $(type $1) 3543a128b33Schristos shift $(($# - 1)) 3553a128b33Schristos _interp="${1##*/} $_procname" 3563a128b33Schristos else 3573a128b33Schristos _interp="$* $_procname" 3583a128b33Schristos fi 359d40d6757Slukem if [ $_interpreter != $1 ]; then 360d40d6757Slukem warn "\$command_interpreter $_interpreter != $1" 361d40d6757Slukem fi 3625e1904ecShe _interpbn=${1##*/} 363d40d6757Slukem _fp_args='_argv' 364d40d6757Slukem _fp_match='case "$_argv" in 36578b99d68Shubertf ${_interp}|"${_interp} "*|"${_interpbn}: "*${_procnamebn}*)' 366d40d6757Slukem else # a normal daemon 367d40d6757Slukem _fp_args='_arg0 _argv' 368d40d6757Slukem _fp_match='case "$_arg0" in 369d40d6757Slukem $_procname|$_procnamebn|${_procnamebn}:|"(${_procnamebn})")' 370d40d6757Slukem fi 371d40d6757Slukem 372d40d6757Slukem _proccheck=' 3737e6759edSchristos ps -o "pid,args" '"$_psargs"' 2>&1 | 374d40d6757Slukem while read _npid '"$_fp_args"'; do 375c47a8060Slukem case "$_npid" in 3767e6759edSchristos ps:|PID) 377c47a8060Slukem continue ;; 378d40d6757Slukem esac ; '"$_fp_match"' 379d40d6757Slukem echo -n "$_pref$_npid" ; 3806096ea59Slukem _pref=" " 381c47a8060Slukem ;; 382c47a8060Slukem esac 383d40d6757Slukem done' 384d40d6757Slukem 385d40d6757Slukem#echo 1>&2 "proccheck is :$_proccheck:" 386d40d6757Slukem eval $_proccheck 3876096ea59Slukem} 3886096ea59Slukem 3896096ea59Slukem# 3903dd07195Schristos# kill_pids signal pid [pid ...] 3913dd07195Schristos# kills the given pids with signal. 3923dd07195Schristos# returns the list of pids killed successfully. 3933dd07195Schristos# 3943dd07195Schristoskill_pids() 3953dd07195Schristos{ 3963dd07195Schristos local signal=$1 3973dd07195Schristos shift 3985af20f98Sotis local list="$*" 3993dd07195Schristos local j= 4003dd07195Schristos local nlist= 4013dd07195Schristos for j in $list; do 4023dd07195Schristos if kill -$signal $j 2>/dev/null; then 4033dd07195Schristos nlist="${nlist}${nlist:+ }$j" 4043dd07195Schristos fi 4053dd07195Schristos done 4063dd07195Schristos echo $nlist 4073dd07195Schristos} 4083dd07195Schristos 4093dd07195Schristos# 4108490f0b0Slukem# wait_for_pids pid [pid ...] 4114c9bb3bcSlukem# spins until none of the pids exist 4123dd07195Schristos# if _rc_kill_ntries is set and exceeded, it SIGKILLS the remaining 4133dd07195Schristos# pids 4148490f0b0Slukem# 4158490f0b0Slukemwait_for_pids() 4168490f0b0Slukem{ 4173dd07195Schristos local ntries=0 4183dd07195Schristos local prefix= 4195af20f98Sotis local nlist= 4205af20f98Sotis local list="$*" 4213dd07195Schristos 4223dd07195Schristos if [ -z "$list" ]; then 4238490f0b0Slukem return 4248490f0b0Slukem fi 4253dd07195Schristos 4264c9bb3bcSlukem while true; do 4275af20f98Sotis nlist=$(kill_pids 0 $list) 4283dd07195Schristos if [ -z "$nlist" ]; then 4298490f0b0Slukem break 4308490f0b0Slukem fi 4313dd07195Schristos if [ "$list" != "$nlist" ]; then 4323dd07195Schristos list=$nlist 4333dd07195Schristos echo -n ${prefix:-"Waiting for PIDS: "}$list 4343dd07195Schristos prefix=", " 435ccc4fd50Sroy fi 436ccc4fd50Sroy # We want this to be a tight loop for a fast exit 437ccc4fd50Sroy sleep 0.05 4383dd07195Schristos ntries=$((ntries + 1)) 4393dd07195Schristos if [ -n "${_rc_kill_ntries}" ]; then 4403dd07195Schristos if [ ${ntries} -gt ${_rc_kill_ntries} ]; then 4413dd07195Schristos kill_pids 9 $list > /dev/null 4423dd07195Schristos fi 4433dd07195Schristos fi 4448490f0b0Slukem done 4453dd07195Schristos if [ -n "$prefix" ]; then 4468490f0b0Slukem echo "." 4474c9bb3bcSlukem fi 4488490f0b0Slukem} 4498490f0b0Slukem 4508490f0b0Slukem# 451bff64ddcSjmmv# run_rc_command argument [parameters] 4521a286b14Slukem# Search for argument in the list of supported commands, which is: 4538490f0b0Slukem# "start stop restart rcvar status poll ${extra_commands}" 4541a286b14Slukem# If there's a match, run ${argument}_cmd or the default method 455bff64ddcSjmmv# (see below), and pass the optional list of parameters to it. 4566096ea59Slukem# 4571a286b14Slukem# If argument has a given prefix, then change the operation as follows: 4581a286b14Slukem# Prefix Operation 4596096ea59Slukem# ------ --------- 460892c0453Slukem# fast Skip the pid check, and set rc_fast=yes 461892c0453Slukem# force Set ${rcvar} to YES, and set rc_force=yes 462f3bab2a8Slukem# one Set ${rcvar} to YES 4636096ea59Slukem# 4646096ea59Slukem# The following globals are used: 465bd11504cSlukem# 4661a286b14Slukem# Name Needed Purpose 4671a286b14Slukem# ---- ------ ------- 4686096ea59Slukem# name y Name of script. 469bd11504cSlukem# 4706096ea59Slukem# command n Full path to command. 4711a286b14Slukem# Not needed if ${rc_arg}_cmd is set for 4726096ea59Slukem# each keyword. 473bd11504cSlukem# 4746096ea59Slukem# command_args n Optional args/shell directives for command. 475bd11504cSlukem# 476d40d6757Slukem# command_interpreter n If not empty, command is interpreted, so 477d40d6757Slukem# call check_{pidfile,process}() appropriately. 478d40d6757Slukem# 4790c2e1a2bSlukem# extra_commands n List of extra commands supported. 480bd11504cSlukem# 48180ce7c6cSlukem# pidfile n If set, use check_pidfile $pidfile $command, 48280ce7c6cSlukem# otherwise use check_process $command. 48380ce7c6cSlukem# In either case, only check if $command is set. 48480ce7c6cSlukem# 48580ce7c6cSlukem# procname n Process name to check for instead of $command. 486bd11504cSlukem# 487bd11504cSlukem# rcvar n This is checked with checkyesno to determine 488bd11504cSlukem# if the action should be run. 489bd11504cSlukem# 4900847f3e3Slukem# ${name}_chroot n Directory to chroot to before running ${command} 49180ce7c6cSlukem# Requires /usr to be mounted. 492bd11504cSlukem# 4930847f3e3Slukem# ${name}_chdir n Directory to cd to before running ${command} 4940847f3e3Slukem# (if not using ${name}_chroot). 495bd11504cSlukem# 4966096ea59Slukem# ${name}_flags n Arguments to call ${command} with. 497bd11504cSlukem# NOTE: $flags from the parent environment 498bd11504cSlukem# can be used to override this. 499bd11504cSlukem# 5004ff90c62She# ${name}_env n Additional environment variable settings 5014ff90c62She# for running ${command} 5024ff90c62She# 503a96d29c7Slukem# ${name}_nice n Nice level to run ${command} at. 504bd11504cSlukem# 5050847f3e3Slukem# ${name}_user n User to run ${command} as, using su(1) if not 5060847f3e3Slukem# using ${name}_chroot. 50780ce7c6cSlukem# Requires /usr to be mounted. 508bd11504cSlukem# 5090847f3e3Slukem# ${name}_group n Group to run chrooted ${command} as. 51080ce7c6cSlukem# Requires /usr to be mounted. 511bd11504cSlukem# 512f6a33791Slukem# ${name}_groups n Comma separated list of supplementary groups 513f6a33791Slukem# to run the chrooted ${command} with. 51480ce7c6cSlukem# Requires /usr to be mounted. 515bd11504cSlukem# 5161a286b14Slukem# ${rc_arg}_cmd n If set, use this as the method when invoked; 5176096ea59Slukem# Otherwise, use default command (see below) 518bd11504cSlukem# 5191a286b14Slukem# ${rc_arg}_precmd n If set, run just before performing the 5201a286b14Slukem# ${rc_arg}_cmd method in the default 5211a286b14Slukem# operation (i.e, after checking for required 5221a286b14Slukem# bits and process (non)existence). 5236096ea59Slukem# If this completes with a non-zero exit code, 5241a286b14Slukem# don't run ${rc_arg}_cmd. 525bd11504cSlukem# 5261a286b14Slukem# ${rc_arg}_postcmd n If set, run just after performing the 5271a286b14Slukem# ${rc_arg}_cmd method, if that method 5289cfa003dSlukem# returned a zero exit code. 5299cfa003dSlukem# 5306096ea59Slukem# required_dirs n If set, check for the existence of the given 5316096ea59Slukem# directories before running the default 5326096ea59Slukem# (re)start command. 533bd11504cSlukem# 5346096ea59Slukem# required_files n If set, check for the readability of the given 5356096ea59Slukem# files before running the default (re)start 5366096ea59Slukem# command. 537bd11504cSlukem# 5386096ea59Slukem# required_vars n If set, perform checkyesno on each of the 5396096ea59Slukem# listed variables before running the default 5406096ea59Slukem# (re)start command. 5416096ea59Slukem# 5421a286b14Slukem# Default behaviour for a given argument, if no override method is 5431a286b14Slukem# provided: 544bd11504cSlukem# 5451a286b14Slukem# Argument Default behaviour 5461a286b14Slukem# -------- ----------------- 5476096ea59Slukem# start if !running && checkyesno ${rcvar} 5486096ea59Slukem# ${command} 549bd11504cSlukem# 5506096ea59Slukem# stop if ${pidfile} 5511a286b14Slukem# rc_pid=$(check_pidfile $pidfile $command) 5526096ea59Slukem# else 5531a286b14Slukem# rc_pid=$(check_process $command) 5541a286b14Slukem# kill $sig_stop $rc_pid 5551a286b14Slukem# wait_for_pids $rc_pid 5564c9bb3bcSlukem# ($sig_stop defaults to TERM.) 557bd11504cSlukem# 5584c9bb3bcSlukem# reload Similar to stop, except use $sig_reload instead, 5594c9bb3bcSlukem# and doesn't wait_for_pids. 5606096ea59Slukem# $sig_reload defaults to HUP. 561bd11504cSlukem# 5626096ea59Slukem# restart Run `stop' then `start'. 5636096ea59Slukem# 5648490f0b0Slukem# status Show if ${command} is running, etc. 5658490f0b0Slukem# 5668490f0b0Slukem# poll Wait for ${command} to exit. 5678490f0b0Slukem# 5688490f0b0Slukem# rcvar Display what rc.conf variable is used (if any). 5698490f0b0Slukem# 5701a286b14Slukem# Variables available to methods, and after run_rc_command() has 5711a286b14Slukem# completed: 5721a286b14Slukem# 5731a286b14Slukem# Variable Purpose 5741a286b14Slukem# -------- ------- 575f3bab2a8Slukem# rc_arg Argument to command, after fast/force/one processing 5761a286b14Slukem# performed 5771a286b14Slukem# 5781a286b14Slukem# rc_flags Flags to start the default command with. 5791a286b14Slukem# Defaults to ${name}_flags, unless overridden 5801a286b14Slukem# by $flags from the environment. 5811a286b14Slukem# This variable may be changed by the precmd method. 5821a286b14Slukem# 5831a286b14Slukem# rc_pid PID of command (if appropriate) 5841a286b14Slukem# 5851a286b14Slukem# rc_fast Not empty if "fast" was provided (q.v.) 5861a286b14Slukem# 5871a286b14Slukem# rc_force Not empty if "force" was provided (q.v.) 5888490f0b0Slukem# 589bd11504cSlukem# 5906096ea59Slukemrun_rc_command() 5916096ea59Slukem{ 5921a286b14Slukem rc_arg=$1 593bd11504cSlukem if [ -z "$name" ]; then 594c47a8060Slukem err 3 'run_rc_command: $name is not set.' 5956096ea59Slukem fi 5966096ea59Slukem 597f3bab2a8Slukem _rc_prefix= 5981a286b14Slukem case "$rc_arg" in 599bd11504cSlukem fast*) # "fast" prefix; don't check pid 6001a286b14Slukem rc_arg=${rc_arg#fast} 601892c0453Slukem rc_fast=yes 6026096ea59Slukem ;; 603f3bab2a8Slukem force*) # "force" prefix; always run 604892c0453Slukem rc_force=yes 605f3bab2a8Slukem _rc_prefix=force 606f3bab2a8Slukem rc_arg=${rc_arg#${_rc_prefix}} 607f3bab2a8Slukem if [ -n "${rcvar}" ]; then 608f3bab2a8Slukem eval ${rcvar}=YES 609f3bab2a8Slukem fi 610f3bab2a8Slukem ;; 611f3bab2a8Slukem one*) # "one" prefix; set ${rcvar}=yes 612f3bab2a8Slukem _rc_prefix=one 613f3bab2a8Slukem rc_arg=${rc_arg#${_rc_prefix}} 614be9b3eeaSlukem if [ -n "${rcvar}" ]; then 615bd11504cSlukem eval ${rcvar}=YES 616be9b3eeaSlukem fi 6176096ea59Slukem ;; 618668efbbcScjs esac 6196096ea59Slukem 6209a803287Sreed _keywords="start stop restart rcvar" 6219a803287Sreed if [ -n "$extra_commands" ]; then 6229a803287Sreed _keywords="${_keywords} ${extra_commands}" 6239a803287Sreed fi 6241a286b14Slukem rc_pid= 6256096ea59Slukem _pidcmd= 62680ce7c6cSlukem _procname=${procname:-${command}} 62780ce7c6cSlukem 628bd11504cSlukem # setup pid check command if not fast 629e063fa5fSkre if [ -z "$rc_fast" ] && [ -n "$_procname" ]; then 6306096ea59Slukem if [ -n "$pidfile" ]; then 6311a286b14Slukem _pidcmd='rc_pid=$(check_pidfile '"$pidfile $_procname $command_interpreter"')' 63280ce7c6cSlukem else 6331a286b14Slukem _pidcmd='rc_pid=$(check_process '"$_procname $command_interpreter"')' 634668efbbcScjs fi 6356096ea59Slukem if [ -n "$_pidcmd" ]; then 6368490f0b0Slukem _keywords="${_keywords} status poll" 6376096ea59Slukem fi 6386096ea59Slukem fi 6396096ea59Slukem 6401a286b14Slukem if [ -z "$rc_arg" ]; then 6416096ea59Slukem rc_usage "$_keywords" 6426096ea59Slukem fi 643bff64ddcSjmmv shift # remove $rc_arg from the positional parameters 6446096ea59Slukem 645c8ddd612Slukem if [ -n "$flags" ]; then # allow override from environment 6461a286b14Slukem rc_flags=$flags 6476096ea59Slukem else 6481a286b14Slukem eval rc_flags=\$${name}_flags 6496096ea59Slukem fi 650c47a8060Slukem eval _chdir=\$${name}_chdir _chroot=\$${name}_chroot \ 651c47a8060Slukem _nice=\$${name}_nice _user=\$${name}_user \ 6524ff90c62She _group=\$${name}_group _groups=\$${name}_groups \ 6534ff90c62She _env=\"\$${name}_env\" 6546096ea59Slukem 65580ce7c6cSlukem if [ -n "$_user" ]; then # unset $_user if running as that user 65680ce7c6cSlukem if [ "$_user" = "$(id -un)" ]; then 65780ce7c6cSlukem unset _user 65880ce7c6cSlukem fi 65980ce7c6cSlukem fi 66080ce7c6cSlukem 661be9b3eeaSlukem # if ${rcvar} is set, and $1 is not 66204784cf3Slukem # "rcvar", then run 663be9b3eeaSlukem # checkyesno ${rcvar} 66474bbb8efSsalo # and return if that failed or warn 66574bbb8efSsalo # user and exit when interactive 666bd11504cSlukem # 667e063fa5fSkre if [ -n "${rcvar}" ] && [ "$rc_arg" != "rcvar" ]; then 668bd11504cSlukem if ! checkyesno ${rcvar}; then 66974bbb8efSsalo # check whether interactive or not 67074bbb8efSsalo if [ -n "$_run_rc_script" ]; then 671bd11504cSlukem return 0 672bd11504cSlukem fi 67374bbb8efSsalo for _elem in $_keywords; do 67474bbb8efSsalo if [ "$_elem" = "$rc_arg" ]; then 67575350585Sapb cat 1>&2 <<EOF 67675350585Sapb\$${rcvar} is not enabled - see ${rcvar_manpage}. 67775350585SapbUse the following if you wish to perform the operation: 67875350585Sapb $0 one${rc_arg} 67975350585SapbEOF 68074bbb8efSsalo exit 1 68174bbb8efSsalo fi 68274bbb8efSsalo done 68374bbb8efSsalo echo 1>&2 "$0: unknown directive '$rc_arg'." 68474bbb8efSsalo rc_usage "$_keywords" 68574bbb8efSsalo fi 686bd11504cSlukem fi 687bd11504cSlukem 688bd11504cSlukem eval $_pidcmd # determine the pid if necessary 6896096ea59Slukem 6906096ea59Slukem for _elem in $_keywords; do 6911a286b14Slukem if [ "$_elem" != "$rc_arg" ]; then 6926096ea59Slukem continue 6936096ea59Slukem fi 6946096ea59Slukem 695bd11504cSlukem # if there's a custom ${XXX_cmd}, 696bd11504cSlukem # run that instead of the default 697bd11504cSlukem # 6981a286b14Slukem eval _cmd=\$${rc_arg}_cmd _precmd=\$${rc_arg}_precmd \ 6991a286b14Slukem _postcmd=\$${rc_arg}_postcmd 7006096ea59Slukem if [ -n "$_cmd" ]; then 701bd11504cSlukem # if the precmd failed and force 702bd11504cSlukem # isn't set, exit 703bd11504cSlukem # 7041a286b14Slukem if ! eval $_precmd && [ -z "$rc_force" ]; then 705bd11504cSlukem return 1 706bd11504cSlukem fi 707bd11504cSlukem 708bff64ddcSjmmv if ! eval $_cmd \"\${@}\" && [ -z "$rc_force" ]; then 7099bcc0986Slukem return 1 7109bcc0986Slukem fi 7119bcc0986Slukem eval $_postcmd 7126096ea59Slukem return 0 7136096ea59Slukem fi 7146096ea59Slukem 715bff64ddcSjmmv if [ ${#} -gt 0 ]; then 716bff64ddcSjmmv err 1 "the $rc_arg command does not take any parameters" 717bff64ddcSjmmv fi 718bff64ddcSjmmv 7191a286b14Slukem case "$rc_arg" in # default operations... 7206096ea59Slukem 7216096ea59Slukem status) 7221a286b14Slukem if [ -n "$rc_pid" ]; then 7231a286b14Slukem echo "${name} is running as pid $rc_pid." 7246096ea59Slukem else 7256096ea59Slukem echo "${name} is not running." 726fa16fd6fSlukem return 1 7276096ea59Slukem fi 7286096ea59Slukem ;; 7296096ea59Slukem 7306096ea59Slukem start) 7311a286b14Slukem if [ -n "$rc_pid" ]; then 7329bd9220cSlukem echo 1>&2 "${name} already running? (pid=$rc_pid)." 7336096ea59Slukem exit 1 7346096ea59Slukem fi 7356096ea59Slukem 736e85d25dbSlukem if [ ! -x ${_chroot}${command} ]; then 7376096ea59Slukem return 0 7386096ea59Slukem fi 7396096ea59Slukem 740bd11504cSlukem # check for required variables, 741bd11504cSlukem # directories, and files 742bd11504cSlukem # 7436096ea59Slukem for _f in $required_vars; do 7446096ea59Slukem if ! checkyesno $_f; then 7453c81b28aSlukem warn "\$${_f} is not enabled." 7461a286b14Slukem if [ -z "$rc_force" ]; then 7476096ea59Slukem return 1 7486096ea59Slukem fi 749bd11504cSlukem fi 7506096ea59Slukem done 7516096ea59Slukem for _f in $required_dirs; do 7526096ea59Slukem if [ ! -d "${_f}/." ]; then 75360d3ee1bSlukem warn "${_f} is not a directory." 7541a286b14Slukem if [ -z "$rc_force" ]; then 7556096ea59Slukem return 1 7566096ea59Slukem fi 757bd11504cSlukem fi 7586096ea59Slukem done 7596096ea59Slukem for _f in $required_files; do 7606096ea59Slukem if [ ! -r "${_f}" ]; then 76160d3ee1bSlukem warn "${_f} is not readable." 7621a286b14Slukem if [ -z "$rc_force" ]; then 7636096ea59Slukem return 1 7646096ea59Slukem fi 765bd11504cSlukem fi 7666096ea59Slukem done 7676096ea59Slukem 768bd11504cSlukem # if the precmd failed and force 769bd11504cSlukem # isn't set, exit 770bd11504cSlukem # 7711a286b14Slukem if ! eval $_precmd && [ -z "$rc_force" ]; then 772bd11504cSlukem return 1 773bd11504cSlukem fi 774bd11504cSlukem 775bd11504cSlukem # setup the command to run, and run it 776be9b3eeaSlukem # 7776096ea59Slukem echo "Starting ${name}." 7780847f3e3Slukem if [ -n "$_chroot" ]; then 7790847f3e3Slukem _doit="\ 780bb9e7fd3Schristos$_env_clear_rc_vars $_env \ 781a96d29c7Slukem${_nice:+nice -n $_nice }\ 7820847f3e3Slukemchroot ${_user:+-u $_user }${_group:+-g $_group }${_groups:+-G $_groups }\ 7831a286b14Slukem$_chroot $command $rc_flags $command_args" 7840847f3e3Slukem else 785eabbaa2fSlukem _doit="\ 786eabbaa2fSlukem${_chdir:+cd $_chdir; }\ 787bb9e7fd3Schristos$_env_clear_rc_vars $_env \ 788eabbaa2fSlukem${_nice:+nice -n $_nice }\ 7891a286b14Slukem$command $rc_flags $command_args" 790ab72f65dSlukem if [ -n "$_user" ]; then 791ab72f65dSlukem _doit="su -m $_user -c 'sh -c \"$_doit\"'" 792ab72f65dSlukem fi 7930847f3e3Slukem fi 7949cfa003dSlukem 7959cfa003dSlukem # if the cmd failed and force 7969cfa003dSlukem # isn't set, exit 7979cfa003dSlukem # 7981a286b14Slukem if ! eval $_doit && [ -z "$rc_force" ]; then 7999cfa003dSlukem return 1 8009cfa003dSlukem fi 8019cfa003dSlukem 8029cfa003dSlukem # finally, run postcmd 8039cfa003dSlukem # 8049cfa003dSlukem eval $_postcmd 8056096ea59Slukem ;; 8066096ea59Slukem 8076096ea59Slukem stop) 8081a286b14Slukem if [ -z "$rc_pid" ]; then 8096096ea59Slukem if [ -n "$pidfile" ]; then 8109bd9220cSlukem echo 1>&2 \ 8116096ea59Slukem "${name} not running? (check $pidfile)." 8126096ea59Slukem else 8139bd9220cSlukem echo 1>&2 "${name} not running?" 8146096ea59Slukem fi 8156096ea59Slukem exit 1 8166096ea59Slukem fi 8176096ea59Slukem 8189cfa003dSlukem # if the precmd failed and force 8199cfa003dSlukem # isn't set, exit 8209cfa003dSlukem # 8211a286b14Slukem if ! eval $_precmd && [ -z "$rc_force" ]; then 822bd11504cSlukem return 1 823bd11504cSlukem fi 8249cfa003dSlukem 8259cfa003dSlukem # send the signal to stop 8269cfa003dSlukem # 8276096ea59Slukem echo "Stopping ${name}." 8281a286b14Slukem _doit="kill -${sig_stop:-TERM} $rc_pid" 829ab72f65dSlukem if [ -n "$_user" ]; then 830ab72f65dSlukem _doit="su -m $_user -c 'sh -c \"$_doit\"'" 831ab72f65dSlukem fi 8329cfa003dSlukem 8339cfa003dSlukem # if the stop cmd failed and force 8349cfa003dSlukem # isn't set, exit 8359cfa003dSlukem # 8361a286b14Slukem if ! eval $_doit && [ -z "$rc_force" ]; then 8379cfa003dSlukem return 1 8389cfa003dSlukem fi 8399cfa003dSlukem 8409cfa003dSlukem # wait for the command to exit, 8419cfa003dSlukem # and run postcmd. 8421a286b14Slukem wait_for_pids $rc_pid 8439cfa003dSlukem eval $_postcmd 8446096ea59Slukem ;; 8456096ea59Slukem 8466096ea59Slukem reload) 8471a286b14Slukem if [ -z "$rc_pid" ]; then 8486096ea59Slukem if [ -n "$pidfile" ]; then 8499bd9220cSlukem echo 1>&2 \ 8506096ea59Slukem "${name} not running? (check $pidfile)." 8516096ea59Slukem else 8529bd9220cSlukem echo 1>&2 "${name} not running?" 8536096ea59Slukem fi 8546096ea59Slukem exit 1 8556096ea59Slukem fi 8566096ea59Slukem echo "Reloading ${name} config files." 8571a286b14Slukem if ! eval $_precmd && [ -z "$rc_force" ]; then 858bd11504cSlukem return 1 859bd11504cSlukem fi 8601a286b14Slukem _doit="kill -${sig_reload:-HUP} $rc_pid" 861ab72f65dSlukem if [ -n "$_user" ]; then 862ab72f65dSlukem _doit="su -m $_user -c 'sh -c \"$_doit\"'" 863ab72f65dSlukem fi 8641a286b14Slukem if ! eval $_doit && [ -z "$rc_force" ]; then 8659cfa003dSlukem return 1 8669cfa003dSlukem fi 8679cfa003dSlukem eval $_postcmd 8686096ea59Slukem ;; 8696096ea59Slukem 8706096ea59Slukem restart) 8711a286b14Slukem if ! eval $_precmd && [ -z "$rc_force" ]; then 872bd11504cSlukem return 1 8736096ea59Slukem fi 874be9b3eeaSlukem # prevent restart being called more 875be9b3eeaSlukem # than once by any given script 876be9b3eeaSlukem # 87715388316Slukem if ${_rc_restart_done:-false}; then 878be9b3eeaSlukem return 0 879be9b3eeaSlukem fi 88015388316Slukem _rc_restart_done=true 8818490f0b0Slukem 882f3bab2a8Slukem ( $0 ${_rc_prefix}stop ) 883f3bab2a8Slukem $0 ${_rc_prefix}start 8846096ea59Slukem 8859cfa003dSlukem eval $_postcmd 8866096ea59Slukem ;; 8876096ea59Slukem 8888490f0b0Slukem poll) 8891a286b14Slukem if [ -n "$rc_pid" ]; then 8901a286b14Slukem wait_for_pids $rc_pid 8918490f0b0Slukem fi 8928490f0b0Slukem ;; 8938490f0b0Slukem 8946096ea59Slukem rcvar) 8956096ea59Slukem echo "# $name" 896bd11504cSlukem if [ -n "$rcvar" ]; then 897bd11504cSlukem if checkyesno ${rcvar}; then 898c34ee371Suwe echo "${rcvar}=YES" 8996096ea59Slukem else 900c34ee371Suwe echo "${rcvar}=NO" 901bd11504cSlukem fi 9026096ea59Slukem fi 9036096ea59Slukem ;; 9046096ea59Slukem 9056096ea59Slukem *) 9066096ea59Slukem rc_usage "$_keywords" 9076096ea59Slukem ;; 9086096ea59Slukem 9096096ea59Slukem esac 9106096ea59Slukem return 0 9116096ea59Slukem done 9126096ea59Slukem 9131a286b14Slukem echo 1>&2 "$0: unknown directive '$rc_arg'." 9146096ea59Slukem rc_usage "$_keywords" 9156096ea59Slukem exit 1 9166096ea59Slukem} 9176096ea59Slukem 9186096ea59Slukem# 9197bc38475Sapb# _have_rc_postprocessor 9207bc38475Sapb# Test whether the current script is running in a context that 9217bc38475Sapb# was invoked from /etc/rc with a postprocessor. 9227bc38475Sapb# 9237bc38475Sapb# If the test fails, some variables may be unset to make 9247bc38475Sapb# such tests more efficient in future. 9257bc38475Sapb# 9267bc38475Sapb_have_rc_postprocessor() 9277bc38475Sapb{ 9287bc38475Sapb # Cheap tests that fd and pid are set, fd is writable. 9298e58c959Sphx [ -n "${_rc_pid}" ] || { unset _rc_pid; return 1; } 9308e58c959Sphx [ -n "${_rc_postprocessor_fd}" ] || { unset _rc_pid; return 1; } 9318e58c959Sphx eval ": >&${_rc_postprocessor_fd}" 2>/dev/null \ 9327bc38475Sapb || { unset _rc_pid; return 1; } 9337bc38475Sapb 9347bc38475Sapb return 0 9357bc38475Sapb} 9367bc38475Sapb 9377bc38475Sapb# 9386096ea59Slukem# run_rc_script file arg 9396096ea59Slukem# Start the script `file' with `arg', and correctly handle the 9406096ea59Slukem# return value from the script. If `file' ends with `.sh', it's 94150aa4839Slukem# sourced into the current environment. If `file' appears to be 94250aa4839Slukem# a backup or scratch file, ignore it. Otherwise if it's 94350aa4839Slukem# executable run as a child process. 944c8ddd612Slukem# 94589fd5357Sapb# If `file' contains "KEYWORD: interactive" and if we are 9467bc38475Sapb# running inside /etc/rc with postprocessing, then the script's 9477bc38475Sapb# stdout and stderr are redirected to $_rc_original_stdout_fd and 94889fd5357Sapb# $_rc_original_stderr_fd, so the output will be displayed on the 94989fd5357Sapb# console but not intercepted by /etc/rc's postprocessor. 95089fd5357Sapb# 9516096ea59Slukemrun_rc_script() 9526096ea59Slukem{ 9536096ea59Slukem _file=$1 9546096ea59Slukem _arg=$2 955e063fa5fSkre if [ -z "$_file" ] || [ -z "$_arg" ]; then 9566096ea59Slukem err 3 'USAGE: run_rc_script file arg' 9576096ea59Slukem fi 9586096ea59Slukem 95974bbb8efSsalo _run_rc_script=true 96074bbb8efSsalo 961d40d6757Slukem unset name command command_args command_interpreter \ 962d40d6757Slukem extra_commands pidfile procname \ 96380ce7c6cSlukem rcvar required_dirs required_files required_vars 9649cfa003dSlukem eval unset ${_arg}_cmd ${_arg}_precmd ${_arg}_postcmd 9650ccd65dfSlukem 96689fd5357Sapb _must_redirect=false 9677bc38475Sapb if _have_rc_postprocessor \ 96889fd5357Sapb && _has_rcorder_keyword interactive $_file 96989fd5357Sapb then 97089fd5357Sapb _must_redirect=true 97189fd5357Sapb fi 97289fd5357Sapb 9736096ea59Slukem case "$_file" in 9746096ea59Slukem *.sh) # run in current shell 97589fd5357Sapb if $_must_redirect; then 97689fd5357Sapb print_rc_metadata \ 97789fd5357Sapb "note:Output from ${_file} is not logged" 9781e2ed7f3Sapb no_rc_postprocess eval \ 9791e2ed7f3Sapb 'set $_arg ; . $_file' 98089fd5357Sapb else 9816096ea59Slukem set $_arg ; . $_file 98289fd5357Sapb fi 9836096ea59Slukem ;; 9846d7e3e1bSlukem *[~#]|*.OLD|*.orig|*,v) # scratch file; skip 98550aa4839Slukem warn "Ignoring scratch file $_file" 98650aa4839Slukem ;; 9876096ea59Slukem *) # run in subshell 98889fd5357Sapb if [ -x $_file ] && $_must_redirect; then 98989fd5357Sapb print_rc_metadata \ 99089fd5357Sapb "note:Output from ${_file} is not logged" 99189fd5357Sapb if [ -n "$rc_fast_and_loose" ]; then 9921e2ed7f3Sapb no_rc_postprocess eval \ 9931e2ed7f3Sapb 'set $_arg ; . $_file' 99489fd5357Sapb else 9951e2ed7f3Sapb no_rc_postprocess eval \ 9961e2ed7f3Sapb '( set $_arg ; . $_file )' 99789fd5357Sapb fi 99889fd5357Sapb elif [ -x $_file ]; then 9990ccd65dfSlukem if [ -n "$rc_fast_and_loose" ]; then 10000ccd65dfSlukem set $_arg ; . $_file 10010ccd65dfSlukem else 10026096ea59Slukem ( set $_arg ; . $_file ) 100350aa4839Slukem fi 100489fd5357Sapb else 100589fd5357Sapb warn "Ignoring non-executable file $_file" 10060ccd65dfSlukem fi 10076096ea59Slukem ;; 10086096ea59Slukem esac 10096096ea59Slukem} 10106096ea59Slukem 10116096ea59Slukem# 10123c81b28aSlukem# load_rc_config command 10132c25ae21Slukem# Source in the configuration file for a given command. 10142c25ae21Slukem# 10152c25ae21Slukemload_rc_config() 10162c25ae21Slukem{ 10172c25ae21Slukem _command=$1 10182c25ae21Slukem if [ -z "$_command" ]; then 10192c25ae21Slukem err 3 'USAGE: load_rc_config command' 10202c25ae21Slukem fi 10212c25ae21Slukem 1022dd2a7e0dSlukem if ${_rc_conf_loaded:-false}; then 1023dd2a7e0dSlukem : 1024dd2a7e0dSlukem else 10252c25ae21Slukem . /etc/rc.conf 102615388316Slukem _rc_conf_loaded=true 1027c47a8060Slukem fi 10285b8623beSfvdl if [ -f /etc/rc.conf.d/"$_command" ]; then 10295b8623beSfvdl . /etc/rc.conf.d/"$_command" 10305b8623beSfvdl fi 10312c25ae21Slukem} 10322c25ae21Slukem 10333c81b28aSlukem# 10343c81b28aSlukem# load_rc_config_var cmd var 10353c81b28aSlukem# Read the rc.conf(5) var for cmd and set in the 10363c81b28aSlukem# current shell, using load_rc_config in a subshell to prevent 10373c81b28aSlukem# unwanted side effects from other variable assignments. 10383c81b28aSlukem# 10393c81b28aSlukemload_rc_config_var() 10403c81b28aSlukem{ 10413c81b28aSlukem if [ $# -ne 2 ]; then 10423c81b28aSlukem err 3 'USAGE: load_rc_config_var cmd var' 10433c81b28aSlukem fi 10443c81b28aSlukem eval $(eval '( 10453c81b28aSlukem load_rc_config '$1' >/dev/null; 1046e063fa5fSkre if [ -n "${'$2'}" ] || [ "${'$2'-UNSET}" != "UNSET" ]; then 10473c81b28aSlukem echo '$2'=\'\''${'$2'}\'\''; 10483c81b28aSlukem fi 10493c81b28aSlukem )' ) 10503c81b28aSlukem} 10512c25ae21Slukem 10522c25ae21Slukem# 10536096ea59Slukem# rc_usage commands 10546096ea59Slukem# Print a usage string for $0, with `commands' being a list of 10556096ea59Slukem# valid commands. 10566096ea59Slukem# 10576096ea59Slukemrc_usage() 10586096ea59Slukem{ 1059f3bab2a8Slukem echo -n 1>&2 "Usage: $0 [fast|force|one](" 10606096ea59Slukem 10616096ea59Slukem _sep= 1062b224530cSchristos for _elem; do 10636096ea59Slukem echo -n 1>&2 "$_sep$_elem" 10646096ea59Slukem _sep="|" 10656096ea59Slukem done 10666096ea59Slukem echo 1>&2 ")" 10676096ea59Slukem exit 1 10686096ea59Slukem} 10696096ea59Slukem 10706096ea59Slukem# 10716096ea59Slukem# err exitval message 10726096ea59Slukem# Display message to stderr and log to the syslog, and exit with exitval. 10736096ea59Slukem# 10746096ea59Slukemerr() 10756096ea59Slukem{ 10766096ea59Slukem exitval=$1 10776096ea59Slukem shift 10786096ea59Slukem 107936ae72d9Sgrant if [ -x /usr/bin/logger ]; then 1080acae4fe5Slukem logger "$0: ERROR: $*" 108136ae72d9Sgrant fi 1082acae4fe5Slukem echo 1>&2 "$0: ERROR: $*" 10836096ea59Slukem exit $exitval 10846096ea59Slukem} 10856096ea59Slukem 10866096ea59Slukem# 10876096ea59Slukem# warn message 10886096ea59Slukem# Display message to stderr and log to the syslog. 10896096ea59Slukem# 10906096ea59Slukemwarn() 10916096ea59Slukem{ 109236ae72d9Sgrant if [ -x /usr/bin/logger ]; then 1093acae4fe5Slukem logger "$0: WARNING: $*" 109436ae72d9Sgrant fi 1095acae4fe5Slukem echo 1>&2 "$0: WARNING: $*" 1096668efbbcScjs} 10972811b170Satatat 10982811b170Satatat# 10992811b170Satatat# backup_file action file cur backup 11002811b170Satatat# Make a backup copy of `file' into `cur', and save the previous 11012811b170Satatat# version of `cur' as `backup' or use rcs for archiving. 11022811b170Satatat# 11032811b170Satatat# This routine checks the value of the backup_uses_rcs variable, 11042811b170Satatat# which can be either YES or NO. 11052811b170Satatat# 11062811b170Satatat# The `action' keyword can be one of the following: 11072811b170Satatat# 11082811b170Satatat# add `file' is now being backed up (and is possibly 11092811b170Satatat# being reentered into the backups system). `cur' 11102811b170Satatat# is created and RCS files, if necessary, are 11112811b170Satatat# created as well. 11122811b170Satatat# 11132811b170Satatat# update `file' has changed and needs to be backed up. 11142811b170Satatat# If `cur' exists, it is copied to to `back' or 11152811b170Satatat# checked into RCS (if the repository file is old), 11162811b170Satatat# and then `file' is copied to `cur'. Another RCS 11172811b170Satatat# check in done here if RCS is being used. 11182811b170Satatat# 11192811b170Satatat# remove `file' is no longer being tracked by the backups 11202811b170Satatat# system. If RCS is not being used, `cur' is moved 11212811b170Satatat# to `back', otherwise an empty file is checked in, 11222811b170Satatat# and then `cur' is removed. 11232811b170Satatat# 11242811b170Satatat# 11252811b170Satatatbackup_file() 11262811b170Satatat{ 11272811b170Satatat _action=$1 11282811b170Satatat _file=$2 11292811b170Satatat _cur=$3 11302811b170Satatat _back=$4 11312811b170Satatat 11322811b170Satatat if checkyesno backup_uses_rcs; then 11332811b170Satatat _msg0="backup archive" 11342811b170Satatat _msg1="update" 11352811b170Satatat 113687c89197Satatat # ensure that history file is not locked 113787c89197Satatat if [ -f $_cur,v ]; then 113887c89197Satatat rcs -q -u -U -M $_cur 113987c89197Satatat fi 114087c89197Satatat 11412811b170Satatat # ensure after switching to rcs that the 11422811b170Satatat # current backup is not lost 11432811b170Satatat if [ -f $_cur ]; then 11442811b170Satatat # no archive, or current newer than archive 1145e063fa5fSkre if [ ! -f $_cur,v ] || [ $_cur -nt $_cur,v ]; then 114687c89197Satatat ci -q -f -u -t-"$_msg0" -m"$_msg1" $_cur 114787c89197Satatat rcs -q -kb -U $_cur 1148a40243dfSlukem co -q -f -u $_cur 11492811b170Satatat fi 11502811b170Satatat fi 11512811b170Satatat 11522811b170Satatat case $_action in 11532811b170Satatat add|update) 11542811b170Satatat cp -p $_file $_cur 115587c89197Satatat ci -q -f -u -t-"$_msg0" -m"$_msg1" $_cur 115687c89197Satatat rcs -q -kb -U $_cur 1157a40243dfSlukem co -q -f -u $_cur 11582811b170Satatat chown root:wheel $_cur $_cur,v 11592811b170Satatat ;; 11602811b170Satatat remove) 11612811b170Satatat cp /dev/null $_cur 116287c89197Satatat ci -q -f -u -t-"$_msg0" -m"$_msg1" $_cur 116387c89197Satatat rcs -q -kb -U $_cur 11642811b170Satatat chown root:wheel $_cur $_cur,v 11652811b170Satatat rm $_cur 11662811b170Satatat ;; 11672811b170Satatat esac 11682811b170Satatat else 11692811b170Satatat case $_action in 11702811b170Satatat add|update) 11712811b170Satatat if [ -f $_cur ]; then 11722811b170Satatat cp -p $_cur $_back 11732811b170Satatat fi 11742811b170Satatat cp -p $_file $_cur 11752811b170Satatat chown root:wheel $_cur 11762811b170Satatat ;; 11772811b170Satatat remove) 11782811b170Satatat mv -f $_cur $_back 11792811b170Satatat ;; 11802811b170Satatat esac 11812811b170Satatat fi 11822811b170Satatat} 11837d2e1537Smycroft 118487fc4e29Schristos# 118587fc4e29Schristos# handle_fsck_error fsck_exit_code 118687fc4e29Schristos# Take action depending on the return code from fsck. 118787fc4e29Schristos# 118887fc4e29Schristoshandle_fsck_error() 118987fc4e29Schristos{ 119087fc4e29Schristos case $1 in 119187fc4e29Schristos 0) # OK 119287fc4e29Schristos return 119387fc4e29Schristos ;; 119487fc4e29Schristos 2) # Needs re-run, still fs errors 119587fc4e29Schristos echo "File system still has errors; re-run fsck manually!" 119687fc4e29Schristos ;; 119787fc4e29Schristos 4) # Root modified 119887fc4e29Schristos echo "Root file system was modified, rebooting ..." 119987fc4e29Schristos reboot -n 120087fc4e29Schristos echo "Reboot failed; help!" 120187fc4e29Schristos ;; 120287fc4e29Schristos 8) # Check failed 120387fc4e29Schristos echo "Automatic file system check failed; help!" 120487fc4e29Schristos ;; 120587fc4e29Schristos 12) # Got signal 120687fc4e29Schristos echo "Boot interrupted." 120787fc4e29Schristos ;; 120887fc4e29Schristos *) 120987fc4e29Schristos echo "Unknown error $1; help!" 121087fc4e29Schristos ;; 121187fc4e29Schristos esac 121287fc4e29Schristos stop_boot 121387fc4e29Schristos} 121487fc4e29Schristos 121589fd5357Sapb# 121689fd5357Sapb# _has_rcorder_keyword word file 121789fd5357Sapb# Check whether a file contains a "# KEYWORD:" comment with a 121889fd5357Sapb# specified keyword in the style used by rcorder(8). 121989fd5357Sapb# 122089fd5357Sapb_has_rcorder_keyword() 122189fd5357Sapb{ 122289fd5357Sapb local word="$1" 122389fd5357Sapb local file="$2" 122489fd5357Sapb local line 122589fd5357Sapb 122689fd5357Sapb [ -r "$file" ] || return 1 122789fd5357Sapb while read line; do 122889fd5357Sapb case "${line} " in 122989fd5357Sapb "# KEYWORD:"*[\ \ ]"${word}"[\ \ ]*) 123089fd5357Sapb return 0 123189fd5357Sapb ;; 123289fd5357Sapb "#"*) 123389fd5357Sapb continue 123489fd5357Sapb ;; 123589fd5357Sapb *[A-Za-z0-9]*) 123689fd5357Sapb # give up at the first non-empty non-comment line 123789fd5357Sapb return 1 123889fd5357Sapb ;; 123989fd5357Sapb esac 124089fd5357Sapb done <"$file" 124189fd5357Sapb return 1 124289fd5357Sapb} 124389fd5357Sapb 124489fd5357Sapb# 124589fd5357Sapb# print_rc_metadata string 124689fd5357Sapb# Print the specified string in such a way that the post-processor 124789fd5357Sapb# inside /etc/rc will treat it as meta-data. 124889fd5357Sapb# 124989fd5357Sapb# If we are not running inside /etc/rc, do nothing. 125089fd5357Sapb# 125189fd5357Sapb# For public use by any rc.d script, the string must begin with 125289fd5357Sapb# "note:", followed by arbitrary text. The intent is that the text 125389fd5357Sapb# will appear in a log file but not on the console. 125489fd5357Sapb# 125589fd5357Sapb# For private use within /etc/rc, the string must contain a 125689fd5357Sapb# keyword recognised by the rc_postprocess_metadata() function 125789fd5357Sapb# defined in /etc/rc, followed by a colon, followed by one or more 125889fd5357Sapb# colon-separated arguments associated with the keyword. 125989fd5357Sapb# 126089fd5357Sapbprint_rc_metadata() 126189fd5357Sapb{ 126289fd5357Sapb # _rc_postprocessor fd, if defined, is the fd to which we must 126389fd5357Sapb # print, prefixing the output with $_rc_metadata_prefix. 126489fd5357Sapb # 12657bc38475Sapb if _have_rc_postprocessor; then 126675350585Sapb command printf "%s%s\n" "$rc_metadata_prefix" "$1" \ 126789fd5357Sapb >&${_rc_postprocessor_fd} 126889fd5357Sapb fi 126989fd5357Sapb} 127089fd5357Sapb 127189fd5357Sapb# 127275350585Sapb# _flush_rc_output 127375350585Sapb# Arrange for output to be flushed, if we are running 127475350585Sapb# inside /etc/rc with postprocessing. 127575350585Sapb# 127675350585Sapb_flush_rc_output() 127775350585Sapb{ 127875350585Sapb print_rc_metadata "nop" 127975350585Sapb} 128075350585Sapb 128175350585Sapb# 128275350585Sapb# print_rc_normal [-n] string 128389fd5357Sapb# Print the specified string in such way that it is treated as 128489fd5357Sapb# normal output, regardless of whether or not we are running 128589fd5357Sapb# inside /etc/rc with post-processing. 128689fd5357Sapb# 128775350585Sapb# If "-n" is specified in $1, then the string in $2 is printed 128875350585Sapb# without a newline; otherwise, the string in $1 is printed 128975350585Sapb# with a newline. 129075350585Sapb# 129175350585Sapb# Intended use cases include: 129275350585Sapb# 129375350585Sapb# o An rc.d script can use ``print_rc_normal -n'' to print a 129475350585Sapb# partial line in such a way that it appears immediately 129575350585Sapb# instead of being buffered by rc(8)'s post-processor. 129675350585Sapb# 129775350585Sapb# o An rc.d script that is run via the no_rc_postprocess 129875350585Sapb# function (so most of its output is invisible to rc(8)'s 129975350585Sapb# post-processor) can use print_rc_normal to force some of its 130075350585Sapb# output to be seen by the post-processor. 130175350585Sapb# 130289fd5357Sapb# 130389fd5357Sapbprint_rc_normal() 130489fd5357Sapb{ 13057bc38475Sapb # print to stdout or _rc_postprocessor_fd, depending on 13067bc38475Sapb # whether not we have an rc postprocessor. 130789fd5357Sapb # 13087bc38475Sapb local fd=1 13097bc38475Sapb _have_rc_postprocessor && fd="${_rc_postprocessor_fd}" 131075350585Sapb case "$1" in 131175350585Sapb "-n") 131275350585Sapb command printf "%s" "$2" >&${fd} 131375350585Sapb _flush_rc_output 131475350585Sapb ;; 131575350585Sapb *) 131675350585Sapb command printf "%s\n" "$1" >&${fd} 131775350585Sapb ;; 131875350585Sapb esac 131989fd5357Sapb} 132089fd5357Sapb 132189fd5357Sapb# 132289fd5357Sapb# no_rc_postprocess cmd... 132389fd5357Sapb# Execute the specified command in such a way that its output 132489fd5357Sapb# bypasses the post-processor that handles the output from 132589fd5357Sapb# most commands that are run inside /etc/rc. If we are not 132689fd5357Sapb# inside /etc/rc, then just execute the command without special 132789fd5357Sapb# treatment. 132889fd5357Sapb# 132989fd5357Sapb# The intent is that interactive commands can be run via 1330*f42f89fdSandvar# no_rc_postprocess(), and their output will appear immediately 133189fd5357Sapb# on the console instead of being hidden or delayed by the 133289fd5357Sapb# post-processor. An unfortunate consequence of the output 133389fd5357Sapb# bypassing the post-processor is that the output will not be 133489fd5357Sapb# logged. 133589fd5357Sapb# 133689fd5357Sapbno_rc_postprocess() 133789fd5357Sapb{ 13387bc38475Sapb if _have_rc_postprocessor; then 133989fd5357Sapb "$@" >&${_rc_original_stdout_fd} 2>&${_rc_original_stderr_fd} 134089fd5357Sapb else 134189fd5357Sapb "$@" 134289fd5357Sapb fi 134389fd5357Sapb} 134489fd5357Sapb 134589fd5357Sapb# 134689fd5357Sapb# twiddle 134789fd5357Sapb# On each call, print a different one of "/", "-", "\\", "|", 134889fd5357Sapb# followed by a backspace. The most recently printed value is 134989fd5357Sapb# saved in $_twiddle_state. 135089fd5357Sapb# 135189fd5357Sapb# Output is to /dev/tty, so this function may be useful even inside 135289fd5357Sapb# a script whose output is redirected. 135389fd5357Sapb# 135489fd5357Sapbtwiddle() 135589fd5357Sapb{ 135689fd5357Sapb case "$_twiddle_state" in 135789fd5357Sapb '/') _next='-' ;; 135889fd5357Sapb '-') _next='\' ;; 135989fd5357Sapb '\') _next='|' ;; 136089fd5357Sapb *) _next='/' ;; 136189fd5357Sapb esac 136275350585Sapb command printf "%s\b" "$_next" >/dev/tty 136389fd5357Sapb _twiddle_state="$_next" 136489fd5357Sapb} 136589fd5357Sapb 1366520fd1e5Schristos# 1367520fd1e5Schristos# human_exit_code 1368520fd1e5Schristos# Print the a human version of the exit code. 1369520fd1e5Schristos# 1370520fd1e5Schristoshuman_exit_code() 1371520fd1e5Schristos{ 1372d6169708Schristos if [ "$1" -lt 127 ] 1373520fd1e5Schristos then 1374520fd1e5Schristos echo "exited with code $1" 13752ae8ee3aSchristos elif [ "$(expr $1 % 256)" -eq 127 ] 1376520fd1e5Schristos then 1377a3299c90Schristos # This cannot really happen because the shell will not 1378a3299c90Schristos # pass stopped job status out and the exit code is limited 1379a3299c90Schristos # to 8 bits. This code is here just for completeness. 1380520fd1e5Schristos echo "stopped with signal $(expr $1 / 256)" 1381520fd1e5Schristos else 1382520fd1e5Schristos echo "terminated with signal $(expr $1 - 128)" 1383520fd1e5Schristos fi 1384520fd1e5Schristos} 1385520fd1e5Schristos 1386f265a7c0Sapb# 1387f265a7c0Sapb# collapse_backslash_newline 1388f265a7c0Sapb# Copy input to output, collapsing <backslash><newline> 1389f265a7c0Sapb# to nothing, but leaving other backslashes alone. 1390f265a7c0Sapb# 1391f265a7c0Sapbcollapse_backslash_newline() 1392f265a7c0Sapb{ 1393f265a7c0Sapb local line 1394f265a7c0Sapb while read -r line ; do 1395f265a7c0Sapb case "$line" in 1396f265a7c0Sapb *\\) 1397f265a7c0Sapb # print it, without the backslash or newline 139875350585Sapb command printf "%s" "${line%?}" 1399f265a7c0Sapb ;; 1400f265a7c0Sapb *) 1401f265a7c0Sapb # print it, with a newline 140275350585Sapb command printf "%s\n" "${line}" 1403f265a7c0Sapb ;; 1404f265a7c0Sapb esac 1405f265a7c0Sapb done 1406f265a7c0Sapb} 1407520fd1e5Schristos 1408532fa0d9Sapb# Shell implementations of basename and dirname, usable before 1409532fa0d9Sapb# the /usr file system is mounted. 1410532fa0d9Sapb# 1411532fa0d9Sapbbasename() 1412532fa0d9Sapb{ 1413532fa0d9Sapb local file="$1" 1414532fa0d9Sapb local suffix="$2" 1415532fa0d9Sapb local base 1416532fa0d9Sapb 1417532fa0d9Sapb base="${file##*/}" # remove up to and including last '/' 1418532fa0d9Sapb base="${base%${suffix}}" # remove suffix, if any 1419532fa0d9Sapb command printf "%s\n" "${base}" 1420532fa0d9Sapb} 1421532fa0d9Sapb 1422532fa0d9Sapbdirname() 1423532fa0d9Sapb{ 1424532fa0d9Sapb local file="$1" 1425532fa0d9Sapb local dir 1426532fa0d9Sapb 1427532fa0d9Sapb case "$file" in 1428532fa0d9Sapb /*/*) dir="${file%/*}" ;; # common case: absolute path 1429532fa0d9Sapb /*) dir="/" ;; # special case: name in root dir 1430532fa0d9Sapb */*) dir="${file%/*}" ;; # common case: relative path with '/' 1431532fa0d9Sapb *) dir="." ;; # special case: name without '/' 1432532fa0d9Sapb esac 1433532fa0d9Sapb command printf "%s\n" "${dir}" 1434532fa0d9Sapb} 1435532fa0d9Sapb 143675350585Sapb# Override the normal "echo" and "printf" commands, so that 143775350585Sapb# partial lines printed by rc.d scripts appear immediately, 143875350585Sapb# instead of being buffered by rc(8)'s post-processor. 143975350585Sapb# 144075350585Sapb# Naive use of the echo or printf commands from rc.d scripts, 144175350585Sapb# elsewhere in rc.subr, or anything else that sources rc.subr, 144275350585Sapb# will call these functions. To call the real echo and printf 144375350585Sapb# commands, use "command echo" or "command printf". 144475350585Sapb# 1445e063fa5fSkre# Avoid use of echo altogether as much as possible, printf works better 1446e063fa5fSkre# 144775350585Sapbecho() 144875350585Sapb{ 1449e063fa5fSkre local IFS=' ' NL='\n' # not a literal newline... 1450e063fa5fSkre 145175350585Sapb case "$1" in 1452e063fa5fSkre -n) NL=; shift;; 145375350585Sapb esac 1454e063fa5fSkre 1455e063fa5fSkre command printf "%s${NL}" "$*" 1456e063fa5fSkre 1457e063fa5fSkre if test -z "${NL}" 1458e063fa5fSkre then 1459e063fa5fSkre _flush_rc_output 1460e063fa5fSkre fi 1461e063fa5fSkre return 0 146275350585Sapb} 1463e063fa5fSkre 146475350585Sapbprintf() 146575350585Sapb{ 146675350585Sapb command printf "$@" 146775350585Sapb case "$1" in 146875350585Sapb *'\n') : ;; 146975350585Sapb *) _flush_rc_output ;; 147075350585Sapb esac 1471e063fa5fSkre return 0 147275350585Sapb} 147375350585Sapb 1474709030f1Schristoskat() { 1475709030f1Schristos local i 1476709030f1Schristos local v 1477709030f1Schristos for i; do 1478709030f1Schristos while read -r v; do 1479709030f1Schristos v="${v%%#*}" 1480709030f1Schristos if [ -z "$v" ]; then 1481709030f1Schristos continue 1482709030f1Schristos fi 1483709030f1Schristos echo "$v" 1484709030f1Schristos done < "$i" 1485709030f1Schristos done 1486709030f1Schristos} 1487709030f1Schristos 14887d2e1537Smycroft_rc_subr_loaded=: 1489