ports/sysutils/bsdadminscripts/files/uma.in
Rene Ladan 40771ce9fa sysutils/bsdadminscripts: fix scripts at runtime.
Previously, pkg_libchk, pkg_upgrade, and uma failed to run.
Bump PORTREVISION

PR:		193003
Submitted by:	Carlos Jacobo Puga Medina <cpm@fbsd.es>
Reviewed by:	marino
2014-08-26 18:57:57 +00:00

436 lines
11 KiB
Bash

#!/bin/sh -f
#
# Copyright (c) 2009
# Dominic Fandrey <kamikaze@bsdforen.de>
#
# 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.
#
# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
#
readonly version=1.1.1
readonly name=uma
# Return value.
errno=0
# Allow things to fail properly by ignoring SIGINT in the main process.
trap '' int
# Used to activate verbose output.
verbose=
# Will be set if files are locally available.
local=
vardir="%%VAR%%"
lock="$vardir/run/$name.lock"
lockpid="$vardir/run/$name.pid"
identpid="$vardir/run/$name.ident.pid"
conf="%%PREFIX%%/etc/$name.conf"
# Use line breaks as a delimiter.
IFS='
'
# Timezone UTC for age comparisons.
export TZ=UTC
# The bit position of errors.
readonly ERR_LOCK=0
readonly ERR_ARG=1
readonly ERR_FETCH_PORTS=2
readonly ERR_FETCH_VULNDB=3
readonly ERR_FETCH_INDEX=4
readonly ERR_EXTRACT_PORTS=5
readonly ERR_UPDATE_PORTS=6
#
# Get environment variables.
#
# Load the configuration file if present.
if [ -e "$conf" ]; then
. "$conf"
fi
# Local index location.
: ${PKG_INDEX="$vardir/db/uma/FTPINDEX"}
: ${FTP_TIMEOUT=60}
# Logic from src/usr.sbin/pkg_install/add/main.c, plus the possibility to
# override the architecture with ARCH.
: ${PACKAGEROOT="ftp://ftp.freebsd.org"}
: ${ARCH="$(uname -m)"}
branch="$(uname -r | tr '[:upper:]' '[:lower:]')"
number="${branch%%.*}"
branch="${branch##*-}"
case "$branch" in
release)
branch=$number-$branch
;;
stable|current)
branch=${number%%.*}-$branch
;;
*)
# Fallback to stable for prerelease and the like.
branch=${number%%.*}-stable
;;
esac
: ${BRANCH=$branch}
: ${PACKAGESITE="$PACKAGEROOT/pub/FreeBSD/ports/$ARCH/packages-$BRANCH/Latest"}
packagetree="${PACKAGESITE%/*?}"
ftp="${PACKAGESITE#*://}"
ftp="${ftp%%/*}"
#
# Generate PACKAGESITE_MIRRORS if only PACKAGEROOT_MIRRORS are given.
# Note that PACKAGEROOT_MIRRORS and PACKAGESITE_MIRRORS are supposed to be
# a ";" or line feed separated list. Semicolons will be converted to line
# feeds in any case.
#
# Set PACKAGEROOT_MIRRORS if not set.
if [ -z "$PACKAGEROOT_MIRRORS" ]; then
PACKAGEROOT_MIRRORS=
for i in $(jot 14); {
PACKAGEROOT_MIRRORS="${PACKAGEROOT_MIRRORS:+$PACKAGEROOT_MIRRORS$IFS}ftp://ftp$i.FreeBSD.org"
}
fi
# Convert semicolon in PACKAGEROOT_MIRRORS.
PACKAGEROOT_MIRRORS="$(echo "$PACKAGEROOT_MIRRORS" | sed "s/;/\\$IFS/g")"
# Build PACKAGESITE_MIRRORS.
if [ -z "${PACKAGESITE_MIRRORS}" ]; then
PACKAGESITE_MIRRORS=
for MIRROR in $PACKAGEROOT_MIRRORS; {
PACKAGESITE_MIRRORS="${PACKAGESITE_MIRRORS:+$PACKAGESITE_MIRRORS$IFS}$MIRROR/pub/FreeBSD/ports/$ARCH/packages-$BRANCH/Latest"
}
fi
# Convert semicolon in PACKAGESITE_MIRRORS.
PACKAGESITE_MIRRORS="$(echo "$PACKAGESITE_MIRRORS" | sed "s/;/\\$IFS/g")"
# Remove duplicates.
PACKAGEROOT_MIRRORS="$(echo "$PACKAGEROOT_MIRRORS" | sort -u)"
PACKAGESITE_MIRRORS="$(echo "$PACKAGESITE_MIRRORS" | sort -u)"
# Determine portsdir
portsdir=$(make -V PORTSDIR -f /usr/share/mk/bsd.port.mk 2> /dev/null)
portsdir="${portsdir:-%%PORTS%%}"
export ARCH BRANCH PKG_INDEX FTP_TIMEOUT PACKAGEROOT PACKAGESITE
export PACKAGEROOT_MIRRORS PACKAGESITE_MIRRORS
#
# This function is called by a trap when the script exits in verbose mode.
# It reads errno to construct error messages.
#
# @param errno
# The exit status of the script.
#
verbose() {
if [ $(($errno >> $ERR_LOCK & 1)) -eq 1 ]; then
echo "ERROR($((1 << $ERR_LOCK))): Lock owned by someone else."
fi
if [ $(($errno >> $ERR_ARG & 1)) -eq 1 ]; then
echo "ERROR($((1 << $ERR_ARG))): An unknown parameter was supplied."
fi
if [ $(($errno >> $ERR_FETCH_PORTS & 1)) -eq 1 ]; then
echo "ERROR($((1 << $ERR_FETCH_PORTS))): Fetching the ports tree failed."
fi
if [ $(($errno >> $ERR_FETCH_VULNDB & 1)) -eq 1 ]; then
echo "ERROR($((1 << $ERR_FETCH_VULNDB))): Fetching security database failed."
fi
if [ $(($errno >> $ERR_FETCH_INDEX & 1)) -eq 1 ]; then
echo "ERROR($((1 << $ERR_FETCH_INDEX))): Fetching remote INDEX failed."
fi
if [ $(($errno >> $ERR_EXTRACT_PORTS & 1)) -eq 1 ]; then
echo "ERROR($((1 << $ERR_EXTRACT_PORTS))): Extracting the ports tree failed."
fi
if [ $(($errno >> $ERR_UPDATE_PORTS & 1)) -eq 1 ]; then
echo "ERROR($((1 << $ERR_UPDATE_PORTS))): Updating the ports tree failed."
fi
}
#
# This function spawns a process that takes over a lock.
#
# @param pid
# The PID of the process that requested the lock.
# @param lock
# The location of the lock file.
# @param lockpid
# The location of the PID file for the lock holding process.
#
secureLock() {
lockf "$lock" sh -c "
trap 'exit 0' term
echo '$pid' > '$lock'
echo \"\$\$\" > '$lockpid'
trap 'rm \"$lockpid\"; exit 0' EXIT
while kill -0 '$pid' 2> /dev/null; do
sleep 2
done
" 2> /dev/null &
}
#
# Checks whether the currently requesting process holds the lock.
#
# @param pid
# The PID of the process that requested the lock.
# @param lock
# The location of the lock file.
# @return
# Returns 0 if the lock is held for the requesting process or 1
# if the lock is missing or owned by another process.
#
hasLock() {
test "$pid" -eq "$(cat "$lock" 2> /dev/null)" 2> /dev/null
return $?
}
#
# Creates a lock for the requesting process.
#
# @param pid
# The PID of the process that requested the lock.
# @param lock
# The location of the lock file.
# @param lockpid
# The location of the PID file for the lock holding process.
# @param portsdir
# The location of the FreeBSD ports tree.
# @return
# Returns 0 on success, 1 on failure.
#
lock() {
local location
# The requestor already holds the lock.
hasLock && return 0
# The process requesting the lock does not exist.
kill -0 "$pid" 2> /dev/null || return 1 $(errno=1)
# Follow symlinks
location="$(pwd)"
if cd "$portsdir" && portsdir="$(pwd -P)"; then
# Portsdir exists, so we can test for make activity. This
# does not cover all cases, but it covers a lot.
if fstat "$portsdir" | awk '{print $2}' | grep -q make; then
errno=1
return 1
fi
fi
cd "$location"
# Try acquiring the lock.
lockf -st 0 "$lock" "$0" secure $pid 2> /dev/null || return 1 $(errno=1)
# Wait until the locking process is properly set up.
while ! [ -e "$lockpid" -a -e "$lock" ]; do
sleep 0.1
done
return 0
}
#
# Frees a lock unless it is held for another process than the requestor.
#
# @param lock
# The location of the lock file.
# @param lockpid
# The location of the PID file for the lock holding process.
# @return
# Returns 0 on success, 1 on failure.
#
unlock() {
if hasLock; then
# Free the lock.
kill -TERM "$(cat "$lockpid")"
# Wait for the locking process to clean up.
while [ -e "$lockpid" -o -e "$lock" ]; do
sleep 0.1
done
return 0
else
errno=1
return 1
fi
}
#
# Prints the command and available parameters.
#
# @param name
# The name of the script.
# @param version
# The version of the script.
#
printHelp() {
echo "$name v$version
usage:
$name [-hv] [pid] [fetch] [extract] [update] [...]
$name [-hv] [pid] fetch [ports] [audit] [ftpindex]
$name [-hv] [pid] extract [ports]
$name [-hv] [pid] update [ports]
$name [-hv] lock [pid]
$name [-hv] unlock [pid]"
}
#
# Reads the parameters and creates variables that indicates the presence
# of these parameters.
#
# The last numeric value is treated as the requestor PID. It also deals
#
# @param @
# All parameters to process.
# @param verbose
# Set to 1 if verbose mode is activated.
# @param cmd_*
# Set by this function to indicate the presence of a parameter.
#
readParams() {
local flag
for flag; {
# A numerical parameter is the PID.
if [ "$flag" -eq "$flag" ] 2> /dev/null; then
pid="${flag}"
continue
fi
# Activate verbose mode for -v.
case "$flag" in
-v | --verbose)
trap 'verbose 1>&2' EXIT
verbose=1
continue
;;
-h | --help)
printHelp
continue
;;
-? | --*)
errno=$((1 << $ERR_ARG))
exit $errno
;;
-*)
# Split parameters.
readParams "${flag%${flag#-?}}" "-${flag#-?}"
continue
;;
esac
# If the variable is not predefined, the command is unknown.
if eval "test -n \"\${cmd_$flag=1}\""; then
errno=$((1 << $ERR_ARG))
exit $errno
fi
setvar "cmd_$flag" 1
}
}
pid="$$"
cmd_lock=
cmd_unlock=
cmd_secure=
cmd_env=
cmd_fetch=
cmd_extract=
cmd_update=
cmd_ports=
cmd_audit=
cmd_ftpindex=
readParams "$@"
#
# Exclusive commands that will cause all others to be ignored, in order
# of priority.
#
if [ -n "$cmd_unlock" ]; then
unlock
return $?
fi
if [ -n "$cmd_secure" ]; then
secureLock
return $?
fi
if [ -n "$cmd_lock" ]; then
lock
return $?
fi
#
# Non-exclusive commands that do not require a lock.
#
if [ -n "$cmd_env" ]; then
echo "ARCH='$ARCH'"
echo "BRANCH='$BRANCH'"
echo "FTP_TIMEOUT='$FTP_TIMEOUT'"
echo "PACKAGEROOT='$PACKAGEROOT'"
echo "PACKAGESITE='$PACKAGESITE'"
echo "PKG_INDEX='$PKG_INDEX'"
echo "PACKAGEROOT_MIRRORS='$PACKAGEROOT_MIRRORS'"
echo "PACKAGESITE_MIRRORS='$PACKAGESITE_MIRRORS'"
fi
# Create a local lock if need be.
localLock=
if ! hasLock; then
localLock=1
lock || return $?
fi
# Ports tree commands.
if [ -n "$cmd_ports" ]; then
if [ -n "$cmd_fetch" ]; then
portsnap fetch || errno="$((1 << $ERR_FETCH_PORTS | $errno))"
fi
if [ -n "$cmd_extract" ]; then
portsnap extract || errno=$((1 << $ERR_EXTRACT_PORTS | $errno))
fi
if [ -n "$cmd_update" ]; then
portsnap update || errno=$((1 << $ERR_UPDATE_PORTS | $errno))
fi
fi
# Portaudit commands.
if [ -n "$cmd_audit" ]; then
if [ -n "$cmd_fetch" ]; then
portaudit -F || errno=$((1 << $ERR_FETCH_VULNDB | $errno))
fi
fi
# Package index commands.
if [ -n "$cmd_ftpindex" ]; then
if ! mkdir -p "${PKG_INDEX%/*}" 2> /dev/null; then
test -n "$verbose" \
&& echo "The directory ${PKG_INDEX%/*} does not exist and cannot be created!"
errno=$((1 << $ERR_FETCH_INDEX | $errno))
elif [ -n "$cmd_fetch" ]; then
fetch -mo "$PKG_INDEX" "$packagetree/INDEX" \
|| errno=$((1 << $ERR_FETCH_INDEX | $errno))
fi
fi
# Free a local lock.
test -n "$localLock" && unlock
return $errno