6c25dec844
This is based on the decision The NetBSD Foundation made in 2008 to do so, which was already applied to src. This change has been applied to code which is likely not in other repositories. ok board@, reviewed by riastradh@
378 lines
11 KiB
Text
378 lines
11 KiB
Text
# $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
|
|
}
|