# $NetBSD: shell-lib,v 1.5 2018/08/22 20:48:37 maya Exp $ # # Copyright (c) 2004 The NetBSD Foundation, Inc. # All rights reserved. # # This code is derived from software contributed to The NetBSD Foundation # by Johnny C. Lam. # # 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. # ###################################################################### # msg_log logfile msg # Output msg to logfile. If logfile is "stdout" or "stderr" # then output to there instead. ###################################################################### msg_log() { : ${echo=echo} _msg_log="$1"; shift case $_msg_log in stdout) $echo "$@" ;; stderr) $echo "$@" 1>&2 ;; *) $echo "$@" >> $_msg_log ;; esac } ###################################################################### # die msg # Output $msg to stderr, and exit with a positive error code. ###################################################################### die() { msg_log stderr "$@" exit 1 } ###################################################################### # check_prog var prog ... # If $var is empty or unset, then set it to the path of one of # the program names in the list. ###################################################################### check_prog() { : ${test=test} _ckp_var="$1"; shift eval _ckp_tmp=\"\$$_ckp_var\" if $test "x$_ckp_tmp" != "x"; then return 0 fi for _ckp_prog do _ckp_IFS="${IFS}"; IFS=":" for _ckp_dir in ${PATH}; do if $test -x "$_ckp_dir/$_ckp_prog"; then eval $_ckp_var=\""$_ckp_dir/$_ckp_prog"\" return 1 fi done IFS="${_ckp_IFS}" done die "$_ckp_var could not be set." } ###################################################################### # shquote arg # Returns a backslashed and quoted version of arg in $shquoted. ###################################################################### shquote() { : ${echo=echo} : ${sed=sed} _shq_arg=$1 _shq_sed="$sed -e 1s/^X//" _shq_sed_quote_subst='s/\([\`\"$\\]\)/\\\1/g' case $_shq_arg in *[\`\"\$\\]*) shquoted=`$echo "X$_shq_arg" | $_shq_sed -e "$_shq_sed_quote_subst"` ;; *) shquoted="$_shq_arg" ;; esac case $shquoted in *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"") shquoted="\"$shquoted\"" ;; esac } ###################################################################### # lock_file -f path [-n token] # Attempt to create a lockfile at $path. Any directories in the # path should already exist. If $token is specified, then assume # that it is unique between machines sharing an NFS mount. # # (1) Create globally-unique filename in the same filesystem as the # lockfile. # (2) Try to create a hard-link from this file to the lockfile, but # ignoring any errors. # (3) If the two files are the same file, then the lock was successfully # obtained; otherwise, the lock attempt wasn't successful. ###################################################################### lock_file() { : ${dirname=dirname} : ${echo=echo} : ${link=link} : ${mkdir=mkdir} : ${mktemp=mktemp} : ${rm=rm} : ${test=test} : ${touch=touch} _lf_lockfile= _lf_nfs= while $test $# -gt 0; do case $1 in -f) _lf_lockfile="$2"; shift ;; -n) _lf_nfs="$2"; shift ;; esac shift done if $test -z "$_lf_lockfile"; then $echo 1>&2 "$0: no lock file specified." exit fi _lf_pid=$$ _lf_lockdir=`$dirname $_lf_lockfile` _lf_uniqfile=`$mktemp "$_lf_lockdir/.lock.$_lf_nfs.$_lf_pid.XXXXXX" 2>/dev/null` || return 1 if $test -n "$_lf_nfs"; then { $echo $_lf_pid; $echo $_lf_nfs; } > $_lf_uniqfile else $echo $_lf_pid > $_lf_uniqfile fi $link $_lf_uniqfile $_lf_lockfile 2>/dev/null if $test $_lf_uniqfile -ef $_lf_lockfile; then _lf_result=0 else _lf_result=1 fi $rm -f $_lf_uniqfile return $_lf_result } ###################################################################### ###################################################################### ### ### Queue routines. The queue is implemented as a set of variables ### that is unique to each queue name, thus the use of multiple queues ### is allowed. ### ###################################################################### ###################################################################### ###################################################################### # init_queue name # Initialize the named queue. ###################################################################### init_queue() { _qname="$1" eval "_q${_qname}head=1111111111" eval "_q${_qname}tail=1111111111" } ###################################################################### # append_queue name item ... # Append items onto the end of the named queue in FIFO order. ###################################################################### append_queue() { : ${test=test} _qname="$1"; shift while $test $# -gt 0; do eval "_qtail=\"\$_q${_qname}tail\"" eval "_q${_qname}${_qtail}=\"\${1}\"" case $_qtail in *000000000) _qtail=${_qtail%000000000}1 ;; *) _qtail=${_qtail}0 ;; esac eval "_q${_qname}tail=\"\${_qtail}\"" shift done } ###################################################################### # prepend_queue name item ... # Prepend items to the head of the named queue in LIFO order. ###################################################################### prepend_queue() { : ${test=test} _qname="$1"; shift while $test $# -gt 0; do eval "_qhead=\"\$_q${_qname}head\"" case $_qhead in *1) _qhead=${_qhead%1}000000000 ;; *) _qhead=${_qhead%0} ;; esac eval "_q${_qname}${_qhead}=\"\${1}\"" eval "_q${_qname}head=\"\${_qhead}\"" shift done } ###################################################################### # head_queue name var # Return the head of the named queue in $var. ###################################################################### head_queue() { _qname="$1"; shift eval "_qhead=\"\$_q${_qname}head\"" eval "${1}=\"\$_q${_qname}${_qhead}\"" } ###################################################################### # pop_queue name var # Pop off the head of the named queue and return it in $var. ###################################################################### pop_queue() { _qname="$1"; shift head_queue $_qname $1 case $_qhead in *000000000) _qhead=${_qhead%000000000}1 ;; *) _qhead=${_qhead}0 ;; esac eval "_q${_qname}head=\"\${_qhead}\"" } ###################################################################### # queue_is_empty name # Return 0 if the named queue is empty and 1 otherwise. ###################################################################### queue_is_empty() { : ${test=test} _qname="$1" eval "_qhead=\"\$_q${_qname}head\"" eval "_qtail=\"\$_q${_qname}tail\"" $test "$_qhead" = "$_qtail" return $? } ###################################################################### ###################################################################### ### ### File queue routines. The file queue is implemented as a file ### whose lines represent the queue elements. The file queue name ### is simply the file used for the queue, thus the use of multiple ### queues is allowed. ### ###################################################################### ###################################################################### ###################################################################### # init_fqueue name # Initialize the named file queue. ###################################################################### init_fqueue() { _fqname="$1" : > "$_fqname" } ###################################################################### # append_fqueue name item ... # Append items onto the end of the named file queue in FIFO order. ###################################################################### append_fqueue() { : ${echo=echo} : ${test=test} _fqname="$1"; shift while $test $# -gt 0; do $echo "$1" >> "$_fqname" shift done } ###################################################################### # prepend_fqueue name item ... # Prepend items to the head of the named file queue in LIFO order. ###################################################################### prepend_fqueue() { : ${cat=cat} : ${echo=echo} : ${mv=mv} _fqname="$1"; shift _fqtmpfile="$_fqname.$$" init_queue _fqtmpqueue prepend_queue _fqtmpqueue "$@" while ! queue_is_empty _fqtmpqueue; do pop_queue _fqtmpqueue _fqelt $echo "$_fqelt" >> "$_fqtmpfile" done $cat "$_fqname" >> "$_fqtmpfile" $mv -f "$_fqtmpfile" "$_fqname" } ###################################################################### # head_fqueue name var # Return the head of the named file queue in $var. ###################################################################### head_fqueue() { : ${head=head} _fqname="$1"; shift _tmp=`$head -n 1 "$_fqname"` eval "${1}=\"\$_tmp\"" } ###################################################################### # pop_fqueue name var # Pop off the head of the named file queue and return it in $var. ###################################################################### pop_fqueue() { : ${mv=mv} : ${sed=sed} _fqname="$1"; shift _fqtmpfile="$_fqname.$$" head_fqueue "$_fqname" $1 $sed "1,1d" "$_fqname" >> "$_fqtmpfile" $mv -f "$_fqtmpfile" "$_fqname" } ###################################################################### # fqueue_is_empty name # Return 0 if the named file queue is empty and >0 otherwise. ###################################################################### fqueue_is_empty() { : ${test=test} : ${wc=wc} _fqname="$1" if $test -f "$_fqname"; then _fqlines=`$wc -l < "$_fqname"` return $_fqlines else return 1 fi }