385 lines
11 KiB
Text
385 lines
11 KiB
Text
# $NetBSD: shell-lib,v 1.4 2006/10/22 00:35:26 rillig 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.
|
|
# 3. All advertising materials mentioning features or use of this software
|
|
# must display the following acknowledgement:
|
|
# This product includes software developed by the NetBSD
|
|
# Foundation, Inc. and its contributors.
|
|
# 4. Neither the name of The NetBSD Foundation nor the names of its
|
|
# contributors may be used to endorse or promote products derived
|
|
# from this software without specific prior written permission.
|
|
#
|
|
# 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
|
|
}
|