Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F148107805
D9434.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
202 KB
Referenced Files
None
Subscribers
None
D9434.diff
View Options
Index: head/MOVED
===================================================================
--- head/MOVED
+++ head/MOVED
@@ -9388,3 +9388,4 @@
devel/rubygem-cocaine-rails5||2017-05-15|Has expired: Use devel/rubygem-cocaine instead
devel/rubygem-climate_control-rails5||2017-05-15|Has expired: Use devel/rubygem-climate_control instead
net/py-twitter|net/py-python-twitter|2017-05-15|Renamed to reflect official name at PyPI/Github
+sysutils/bsdadminscripts|ports-mgmt/bsdadminscripts|2017-05-17|Move into more appropiate category
Index: head/ports-mgmt/Makefile
===================================================================
--- head/ports-mgmt/Makefile
+++ head/ports-mgmt/Makefile
@@ -3,6 +3,8 @@
COMMENT = Ports for managing, installing, and developing FreeBSD ports and packages
+ SUBDIR += bsdadminscripts
+ SUBDIR += bsdadminscripts2
SUBDIR += chucky
SUBDIR += create-rb-port
SUBDIR += dialog4ports
Index: head/ports-mgmt/bsdadminscripts/Makefile
===================================================================
--- head/ports-mgmt/bsdadminscripts/Makefile
+++ head/ports-mgmt/bsdadminscripts/Makefile
@@ -0,0 +1,57 @@
+# $FreeBSD$
+
+PORTNAME= bsdadminscripts
+PORTVERSION= 6.1.1
+PORTREVISION= 8
+CATEGORIES= ports-mgmt sysutils
+MASTER_SITES= SF/${PORTNAME}/${PORTNAME}
+
+MAINTAINER= ports@FreeBSD.org
+COMMENT= Collection of administration scripts
+
+LICENSE= BSD2CLAUSE
+
+NO_BUILD= yes
+NO_ARCH= yes
+
+TMP?= /tmp
+VAR?= /var
+
+PORTDOCS= ABOUT CHANGES INSTALL NOTES THANKS
+
+OPTIONS_DEFINE= DOCS
+
+SUB_FILES= distviper pkg_libchk pkg_upgrade uma
+SUB_LIST= TMP=${TMP} PREFIX=${PREFIX} VAR=${VAR} PORTS=${PORTSDIR}
+
+DOCS_VARS_OFF= EVALDOCS=-nodoc
+
+do-install:
+ cd ${WRKSRC}/src && ${SH} install.sh \
+ -prefix=${STAGEDIR}${PREFIX} \
+ -ports=${STAGEDIR}${PORTSDIR} \
+ -distdir=${STAGEDIR}${DISTDIR} \
+ -datadir=${STAGEDIR}${DATADIR} \
+ ${EVALDOCS}
+.for n in distviper pkg_libchk pkg_upgrade uma
+ ${MV} ${WRKDIR}/${n} ${WRKSRC}/src
+ ${INSTALL_SCRIPT} ${WRKSRC}/src/${n} ${STAGEDIR}${PREFIX}/sbin
+.endfor
+ ${INSTALL_DATA} ${WRKSRC}/src/buildflags.mk ${STAGEDIR}${DATADIR}
+ ${INSTALL_DATA} ${WRKSRC}/src/buildflags.conf.sample \
+ ${STAGEDIR}${PREFIX}/etc
+ ${INSTALL_DATA} ${WRKSRC}/src/uma.conf.sample ${STAGEDIR}${PREFIX}/etc
+
+.for f in bsdadminscripts buildflags.awk buildflags.conf buildflags.mk \
+ distviper pkg_libchk pkg_upgrade pkg_validate portconfig rcstart uma
+ ${INSTALL_MAN} ${WRKSRC}/src/${f}.1 ${STAGEDIR}${MAN1PREFIX}/man/man1
+.endfor
+ ${MKDIR} ${STAGEDIR}${ETCDIR}
+ ${MV} ${STAGEDIR}${PREFIX}/etc/*.sample ${STAGEDIR}${ETCDIR}
+ ${RM} -r ${STAGEDIR}${PREFIX}/etc/*.sample
+
+post-install-DOCS-on:
+ ${MKDIR} ${STAGEDIR}${DOCSDIR}
+ cd ${WRKSRC} && ${INSTALL_DATA} ${PORTDOCS} ${STAGEDIR}${DOCSDIR}
+
+.include <bsd.port.mk>
Index: head/ports-mgmt/bsdadminscripts/distinfo
===================================================================
--- head/ports-mgmt/bsdadminscripts/distinfo
+++ head/ports-mgmt/bsdadminscripts/distinfo
@@ -0,0 +1,2 @@
+SHA256 (bsdadminscripts-6.1.1.tar.gz) = 68b47c51801a8ce1e7b69ec654c7521b1b1fcf2d3fe9184f4d2e4a1b6f4656bb
+SIZE (bsdadminscripts-6.1.1.tar.gz) = 73925
Index: head/ports-mgmt/bsdadminscripts/files/distviper.in
===================================================================
--- head/ports-mgmt/bsdadminscripts/files/distviper.in
+++ head/ports-mgmt/bsdadminscripts/files/distviper.in
@@ -0,0 +1,227 @@
+#!/bin/sh
+#
+# 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 name=distviper
+readonly version=1.1
+
+verbose=
+demo=
+quiet=
+interactive=
+
+# Determine portsdir
+portsdir="$(make -V PORTSDIR -f /usr/share/mk/bsd.port.mk)"
+if [ ! -d "$portsdir" ]; then
+ echo "The PORTSDIR '$portsdir' is missing."
+ exit 1
+fi
+
+# Determine distdir
+distdir="$(make -V DISTDIR -f /usr/share/mk/bsd.port.mk)"
+if [ ! -d "$distdir" ]; then
+ echo "The DISTDIR '$distdir' is missing."
+ exit 2
+fi
+
+# Extract file from distinfo.
+extractFileCmd="sed -E -e 's/^[^(]*\(//1' -e 's/\).*$//1'"
+
+# Display help.
+printHelp() {
+ echo "$name v$version
+usage: $name [-d] [-h] [-i] [-q] [-v] [fast|thorough]"
+}
+
+#
+# Handle parameters.
+#
+# @param $1
+# The parameter to handle.
+# @param $verbose
+# Is set to create verbose output.
+# @param $demo
+# Is set to only print the output that would occur.
+# @param $quiet
+# Is set to act without creating any output.
+# @return
+# Returns 0 if the processed parameter was a valid parameter,
+# returns 1 if not.
+#
+readParams() {
+ case "$1" in
+ "-d" | "--demo")
+ demo=1
+ return 0
+ ;;
+ "-h" | "--help")
+ printHelp
+ exit 0
+ ;;
+ "-i" | "--interactive")
+ interactive=-i
+ return 0
+ ;;
+ "-q" | "--quiet")
+ quiet=1
+ return 0
+ ;;
+ "-v" | "--verbose")
+ verbose=1
+ return 0
+ ;;
+ -? | --*)
+ return 1
+ ;;
+ -*)
+ # Split parameters.
+ # first parameter
+ readParams "${1%${1#-?}}" || return $?
+ # remaining parameters
+ readParams "-${1#-?}"
+ return $?
+ ;;
+ *)
+ return 1
+ ;;
+ esac
+}
+
+#
+# This algorithm outputs the distfiles of installed ports. If a port downloads
+# a distfile through depending on the fetch target of another port, it
+# is missed, in case that other port is not installed as well.
+#
+# @param $portsdir
+# The direcotry holding the ports tree.
+#
+getDistFiles_fast() {
+ for port in $(pkg_info -qoa); {
+ if [ -e "$portsdir/$port/distinfo" ]; then
+ eval "$extractFileCmd '$portsdir/$port/distinfo'" | uniq
+ fi
+ }
+}
+
+#
+# This algorithm outputs the distfiles of all ports.
+#
+# @param $portsdir
+# The direcotry holding the ports tree.
+#
+getDistFiles_thorough() {
+ find -H "$portsdir" -type f -name distinfo | \
+ eval "xargs $extractFileCmd" | uniq
+}
+
+# The current parameter processing stage.
+stage=params
+
+# The selected algorithm for finding distfiles to keep.
+algorithm=thorough
+
+# Parse the command line parameters.
+for command; {
+ # Read parameters until an unknown one is encountered.
+ # In that case switch into command stage.
+ if [ "$stage" = "params" ]; then
+ if ! readParams "$command"; then
+ stage=command
+ fi
+ fi
+
+ # All parameters have been read, now either nothing or a mode
+ # command should occur.
+ if [ "$stage" = "command" ]; then
+ stage=end
+ case "$command" in
+ thorough | fast)
+ algorithm="$command"
+ ;;
+ -*)
+ echo "$name: Unknown parameter '$command'" \
+ "encountered, exiting." 1>&2
+ return 1
+ ;;
+ *)
+ echo "$name: Unknown command '$command'" \
+ "encountered, exiting." 1>&2
+ return 2
+ ;;
+ esac
+ # Skip everything following and continue with the next
+ # argument.
+ continue
+ fi
+
+ # Still being in the loop at this stage means unexpected parameters
+ # have been encountered.
+ if [ "$stage" = "end" ]; then
+ echo "$name: The command '$command' is not allowed here, only" \
+ "one command at a time is permitted." 1>&2
+ return 3
+ fi
+}
+
+# Check for inprobable options.
+if [ -n "$interactive" -a -n "$demo" ]; then
+ echo "$name: Interactive mode is ignored in demo mode." 1>&2
+fi
+
+test -n "$verbose" && echo "Create a list of up to date distfiles to keep" \
+ "using a $algorithm algorithm:"
+
+# Create the list of files to keep, using the selected algorithm.
+keepFiles="$(eval "getDistFiles_$algorithm" | sort -u)"
+if [ -n "$verbose" ]; then
+ echo "$(($(echo "$keepFiles" | wc -l))) files recorded for keeping."
+ echo "Search and delete outdated distfiles:"
+fi
+
+# Files before deletion.
+filesCount="$(($(find -H "$distdir" -type f|wc -l)))"
+filesDelete=0
+
+# Seek and destroy files not in the $keepFiles list.
+for file in $(find -H "$distdir" -type f); {
+ file="${file#$distdir/}"
+
+ if (echo "$keepFiles" | grep -qx "$file"); then
+ test -n "$verbose" && echo "keep $file"
+ else
+ test -z "$quiet" && echo "delete $file"
+ test -z "$demo" && rm $interactive "$distdir/$file"
+ filesDelete=$(($filesDelete + 1))
+ fi
+}
+
+# The number of deleted files
+filesDeleted="$(($filesCount - $(find -H "$distdir" -type f|wc -l)))"
+
+test -z "$demo" && find -H -d "$distdir" -type d -exec rmdir \{} \; 2> /dev/null
+
+if [ -n "$verbose" ]; then
+ echo "$filesDelete files were suggested for deletion."
+ echo "$filesDeleted files of $filesCount have been removed."
+fi
+
+return 0
Index: head/ports-mgmt/bsdadminscripts/files/pkg_libchk.in
===================================================================
--- head/ports-mgmt/bsdadminscripts/files/pkg_libchk.in
+++ head/ports-mgmt/bsdadminscripts/files/pkg_libchk.in
@@ -0,0 +1,484 @@
+#!/bin/sh -f
+#
+# Copyright (c) 2007-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 name=pkg_libchk
+readonly version=1.6.1
+readonly osname=`uname -s`
+readonly pkgng=`make -f /usr/share/mk/bsd.port.mk -V WITH_PKGNG`
+
+# Use a line break as delimiter.
+IFS='
+'
+
+# Filename prefix for shared data
+sharedprefix="%%TMP%%/$$"
+shared="locks"
+
+#
+# This function remembers a lock to allow later deletion with the
+# lockUnregisterAll() function.
+#
+# @param $1
+# The name of the lock.
+lockRegister() {
+ local lock
+ lock="$sharedprefix-$shared"
+ lockf -k "$lock" sh -c "
+ if ! grep -qE '^$1\$' '$lock'; then
+ echo '$1' >> '$lock'
+ fi
+ "
+}
+
+#
+# Unregisters all locks.
+#
+lockUnregisterAll() {
+ wait
+ for register in $(cat "$sharedprefix-$shared"); {
+ lockf "$sharedprefix-$register" wait
+ }
+ lockf "$sharedprefix-$shared" wait
+}
+
+#
+# This function creates a semaphore.
+#
+# @param $1
+# The name of the semaphore.
+# @param $2
+# The size of the semaphore.
+#
+semaphoreCreate() {
+ local lock
+ lockRegister "semaphore-$1"
+ lock="$sharedprefix-semaphore-$1"
+ lockf -k "$lock" echo "$2" > "$lock"
+ eval "semaphore_$1_size=$2"
+}
+
+#
+# This function waits until the semaphore is free und registers its use.
+# Everything that uses this also has to call the semaphoreFree() function.
+#
+# @param $1
+# The name of the semaphore.
+#
+semaphoreUse() {
+ local lock semaphores
+ lock="$sharedprefix-semaphore-$1"
+ while ! lockf -k "$lock" sh -c "
+ state=\$(cat '$lock')
+ if [ \"\$state\" -gt 0 ]; then
+ echo \"\$((\$state - 1))\" > '$lock'
+ exit 0
+ fi
+ exit 1
+ "; do
+ sleep 0.1
+ done
+}
+
+#
+# This function frees a semaphore.
+#
+# @param $1
+# The name of the semaphore.
+#
+semaphoreFree() {
+ local lock
+ lock="$sharedprefix-semaphore-$1"
+ lockf -k "$lock" sh -c "
+ state=\"\$((\"\$(cat '$lock')\" + 1))\"
+ echo \"\$state\" > '$lock'
+ "
+}
+
+#
+# This function sets a new status and prints it.
+#
+# @param $1
+# The status message.
+# @param $clean
+# If set status handling is disabled.
+#
+statusSet() {
+ # In clean mode status handling is disabled.
+ test -z "$clean" || return 0
+ local lock
+ lock="$sharedprefix-status"
+ lockf -k "$lock" sh -c "
+ status=\"\$(cat '$lock')\"
+ echo '$1' > '$lock'
+ printf \"\\r%-\${#status}s\\r\" '$1' > /dev/tty
+ "
+}
+
+#
+# This function prints a message and the current status behind it.
+#
+# @param $1
+# The message to print.
+# @param $clean
+# If set the status will not be printed.
+#
+statusPrint() {
+ if [ -z "$clean" ]; then
+ local lock
+ lock="$sharedprefix-status"
+ lockf -k "$lock" sh -c "
+ status=\"\$(cat '$lock')\"
+ printf \"%-\${#status}s\\r\" '' > /dev/tty
+ echo '$1'
+ printf '%s\\r' \"\$status\" > /dev/tty
+ "
+ else
+ echo "$1"
+ fi
+}
+
+#
+# Waits for a semaphore to be completely free and counts down the remaining
+# number of locks.
+#
+# @param $1
+# The semaphore to watch.
+# @param $2
+# The status message to print, insert %d in the place where the number
+# of remaining locks belong.
+#
+semaphoreCountDown() {
+ local free size
+ while read -t1 free < "$sharedprefix-semaphore-$1"; do
+ size=$(eval "echo \$semaphore_$1_size")
+ statusSet "$(printf "$2" $(( $size - $free )))"
+ test "$free" -eq "$size" && break
+ sleep 0.1
+ done
+ wait
+}
+
+# Clean up upon exit.
+trap '
+ semaphoreCountDown jobs "Terminated by signal, waiting for %d jobs to die."
+ echo > /dev/tty
+ lockUnregisterAll
+ exit 255
+' int term
+
+#
+# This function checks whether a given binary or library directly depends
+# on a missing library.
+# It goes a long way to prevent all kinds of false positives.
+# It always returns 2 (false) for Linux and other non-native libraries
+# and binaries.
+# It also checks whether the missing dependency is really a direct dependency
+# (indirect dependencies have to be fixed somewhere else).
+#
+# @param $1
+# The library or binary to check.
+# @return
+# Returns 0 (true) if a library is missing.
+# Returns 1 if everything is all right.
+# Returns 2 if the check cannot be performed (not a native library).
+#
+dependencyMissing() {
+ local missing file direct libfound
+
+ # We cannot handle non-native binaries,
+ # so assume everything is in order.
+ if ! readelf -e "$1" 2>&1 | \
+ grep -E "^[[:space:]]*OS/ABI:[[:space:]]*UNIX - $osname\$" \
+ > /dev/null
+ then
+ return 2
+ # Nothing is missing.
+ elif ! missing="$(ldd "$1" 2>&1 | grep -E "$match_expr")"; then
+ return 1
+ fi
+
+ # The return status. The value 1 assumes that this is a false positive.
+ status=1
+
+ # Only report misses for direct dependencies.
+ direct="$(
+ readelf -d "$1" 2> /dev/null | \
+ grep 'Shared library:' | \
+ sed -E -e 's|^[^[]*\[||1' -e 's|\]$||1'
+ )"
+
+ # Compare every missing depency with the list of direct dependencies
+ # and report that the dependency is missing if the missing file is
+ # a direct dependency.
+ for file in $missing; {
+ # Strip the missing file of additional information.
+ file="$(echo "$file" | sed -E \
+ -e 's| => .*$||1' \
+ -e 's|^[[:space:]]*||1' \
+ -e 's|^.*dependency ||1' \
+ -e 's| not found$||1'
+ )"
+
+ # If in mean mode we do not check for false positives.
+ if [ -n "$mean" ]; then
+ test -n "$raw" && return 0
+ statusPrint "$package_name: $1 misses $file"
+ continue
+ fi
+
+ # Handle the case where a library is not found, but exists
+ # somewhere in the package. This is for packages that do not
+ # rely on the OS to find libraries.
+ libfound=
+ for library in $(echo "$libraries" | grep -E "/$file\$"); {
+ # The library exists after all.
+ test -e "$library" && libfound=1 && break
+ }
+ if test "$libfound"; then
+ test -n "$verbose" && statusPrint "$package_name: \
+located: $1 misses $file found at $library."
+ continue
+ fi
+
+ # Compare the file with the list of direct dependencies.
+ # If it's not in than it's only an indirect dependency and
+ # cannot be fixed by rebuilding this port.
+ if echo "$direct" | grep -E "^$file\$" > /dev/null; then
+ test -n "$raw" && return 0
+ statusPrint "$package_name: $1 misses $file"
+ status=0
+ elif [ -n "$verbose" ]; then
+ statusPrint "$package_name: inderect: $1 \
+misses $file is an inderect dependency."
+ fi
+ }
+
+ return $status
+}
+
+#
+# Checks the parameters for options.
+#
+# @param $packages
+# The parameters to pkg_info -E that will result in the
+# names of the packages to work on.
+# @param $recursive
+# Contains the appropriate parameter to get the
+# dependencies of the given packages from pkg_info.
+# @param $Recursive
+# Contains the appropriate parameter to get the
+# packages depending on the given packages from pkg_info.
+# @param $raw
+# Is set to trigger raw printing.
+# @param $clean
+# Is set to trigger printing without status messages.
+# @param $verbose
+# Is set to be verbose about false positives.
+# @param $mean
+# Is set to switch into mean mode. That means no
+# checking of false positives.
+# @param $compat
+# Delete to avoid detecting compat libraries as misses.
+# @param $origin
+# Is set to turn the print origin mode on.
+# @semaphore jobs
+# Is set to limit the amount of parallel jobs.
+#
+readParams() {
+ local option
+
+ for option {
+ case "$option" in
+ "-a" | "--all")
+ packages="-a"
+ ;;
+ "-c" | "--clean")
+ clean=1
+ ;;
+ "-h" | "--help")
+ printHelp
+ ;;
+ -j* | --jobs*)
+ local jobs
+ jobs="${option#-j}"
+ jobs="${jobs#--jobs}"
+ if [ "$jobs" -ne "$jobs" ] 2> /dev/null; then
+ echo "The -j option must be followed" \
+ "by a number."
+ exit 3
+ elif [ "$jobs" -lt 1 ]; then
+ echo "The -j option must specify at" \
+ "least 1 job."
+ exit 3
+ else
+ semaphoreCreate jobs "$jobs"
+ fi
+ ;;
+ "-m" | "--mean")
+ mean=1
+ ;;
+ "-n" | "--no-compat")
+ compat=
+ ;;
+ "-o" | "--origin")
+ origin=1
+ ;;
+ "-q" | "--raw")
+ raw=1
+ if [ -n "$verbose" ]; then
+ echo "The parameters -v and -q may" \
+ "not be used at the same time."
+ exit 2
+ fi
+ ;;
+ "-r" | "--recursive")
+ recursive="-r"
+ ;;
+ "-R" | "--upward-recursive")
+ Recursive="-R"
+ ;;
+ "-v" | "--verbose")
+ verbose=1
+ if [ -n "$raw" ]; then
+ echo "The parameters -q and -v may" \
+ "not be used at the same time."
+ exit 2
+ fi
+ ;;
+ -? | --*)
+ echo "Unknown parameter \"$option\"."
+ exit 1
+ ;;
+ -*)
+ readParams "${option%${option#-?}}"
+ readParams "-${option#-?}"
+ ;;
+ *)
+ packages="$packages${packages:+$IFS}$option"
+ ;;
+ esac
+ }
+}
+
+#
+# Display a short help message.
+#
+printHelp() {
+ echo "$name v$version
+usage: $name [-a] [-c] [-h] [-jN] [-m] [-n] [-o] [-q] [-r] [-R] [-v] [packages]"
+ exit 0
+}
+
+# Create the expression to match to find files linking against compat libraries.
+# This can be emptied by readParams to deactivate that feature.
+prefix="$(make -f /usr/share/mk/bsd.port.mk -VPREFIX 2> /dev/null || \
+ echo '%%PREFIX%%')"
+compat="=> $prefix/lib/compat|"
+
+# Create the semaphore with CPU cores * 2 jobs.
+semaphoreCreate jobs "$(($(sysctl -n hw.ncpu 2> /dev/null || echo 1) * 2))"
+# Register the status lock.
+lockRegister status
+
+# Read the parameters.
+readParams "$@"
+
+statusSet 'Preparing ...'
+
+# Get the packages to work on.
+test -z "$packages" && packages="-a"
+if [ -n "$pkgng" ]; then
+ packages="$(pkg info -q $packages)"
+ test -z "$recursive" -a -z "$Recursive" || packages="$packages
+ $(pkg info -q $recursive $Recursive "$packages" 2> /dev/null | \
+ sed -E 's|^@pkgdep[[:space:]]*||1')"
+else
+ packages="$(pkg_info -E $packages)"
+ test -z "$recursive" -a -z "$Recursive" || packages="$packages
+ $(pkg_info -q $recursive $Recursive "$packages" 2> /dev/null | \
+ sed -E 's|^@pkgdep[[:space:]]*||1')"
+fi
+
+# Create the regexp to match ldd output
+match_expr="$compat=> not found|dependency .+ not found"
+
+# The packages to check.
+package_amount="$(echo "$packages" | wc -l | sed 's|[[:space:]]||g')"
+package_num=0
+
+# Check each selected package.
+for package in $packages; {
+ package_num="$(($package_num + 1))"
+ if [ -n "$pkgng" ]; then
+ test $origin \
+ && package_name="$(pkg info -qo "$package")" \
+ || package_name="$package"
+ else
+ test $origin \
+ && package_name="$(pkg_info -qo "$package")" \
+ || package_name="$package"
+ fi
+
+ # Print what we're doing.
+ statusSet "Starting job $package_num of $package_amount: $package_name"
+
+ semaphoreUse jobs
+ (
+ # Remember freeing the semaphore.
+ trap 'semaphoreFree jobs' EXIT
+
+ files=""
+ if [ -n "$pkgng" ]; then
+ files="$(pkg info -lq "$package")"
+ else
+ files="$(pkg_info -qL "$package")"
+ fi
+ # Get the programs libraries in case it doesn't use the
+ # operating system to find its libraries.
+ libraries="$(echo "$files" | grep -E '\.so[\.0-9]*$')"
+
+ outdated=0
+ broken=
+
+ # Check each file of each package.
+ for file in $files; {
+ if [ ! -L "$file" -a \( \
+ -x "$file" -o \
+ -n "$(echo "$file" | grep -E '\.so[\.0-9]*$')" \
+ \) ]; then
+ if dependencyMissing "$file"; then
+ if [ -n "$raw" ]; then
+ statusPrint "$package_name"
+ break 1
+ fi
+ fi
+ fi
+ }
+ ) &
+}
+
+semaphoreCountDown jobs "Waiting for %d remaining jobs to finish."
+statusSet
+lockUnregisterAll
+
+exit 0
Index: head/ports-mgmt/bsdadminscripts/files/pkg_upgrade.in
===================================================================
--- head/ports-mgmt/bsdadminscripts/files/pkg_upgrade.in
+++ head/ports-mgmt/bsdadminscripts/files/pkg_upgrade.in
@@ -0,0 +1,2239 @@
+#!/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
+readonly name=pkg_upgrade
+
+# Error table.
+readonly ERR_LOCK=1
+readonly ERR_ARG=2
+readonly ERR_INDEX=3
+readonly ERR_FETCH=4
+readonly ERR_SORT=5
+readonly ERR_BACKUP_MISS=6
+readonly ERR_BACKUP_UNKNOWN=7
+readonly ERR_INSTALL=8
+readonly ERR_USER=9
+readonly ERR_TERM=10
+readonly ERR_PACKAGE_FORMAT=11
+readonly ERR_CONFLICT=12
+
+# Constant assignments.
+readonly logfile="%%VAR%%/log/$name.log"
+readonly pid=$$
+
+# Get some environment variables from uma. This includes PACKAGESITE,
+# TMPDIR and PKG_INDEX.
+eval "$(uma env $pid)"
+
+# The remote package repository, derived from PACKAGESITE.
+# If this matches the PACKAGES environment variable all downloading operations
+# will be omitted.
+readonly packagerepos="${PACKAGESITE%/*?}"
+
+# Environment variables.
+: ${PACKAGES="$(make -V PACKAGES -f /usr/share/mk/bsd.port.mk 2> /dev/null)"}
+PACKAGES="${PACKAGES:-%%PORTS%%/packages}"
+: ${PKG_DBDIR=%%VAR%%/db/pkg}
+: ${TMPDIR=%%TMP%%}
+: ${PKG_TMPDIR=$TMPDIR}
+
+# This is where backup packages will be stored.
+readonly packagebackup="$PACKAGES/$name-backup"
+# This is where the download manager will listen for messages.
+readonly queueMessages="$TMPDIR/pkg_upgrade.messages.queue"
+
+# Export environment variables to ensure that every tool uses the same ones.
+export ARCH PACKAGEROOT PACKAGESITE FTP_TIMEOUT PKG_INDEX
+export PACKAGEROOT_MIRRORS PACKAGESITE_MIRRORS
+export PACKAGES PKG_DBDIR TMPDIR PKG_TMPDIR
+
+# Direct index access.
+readonly IDX_PKG=0
+readonly IDX_ORIGIN=1
+readonly IDX_PREFIX=2
+readonly IDX_COMMENT=3
+readonly IDX_DESCRIPTION=4
+readonly IDX_MAINTAINER=5
+readonly IDX_CATEGORIES=6
+readonly IDX_DIRECTDEPENDS=7
+readonly IDX_DEPENDS=8
+readonly IDX_WWW=9
+readonly IDX_PERLVERSION=10
+readonly IDX_PERLMODULES=11
+
+# Input field seperator without spaces.
+IFS='
+'
+
+# Parameter flags.
+pAll=
+pNoBackup=
+pClean=
+pExitOnConflict=
+pForce=
+pFetchOnly=
+pInteractive=
+pJobs=
+pListDiscarded=
+pNoActions=
+pNoLogging=
+pParanoid=
+pRecursive=
+pReplaceConflicts=
+pMoreRecursive=
+pUpwardRecursive=
+pMoreUpwardRecursive=
+pVerbose=
+
+# The categories for packages.
+older=
+newer=
+unindexed=
+multiple=
+error=
+
+# A cache for the pkgDepends function.
+dependsChecked=
+
+# The names of packages that do not have a verified download.
+pending=
+
+#
+# The list of packages to upgrade.
+#
+
+# <origin>;<newPackage>
+upgrade=
+upgradeDepends=
+upgradeDepending=
+
+# The <newOrgin>;<newPackage> part can also be found in $upgrade.
+# <newOrigin>;<newPackage>|<oldOrigin>;<oldPackage>
+replace=
+
+# A list of dependency substitutions for new packages.
+# <originalOrigin>;<originalName>|<newDependencyOrigin>;<newDependencyName>
+substituteDepends=
+
+# The current status line.
+status=
+
+# The ports directory as used in the index file.
+idxports=
+
+#
+# Table Of Functions
+# In order of appearance.
+#
+# getIndex() Fetch the latest INDEX
+# getLock() Acquire a lock
+# printStatus() Print status messages on the terminal
+# error() Terminate with an error message
+# warn() Print a warning on stderr
+# verbose() Print a message, but only in verbose mode
+# log() Log activity into a log file
+# getIdxEscape() Escape origins and packages for regular expressions
+# getIdxRows() Filter index rows with an escaped expression
+# getIdxRowsEscaped() Filter index rows with an expression
+# getIdxColumn() Get a certain column from index rows
+# pkgAll() Make a list of outdated packages
+# pkgDepends() Check dependencies
+# pkgDepending() Check upwards dependencies
+# pkgDependencies() Run all dependency checks
+# printProgress() Print numerical progress output
+# pkgSort() Sort packages by dependency
+# printTask() Print the tasks to perform for a package
+# pkgList() List all tasks in 'no actions' mode
+# pkgDownload() Download all required packages
+# pkgUpgrade() Upgrade all scheduled packages
+# substituteDepends() Adjust dependencies of upgraded packages
+# upgradePackage() Upgrade a given package
+# identifyPackage() Identify a package by a user given string
+# printHelp() Print program parameters and terminate
+# readParams() Read the command line parameters
+# readContents() Read the +CONTENTS of a package file
+# downloadManager() Start a background download manager
+# downloadManagerFetch()
+# Try to fetch a package from a mirror
+# downloadManagerMsgRetry()
+# Tell the download manager to retry a download
+# downloadManagerMsgFinished()
+# Tell the download manager a download has been completed
+# downloadManagerMsgRequest()
+# Request a download from the download manager
+# downloadManagerMsgExit()
+# Tell the download manager to terminate
+# validatePackage() Validate a downloaded package
+#
+
+
+#
+# Update the local copy of the index and start the download manager.
+#
+# @param idxports
+# This is set to the ports directory used in the index file. This is
+# required for many index operations. If already set the index is
+# assumed to be up to date and nothing is done.
+# @param pVerbose
+# Activate verbose output.
+#
+getIndex() {
+ # The index has already been updated.
+ if [ -n "$idxports" ]; then
+ return 0
+ fi
+
+ # Free the lock upon termination.
+ trap "uma unlock $pid" EXIT
+
+ # First acquire the lock.
+ getLock
+
+ verbose "Synchronize the local index copy with the package server."
+
+ # Try to update the index.
+ if ! uma $pVerbose fetch ftpindex $pid; then
+ exit $ERR_INDEX
+ fi
+
+ # Set the ports directory used in the index.
+ idxports="$(getIdxColumn $IDX_ORIGIN "$(head -n 1 "$PKG_INDEX")")"
+ idxports="${idxports%/*/*}"
+
+ # Start the download manager.
+ downloadManager
+}
+
+#
+# Acquires the uma (Update Manager) lock. And spawns a process that locks
+# onto PKG_DBDIR to block the ports from messing with us.
+#
+getLock() {
+ # Acquire the lock.
+ if ! uma lock $pid; then
+ if [ "$USER" != "root" ]; then
+ error $ERR_LOCK "The command $name has to be run as root."
+ else
+ error $ERR_LOCK "The uma (Update MAnager) lock could not be acquired, it appears the package/ports infrastructure is in use."
+ fi
+ fi
+
+ # Lock onto PKG_DBDIR to avoid ports getting into our way.
+ # The ports tree locks onto PKG_DBDIR during install and deinstall.
+ # Since it does not use uma we use this lock to make sure the ports
+ # tree does not get into our way later.
+ if ! lockf -kst 0 "$PKG_DBDIR" sh -c "lockf -k '$PKG_DBDIR' sh -c 'while kill -0 $pid 2> /dev/null; do sleep 2; done' &"; then
+ error $ERR_LOCK "Locking $PKG_DBDIR failed, the ports tree might be in use."
+ fi
+}
+
+#
+# Prints a status message to the terminal device /dev/tty.
+#
+# @param 1
+# The message to print
+# @param status
+# The last printed message, used for clearing the status line before
+# printing a new status.
+# @param pClean
+# If set, do not print status messages.
+#
+printStatus() {
+ test -n "$pClean" && return 0
+ printf "\r%${#status}s\r%s\r" '' "$1" > /dev/tty
+ status="$1"
+}
+
+#
+# Exits with the given error and message on stderr.
+#
+# @param 1
+# The error number to exit with.
+# @param 2
+# The message to exit with.
+#
+error() {
+ # Clear the status line.
+ printStatus
+ echo "$name: $2" 1>&2
+ exit "$1"
+}
+
+#
+# Writes a warning message to stderr.
+#
+# @param 1
+# The message to write.
+#
+warn() {
+ # Clear the status line.
+ printStatus
+ echo "$name: $1" 1>&2
+}
+
+#
+# Outputs verbose messages on stdout.
+#
+# @param @
+# All the parameters to be output.
+# @param pVerbose
+# If this is not set, do not output anything.
+#
+verbose() {
+ test -z "$pVerbose" && return 0
+ echo "$@"
+}
+
+#
+# Logs the given message into a log file.
+#
+# The following format is used.
+#
+# <UTC timestamp> - <date> - (<error>|DONE): <message>
+#
+# UTC timestamp := The output of 'date -u '+%s'
+# date := The output of 'date'
+#
+# @param 1
+# The error number for the log, if this is 0, the message will be
+# preceded by "DONE:" instead of "ERROR($1):".
+# @param 2
+# The message to log.
+# @param logfile
+# The name of the file to log into.
+# @param pNoLogging
+# If set, logging is not performed.
+#
+log() {
+ test -n "$pNoLogging" && return 0
+
+ if [ $1 -eq 0 ]; then
+ echo "$(date -u '+%s') - $(date) - DONE: $2" >> $logfile
+ else
+ echo "$(date -u '+%s') - $(date) - ERROR($1): $2" >> $logfile
+ fi
+}
+
+#
+# An escape function for package names fed to the getIdxColumn function.
+# This function reads from the standard input unless a file is named
+# in the parameters.
+# Note that the escaping is done for extended regular expressions, however
+# only characters that can appear in package names are escaped.
+#
+# @param @
+# More parameters can be added to the sed command.
+#
+getIdxEscape() {
+ sed -E -e 's/([+.])/\\\1/g' "$@"
+}
+
+#
+# Outputs all rows of the index that match a given pattern in a column.
+# The pattern should not match '|'.
+#
+# @param 1
+# The column that has to match the pattern.
+# @param 2
+# The pattern that has to be matched, an extended regular expression.
+# @param 3
+# Optional, the rows to match against instead of using the index file.
+#
+getIdxRows() {
+ if [ -z "$3" ]; then
+ grep -E "^([^|]*\|){$1}($2)(\|.*)?\$" "$PKG_INDEX"
+ else
+ echo "$3" | grep -E "^([^|]*\|){$1}($2)(\|.*)?\$"
+ fi
+}
+
+#
+# Outputs all rows of the index that match a given string.
+# The string should not contain '|'.
+#
+# @param 1
+# The column that has to match the string.
+# @param 2
+# The string that has to be matched.
+# @param 3
+# Optional, the rows to match against instead of using the index file.
+#
+getIdxRowsEscaped() {
+ getIdxRows $1 "$(echo "$2" | getIdxEscape)" "$3"
+}
+
+#
+# Outputs a column of each index row piped into it.
+#
+# @param 1
+# The column to output.
+# @param 2
+# The rows to output the columns from.
+#
+getIdxColumn() {
+ echo "$2" | sed -E "s,^([^|]*\|){$1}([^|]*)\|.*,\2,1"
+}
+
+#
+# Stores all the packages not in sync with the index file in categories.
+#
+# @param older
+# The list of packages older than those in the index.
+# @param newer
+# The list of packages newer than those in the index.
+# @param unindexed
+# The list of packages not in the index.
+# @param multiple
+# The list of packages that have multiple index entries.
+# @param error
+# The list of packages with broken package database entries.
+# @param pForce
+# If set, register all installed packages in the index as outdated.
+# @param pAll
+# If set, add all outdated packages to the list of packages to upgrade.
+# @param pListDiscarded
+# If set, list all the packages that are ignored.
+# @param upgrade
+# The list to add packages to if pAll is set.
+#
+pkgAll() {
+ local package pkgname origin operator row discarded
+
+ # There's nothing to be done if all of the following conditions are
+ # met:
+ # - Nothing is yet listed for upgrading, so we do not need a list
+ # of outdated packages for dependency checking.
+ # - The updating of all packages is not requested.
+ # - The listing of ignored (i.e. not indexed) packages is not
+ # requested.
+ test -z "$upgrade" -a -z "$pAll" -a -z "$pListDiscarded" && return 0
+
+ verbose "Make a list of outdated packages."
+
+ printStatus "Reading version information of installed packages ..."
+
+ if [ -n "$pForce" ]; then
+ # In force mode it is assumed that all installed packages to
+ # be found in the index are outdated.
+ for package in $(pkg_version -Io "${PKG_INDEX}"); {
+ origin="${package%% *}"
+ row="$(getIdxRowsEscaped $IDX_ORIGIN "$idxports/$origin")"
+ pkgname="$(getIdxColumn $IDX_PKG "$row")"
+ printStatus "Checking <$pkgname>."
+ operator="${package##* }"
+ case "$operator" in
+ '?')
+ unindexed="$unindexed${unindexed:+$IFS}$origin"
+ ;;
+ '!')
+ error="$error${error:+$IFS}$origin"
+ ;;
+ *)
+ older="$older${older:+$IFS}$origin;$pkgname"
+ ;;
+ esac
+ }
+ else
+ # Categorize installed packages and their relations to the
+ # index.
+ for package in $(pkg_version -IoL = ${PKG_INDEX}); {
+ origin="${package%% *}"
+ row="$(getIdxRowsEscaped $IDX_ORIGIN "$idxports/$origin")"
+ pkgname="$(getIdxColumn $IDX_PKG "$row")"
+ printStatus "Checking <${pkgname:-$(pkg_info -qO $origin)}>."
+ operator="${package##* }"
+ case "$operator" in
+ '<')
+ older="$older${older:+$IFS}$origin;$pkgname"
+ ;;
+ '>')
+ newer="$newer${newer:+$IFS}$origin;$pkgname"
+ ;;
+ '?')
+ unindexed="$unindexed${unindexed:+$IFS}$origin"
+ ;;
+ '*')
+ multiple="$multiple${multiple:+$IFS}$origin"
+ ;;
+ '!')
+ error="$error${error:+$IFS}$origin"
+ ;;
+ esac
+ }
+ fi
+
+ printStatus "Assemble checked packages ..."
+
+ # Remove packages to upgrade from the list of outdated packages.
+ for package in $upgrade; {
+ older="$(echo "$older" | grep -vx "$package")"
+ }
+
+ # Append outdated packages to the list of packages to update if all
+ # packages are to be updated.
+ if [ -n "$pAll" ]; then
+ downloadManagerMsgRequest "$older"
+ upgrade="$upgrade${older:+${upgrade:+$IFS}}$older"
+ older=
+ fi
+
+ # Clear the status line.
+ printStatus
+
+ # Print the discarded packages.
+ if [ -n "$pListDiscarded" ]; then
+ verbose "List discarded packages."
+
+ discarded="$unindexed$IFS$multipleIFS$error"
+ discarded="$(echo "$discarded" | grep -vFx '' | sort -u)"
+
+ test -n "$discarded" && echo "$discarded"
+ fi
+}
+
+#
+# Adds all missing dependencies to the list of packages to upgrade.
+#
+# @param 1
+# This is used to check the dependencies of newly added depending
+# packages.
+# @param upgrade
+# The primary list of packages to upgrade (read only).
+# @param upgradeDepends
+# The list to add packages to upgrade to.
+# @param older
+# The list of outdated packages. Packages for upgrading are removed from
+# it.
+# @param dependsChecked
+# A list of already checked dependencies, to avoid double checks.
+# @param pRecursive
+# If set, also add outdated dependencies to the upgrade list.
+# @param pMoreRecursive
+# If set, also update the dependencies of depending packages.
+# @param pForce
+# If set together with pRecursive, add all dependencies to the upgrade
+# list.
+#
+pkgDepends() {
+ local pkgname package row rows depends origin escapedPkg upgradeList
+
+ printStatus "Preparing dependency checks ..."
+
+ # In thorough mode the depencies of depending packages are updated, too.
+ upgradeList="${1:-$upgrade}"
+
+ # Luckily packages know their indirect dependencies, too. This way
+ # it is not necessary to check for dependencies recursively.
+ depends=
+ for package in $upgradeList; {
+ row="$(getIdxRowsEscaped $IDX_ORIGIN "$idxports/${package%;*}")"
+ row="$(getIdxColumn $IDX_DEPENDS "$row")"
+ depends="$depends${depends:+${row:+ }}$row"
+ }
+
+ # Reformat depends and throw out duplicates.
+ depends="$(
+ echo "$depends" | sed "s/ /\\$IFS/g" | sort -u
+ )"
+
+ # Do some prefiltering.
+ rows="$(getIdxRowsEscaped $IDX_PKG "$(echo "$depends" | rs -TC\|)")"
+
+ # Check for missing or outdated dependencies.
+ for pkgname in $depends; {
+ escapedPkg="$(echo "$pkgname" | getIdxEscape)"
+
+ # Skip packages already checked.
+ if echo "$dependsChecked" | grep -qFx "$pkgname"; then
+ continue
+ fi
+ dependsChecked="$dependsChecked${dependsChecked:+$IFS}$pkgname"
+
+ printStatus "Check dependency <$pkgname>."
+
+ # Skip this if this package is already scheduled for updating.
+ if echo "$upgrade${upgradeDepending:+$IFS$upgradeDepending}" | grep -qF ";$pkgname"; then
+ continue
+ fi
+
+ row="$(getIdxRows $IDX_PKG "$escapedPkg" "$rows")"
+
+ # If this package could not be identified this is an index
+ # incosistency, that can only be ignored.
+ if [ -z "$row" ]; then
+ warn "Ignore index inconsistency, the dependency <$pkgname> is not in the index." 1>&2
+ continue
+ fi
+
+ origin="$(getIdxColumn $IDX_ORIGIN "$row")"
+ origin="${origin#$idxports/}"
+ package="$origin;$(getIdxColumn $IDX_PKG "$row")"
+
+ #
+ # Deal with dependencies according to set parameters.
+ #
+ if [ -z "$(pkg_info -qO "$origin")" ]; then
+ # The depency is not installed.
+ upgradeDepends="$upgradeDepends${upgradeDepends:+$IFS}$package"
+ # Request a package download.
+ downloadManagerMsgRequest "$package"
+ elif [ -n "$pMoreRecursive" -o -n "$pRecursive" -a -z "$1" ]; then
+ # Check whether the dependency is outdated.
+ if echo "$older" | grep -qFx "$package"; then
+ upgradeDepends="$upgradeDepends${upgradeDepends:+$IFS}$package"
+ older="$(echo "$older" | grep -vFx "$package")"
+ # Request a package download.
+ downloadManagerMsgRequest "$package"
+ fi
+ fi
+ }
+}
+
+#
+# Checks whether packages depending on the packages to update require updating.
+#
+# @param 1
+# This is used to check the depending packages of newly added
+# dependencies.
+# @param older
+# The list of outdated packages. If pForce is set, this includes all
+# installed packages listed in the index.
+# @param upgrade
+# The primary list of packages to upgrade (read only).
+# @param upgradeDepending
+# The list of depending packages to upgrade.
+# @param pUpwardRecursive
+# If not set nothing is done.
+# @param pMoreUpwardRecursive
+# Also check the depending packages of depencencies.
+# @param pAll
+# If this is set do nothing.
+#
+pkgDepending() {
+ # Without the upwardRecursive option this is completely
+ # unnecessary.
+ if [ -z "$pUpwardRecursive" ]; then
+ return 0
+ fi
+
+ # If all packages are already going to be upgraded, there is no
+ # need for this.
+ if [ -n "$pAll" ]; then
+ return 0
+ fi
+
+ # Only update depending packages of dependencies in thorough mode.
+ if [ -n "$1" -a -z "$pMoreUpwardRecursive" ]; then
+ return 0
+ fi
+
+ local package pkgname origin row depends escapedPkg upgradeList
+
+ printStatus "Preparing upwards dependency checks ..."
+
+ # In thorough mode the depencies of depending packages are updated, too.
+ upgradeList="${1:-$upgrade}"
+
+ # Do some prefiltering.
+ rows="$(getIdxRowsEscaped $IDX_ORIGIN "$(
+ echo "$older" | rs -TC\| | sed -E "s'([^;|]*);[^|]*'$idxports/\1'g"
+ )")"
+
+ # For each outdated package, check whether it depends on a package
+ # to upgrade. In force mode outdated packages are all packages, so
+ # the difference does not have to be made here.
+ for package in $older; {
+ # Skip this if this package is already scheduled for updating.
+ if echo "$upgrade${upgradeDepends:+$IFS$upgradeDepends}${upgradeDepending:+$IFS$upgradeDepending}" | grep -qFx "$package"; then
+ continue
+ fi
+
+ printStatus "Check for upwards dependency <${package#*;}>."
+
+ origin="${package%;*}"
+ row="$(getIdxRowsEscaped $IDX_ORIGIN "$idxports/$origin" "$rows")"
+
+ # Ignore unindexed packages.
+ if [ -z "$row" ]; then
+ continue
+ fi
+
+ depends="$(getIdxColumn $IDX_DEPENDS "$row")"
+
+ # It has no dependencies, so it cannot depend on anything
+ # in the upgrade list.
+ if [ -z "$depends" ]; then
+ continue
+ fi
+
+ # Reformat dependencies.
+ depends="$(echo "$depends" | sed -Ee "s/([^ ]+)/;\1/g" -e "s/ /\\$IFS/g")"
+
+ # Check every dependency for matching the upgrade packages.
+ if echo "$upgradeList" | grep -qF "$depends"; then
+ upgradeDepending="$upgradeDepending${upgradeDepending:+$IFS}$package"
+ older="$(echo "$older" | grep -vFx "$package")"
+ downloadManagerMsgRequest "$package"
+ fi
+ }
+}
+
+#
+# This function calls pkgDepending and pkgDepends until no new packages
+# show up for updating. All the clever stuff happens in those functions.
+#
+# @param upgrade
+# The list of packages to upgrade.
+# @param upgradeDepends
+# The list of dependencies to add to the list of packages to upgrade.
+# @param upgradeDepending
+# The list of depending packages to add to the list of packages
+# to upgrade.
+#
+pkgDependencies() {
+ test -z "$upgrade" && return 0
+
+ verbose "Perform dependency checks."
+
+ # Run the primary dependency checks.
+ pkgDepending
+ downloadManagerMsgRequest "$upgradeDepending"
+ pkgDepends
+ downloadManagerMsgRequest "$upgradeDepends"
+
+ # The idea is to keep on checking until nothing new shows up.
+ # Whether that is the case depends on the level of recursiveness.
+ while [ -n "$upgradeDepends$upgradeDepending" ]; do
+ if [ -n "$upgradeDepends" ]; then
+ # Deal with packages depending on the updated packages.
+ pkgDepending "$upgradeDepends"
+ upgrade="$upgradeDepends$IFS$upgrade"
+ upgradeDepends=
+ fi
+
+ if [ -n "$upgradeDepending" ]; then
+ # Deal with missing or outdated dependencies.
+ pkgDepends "$upgradeDepending"
+ upgrade="$upgrade$IFS$upgradeDepending"
+ upgradeDepending=
+ fi
+ done
+
+ # Clear the status line.
+ printStatus
+}
+
+#
+# Prints a progress message to the terminal device /dev/tty.
+#
+# @param 1
+# Total amount of operations to do.
+# @param 2
+# The amount of operations performed.
+# @param 3
+# The name of the package that is currently operated on.
+# @param 4
+# The text prepending the progress information.
+# @param status
+# The last printed message, used for clearing the status line before
+# printing a new status.
+# @param pClean
+# If set, do not print progress messages.
+#
+printProgress() {
+ test -n "$pClean" && return 0
+ printf "\r%${#status}s\r$4 %${#1}s of %${#1}s (%3s%%) <$3>.\r" '' "$2" "$1" "$(($2 * 100 / $1))" > /dev/tty
+ status="$4 $1 of $1 (100%) <$3>."
+}
+
+#
+# Sorts the packages to upgrade by dependency.
+#
+# The trick is to have a list of already sorted packages. Each package added
+# to the list is inserted right behind its last dependency already present
+# there.
+# Packages without any dependencies in the sorted list are prepended. This
+# way it is ensured that they end up before all already sorted packages
+# that depend on them, without additional checking.
+#
+# @param upgrade
+# The list of packages to sort.
+# @param pParanoid
+# If set, make cyclic dependency checks.
+#
+pkgSort() {
+ local rows sorted package row depends dependency pkgname
+ local totalCount count
+
+ test -z "$upgrade" && return 0
+
+ verbose "Sort packages by dependency."
+
+ printStatus "Prepare sorting of packages ..."
+
+ # Limit rows to whatever is currently required.
+ rows="$(getIdxRowsEscaped $IDX_ORIGIN "$(
+ echo "$upgrade" | getIdxEscape -e 's/;.*//1' -e "s,^,$idxports/,1" | rs -TC\|
+ )")"
+
+ # The number of packages
+ totalCount=$(($(echo "$upgrade" | wc -l)))
+ count=0
+
+ # Sort each package into the list of sorted packages.
+ sorted=
+ for package in $upgrade; {
+ count=$(($count + 1))
+ pkgname="${package#*;}"
+ printProgress $totalCount $count "$pkgname" 'Sort'
+
+ # Get the list of dependencies that should be updated before
+ # the current package.
+ row="$(getIdxRowsEscaped $IDX_PKG "$pkgname" "$rows")"
+ depends="$(getIdxColumn $IDX_DEPENDS "$row" | sed -E "s/ /\\$IFS/g")"
+
+ # Get the last matching dependency in the list.
+ dependency="$(echo "$sorted" | grep -Fx "$depends" | tail -n 1)"
+
+ # If there is no match, just prepend to the list.
+ if [ -z "$dependency" ]; then
+ sorted="$pkgname${sorted:+$IFS$sorted}"
+ continue
+ fi
+
+ # Insert right behind the match.
+ dependency="$(echo "$dependency" | getIdxEscape)"
+ sorted="$(echo "$sorted" | sed -E "s/^$dependency$/$dependency\\$IFS$pkgname/1")"
+ }
+
+ # Perform optional cyclic dependency check.
+ if [ -n "$pParanoid" ]; then
+ printStatus "Validate sorting order ..."
+
+ # Validate the sort order.
+ count=0
+ for pkgname in $sorted; {
+ count=$(($count + 1))
+ printProgress $totalCount $count "$pkgname" 'Validate'
+
+ # Get the list of dependencies that should be updated before
+ # the current package.
+ row="$(getIdxRowsEscaped $IDX_PKG "$pkgname" "$rows")"
+ depends="$(getIdxColumn $IDX_DEPENDS "$row" | sed -E "s/ /\\$IFS/g")"
+
+ # Append the package to the list of dependencies to match.
+ depends="${depends:+$depends$IFS}$pkgname"
+
+ # Get the last match in the list.
+ dependency="$(echo "$sorted" | grep -Fx "$depends" | tail -n 1)"
+ # The last match has to be the package.
+ if [ "$dependency" != "$pkgname" ]; then
+ error $ERR_SORT "The package <$pkgname> was not sorted properly, a likely cause is a circular dependency."
+ fi
+ }
+ fi
+
+ printStatus "Assemble sorted packages ..."
+
+ # Replace package names with <origin>;<package> pairs.
+ for package in $upgrade; {
+ pkgname="$(echo "${package#*;}" | getIdxEscape)"
+ sorted="$(echo "$sorted" | sed -E "s'^$pkgname\$'$package'1")"
+ }
+
+ upgrade="$sorted"
+ printStatus
+}
+
+#
+# Prints the update/replace/install task.
+#
+# @param 1
+# The package to upgrade/install.
+# @param replace
+# The list of packages to replace.
+#
+printTask() {
+ local package newPkgname newOrigin oldPkgname oldOrigin
+
+ # Get the name and origin of the new package.
+ newPkgname="${1#*;}"
+ newOrigin="${1%;*}"
+
+ # Look for a package the new one replaces.
+ package="$(echo "$replace" | grep -F "$1|")"
+
+ # Look for a package this one replaces.
+ # The current package actually replaces another one.
+ if [ -n "$package" ]; then
+ # Get the name and origin of the old package.
+ package="${package#*|}"
+ oldPkgname="${package#*;}"
+ oldOrigin="${package%;*}"
+
+ echo "Replace <$oldPkgname> ($oldOrigin) with <$newPkgname> ($newOrigin)"
+ return 0
+ fi
+
+ # Check whether there's an old version of this package around.
+ package="$(pkg_info -qO "$newOrigin")"
+
+ # An older package with this origin is installed.
+ if [ -n "$package" ]; then
+ echo "Update <$package> to <$newPkgname> ($newOrigin)"
+ return 0
+ fi
+
+ # Aparently this package will be newly installed.
+ echo "Install <$newPkgname> ($newOrigin)"
+}
+
+#
+# List the packages that are going to be upgraded, installed and replaced.
+# If the 'no actions' mode is active.
+#
+# @param upgrade
+# The list of packages to upgrade.
+# @param pNoActions
+# Print the list of tasks.
+#
+pkgList() {
+ # Only list packages in "no actions" mode.
+ test -z "$pNoActions" && return 0
+
+ test -z "$upgrade" && return 0
+
+ local package
+
+ verbose "The following packages will be updated:"
+
+ for package in $upgrade; {
+ printTask "$package"
+ }
+}
+
+#
+# Wait for downloaded packages and validate them.
+#
+# @param upgrade
+# The list of packages to download.
+# @param pending
+# The list of pending downloads.
+# @param packagerepos
+# The location of the remote package repository (derived from
+# PACKAGESITE). If this is identical with the local repository,
+# the download manager was not started.
+# @param pNoActions
+# Do not download anything.
+#
+pkgDownload() {
+ test -n "$pNoActions" && return 0
+
+ test -z "$upgrade" && return 0
+
+ local package total count line
+
+ verbose "Validate downloaded packages."
+
+ printStatus "Waiting for downloads ..."
+
+ # Create a list of the package names to validate.
+ # Entries are removed from this list by validatePackage().
+ pending="$(echo "$upgrade" | sed 's/.*;//1')"
+
+ # The total number of packages to validate.
+ total="$(($(echo "$upgrade" | wc -l)))"
+
+ # Check whether the download manager is available.
+ if [ "$PACKAGES" = "$packagerepos" ]; then
+ #
+ # The local repository is identical with the remote repository
+ # so the assumption is all packages should already be there.
+ #
+
+ # Validate all packages.
+ for package in $pending; {
+ count=$(($count + 1))
+ printProgress $total $count "$package" "Validate"
+ validatePackage "$package"
+ }
+ else
+ #
+ # The download manager is available, so hang on to its message
+ # queue and proceed with validating as packages are finished.
+ #
+ count=0
+
+ while [ -n "$pending" ]; do
+ read line
+ case "$line" in
+ finished:*)
+ count=$(($count + 1))
+ package="${line##*;}"
+ printProgress $total $count "$package" "Validate"
+ validatePackage "$package"
+ ;;
+ esac
+ done < "$queueMessages"
+
+ # Stop the download manager.
+ downloadManagerMsgExit
+ fi
+
+ # Clear the status line.
+ printStatus
+}
+
+#
+# Upgrade each package.
+#
+# @param upgrade
+# The list of packages to upgrade.
+# @param conflictReplace
+# This list is reset for conflict handling.
+# @param pNoActions
+# Do not update anything.
+# @param pFetchOnly
+# Do not update anything.
+#
+pkgUpgrade() {
+ test -n "$pNoActions" -o -n "$pFetchOnly" && return 0
+
+ test -z "$upgrade" && return 0
+
+ local package
+
+ verbose "Install $(($(echo "$upgrade" | wc -l))) package(s)."
+
+ for package in $upgrade; {
+ upgradePackage "$package"
+ }
+}
+
+#
+# To handle conflicts this function removes dependencies from a given package
+# and appends one or more new ones to take their place. Also the +REQUIRED_BY
+# files of the appended dependencies are updated.
+#
+# @param 1
+# The name of the package to which to apply the substitutions.
+# @param substituteDepends
+# The list of dependency substitutions that should take place.
+#
+substituteDepends() {
+ # End here if there's nothing to substitute.
+ test -z "$substituteDepends" && return 0
+
+ local line originalOrigin originalPkgname newOrigin newPkgname
+ local contents append remove requiredBy
+
+ printStatus "Adjust the dependencies of <$1> ..."
+
+ # Get the contents file.
+ contents="$(cat "$PKG_DBDIR/$1/+CONTENTS")"
+
+ # Because there can be several substitutions for a single package
+ # the new ones will be added to the end of the +CONTENTS file and all
+ # the matches will be removed later.
+ append=
+ remove=
+ for line in $substituteDepends; {
+ # Get original origin and package name from the line.
+ originalOrigin="${line%%;*}"
+ originalPkgname="${line%|*}"
+ originalPkgname="${originalPkgname#*;}"
+
+ # Continue with the next line if this one does not match.
+ if ! echo "$contents" | grep -qFx "@pkgdep $originalPkgname"; then
+ continue
+ fi
+
+ # Get new origin and package name from the line.
+ newOrigin="${line#*|}"
+ newPkgname="${newOrigin#*;}"
+ newOrigin="${newOrigin%;*}"
+
+ warn "Add dependency <$newPkgname> ($newOrigin)."
+
+ # Remember what to append and what to remove.
+ remove="${remove:+$remove$IFS}@pkgdep $originalPkgname$IFS@comment DEPORIGIN:$originalOrigin"
+ # Just for the very unlikely case that two dependencies get
+ # replaced for conflicting with the same package, check that
+ # a dependency is not added twice.
+ if ! echo "$append" | grep -qFx "@pkgdep $newPkgname"; then
+ append="$append$IFS@pkgdep $newPkgname$IFS@comment DEPORIGIN:$newOrigin"
+ fi
+
+ # Make an entry for the package in the +REQUIRED_BY file of
+ # of the dependency to append.
+ requiredBy="$(cat "$PKG_DBDIR/$newPkgname/+REQUIRED_BY" 2> /dev/null)"
+ requiredBy="${requiredBy:+$requiredBy$IFS}$1"
+ echo "$requiredBy" | sort -u > "$PKG_DBDIR/$newPkgname/+REQUIRED_BY"
+ }
+
+ # Remove the original dependency entries.
+ contents="$(echo "$contents" | grep -vFx "$remove")"
+ # Write the new file. Note that $append always starts with a newline.
+ echo "$contents$append" > "$PKG_DBDIR/$1/+CONTENTS"
+}
+
+#
+# Install the given package. This is where the magic happens.
+#
+# @param replace
+# The list of packages to replace (read only).
+# @param substituteDepends
+# A list of dependency substitutions that should take place for each
+# newly installed package to resolve conflicting packages.
+# @param packagebackup
+# The location for backup packages. This is derived from PACKAGES.
+# @param pNoBackup
+# If set, delete backups after successful completion.
+#
+upgradePackage() {
+ local task targetPackage targetPkgname targetOrigin package replace
+ local escapedPkg removePackages origin file conflict conflicting
+ local replacePkgdep requiredBy count
+ local signal
+
+ # Get a string with the current upgrade task.
+ task="$(printTask "$1")"
+ echo "===> $task"
+
+ targetPackage="$1"
+ targetPkgname="${1#*;}"
+ targetOrigin="${1%;*}"
+
+ printStatus "Prepare installation of <$targetPkgname> ..."
+
+ # Get the packages to replace with this one. Several packages can be
+ # replaced with a single one.
+ escapedPkg="$(echo "$targetPackage" | getIdxEscape)"
+ replace="$(echo "$replace" | grep -Ex "$escapedPkg\|.*" | sed -E "s'^$escapedPkg\|''1")"
+
+ # Append the current package to the list of packages to replace.
+ replace="${replace:+$replace$IFS}$targetPackage"
+
+ # Create the list of outdated packages that have to be backed up
+ # and for which pkgdb adjustments have to be made after successful
+ # installation of the new package.
+ # Also create the necessary sed expressions to update the
+ # package database.
+ removePackages=
+ replacePkgdep=
+ for package in $replace; {
+ origin="${package%;*}"
+ package="$(pkg_info -qO "$origin")"
+ test -z "$package" && continue
+ removePackages="$removePackages${removePackages:+$IFS}$package"
+ package="$(echo "$package" | getIdxEscape)"
+ replacePkgdep="$replacePkgdep -e 's|^@pkgdep $package\$|@pkgdep $targetPkgname|1'"
+ if [ "$origin" != "$targetOrigin" ]; then
+ replacePkgdep="$replacePkgdep -e 's|^@comment DEPORIGIN: $origin\$|@comment DEPORIGIN:$targetOrigin|1'"
+ fi
+
+ }
+
+ # Get a list of conflicting packages. The conflicts list is
+ # provided by readContents().
+ readContents "$PACKAGES/All/$targetPkgname.tbz"
+ conflicting=
+ for conflict in $conflicts; {
+ # Match the conflict pattern against installed packages.
+ for conflict in $(pkg_info -E "$conflict"); {
+ escapedPkg="$(echo "$conflict" | getIdxEscape)"
+ # Only add to the conflicting list if the conflicting
+ # package is not in the list of packages to replace.
+ if ! echo "$removePackages" | grep -qEx "$escapedPkg"; then
+ conflicting="${conflicting:+$conflicting$IFS}$conflict"
+ fi
+ }
+ }
+ # Remove duplicated entries.
+ conflicting="$(echo "$conflicting" | sort -u)"
+
+ # Check whether any conflicts were found.
+ if [ -n "$conflicting" ]; then
+ # What happens now depends on the user preferences.
+ if [ -n "$pExitOnConflict" ]; then
+ # The user has chosen to bail out when a conflict
+ # occurs.
+ log $ERR_CONFLICT "$task"
+ error $ERR_CONFLICT "The package <$targetPkgname> conflicts with the following packages:$IFS$conflicting"
+ elif [ -n "$pReplaceConflicts" ]; then
+ # The user has chosen that conflicting packages should
+ # be replaced as if they were explicitly listed for
+ # replacing.
+ conflicts=
+ for package in $conflicting; {
+ warn "The package <$package> conflicts with <$targetPkgname> and will be replaced."
+ removePackages="$removePackages${removePackages:+$IFS}$package"
+ origin="$(pkg_info -qo "$package")"
+ # The next line is just for prettier log output.
+ conflicts="${conflicts:+$conflicts, }<$package> ($origin)"
+ package="$(echo "$package" | getIdxEscape)"
+ replacePkgdep="$replacePkgdep -e 's|^@pkgdep $package\$|@pkgdep $targetPkgname|1'"
+ if [ "$origin" != "$targetOrigin" ]; then
+ replacePkgdep="$replacePkgdep -e 's|^@comment DEPORIGIN: $origin\$|@comment DEPORIGIN:$targetOrigin|1'"
+ fi
+ }
+ log 0 "Conflict <$targetPkgname> ($targetOrigin) remove package(s) $conflicts"
+ else
+ # The default action is to assume that the conflicting
+ # packages fulfill the required functionality.
+ conflicts=
+ for package in $conflicting; {
+ warn "The package <$targetPkgname> will not be installed in favour of <$package>, because they conflict."
+ origin="$(pkg_info -qo "$package")"
+ # Record the necessary substitutions.
+ # TODO: Later versions will have to store this
+ # for resume.
+ substituteDepends="${substituteDepends:+$substituteDepends$IFS}$targetPackage|$origin;$package"
+ # This is just for prettier log output.
+ conflicts="${conflicts:+$conflicts, }<$package> ($origin)"
+ }
+ # Log the conflict resolution.
+ log 0 "Conflict <$targetPkgname> ($targetOrigin) favour package(s) $conflicts"
+ # Skip to the next package.
+ return 0
+ fi
+ fi
+
+ # Backup packages.
+ mkdir -p "$packagebackup"
+ for package in $removePackages; {
+ printStatus "Backup <$package>."
+ pkg_create -b "$package" "$packagebackup/$package"
+ case $? in
+ 0)
+ # Everything went well.
+ ;;
+ 1)
+ # If this happens someone's been messing with
+ # the packages just milliseconds ago.
+ log $ERR_BACKUP_MISS "$task"
+ error $ERR_BACKUP_MISS "The backup of <$package> failed. The package is missing."
+ ;;
+ 2)
+ # Fortunately pkg_create backs up as much as
+ # as is possible. That the backup (and hence
+ # the present package) is incomplete is all
+ # the more reason to upgrade.
+ # I do not understand why portmaster is
+ # interactive in this case.
+ warn "Ignoring incomplete backup of <$package>."
+ ;;
+ *)
+ # Well, I've got no idea at all what else
+ # could go wrong. Too bad the return codes
+ # of pkg_create are not documented.
+ log $ERR_BACKUP_UNKNOWN "$task"
+ error $ERR_BACKUP_UNKNOWN "The backup of <$package> failed for unknown reasons."
+ ;;
+ esac
+ }
+
+ # Block SIGINT (CTRL-C), because that would really wrack havoc upon
+ # the package database in the following section.
+ signal=
+ trap "signal=$ERR_USER" sigint
+ trap "signal=$ERR_TERM" sigterm
+
+ # Delete packages.
+ requiredBy=
+ count=-1
+ for package in $removePackages; {
+ printStatus "Delete <$package>."
+ # Remember +REQUIRED_BY contents for roll-back.
+ count=$(($count + 1))
+ local "requiredBy$count"
+ setvar "requiredBy$count" "$(cat "$PKG_DBDIR/$package/+REQUIRED_BY" 2> /dev/null)"
+ # Remember +REQUIRED_BY contents for the new package.
+ requiredBy="${requiredBy:+$requiredBy$IFS}$(cat "$PKG_DBDIR/$package/+REQUIRED_BY" 2> /dev/null)"
+ # Finally delete the package.
+ pkg_delete -f "$package"
+ }
+
+ # Update the package database.
+ printStatus "Update package database for <$targetPkgname>."
+ if [ -n "$replacePkgdep" ]; then
+ for file in $(find "$PKG_DBDIR" -name '+CONTENTS'); {
+ eval "sed -Ei '.$name' $replacePkgdep '$file'"
+ }
+ fi
+
+ # If an old version of this package was favoured in a conflict,
+ # the substituteDepends list has to be changed.
+ substituteDepends="$(echo "$substituteDepends" | sed "s'\|$targetOrigin;.*'|$targetPackage'1")"
+
+ # Try to install the new package.
+ printStatus "Install <$targetPkgname>."
+ if ! env PKG_PATH="$PACKAGES/All" pkg_add -f "$targetPkgname"; then
+ # Installation went wrong, roll back!
+ printStatus "Roll back changes for <$targetPkgname>."
+ for file in $(find "$PKG_DBDIR" -name "*.$name"); {
+ mv -f "$file" "${file%.$name}"
+ }
+ count=-1
+ for package in $removePackages; {
+ # Restore package.
+ env PKG_PATH="$packagebackup" pkg_add -f "$package"
+ # Recover +REQUIRED_BY file.
+ count=$(($count + 1))
+ eval "echo \"\$requiredBy$count\"" > "$PKG_DBDIR/$package/+REQUIRED_BY"
+ # Remove the backup if set.
+ test -n "$pNoBackup" && rm "$packagebackup/$package.tbz"
+ }
+ log $ERR_INSTALL "$task"
+ error $ERR_INSTALL "The installation of <$targetPkgname> failed."
+ fi
+
+ # Add the +REQUIRED_BY contents of all deleted packages to the
+ # +REQUIRED_BY file of the new one.
+ requiredBy="$(echo "$(cat "$PKG_DBDIR/$targetPkgname/+REQUIRED_BY" 2> /dev/null)$IFS$requiredBy" | grep -vFx '' | sort -u)"
+ echo "$requiredBy" > "$PKG_DBDIR/$targetPkgname/+REQUIRED_BY"
+
+ # Make dependency substitutions from conflict resolving.
+ substituteDepends "$targetPkgname"
+
+ # Log successful completion of the task.
+ log 0 "$task"
+
+ # Remove backups if set.
+ if [ -n "$pNoBackup" ]; then
+ for package in $removePackages; {
+ printStatus "Remove backup of <$package>."
+ rm "$packagebackup/$package.tbz"
+ }
+ fi
+
+ # Remove package database backups.
+ # TODO: Later versions will instead store them to allow a rollback.
+ printStatus "Remove database backups for <$targetPkgname>."
+ find "$PKG_DBDIR" -name "*.$name" -exec rm \{\} \;
+
+ # Clear the status line.
+ printStatus
+ echo "=> $task succeeded"
+
+ # Bail out if SIGINT or SIGTERM were encountered.
+ if [ -n "$signal" ]; then
+ error $signal "The process was interrupted."
+ fi
+
+ # Reactivate default signal handlers.
+ trap - sigint sigterm
+}
+
+#
+# Identify the package by a given string. Outputs the origin of all matched
+# packages, as well as the package name of the newest available package.
+# The output is in the following shape:
+# <origin>;<package>
+#
+# The shell wildcards '*' and '?' are supported.
+# Origin and package names with wildcards are matched against installed
+# packages. Unambiguous package names and origins are matched against the
+# index.
+#
+# @param 1
+# The package identifier to find matches for.
+#
+identifyPackage() {
+ local packages package mangledPackage rows matchingRows mangledRows
+ local origins origin guess escapedPkg
+
+ # Check for wildcards.
+ guess=
+ if echo "$1" | grep -qE '\*|\?|\[.*]'; then
+ guess=1
+ fi
+ package="$1"
+
+ # Distuinguish between origins and packages.
+ case "$package" in
+ */*)
+ # An origin has been given.
+ if [ -n "$guess" ]; then
+ # Wildcards present, match against installed
+ # packages.
+
+ # Get all matching packages.
+ packages="$(pkg_info -qO "$package")"
+
+ # Convert for use in a regular expression.
+ package="$(echo "$package" | getIdxEscape -e 's/\*/[^|]*/g' -e 's/\?/[^|]/g')"
+ # Get rows matching the given package origin.
+ # This is a performance tweak, so the whole
+ # index will not have to be parsed in the
+ # following output loop.
+ rows="$(getIdxRows $IDX_ORIGIN "$idxports/$package")"
+
+ # Output all matching packages.
+ for package in $packages; {
+ # Get the origin.
+ origin="$(pkg_info -qo "$package")"
+
+ # Match this package origin against the
+ # previously filtered rows.
+ package="$(getIdxRowsEscaped $IDX_ORIGIN "$idxports/$origin" "$rows")"
+ # Get the package name of the newest
+ # package from the index.
+ package="$(getIdxColumn $IDX_PKG "$package")"
+ # Output origin/package pair.
+ echo "$origin;$package"
+ }
+
+ # If no matches have been found, terminate.
+ if [ -z "$packages" ]; then
+ error $ERR_ARG "Package origin <$package> not matched by any installed package!" 1>&2
+ fi
+ else
+ # There is an unambigious origin, match it
+ # against the index.
+ origin="$package"
+ # Get the index row.
+ rows="$(getIdxRowsEscaped $IDX_ORIGIN "$idxports/$origin")"
+ # Get the package name column.
+ package="$(getIdxColumn $IDX_PKG "$rows")"
+ # Output origin/package pair, if a package for
+ # the given origin was found.
+ if [ -n "$package" ]; then
+ # Output origin/package pair.
+ echo "$origin;$package"
+ else
+ error $ERR_ARG "Package origin <$origin> not in index!" 1>&2
+ fi
+ fi
+ ;;
+ *)
+ # A package name has been given.
+ if [ -n "$guess" ]; then
+ # Wildcards present, match against installed
+ # packages.
+
+ # Get the origins of matching packages.
+ origins="$(pkg_info -qo "$package")"
+
+ # Prepare the package name for use in a
+ # regular expression.
+ package="$(echo "$package" | getIdxEscape -e 's/\*/[^|]*/g' -e 's/\?/[^|]/g')"
+ # Get rows matching the given package name.
+ # This is a performance tweak, so the whole
+ # index will not have to be parsed in the
+ # following output loop.
+ rows="$(getIdxRows $IDX_PKG "$package")"
+ # Output all matching packages.
+ for origin in $origins; {
+ # Get the index row for this origin.
+ package="$(getIdxRowsEscaped $IDX_ORIGIN "$idxports/$origin" "$rows")"
+ # Get the latest package name from the
+ # index.
+ package="$(getIdxColumn $IDX_PKG "$package")"
+ # Output origin/package pair.
+ echo "$origin;$package"
+ }
+
+ # If no matches have been found, terminate.
+ if [ -z "$origins" ]; then
+ error $ERR_ARG "Package identifier <$package> not matched!" 1>&2
+ fi
+ else
+ # A package name without wildcards has been
+ # given. This is expected to either be an exact
+ # package name or a LATEST_LINK name.
+
+ # TODO: This would be much better if
+ # LATEST_LINK was known. This is information
+ # simply missing in the index.
+ # To make up for this some guessing is done in
+ # case of no matches or more than one match.
+ # But this fails for apache13 and probably
+ # other packages as well.
+
+ # First try whether it is the current version
+ # of a package.
+ origin="$(pkg_info -qo "$package" 2> /dev/null)"
+ if [ -n "$origin" ]; then
+ # Get the matching index rows.
+ rows="$(getIdxRowsEscaped $IDX_ORIGIN "$idxports/$origin")"
+ fi
+
+ # If it's not a current version, match against
+ # the index.
+ if [ -z "$rows" ]; then
+ # Get the matching rows. This should be
+ # only one, but it won't be for ports
+ # that define a proprietary LATEST_LINK.
+ escapedPkg="$(echo "$package" | getIdxEscape)"
+ rows="$(getIdxRows $IDX_PKG "$escapedPkg(-[^-]+)?")"
+ fi
+
+ # No match, start some guessing.
+ # This fails for packages with a version tail,
+ # which is just what is wanted.
+ if [ -z "$rows" ]; then
+ # Assume this is a LATEST_LINK kind
+ # package name and remove the trailing
+ # numbers.
+ mangledPackage="$(echo "$package" | sed -E 's/[0-9]+$//1')"
+ # Get the matching rows, this is likely
+ # to be too many (i.e. more than one).
+ rows="$(getIdxRows $IDX_PKG "$mangledPackage-[^-]+")"
+ fi
+
+ # If there is more than one matching row,
+ # try to match against the origin.
+ if [ "$(($(echo "$rows" | wc -l)))" -gt "1" ]; then
+ # Match against the origin.
+ rows="$(getIdxRows $IDX_ORIGIN "[^|]*/$package" "$rows")"
+
+ # If there is still more than one
+ # match, match against the origins
+ # of existing packages.
+ if [ "$(($(echo "$rows" | wc -l)))" -gt "1" ]; then
+ for origin in $(getIdxColumn $IDX_ORIGIN "$rows"); {
+ test -n "$(pkg_info -qO "$origin")" \
+ && matchingRows="$matchingRows${matchingRows:+$IFS}$(getIdxRowsEscaped $IDX_ORIGIN "$origin" "$rows")"
+ }
+ rows="$matchingRows"
+ fi
+
+ # Either a single origin is matched or
+ # it's time to bail out and give up.
+ if [ "$(($(echo "$rows" | wc -l)))" -ne "1" ]; then
+ # The wrong amount of matches
+ # has occured. Bail out.
+ error $ERR_ARG "Package identifier <$package> not unambiguously matched!" 1>&2
+ fi
+ fi
+
+ # Output if a package has been matched.
+ if [ -n "$rows" ]; then
+ # Get the origin of the given package.
+ origin="$(getIdxColumn $IDX_ORIGIN "$rows")"
+ # Geth the package name.
+ package="$(getIdxColumn $IDX_PKG "$rows")"
+ # Output origin/package pair.
+ echo "${origin#$idxports/};$package"
+ else
+ error $ERR_ARG "Package identifier <$package> not in index!" 1>&2
+ fi
+ fi
+ ;;
+ esac
+}
+
+#
+# Prints the parameter list and terminates the program.
+#
+printHelp() {
+ printf "$name v$version
+usage:
+ $name -h
+ $name -a [-b] [-bcCdfFlnpvX] [-o new existing] [update] [install]
+ $name [-bcCdfFlnpvX] [-r [-r]] [-R [-R]] [-o new existing]
+ %${#name}s [update] [install]\n" ''
+ exit 0
+}
+
+#
+# Parse the command line parameters.
+#
+# @param upgrade
+# A list of packages to upgrade.
+# @param depth
+# This is used by the function to store the recursion depth and
+# should be unset when calling it.
+# @param origin
+# This is used by the function across differtent recursion depths to
+# remember whether a package origin is expected.
+# @param pAll
+# Is set if all packages should be update.
+# @param pNoBackup
+# Is set if backups could not be fetched.
+# @param pClean
+# Is set to turn off status messages.
+# @param pReplaceConflicts
+# Is set to replace conflicting packages with new ones instead of
+# leaving them alone.
+# @param pExitOnConflict
+# Is set to stop the program if a conflict is encountered.
+# @param pForce
+# Is set to force the update of packages that are not really updated.
+# @param pFetchOnly
+# Is set to only fetch packages instead of installing/upgrading them.
+# @param pInteractive
+# TODO: Reserved for future versions (resume/roll-back).
+# @param pJobs
+# TODO: Reserved for future versions (pkg_libchk tests).
+# @param pListDiscarded
+# Is set to activate the listing of packages that are ignored because
+# they are not set in the INDEX.
+# @param pNoActions
+# Is set if no actions should be performed but a list of what would have
+# been done should get printed.
+# @param pNoLogging
+# Turn off logging.
+# @param pParanoid
+# Is set to activate cyclic dependency checks.
+# @param pRecursive
+# Is set to activate updating of dependencies.
+# @param pMoreRecursive
+# Is set to activate updating of dependencies of depending packages.
+# @param pUpwardRecursive
+# Is set to activate updating of depending packages.
+# @param pMoreUpwardRecursive
+# Is set to activate updating of packages depending on dependencies.
+# @param pVerbose
+# Is set to activate informative output.
+#
+readParams() {
+ local arg package escapedPkg depth
+ # Store the recursion depth. Note that counting down is dealt with
+ # by making depth local.
+ depth=$((${depth:--1} + 1))
+
+ # This is used to remember whether the next parameter should
+ # be a replacing package or a packge to be replaced.
+ origin=${origin:-0}
+
+ for arg {
+ #
+ # Handle package replacements.
+ #
+ if [ $origin -eq 1 ]; then
+ # Store the replacement.
+ package="$(identifyPackage "$arg")" || exit $?
+ if [ -z "$package" -o "$(($(echo "$package" | wc -l)))" -ne "1" ]; then
+ error $ERR_ARG "The package identifier <$arg> is not unambiguous."
+ fi
+ upgrade="$upgrade${upgrade:+$IFS}$package"
+ replace="$replace${replace:+$IFS}$package"
+ origin=2
+ # Request the download.
+ downloadManagerMsgRequest "$package"
+ continue
+ fi
+ if [ $origin -eq 2 ]; then
+ # Store what to replace.
+ # This is taken from the package database not the index.
+
+ case "$arg" in
+ */*)
+ # Assume arg is an origin.
+ package="$(pkg_info -qO "$arg")"
+ package="$(pkg_info -qo "$package" 2> /dev/null);$package"
+ ;;
+ *)
+ # Assume arg is a package identifier.
+ package="$(pkg_info -qo "$arg" 2> /dev/null);$(pkg_info -E "$arg" 2> /dev/null)"
+
+ # Maybe arg is a package identifier
+ # without a version tail.
+ if [ "$package" = ";" ]; then
+ package="$(pkg_info -qo "$arg-*" 2> /dev/null);$(pkg_info -E "$arg-*" 2> /dev/null)"
+ fi
+ ;;
+ esac
+
+ # Arg is not installed.
+ if [ "$package" = ";" ]; then
+ error $ERR_ARG "The package <$arg> is not installed and thus cannot be replaced."
+ fi
+ # It appears arg is an identifier that is
+ # not unambiguous.
+ if [ "$(($(echo "$package" | wc -l)))" -ne "1" ]; then
+ error $ERR_ARG "The package identifier <$arg> is not unambiguous."
+ fi
+ # A package can only be replaced once.
+ escapedPkg="$(echo "$package" | getIdxEscape)"
+ if echo "$replace" | grep -qEx ".*\|$escapedPkg"; then
+ error $ERR_ARG "The package <$arg> is already listed for replacement."
+ fi
+ replace="$replace|$package"
+ origin=0
+ continue
+ fi
+
+ #
+ # Identify arguments.
+ #
+ case "$arg" in
+ "-a" | "--all")
+ pAll=1
+ if [ -n "$pRecursive" ]; then
+ error $ERR_ARG "Recursiveness has no effect, because all packages are already selected for processing."
+ fi
+ if [ -n "$pUpwardRecursive" ]; then
+ error $ERR_ARG "Upward recursiveness has no effect, because all packages are already selected for processing."
+ fi
+ ;;
+ "-b" | "--no-backup")
+ pNoBackup=1
+ ;;
+ "-c" | "--clean")
+ pClean=-c
+ ;;
+ "-C" | "--replace-conflicts")
+ if [ -n "$pExitOnConflict" ]; then
+ error $ERR_ARG "The 'replace conflicts' and 'exit on conflict' modes are mutually exclusive."
+ fi
+ pReplaceConflicts=1
+ ;;
+ "-d" | "--list-discarded")
+ pListDiscarded=1
+ ;;
+ "-f" | "--force")
+ pForce=1
+ ;;
+ "-F" | "--fetch-only")
+ if [ -n "$pNoActions" ]; then
+ error $ERR_ARG "The 'no actions' and 'fetch only' modes are mutually exclusive."
+ fi
+ pFetchOnly=1
+ ;;
+ "-h" | "--help")
+ printHelp
+ ;;
+ "-i" | "--interactive")
+ # TODO: not yet used
+ pInteractive=1
+ ;;
+ -j* | --jobs*)
+ # TODO: not yet used
+ pJobs="$arg"
+ if ! pkg_libchk "$pJobs" DUMMY/DUMMY 1>&2; then
+ exit $ERR_ARG
+ fi
+ ;;
+ "-l" | "--no-logging")
+ pNoLogging=1
+ ;;
+ "-n" | "--no-actions")
+ if [ -n "$pFetchOnly" ]; then
+ error $ERR_ARG "The 'no actions' and 'fetch only' modes are mutually exclusive."
+ fi
+ pNoActions=1
+ ;;
+ "-o" | "--origin")
+ # Make sure the local index copy is up to date.
+ getIndex
+ origin=1
+ ;;
+ "-p" | "--paranoid")
+ pParanoid=1
+ ;;
+ "-r" | "--recursive")
+ if [ -n "$pMoreRecursive" ]; then
+ error $ERR_ARG "There are only two levels of recursiveness."
+ elif [ -n "$pRecursive" ]; then
+ pMoreRecursive=1
+ else
+ pRecursive=1
+ fi
+ if [ -n "$pAll" ]; then
+ error $ERR_ARG "Recursiveness has no effect, because all packages are already selected for processing."
+ fi
+ ;;
+ "-R" | "--upward-recursive")
+ if [ -n "$pMoreUpwardRecursive" ]; then
+ error $ERR_ARG "There are only two levels of upward recursiveness."
+ elif [ -n "$pUpwardRecursive" ]; then
+ pMoreUpwardRecursive=1
+ else
+ pUpwardRecursive=1
+ fi
+ if [ -n "$pAll" ]; then
+ error $ERR_ARG "Upward recursiveness has no effect, because all packages are already selected for processing."
+ fi
+ ;;
+ "-v" | "--verbose")
+ pVerbose=-v
+ ;;
+ "-X" | "--exit-on-conflict")
+ if [ -n "$pReplaceConflicts" ]; then
+ error $ERR_ARG "The 'exit on conflict' and 'replace conflicts' modes are mutually exclusive."
+ fi
+ pExitOnConflict=1
+ ;;
+ -? | --*)
+ error $ERR_ARG "Unknown parameter \"$arg\"."
+ ;;
+ -*)
+ # Split parmeters.
+ readParams "${arg%%${arg#-?}}" "-${arg#-?}"
+ ;;
+ *)
+ # Make sure the local index copy is up to date.
+ getIndex
+ # Add package to the list of packages to
+ # upgrade/install.
+ package="$(identifyPackage "$arg")" || exit $?
+ upgrade="$upgrade${upgrade:+$IFS}$package"
+ # Request the download.
+ downloadManagerMsgRequest "$package"
+ ;;
+ esac
+ }
+
+ #
+ # Only perform the following steps if this is the root call
+ # to this function (recursion depth = 0).
+ #
+ if [ $depth -eq 0 ]; then
+ #
+ # Deal with missing parameters.
+ #
+ if [ $origin -eq 1 ]; then
+ error $ERR_ARG "Incomplete parameters, missing origin."
+ fi
+ if [ $origin -eq 2 ]; then
+ error $ERR_ARG "Incomplete parameters, missing package to replace."
+ fi
+
+ #
+ # Deal with invalid levels of recursiveness.
+ #
+ if [ -n "$pMoreRecursive" -a -z "$pUpwardRecursive" ]; then
+ error $ERR_ARG "Thorough recursiveness can only be used in conjunction with upwards recursiveness."
+ fi
+
+ #
+ # Remove duplicates in the list of packages to upgrade.
+ #
+ upgrade="$(echo "$upgrade" | sort -u)"
+ # Reset global variables.
+ origin=
+ fi
+}
+
+#
+# Reads all the required +CONTENTS information from a package.
+# The information is stored in variables.
+#
+# @param 1
+# The name of the package file.
+# @param pkgname
+# The name of the package.
+# @param origin
+# The origin of the package.
+# @param depends
+# The dependencies of the package in the format "<origin>;<package>",
+# in reverse order.
+# @param conflicts
+# A list of regular expressions that can be used to identify conflicting
+# packages.
+#
+readContents() {
+ local contents line format
+ contents="$(tar -xOf "$1" '+CONTENTS')"
+ format=
+
+ pkgname=
+ origin=
+ depends=
+ conflicts=
+ for line in $contents; {
+ case "$line" in
+ @name\ *)
+ pkgname="${line#@name }"
+ ;;
+ @pkgdep\ *)
+ depends=";${line#@pkgdep }${depends:+$IFS}$depends"
+ ;;
+ @comment\ *)
+ line="${line#@comment }"
+ case "$line" in
+ DEPORIGIN:*)
+ depends="${line#*:}$depends"
+ ;;
+ PKG_FORMAT_REVISION:*)
+ format="${line#*:}"
+ ;;
+ ORIGIN:*)
+ origin="${line#*:}"
+ ;;
+ esac
+ ;;
+ @conflicts\ *)
+ conflicts="${conflicts:+$conflicts$IFS}${line#@conflicts }"
+ ;;
+ esac
+ }
+
+ if [ "$format" != "1.1" ]; then
+ error $ERR_PACKAGE_FORMAT "Unknown package format in <$1>, bailing out!"
+ fi
+
+ return 0
+}
+
+#
+# Starts a download manager that can be instructed through a queue.
+# A process that wants to know what's going on with the download manager
+# can simply read from the queue as well.
+#
+# The download manager keeps as many downloads running as there are
+# PACKAGESITE_MIRRORS. Should a download fail, it is retried as soon
+# as no untried downloads remain. Every download is only retried once.
+# A download is never attempted from the master server.
+#
+# @param queueMessages
+# The queue to create and read from.
+# @param packagerepos
+# The location of the remote package repository (derived from
+# PACKAGESITE). If this is identical with the local repository,
+# the download manager will not be started.
+# @param pNoActions
+# If set, the download manager will not be started.
+#
+downloadManager() {
+ # No actions mode, this includes no downloads.
+ test -n "$pNoActions" && return 0
+
+ # Packages are locally available, no downloads.
+ test "$PACKAGES" = "$packagerepos" && return 0
+
+ verbose "Start the download manager."
+
+ # Initialize the queue.
+ rm "$queueMessages" 2> /dev/null
+ touch "$queueMessages"
+
+ #
+ # The following block is forked away.
+ # Note that all variable assignments happen in a separate process
+ # and hence have no effect on the outside.
+ #
+ (
+ # Remove the queue when exiting and get rid of pending jobs.
+ trap "
+ kill \$(jobs -ls) > /dev/null 2>&1
+ rm '$queueMessages' 2> /dev/null
+ exit
+ " EXIT sigint sigterm
+
+ # The jobs yet to be done.
+ jobs=
+ # The available mirrors.
+ mirrors="$PACKAGESITE_MIRRORS"
+ # The jobs that should be retried.
+ retry=
+ # The jobs that have been retried.
+ retried=
+ # The last line read from the socket.
+ line=
+
+ # Keep on running as long as the father process is around.
+ # Note that this while loop has the message queue as stdin.
+ while kill -0 "$pid" 2> /dev/null; do
+ # Check for a message in the queue.
+ # There is nothing to be done, if there was no message,
+ # none the less it times out to allow the terminal
+ # to catch signals.
+ read -t 2 line
+ # Process messages.
+ case "$line" in
+ finished:*)
+ # A download has been finished.
+ # Add the mirror that was used to
+ # the list of available mirrors.
+ mirror="${line#finished:}"
+ mirror="${mirror%;*}"
+ mirrors="${mirrors:+$mirrors$IFS}$mirror"
+ ;;
+ retry:*)
+ # A download was not finished
+ # successfuly.
+ mirror="${line#retry:}"
+ job="${mirror##*;}"
+ mirror="${mirror%;*}"
+ if echo "$retried" | grep -qFx "$job"; then
+ # If this package has already
+ # had a retry, mark it as
+ # finished to hand it over
+ # to the package validation
+ # that can fetch from the
+ # master server.
+ downloadManagerMsgFinished "$mirror" "$job"
+ else
+ # The first retry request.
+ # Free the mirror and list
+ # the package for retry.
+ mirrors="${mirrors:+$mirrors$IFS}$mirror"
+ retry="${retry:+$retry$IFS}$job"
+ fi
+ ;;
+ request:*)
+ # Append requested downloads to the
+ # list of available jobs.
+ jobs="${jobs:+$jobs$IFS}${line#request:}"
+ ;;
+ exit)
+ # The download manager has been told
+ # to terminate.
+ break
+ ;;
+ esac
+ # Delete the line, so it cannot be read again in the
+ # next iteration, if reading from the queue has
+ # timed out.
+ line=
+
+ # If any mirrors are available and there are jobs
+ # in the queue, now is the time to dispatch them.
+ while [ -n "$jobs" -a -n "$mirrors" ]; do
+ mirror="${mirrors%%$IFS*}"
+ mirrors="${mirrors#$mirror}"
+ mirrors="${mirrors#$IFS}"
+ job="${jobs%%$IFS*}"
+ jobs="${jobs#$job}"
+ jobs="${jobs#$IFS}"
+ downloadManagerFetch "$mirror" "$job" &
+ done
+
+ # If we have run out of jobs, give the retry stuff.
+ # a try.
+ while [ -n "$retry" -a -n "$mirrors" ]; do
+ mirror="${mirrors%%$IFS*}"
+ mirrors="${mirrors#$mirror}"
+ mirrors="${mirrors#$IFS}"
+ job="${retry%%$IFS*}"
+ retry="${retry#$job}"
+ retry="${retry#$IFS}"
+ # Remember that this job has been retried.
+ retried="${retried:+$retried$IFS}$job"
+ downloadManagerFetch "$mirror" "$job" &
+ done
+ done < "$queueMessages"
+ ) &
+}
+
+#
+# This is forked off by the download manager to download a package from
+# a mirror.
+# If the package is already present a download is not attempted.
+#
+# @param 1
+# The mirror to download from.
+# @param 2
+# The name of the package to download.
+#
+downloadManagerFetch() {
+ # Get rid of pending jobs.
+ trap "
+ kill \$(jobs -ls) > /dev/null 2>&1
+ exit
+ " EXIT sigint sigterm
+
+ # Only do something if the package is not present.
+ if ! [ -e "$PACKAGES/All/$2.tbz" ]; then
+ # Create the download location.
+ mkdir -p "$PACKAGES/All" 2> /dev/null
+
+ # Attempt download from mirror.
+ # This is forked off, to allow the shell to catch signals.
+ fetch -qmo "$PACKAGES/All/$2.tbz" "${1%/*?}/All/$2.tbz" > /dev/null 2>&1 &
+ if ! wait $!; then
+ # Release the mirror and mark the package for a retry.
+ downloadManagerMsgRetry "$1" "$2"
+ return 0
+ fi
+ fi
+
+ # Release the mirror and mark package finished.
+ downloadManagerMsgFinished "$1" "$2"
+}
+
+#
+# Tells the download manager, that a download was unsuccessful.
+#
+# @param 1
+# The mirror that was used.
+# @param 2
+# The name of the package that was not downloaded.
+# @param queueMessages
+# The message queue to the download manager.
+#
+downloadManagerMsgRetry() {
+ # Do not send anything without a queue.
+ test ! -e "$queueMessages" && return 0
+
+ lockf -k "$queueMessages" sh -c "echo 'retry:$1;$2' >> '$queueMessages'"
+}
+
+#
+# Tells the download manager, that a download has been finished.
+#
+# @param 1
+# The mirror that was used.
+# @param 2
+# The name of the downloaded package.
+# @param queueMessages
+# The message queue to the download manager.
+#
+downloadManagerMsgFinished() {
+ # Do not send anything without a queue.
+ test ! -e "$queueMessages" && return 0
+
+ lockf -k "$queueMessages" sh -c "echo 'finished:$1;$2' >> '$queueMessages'"
+}
+
+#
+# Requests the download of packages from the download manager.
+#
+# @param 1
+# A list of packages for download.
+# @param queueMessages
+# The message queue to the download manager.
+#
+downloadManagerMsgRequest() {
+ # Do not send anything without a queue.
+ test ! -e "$queueMessages" && return 0
+
+ local request
+ for request in $1; {
+ lockf -k "$queueMessages" sh -c "echo 'request:${request#*;}' >> '$queueMessages'"
+ }
+}
+
+#
+# Instructs the download manager to terminate.
+#
+# @param queueMessages
+# The message queue to the download manager.
+#
+downloadManagerMsgExit() {
+ # Do not send anything without a queue.
+ test ! -e "$queueMessages" && return 0
+
+ lockf -k "$queueMessages" sh -c "echo 'exit' >> '$queueMessages'"
+}
+
+#
+# Validates a single package. Validation means it checks whether a package
+# is a complete tar archive. Damaged or missing packages will be (re)downloaded
+# from the master server (the one named by PACKAGESITE).
+# If the package is a valid tar archive the +CONTENTS file will be checked,
+# as well.
+#
+# @param 1
+# The name of the package to validate.
+# @param packagerepos
+# The location of the remote package collection. This is derived from
+# PACKAGESITE.
+# @param pending
+# The list of pending packages.
+# @return
+# Return 0 on success.
+#
+validatePackage() {
+ local package
+ package="$1.tbz"
+
+ # Check whether the package is intact and present.
+ if ! tar -tf "$PACKAGES/All/$package" > /dev/null 2>&1; then
+ # If the package repository and the local package collection
+ # are identical, there's no chance to get the package if it's
+ # not already there.
+ if [ "$PACKAGES" = "$packagerepos" ]; then
+ error $ERR_FETCH "The package <$package> is not present."
+ fi
+
+ # Clean up whatever crap is there.
+ rm "$PACKAGES/All/$package" 2> /dev/null
+
+ # Try to get the package from the master server.
+ fetch -mo "$PACKAGES/All/$package" "$packagerepos/All/$package"
+
+ # Check whether the package is present.
+ if ! [ -e "$PACKAGES/All/$package" ]; then
+ error $ERR_FETCH "The package <$package> could not be fetched."
+ fi
+
+ # Check whether the package is a valid tar archive.
+ if ! tar -tf "$PACKAGES/All/$package" > /dev/null 2>&1; then
+ error $ERR_FETCH "The package <$package> could not be read."
+ fi
+ fi
+
+ # Check whether we can read the package +CONTENTS format.
+ readContents "$PACKAGES/All/$package"
+
+ # Remove this package from the list of pending packages.
+ pending="$(echo "$pending" | grep -vFx "$1")"
+
+ # The package is present and intact.
+ return 0
+}
+
+#
+# Let's get it on! The declarative part is finally over.
+#
+
+# Ignore some signals that should not occur.
+trap 'warn "Discard signal SIGHUP."' sighup
+trap 'warn "Discard signal SIGUSR1."' sigusr1
+trap 'warn "Discard signal SIGUSR2."' sigusr2
+
+#
+# Parse command line parameters.
+#
+readParams "$@"
+
+# Make sure the index is available for the following operations.
+getIndex
+
+#
+# Populate the list of packages out of sync with the index.
+#
+pkgAll
+
+#
+# Perform dependency checking.
+#
+pkgDependencies
+
+#
+# Sort packages by their dependencies.
+#
+pkgSort
+
+#
+# Display tasks.
+#
+pkgList
+
+#
+# Download packages.
+#
+pkgDownload
+
+#
+# Upgrade packages.
+#
+pkgUpgrade
+
+exit 0
Index: head/ports-mgmt/bsdadminscripts/files/uma.in
===================================================================
--- head/ports-mgmt/bsdadminscripts/files/uma.in
+++ head/ports-mgmt/bsdadminscripts/files/uma.in
@@ -0,0 +1,436 @@
+#!/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
+
Index: head/ports-mgmt/bsdadminscripts/pkg-descr
===================================================================
--- head/ports-mgmt/bsdadminscripts/pkg-descr
+++ head/ports-mgmt/bsdadminscripts/pkg-descr
@@ -0,0 +1,7 @@
+This is a collection of administration scripts. At the moment it
+consists of a script to control rc.d scripts at runtime, a
+script that runs common make targets on batches of ports, scripts to set
+variables for make jobs (like portconf, but with more possibilities).
+And scripts to check for broken packages and missing libraries.
+
+WWW: https://sourceforge.net/projects/bsdadminscripts/
Index: head/ports-mgmt/bsdadminscripts/pkg-plist
===================================================================
--- head/ports-mgmt/bsdadminscripts/pkg-plist
+++ head/ports-mgmt/bsdadminscripts/pkg-plist
@@ -0,0 +1,35 @@
+sbin/distviper
+sbin/pkg_libchk
+sbin/pkg_upgrade
+sbin/pkg_validate
+sbin/portconfig
+sbin/rcstart
+sbin/uma
+sbin/rcstatus
+sbin/rcstop
+sbin/rcrestart
+sbin/rconestart
+sbin/rconestatus
+sbin/rconestop
+sbin/rconerestart
+sbin/portbuild
+sbin/portclean
+sbin/portfetch
+sbin/portpackage
+sbin/portconfig-recursive
+sbin/portfetch-recursive
+man/man1/bsdadminscripts.1.gz
+man/man1/buildflags.awk.1.gz
+man/man1/buildflags.conf.1.gz
+man/man1/buildflags.mk.1.gz
+man/man1/distviper.1.gz
+man/man1/pkg_libchk.1.gz
+man/man1/pkg_upgrade.1.gz
+man/man1/pkg_validate.1.gz
+man/man1/portconfig.1.gz
+man/man1/rcstart.1.gz
+man/man1/uma.1.gz
+%%ETCDIR%%/buildflags.conf.sample
+%%ETCDIR%%/uma.conf.sample
+%%DATADIR%%/buildflags.awk
+%%DATADIR%%/buildflags.mk
Index: head/ports-mgmt/bsdadminscripts2/Makefile
===================================================================
--- head/ports-mgmt/bsdadminscripts2/Makefile
+++ head/ports-mgmt/bsdadminscripts2/Makefile
@@ -0,0 +1,27 @@
+# $FreeBSD$
+
+PORTNAME= bsdadminscripts2
+DISTVERSION= 0.2.0
+CATEGORIES= ports-mgmt
+
+MAINTAINER= kami@FreeBSD.org
+COMMENT= Collection of administration scripts
+
+LICENSE= ISCL
+LICENSE_FILE= ${WRKSRC}/LICENSE.md
+
+USE_GITHUB= yes
+GH_ACCOUNT= lonkamikaze
+GH_PROJECT= bsda2
+
+NO_BUILD= yes
+NO_ARCH= yes
+
+CONFLICTS_INSTALL= bsdadminscripts
+
+do-install:
+ @cd ${WRKSRC} && ${SH} install.sh \
+ -destdir="${STAGEDIR}" -prefix="${PREFIX}" \
+ -datadir="${DATADIR}" -docsdir="${DOCSDIR}"
+
+.include <bsd.port.mk>
Index: head/ports-mgmt/bsdadminscripts2/distinfo
===================================================================
--- head/ports-mgmt/bsdadminscripts2/distinfo
+++ head/ports-mgmt/bsdadminscripts2/distinfo
@@ -0,0 +1,3 @@
+TIMESTAMP = 1495004940
+SHA256 (lonkamikaze-bsda2-0.2.0_GH0.tar.gz) = 87bb936982bc07b248a9610030660ca8503eeca9de352e64dac56425717d655c
+SIZE (lonkamikaze-bsda2-0.2.0_GH0.tar.gz) = 71534
Index: head/ports-mgmt/bsdadminscripts2/pkg-descr
===================================================================
--- head/ports-mgmt/bsdadminscripts2/pkg-descr
+++ head/ports-mgmt/bsdadminscripts2/pkg-descr
@@ -0,0 +1,10 @@
+This is a collection of scripts around the use of ports and packages.
+
+It allows you to:
+- check library dependencies without producing false positives (pkg_libchk)
+- lets you manage the autoremove flag for leaf packages (pkg_trim)
+- remove obsolete or damaged distfiles (distviper)
+- manage build flags (buildflags.conf)
+- auto-create pkg-plist files taking port options into account (makeplist)
+
+WWW: https://github.com/lonkamikaze/bsda2
Index: head/ports-mgmt/bsdadminscripts2/pkg-plist
===================================================================
--- head/ports-mgmt/bsdadminscripts2/pkg-plist
+++ head/ports-mgmt/bsdadminscripts2/pkg-plist
@@ -0,0 +1,34 @@
+@sample etc/buildflags.conf.sample
+man/man1/buildflags.awk.1.gz
+man/man1/buildflags.conf.1.gz
+man/man1/buildflags.mk.1.gz
+man/man1/pkg_libchk.1.gz
+man/man8/distviper.8.gz
+man/man8/makeplist.8.gz
+man/man8/pkg_trim.8.gz
+sbin/distviper
+sbin/makeplist
+sbin/pkg_libchk
+sbin/pkg_trim
+%%DATADIR%%/bsda_bsdmake.sh
+%%DATADIR%%/bsda_container.sh
+%%DATADIR%%/bsda_dialog.sh
+%%DATADIR%%/bsda_fifo.sh
+%%DATADIR%%/bsda_obj.sh
+%%DATADIR%%/bsda_opts.sh
+%%DATADIR%%/bsda_tty.sh
+%%DATADIR%%/bsda_util.sh
+%%DATADIR%%/buildflags.awk
+%%DATADIR%%/buildflags.mk
+%%DATADIR%%/distviper.sh
+%%DATADIR%%/interrupt.mk
+%%DATADIR%%/makeplist.sh
+%%DATADIR%%/options.mk
+%%DATADIR%%/pkg_info.sh
+%%DATADIR%%/pkg_libchk.sh
+%%DATADIR%%/pkg_options.sh
+%%DATADIR%%/pkg_query.sh
+%%DATADIR%%/pkg_trim.sh
+%%PORTDOCS%%%%DOCSDIR%%/bsda_obj.md
+%%PORTDOCS%%%%DOCSDIR%%/LICENSE.md
+%%PORTDOCS%%%%DOCSDIR%%/README.md
Index: head/sysutils/Makefile
===================================================================
--- head/sysutils/Makefile
+++ head/sysutils/Makefile
@@ -104,7 +104,6 @@
SUBDIR += boxbackup-devel
SUBDIR += brasero
SUBDIR += bsd-splash-changer
- SUBDIR += bsdadminscripts
SUBDIR += bsdconfig
SUBDIR += bsdcrashtar
SUBDIR += bsdhwmon
Index: head/sysutils/bsdadminscripts/Makefile
===================================================================
--- head/sysutils/bsdadminscripts/Makefile
+++ head/sysutils/bsdadminscripts/Makefile
@@ -1,58 +0,0 @@
-# Created by: Dominic Fandrey <lon_kamikaze@gmx.de>
-# $FreeBSD$
-
-PORTNAME= bsdadminscripts
-PORTVERSION= 6.1.1
-PORTREVISION= 8
-CATEGORIES= sysutils ports-mgmt
-MASTER_SITES= SF/${PORTNAME}/${PORTNAME}
-
-MAINTAINER= ports@FreeBSD.org
-COMMENT= Collection of administration scripts
-
-LICENSE= BSD2CLAUSE
-
-NO_BUILD= yes
-NO_ARCH= yes
-
-TMP?= /tmp
-VAR?= /var
-
-PORTDOCS= ABOUT CHANGES INSTALL NOTES THANKS
-
-OPTIONS_DEFINE= DOCS
-
-SUB_FILES= distviper pkg_libchk pkg_upgrade uma
-SUB_LIST= TMP=${TMP} PREFIX=${PREFIX} VAR=${VAR} PORTS=${PORTSDIR}
-
-DOCS_VARS_OFF= EVALDOCS=-nodoc
-
-do-install:
- cd ${WRKSRC}/src && ${SH} install.sh \
- -prefix=${STAGEDIR}${PREFIX} \
- -ports=${STAGEDIR}${PORTSDIR} \
- -distdir=${STAGEDIR}${DISTDIR} \
- -datadir=${STAGEDIR}${DATADIR} \
- ${EVALDOCS}
-.for n in distviper pkg_libchk pkg_upgrade uma
- ${MV} ${WRKDIR}/${n} ${WRKSRC}/src
- ${INSTALL_SCRIPT} ${WRKSRC}/src/${n} ${STAGEDIR}${PREFIX}/sbin
-.endfor
- ${INSTALL_DATA} ${WRKSRC}/src/buildflags.mk ${STAGEDIR}${DATADIR}
- ${INSTALL_DATA} ${WRKSRC}/src/buildflags.conf.sample \
- ${STAGEDIR}${PREFIX}/etc
- ${INSTALL_DATA} ${WRKSRC}/src/uma.conf.sample ${STAGEDIR}${PREFIX}/etc
-
-.for f in bsdadminscripts buildflags.awk buildflags.conf buildflags.mk \
- distviper pkg_libchk pkg_upgrade pkg_validate portconfig rcstart uma
- ${INSTALL_MAN} ${WRKSRC}/src/${f}.1 ${STAGEDIR}${MAN1PREFIX}/man/man1
-.endfor
- ${MKDIR} ${STAGEDIR}${ETCDIR}
- ${MV} ${STAGEDIR}${PREFIX}/etc/*.sample ${STAGEDIR}${ETCDIR}
- ${RM} -r ${STAGEDIR}${PREFIX}/etc/*.sample
-
-post-install-DOCS-on:
- ${MKDIR} ${STAGEDIR}${DOCSDIR}
- cd ${WRKSRC} && ${INSTALL_DATA} ${PORTDOCS} ${STAGEDIR}${DOCSDIR}
-
-.include <bsd.port.mk>
Index: head/sysutils/bsdadminscripts/distinfo
===================================================================
--- head/sysutils/bsdadminscripts/distinfo
+++ head/sysutils/bsdadminscripts/distinfo
@@ -1,2 +0,0 @@
-SHA256 (bsdadminscripts-6.1.1.tar.gz) = 68b47c51801a8ce1e7b69ec654c7521b1b1fcf2d3fe9184f4d2e4a1b6f4656bb
-SIZE (bsdadminscripts-6.1.1.tar.gz) = 73925
Index: head/sysutils/bsdadminscripts/files/distviper.in
===================================================================
--- head/sysutils/bsdadminscripts/files/distviper.in
+++ head/sysutils/bsdadminscripts/files/distviper.in
@@ -1,227 +0,0 @@
-#!/bin/sh
-#
-# 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 name=distviper
-readonly version=1.1
-
-verbose=
-demo=
-quiet=
-interactive=
-
-# Determine portsdir
-portsdir="$(make -V PORTSDIR -f /usr/share/mk/bsd.port.mk)"
-if [ ! -d "$portsdir" ]; then
- echo "The PORTSDIR '$portsdir' is missing."
- exit 1
-fi
-
-# Determine distdir
-distdir="$(make -V DISTDIR -f /usr/share/mk/bsd.port.mk)"
-if [ ! -d "$distdir" ]; then
- echo "The DISTDIR '$distdir' is missing."
- exit 2
-fi
-
-# Extract file from distinfo.
-extractFileCmd="sed -E -e 's/^[^(]*\(//1' -e 's/\).*$//1'"
-
-# Display help.
-printHelp() {
- echo "$name v$version
-usage: $name [-d] [-h] [-i] [-q] [-v] [fast|thorough]"
-}
-
-#
-# Handle parameters.
-#
-# @param $1
-# The parameter to handle.
-# @param $verbose
-# Is set to create verbose output.
-# @param $demo
-# Is set to only print the output that would occur.
-# @param $quiet
-# Is set to act without creating any output.
-# @return
-# Returns 0 if the processed parameter was a valid parameter,
-# returns 1 if not.
-#
-readParams() {
- case "$1" in
- "-d" | "--demo")
- demo=1
- return 0
- ;;
- "-h" | "--help")
- printHelp
- exit 0
- ;;
- "-i" | "--interactive")
- interactive=-i
- return 0
- ;;
- "-q" | "--quiet")
- quiet=1
- return 0
- ;;
- "-v" | "--verbose")
- verbose=1
- return 0
- ;;
- -? | --*)
- return 1
- ;;
- -*)
- # Split parameters.
- # first parameter
- readParams "${1%${1#-?}}" || return $?
- # remaining parameters
- readParams "-${1#-?}"
- return $?
- ;;
- *)
- return 1
- ;;
- esac
-}
-
-#
-# This algorithm outputs the distfiles of installed ports. If a port downloads
-# a distfile through depending on the fetch target of another port, it
-# is missed, in case that other port is not installed as well.
-#
-# @param $portsdir
-# The direcotry holding the ports tree.
-#
-getDistFiles_fast() {
- for port in $(pkg_info -qoa); {
- if [ -e "$portsdir/$port/distinfo" ]; then
- eval "$extractFileCmd '$portsdir/$port/distinfo'" | uniq
- fi
- }
-}
-
-#
-# This algorithm outputs the distfiles of all ports.
-#
-# @param $portsdir
-# The direcotry holding the ports tree.
-#
-getDistFiles_thorough() {
- find -H "$portsdir" -type f -name distinfo | \
- eval "xargs $extractFileCmd" | uniq
-}
-
-# The current parameter processing stage.
-stage=params
-
-# The selected algorithm for finding distfiles to keep.
-algorithm=thorough
-
-# Parse the command line parameters.
-for command; {
- # Read parameters until an unknown one is encountered.
- # In that case switch into command stage.
- if [ "$stage" = "params" ]; then
- if ! readParams "$command"; then
- stage=command
- fi
- fi
-
- # All parameters have been read, now either nothing or a mode
- # command should occur.
- if [ "$stage" = "command" ]; then
- stage=end
- case "$command" in
- thorough | fast)
- algorithm="$command"
- ;;
- -*)
- echo "$name: Unknown parameter '$command'" \
- "encountered, exiting." 1>&2
- return 1
- ;;
- *)
- echo "$name: Unknown command '$command'" \
- "encountered, exiting." 1>&2
- return 2
- ;;
- esac
- # Skip everything following and continue with the next
- # argument.
- continue
- fi
-
- # Still being in the loop at this stage means unexpected parameters
- # have been encountered.
- if [ "$stage" = "end" ]; then
- echo "$name: The command '$command' is not allowed here, only" \
- "one command at a time is permitted." 1>&2
- return 3
- fi
-}
-
-# Check for inprobable options.
-if [ -n "$interactive" -a -n "$demo" ]; then
- echo "$name: Interactive mode is ignored in demo mode." 1>&2
-fi
-
-test -n "$verbose" && echo "Create a list of up to date distfiles to keep" \
- "using a $algorithm algorithm:"
-
-# Create the list of files to keep, using the selected algorithm.
-keepFiles="$(eval "getDistFiles_$algorithm" | sort -u)"
-if [ -n "$verbose" ]; then
- echo "$(($(echo "$keepFiles" | wc -l))) files recorded for keeping."
- echo "Search and delete outdated distfiles:"
-fi
-
-# Files before deletion.
-filesCount="$(($(find -H "$distdir" -type f|wc -l)))"
-filesDelete=0
-
-# Seek and destroy files not in the $keepFiles list.
-for file in $(find -H "$distdir" -type f); {
- file="${file#$distdir/}"
-
- if (echo "$keepFiles" | grep -qx "$file"); then
- test -n "$verbose" && echo "keep $file"
- else
- test -z "$quiet" && echo "delete $file"
- test -z "$demo" && rm $interactive "$distdir/$file"
- filesDelete=$(($filesDelete + 1))
- fi
-}
-
-# The number of deleted files
-filesDeleted="$(($filesCount - $(find -H "$distdir" -type f|wc -l)))"
-
-test -z "$demo" && find -H -d "$distdir" -type d -exec rmdir \{} \; 2> /dev/null
-
-if [ -n "$verbose" ]; then
- echo "$filesDelete files were suggested for deletion."
- echo "$filesDeleted files of $filesCount have been removed."
-fi
-
-return 0
Index: head/sysutils/bsdadminscripts/files/pkg_libchk.in
===================================================================
--- head/sysutils/bsdadminscripts/files/pkg_libchk.in
+++ head/sysutils/bsdadminscripts/files/pkg_libchk.in
@@ -1,484 +0,0 @@
-#!/bin/sh -f
-#
-# Copyright (c) 2007-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 name=pkg_libchk
-readonly version=1.6.1
-readonly osname=`uname -s`
-readonly pkgng=`make -f /usr/share/mk/bsd.port.mk -V WITH_PKGNG`
-
-# Use a line break as delimiter.
-IFS='
-'
-
-# Filename prefix for shared data
-sharedprefix="%%TMP%%/$$"
-shared="locks"
-
-#
-# This function remembers a lock to allow later deletion with the
-# lockUnregisterAll() function.
-#
-# @param $1
-# The name of the lock.
-lockRegister() {
- local lock
- lock="$sharedprefix-$shared"
- lockf -k "$lock" sh -c "
- if ! grep -qE '^$1\$' '$lock'; then
- echo '$1' >> '$lock'
- fi
- "
-}
-
-#
-# Unregisters all locks.
-#
-lockUnregisterAll() {
- wait
- for register in $(cat "$sharedprefix-$shared"); {
- lockf "$sharedprefix-$register" wait
- }
- lockf "$sharedprefix-$shared" wait
-}
-
-#
-# This function creates a semaphore.
-#
-# @param $1
-# The name of the semaphore.
-# @param $2
-# The size of the semaphore.
-#
-semaphoreCreate() {
- local lock
- lockRegister "semaphore-$1"
- lock="$sharedprefix-semaphore-$1"
- lockf -k "$lock" echo "$2" > "$lock"
- eval "semaphore_$1_size=$2"
-}
-
-#
-# This function waits until the semaphore is free und registers its use.
-# Everything that uses this also has to call the semaphoreFree() function.
-#
-# @param $1
-# The name of the semaphore.
-#
-semaphoreUse() {
- local lock semaphores
- lock="$sharedprefix-semaphore-$1"
- while ! lockf -k "$lock" sh -c "
- state=\$(cat '$lock')
- if [ \"\$state\" -gt 0 ]; then
- echo \"\$((\$state - 1))\" > '$lock'
- exit 0
- fi
- exit 1
- "; do
- sleep 0.1
- done
-}
-
-#
-# This function frees a semaphore.
-#
-# @param $1
-# The name of the semaphore.
-#
-semaphoreFree() {
- local lock
- lock="$sharedprefix-semaphore-$1"
- lockf -k "$lock" sh -c "
- state=\"\$((\"\$(cat '$lock')\" + 1))\"
- echo \"\$state\" > '$lock'
- "
-}
-
-#
-# This function sets a new status and prints it.
-#
-# @param $1
-# The status message.
-# @param $clean
-# If set status handling is disabled.
-#
-statusSet() {
- # In clean mode status handling is disabled.
- test -z "$clean" || return 0
- local lock
- lock="$sharedprefix-status"
- lockf -k "$lock" sh -c "
- status=\"\$(cat '$lock')\"
- echo '$1' > '$lock'
- printf \"\\r%-\${#status}s\\r\" '$1' > /dev/tty
- "
-}
-
-#
-# This function prints a message and the current status behind it.
-#
-# @param $1
-# The message to print.
-# @param $clean
-# If set the status will not be printed.
-#
-statusPrint() {
- if [ -z "$clean" ]; then
- local lock
- lock="$sharedprefix-status"
- lockf -k "$lock" sh -c "
- status=\"\$(cat '$lock')\"
- printf \"%-\${#status}s\\r\" '' > /dev/tty
- echo '$1'
- printf '%s\\r' \"\$status\" > /dev/tty
- "
- else
- echo "$1"
- fi
-}
-
-#
-# Waits for a semaphore to be completely free and counts down the remaining
-# number of locks.
-#
-# @param $1
-# The semaphore to watch.
-# @param $2
-# The status message to print, insert %d in the place where the number
-# of remaining locks belong.
-#
-semaphoreCountDown() {
- local free size
- while read -t1 free < "$sharedprefix-semaphore-$1"; do
- size=$(eval "echo \$semaphore_$1_size")
- statusSet "$(printf "$2" $(( $size - $free )))"
- test "$free" -eq "$size" && break
- sleep 0.1
- done
- wait
-}
-
-# Clean up upon exit.
-trap '
- semaphoreCountDown jobs "Terminated by signal, waiting for %d jobs to die."
- echo > /dev/tty
- lockUnregisterAll
- exit 255
-' int term
-
-#
-# This function checks whether a given binary or library directly depends
-# on a missing library.
-# It goes a long way to prevent all kinds of false positives.
-# It always returns 2 (false) for Linux and other non-native libraries
-# and binaries.
-# It also checks whether the missing dependency is really a direct dependency
-# (indirect dependencies have to be fixed somewhere else).
-#
-# @param $1
-# The library or binary to check.
-# @return
-# Returns 0 (true) if a library is missing.
-# Returns 1 if everything is all right.
-# Returns 2 if the check cannot be performed (not a native library).
-#
-dependencyMissing() {
- local missing file direct libfound
-
- # We cannot handle non-native binaries,
- # so assume everything is in order.
- if ! readelf -e "$1" 2>&1 | \
- grep -E "^[[:space:]]*OS/ABI:[[:space:]]*UNIX - $osname\$" \
- > /dev/null
- then
- return 2
- # Nothing is missing.
- elif ! missing="$(ldd "$1" 2>&1 | grep -E "$match_expr")"; then
- return 1
- fi
-
- # The return status. The value 1 assumes that this is a false positive.
- status=1
-
- # Only report misses for direct dependencies.
- direct="$(
- readelf -d "$1" 2> /dev/null | \
- grep 'Shared library:' | \
- sed -E -e 's|^[^[]*\[||1' -e 's|\]$||1'
- )"
-
- # Compare every missing depency with the list of direct dependencies
- # and report that the dependency is missing if the missing file is
- # a direct dependency.
- for file in $missing; {
- # Strip the missing file of additional information.
- file="$(echo "$file" | sed -E \
- -e 's| => .*$||1' \
- -e 's|^[[:space:]]*||1' \
- -e 's|^.*dependency ||1' \
- -e 's| not found$||1'
- )"
-
- # If in mean mode we do not check for false positives.
- if [ -n "$mean" ]; then
- test -n "$raw" && return 0
- statusPrint "$package_name: $1 misses $file"
- continue
- fi
-
- # Handle the case where a library is not found, but exists
- # somewhere in the package. This is for packages that do not
- # rely on the OS to find libraries.
- libfound=
- for library in $(echo "$libraries" | grep -E "/$file\$"); {
- # The library exists after all.
- test -e "$library" && libfound=1 && break
- }
- if test "$libfound"; then
- test -n "$verbose" && statusPrint "$package_name: \
-located: $1 misses $file found at $library."
- continue
- fi
-
- # Compare the file with the list of direct dependencies.
- # If it's not in than it's only an indirect dependency and
- # cannot be fixed by rebuilding this port.
- if echo "$direct" | grep -E "^$file\$" > /dev/null; then
- test -n "$raw" && return 0
- statusPrint "$package_name: $1 misses $file"
- status=0
- elif [ -n "$verbose" ]; then
- statusPrint "$package_name: inderect: $1 \
-misses $file is an inderect dependency."
- fi
- }
-
- return $status
-}
-
-#
-# Checks the parameters for options.
-#
-# @param $packages
-# The parameters to pkg_info -E that will result in the
-# names of the packages to work on.
-# @param $recursive
-# Contains the appropriate parameter to get the
-# dependencies of the given packages from pkg_info.
-# @param $Recursive
-# Contains the appropriate parameter to get the
-# packages depending on the given packages from pkg_info.
-# @param $raw
-# Is set to trigger raw printing.
-# @param $clean
-# Is set to trigger printing without status messages.
-# @param $verbose
-# Is set to be verbose about false positives.
-# @param $mean
-# Is set to switch into mean mode. That means no
-# checking of false positives.
-# @param $compat
-# Delete to avoid detecting compat libraries as misses.
-# @param $origin
-# Is set to turn the print origin mode on.
-# @semaphore jobs
-# Is set to limit the amount of parallel jobs.
-#
-readParams() {
- local option
-
- for option {
- case "$option" in
- "-a" | "--all")
- packages="-a"
- ;;
- "-c" | "--clean")
- clean=1
- ;;
- "-h" | "--help")
- printHelp
- ;;
- -j* | --jobs*)
- local jobs
- jobs="${option#-j}"
- jobs="${jobs#--jobs}"
- if [ "$jobs" -ne "$jobs" ] 2> /dev/null; then
- echo "The -j option must be followed" \
- "by a number."
- exit 3
- elif [ "$jobs" -lt 1 ]; then
- echo "The -j option must specify at" \
- "least 1 job."
- exit 3
- else
- semaphoreCreate jobs "$jobs"
- fi
- ;;
- "-m" | "--mean")
- mean=1
- ;;
- "-n" | "--no-compat")
- compat=
- ;;
- "-o" | "--origin")
- origin=1
- ;;
- "-q" | "--raw")
- raw=1
- if [ -n "$verbose" ]; then
- echo "The parameters -v and -q may" \
- "not be used at the same time."
- exit 2
- fi
- ;;
- "-r" | "--recursive")
- recursive="-r"
- ;;
- "-R" | "--upward-recursive")
- Recursive="-R"
- ;;
- "-v" | "--verbose")
- verbose=1
- if [ -n "$raw" ]; then
- echo "The parameters -q and -v may" \
- "not be used at the same time."
- exit 2
- fi
- ;;
- -? | --*)
- echo "Unknown parameter \"$option\"."
- exit 1
- ;;
- -*)
- readParams "${option%${option#-?}}"
- readParams "-${option#-?}"
- ;;
- *)
- packages="$packages${packages:+$IFS}$option"
- ;;
- esac
- }
-}
-
-#
-# Display a short help message.
-#
-printHelp() {
- echo "$name v$version
-usage: $name [-a] [-c] [-h] [-jN] [-m] [-n] [-o] [-q] [-r] [-R] [-v] [packages]"
- exit 0
-}
-
-# Create the expression to match to find files linking against compat libraries.
-# This can be emptied by readParams to deactivate that feature.
-prefix="$(make -f /usr/share/mk/bsd.port.mk -VPREFIX 2> /dev/null || \
- echo '%%PREFIX%%')"
-compat="=> $prefix/lib/compat|"
-
-# Create the semaphore with CPU cores * 2 jobs.
-semaphoreCreate jobs "$(($(sysctl -n hw.ncpu 2> /dev/null || echo 1) * 2))"
-# Register the status lock.
-lockRegister status
-
-# Read the parameters.
-readParams "$@"
-
-statusSet 'Preparing ...'
-
-# Get the packages to work on.
-test -z "$packages" && packages="-a"
-if [ -n "$pkgng" ]; then
- packages="$(pkg info -q $packages)"
- test -z "$recursive" -a -z "$Recursive" || packages="$packages
- $(pkg info -q $recursive $Recursive "$packages" 2> /dev/null | \
- sed -E 's|^@pkgdep[[:space:]]*||1')"
-else
- packages="$(pkg_info -E $packages)"
- test -z "$recursive" -a -z "$Recursive" || packages="$packages
- $(pkg_info -q $recursive $Recursive "$packages" 2> /dev/null | \
- sed -E 's|^@pkgdep[[:space:]]*||1')"
-fi
-
-# Create the regexp to match ldd output
-match_expr="$compat=> not found|dependency .+ not found"
-
-# The packages to check.
-package_amount="$(echo "$packages" | wc -l | sed 's|[[:space:]]||g')"
-package_num=0
-
-# Check each selected package.
-for package in $packages; {
- package_num="$(($package_num + 1))"
- if [ -n "$pkgng" ]; then
- test $origin \
- && package_name="$(pkg info -qo "$package")" \
- || package_name="$package"
- else
- test $origin \
- && package_name="$(pkg_info -qo "$package")" \
- || package_name="$package"
- fi
-
- # Print what we're doing.
- statusSet "Starting job $package_num of $package_amount: $package_name"
-
- semaphoreUse jobs
- (
- # Remember freeing the semaphore.
- trap 'semaphoreFree jobs' EXIT
-
- files=""
- if [ -n "$pkgng" ]; then
- files="$(pkg info -lq "$package")"
- else
- files="$(pkg_info -qL "$package")"
- fi
- # Get the programs libraries in case it doesn't use the
- # operating system to find its libraries.
- libraries="$(echo "$files" | grep -E '\.so[\.0-9]*$')"
-
- outdated=0
- broken=
-
- # Check each file of each package.
- for file in $files; {
- if [ ! -L "$file" -a \( \
- -x "$file" -o \
- -n "$(echo "$file" | grep -E '\.so[\.0-9]*$')" \
- \) ]; then
- if dependencyMissing "$file"; then
- if [ -n "$raw" ]; then
- statusPrint "$package_name"
- break 1
- fi
- fi
- fi
- }
- ) &
-}
-
-semaphoreCountDown jobs "Waiting for %d remaining jobs to finish."
-statusSet
-lockUnregisterAll
-
-exit 0
Index: head/sysutils/bsdadminscripts/files/pkg_upgrade.in
===================================================================
--- head/sysutils/bsdadminscripts/files/pkg_upgrade.in
+++ head/sysutils/bsdadminscripts/files/pkg_upgrade.in
@@ -1,2239 +0,0 @@
-#!/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
-readonly name=pkg_upgrade
-
-# Error table.
-readonly ERR_LOCK=1
-readonly ERR_ARG=2
-readonly ERR_INDEX=3
-readonly ERR_FETCH=4
-readonly ERR_SORT=5
-readonly ERR_BACKUP_MISS=6
-readonly ERR_BACKUP_UNKNOWN=7
-readonly ERR_INSTALL=8
-readonly ERR_USER=9
-readonly ERR_TERM=10
-readonly ERR_PACKAGE_FORMAT=11
-readonly ERR_CONFLICT=12
-
-# Constant assignments.
-readonly logfile="%%VAR%%/log/$name.log"
-readonly pid=$$
-
-# Get some environment variables from uma. This includes PACKAGESITE,
-# TMPDIR and PKG_INDEX.
-eval "$(uma env $pid)"
-
-# The remote package repository, derived from PACKAGESITE.
-# If this matches the PACKAGES environment variable all downloading operations
-# will be omitted.
-readonly packagerepos="${PACKAGESITE%/*?}"
-
-# Environment variables.
-: ${PACKAGES="$(make -V PACKAGES -f /usr/share/mk/bsd.port.mk 2> /dev/null)"}
-PACKAGES="${PACKAGES:-%%PORTS%%/packages}"
-: ${PKG_DBDIR=%%VAR%%/db/pkg}
-: ${TMPDIR=%%TMP%%}
-: ${PKG_TMPDIR=$TMPDIR}
-
-# This is where backup packages will be stored.
-readonly packagebackup="$PACKAGES/$name-backup"
-# This is where the download manager will listen for messages.
-readonly queueMessages="$TMPDIR/pkg_upgrade.messages.queue"
-
-# Export environment variables to ensure that every tool uses the same ones.
-export ARCH PACKAGEROOT PACKAGESITE FTP_TIMEOUT PKG_INDEX
-export PACKAGEROOT_MIRRORS PACKAGESITE_MIRRORS
-export PACKAGES PKG_DBDIR TMPDIR PKG_TMPDIR
-
-# Direct index access.
-readonly IDX_PKG=0
-readonly IDX_ORIGIN=1
-readonly IDX_PREFIX=2
-readonly IDX_COMMENT=3
-readonly IDX_DESCRIPTION=4
-readonly IDX_MAINTAINER=5
-readonly IDX_CATEGORIES=6
-readonly IDX_DIRECTDEPENDS=7
-readonly IDX_DEPENDS=8
-readonly IDX_WWW=9
-readonly IDX_PERLVERSION=10
-readonly IDX_PERLMODULES=11
-
-# Input field seperator without spaces.
-IFS='
-'
-
-# Parameter flags.
-pAll=
-pNoBackup=
-pClean=
-pExitOnConflict=
-pForce=
-pFetchOnly=
-pInteractive=
-pJobs=
-pListDiscarded=
-pNoActions=
-pNoLogging=
-pParanoid=
-pRecursive=
-pReplaceConflicts=
-pMoreRecursive=
-pUpwardRecursive=
-pMoreUpwardRecursive=
-pVerbose=
-
-# The categories for packages.
-older=
-newer=
-unindexed=
-multiple=
-error=
-
-# A cache for the pkgDepends function.
-dependsChecked=
-
-# The names of packages that do not have a verified download.
-pending=
-
-#
-# The list of packages to upgrade.
-#
-
-# <origin>;<newPackage>
-upgrade=
-upgradeDepends=
-upgradeDepending=
-
-# The <newOrgin>;<newPackage> part can also be found in $upgrade.
-# <newOrigin>;<newPackage>|<oldOrigin>;<oldPackage>
-replace=
-
-# A list of dependency substitutions for new packages.
-# <originalOrigin>;<originalName>|<newDependencyOrigin>;<newDependencyName>
-substituteDepends=
-
-# The current status line.
-status=
-
-# The ports directory as used in the index file.
-idxports=
-
-#
-# Table Of Functions
-# In order of appearance.
-#
-# getIndex() Fetch the latest INDEX
-# getLock() Acquire a lock
-# printStatus() Print status messages on the terminal
-# error() Terminate with an error message
-# warn() Print a warning on stderr
-# verbose() Print a message, but only in verbose mode
-# log() Log activity into a log file
-# getIdxEscape() Escape origins and packages for regular expressions
-# getIdxRows() Filter index rows with an escaped expression
-# getIdxRowsEscaped() Filter index rows with an expression
-# getIdxColumn() Get a certain column from index rows
-# pkgAll() Make a list of outdated packages
-# pkgDepends() Check dependencies
-# pkgDepending() Check upwards dependencies
-# pkgDependencies() Run all dependency checks
-# printProgress() Print numerical progress output
-# pkgSort() Sort packages by dependency
-# printTask() Print the tasks to perform for a package
-# pkgList() List all tasks in 'no actions' mode
-# pkgDownload() Download all required packages
-# pkgUpgrade() Upgrade all scheduled packages
-# substituteDepends() Adjust dependencies of upgraded packages
-# upgradePackage() Upgrade a given package
-# identifyPackage() Identify a package by a user given string
-# printHelp() Print program parameters and terminate
-# readParams() Read the command line parameters
-# readContents() Read the +CONTENTS of a package file
-# downloadManager() Start a background download manager
-# downloadManagerFetch()
-# Try to fetch a package from a mirror
-# downloadManagerMsgRetry()
-# Tell the download manager to retry a download
-# downloadManagerMsgFinished()
-# Tell the download manager a download has been completed
-# downloadManagerMsgRequest()
-# Request a download from the download manager
-# downloadManagerMsgExit()
-# Tell the download manager to terminate
-# validatePackage() Validate a downloaded package
-#
-
-
-#
-# Update the local copy of the index and start the download manager.
-#
-# @param idxports
-# This is set to the ports directory used in the index file. This is
-# required for many index operations. If already set the index is
-# assumed to be up to date and nothing is done.
-# @param pVerbose
-# Activate verbose output.
-#
-getIndex() {
- # The index has already been updated.
- if [ -n "$idxports" ]; then
- return 0
- fi
-
- # Free the lock upon termination.
- trap "uma unlock $pid" EXIT
-
- # First acquire the lock.
- getLock
-
- verbose "Synchronize the local index copy with the package server."
-
- # Try to update the index.
- if ! uma $pVerbose fetch ftpindex $pid; then
- exit $ERR_INDEX
- fi
-
- # Set the ports directory used in the index.
- idxports="$(getIdxColumn $IDX_ORIGIN "$(head -n 1 "$PKG_INDEX")")"
- idxports="${idxports%/*/*}"
-
- # Start the download manager.
- downloadManager
-}
-
-#
-# Acquires the uma (Update Manager) lock. And spawns a process that locks
-# onto PKG_DBDIR to block the ports from messing with us.
-#
-getLock() {
- # Acquire the lock.
- if ! uma lock $pid; then
- if [ "$USER" != "root" ]; then
- error $ERR_LOCK "The command $name has to be run as root."
- else
- error $ERR_LOCK "The uma (Update MAnager) lock could not be acquired, it appears the package/ports infrastructure is in use."
- fi
- fi
-
- # Lock onto PKG_DBDIR to avoid ports getting into our way.
- # The ports tree locks onto PKG_DBDIR during install and deinstall.
- # Since it does not use uma we use this lock to make sure the ports
- # tree does not get into our way later.
- if ! lockf -kst 0 "$PKG_DBDIR" sh -c "lockf -k '$PKG_DBDIR' sh -c 'while kill -0 $pid 2> /dev/null; do sleep 2; done' &"; then
- error $ERR_LOCK "Locking $PKG_DBDIR failed, the ports tree might be in use."
- fi
-}
-
-#
-# Prints a status message to the terminal device /dev/tty.
-#
-# @param 1
-# The message to print
-# @param status
-# The last printed message, used for clearing the status line before
-# printing a new status.
-# @param pClean
-# If set, do not print status messages.
-#
-printStatus() {
- test -n "$pClean" && return 0
- printf "\r%${#status}s\r%s\r" '' "$1" > /dev/tty
- status="$1"
-}
-
-#
-# Exits with the given error and message on stderr.
-#
-# @param 1
-# The error number to exit with.
-# @param 2
-# The message to exit with.
-#
-error() {
- # Clear the status line.
- printStatus
- echo "$name: $2" 1>&2
- exit "$1"
-}
-
-#
-# Writes a warning message to stderr.
-#
-# @param 1
-# The message to write.
-#
-warn() {
- # Clear the status line.
- printStatus
- echo "$name: $1" 1>&2
-}
-
-#
-# Outputs verbose messages on stdout.
-#
-# @param @
-# All the parameters to be output.
-# @param pVerbose
-# If this is not set, do not output anything.
-#
-verbose() {
- test -z "$pVerbose" && return 0
- echo "$@"
-}
-
-#
-# Logs the given message into a log file.
-#
-# The following format is used.
-#
-# <UTC timestamp> - <date> - (<error>|DONE): <message>
-#
-# UTC timestamp := The output of 'date -u '+%s'
-# date := The output of 'date'
-#
-# @param 1
-# The error number for the log, if this is 0, the message will be
-# preceded by "DONE:" instead of "ERROR($1):".
-# @param 2
-# The message to log.
-# @param logfile
-# The name of the file to log into.
-# @param pNoLogging
-# If set, logging is not performed.
-#
-log() {
- test -n "$pNoLogging" && return 0
-
- if [ $1 -eq 0 ]; then
- echo "$(date -u '+%s') - $(date) - DONE: $2" >> $logfile
- else
- echo "$(date -u '+%s') - $(date) - ERROR($1): $2" >> $logfile
- fi
-}
-
-#
-# An escape function for package names fed to the getIdxColumn function.
-# This function reads from the standard input unless a file is named
-# in the parameters.
-# Note that the escaping is done for extended regular expressions, however
-# only characters that can appear in package names are escaped.
-#
-# @param @
-# More parameters can be added to the sed command.
-#
-getIdxEscape() {
- sed -E -e 's/([+.])/\\\1/g' "$@"
-}
-
-#
-# Outputs all rows of the index that match a given pattern in a column.
-# The pattern should not match '|'.
-#
-# @param 1
-# The column that has to match the pattern.
-# @param 2
-# The pattern that has to be matched, an extended regular expression.
-# @param 3
-# Optional, the rows to match against instead of using the index file.
-#
-getIdxRows() {
- if [ -z "$3" ]; then
- grep -E "^([^|]*\|){$1}($2)(\|.*)?\$" "$PKG_INDEX"
- else
- echo "$3" | grep -E "^([^|]*\|){$1}($2)(\|.*)?\$"
- fi
-}
-
-#
-# Outputs all rows of the index that match a given string.
-# The string should not contain '|'.
-#
-# @param 1
-# The column that has to match the string.
-# @param 2
-# The string that has to be matched.
-# @param 3
-# Optional, the rows to match against instead of using the index file.
-#
-getIdxRowsEscaped() {
- getIdxRows $1 "$(echo "$2" | getIdxEscape)" "$3"
-}
-
-#
-# Outputs a column of each index row piped into it.
-#
-# @param 1
-# The column to output.
-# @param 2
-# The rows to output the columns from.
-#
-getIdxColumn() {
- echo "$2" | sed -E "s,^([^|]*\|){$1}([^|]*)\|.*,\2,1"
-}
-
-#
-# Stores all the packages not in sync with the index file in categories.
-#
-# @param older
-# The list of packages older than those in the index.
-# @param newer
-# The list of packages newer than those in the index.
-# @param unindexed
-# The list of packages not in the index.
-# @param multiple
-# The list of packages that have multiple index entries.
-# @param error
-# The list of packages with broken package database entries.
-# @param pForce
-# If set, register all installed packages in the index as outdated.
-# @param pAll
-# If set, add all outdated packages to the list of packages to upgrade.
-# @param pListDiscarded
-# If set, list all the packages that are ignored.
-# @param upgrade
-# The list to add packages to if pAll is set.
-#
-pkgAll() {
- local package pkgname origin operator row discarded
-
- # There's nothing to be done if all of the following conditions are
- # met:
- # - Nothing is yet listed for upgrading, so we do not need a list
- # of outdated packages for dependency checking.
- # - The updating of all packages is not requested.
- # - The listing of ignored (i.e. not indexed) packages is not
- # requested.
- test -z "$upgrade" -a -z "$pAll" -a -z "$pListDiscarded" && return 0
-
- verbose "Make a list of outdated packages."
-
- printStatus "Reading version information of installed packages ..."
-
- if [ -n "$pForce" ]; then
- # In force mode it is assumed that all installed packages to
- # be found in the index are outdated.
- for package in $(pkg_version -Io "${PKG_INDEX}"); {
- origin="${package%% *}"
- row="$(getIdxRowsEscaped $IDX_ORIGIN "$idxports/$origin")"
- pkgname="$(getIdxColumn $IDX_PKG "$row")"
- printStatus "Checking <$pkgname>."
- operator="${package##* }"
- case "$operator" in
- '?')
- unindexed="$unindexed${unindexed:+$IFS}$origin"
- ;;
- '!')
- error="$error${error:+$IFS}$origin"
- ;;
- *)
- older="$older${older:+$IFS}$origin;$pkgname"
- ;;
- esac
- }
- else
- # Categorize installed packages and their relations to the
- # index.
- for package in $(pkg_version -IoL = ${PKG_INDEX}); {
- origin="${package%% *}"
- row="$(getIdxRowsEscaped $IDX_ORIGIN "$idxports/$origin")"
- pkgname="$(getIdxColumn $IDX_PKG "$row")"
- printStatus "Checking <${pkgname:-$(pkg_info -qO $origin)}>."
- operator="${package##* }"
- case "$operator" in
- '<')
- older="$older${older:+$IFS}$origin;$pkgname"
- ;;
- '>')
- newer="$newer${newer:+$IFS}$origin;$pkgname"
- ;;
- '?')
- unindexed="$unindexed${unindexed:+$IFS}$origin"
- ;;
- '*')
- multiple="$multiple${multiple:+$IFS}$origin"
- ;;
- '!')
- error="$error${error:+$IFS}$origin"
- ;;
- esac
- }
- fi
-
- printStatus "Assemble checked packages ..."
-
- # Remove packages to upgrade from the list of outdated packages.
- for package in $upgrade; {
- older="$(echo "$older" | grep -vx "$package")"
- }
-
- # Append outdated packages to the list of packages to update if all
- # packages are to be updated.
- if [ -n "$pAll" ]; then
- downloadManagerMsgRequest "$older"
- upgrade="$upgrade${older:+${upgrade:+$IFS}}$older"
- older=
- fi
-
- # Clear the status line.
- printStatus
-
- # Print the discarded packages.
- if [ -n "$pListDiscarded" ]; then
- verbose "List discarded packages."
-
- discarded="$unindexed$IFS$multipleIFS$error"
- discarded="$(echo "$discarded" | grep -vFx '' | sort -u)"
-
- test -n "$discarded" && echo "$discarded"
- fi
-}
-
-#
-# Adds all missing dependencies to the list of packages to upgrade.
-#
-# @param 1
-# This is used to check the dependencies of newly added depending
-# packages.
-# @param upgrade
-# The primary list of packages to upgrade (read only).
-# @param upgradeDepends
-# The list to add packages to upgrade to.
-# @param older
-# The list of outdated packages. Packages for upgrading are removed from
-# it.
-# @param dependsChecked
-# A list of already checked dependencies, to avoid double checks.
-# @param pRecursive
-# If set, also add outdated dependencies to the upgrade list.
-# @param pMoreRecursive
-# If set, also update the dependencies of depending packages.
-# @param pForce
-# If set together with pRecursive, add all dependencies to the upgrade
-# list.
-#
-pkgDepends() {
- local pkgname package row rows depends origin escapedPkg upgradeList
-
- printStatus "Preparing dependency checks ..."
-
- # In thorough mode the depencies of depending packages are updated, too.
- upgradeList="${1:-$upgrade}"
-
- # Luckily packages know their indirect dependencies, too. This way
- # it is not necessary to check for dependencies recursively.
- depends=
- for package in $upgradeList; {
- row="$(getIdxRowsEscaped $IDX_ORIGIN "$idxports/${package%;*}")"
- row="$(getIdxColumn $IDX_DEPENDS "$row")"
- depends="$depends${depends:+${row:+ }}$row"
- }
-
- # Reformat depends and throw out duplicates.
- depends="$(
- echo "$depends" | sed "s/ /\\$IFS/g" | sort -u
- )"
-
- # Do some prefiltering.
- rows="$(getIdxRowsEscaped $IDX_PKG "$(echo "$depends" | rs -TC\|)")"
-
- # Check for missing or outdated dependencies.
- for pkgname in $depends; {
- escapedPkg="$(echo "$pkgname" | getIdxEscape)"
-
- # Skip packages already checked.
- if echo "$dependsChecked" | grep -qFx "$pkgname"; then
- continue
- fi
- dependsChecked="$dependsChecked${dependsChecked:+$IFS}$pkgname"
-
- printStatus "Check dependency <$pkgname>."
-
- # Skip this if this package is already scheduled for updating.
- if echo "$upgrade${upgradeDepending:+$IFS$upgradeDepending}" | grep -qF ";$pkgname"; then
- continue
- fi
-
- row="$(getIdxRows $IDX_PKG "$escapedPkg" "$rows")"
-
- # If this package could not be identified this is an index
- # incosistency, that can only be ignored.
- if [ -z "$row" ]; then
- warn "Ignore index inconsistency, the dependency <$pkgname> is not in the index." 1>&2
- continue
- fi
-
- origin="$(getIdxColumn $IDX_ORIGIN "$row")"
- origin="${origin#$idxports/}"
- package="$origin;$(getIdxColumn $IDX_PKG "$row")"
-
- #
- # Deal with dependencies according to set parameters.
- #
- if [ -z "$(pkg_info -qO "$origin")" ]; then
- # The depency is not installed.
- upgradeDepends="$upgradeDepends${upgradeDepends:+$IFS}$package"
- # Request a package download.
- downloadManagerMsgRequest "$package"
- elif [ -n "$pMoreRecursive" -o -n "$pRecursive" -a -z "$1" ]; then
- # Check whether the dependency is outdated.
- if echo "$older" | grep -qFx "$package"; then
- upgradeDepends="$upgradeDepends${upgradeDepends:+$IFS}$package"
- older="$(echo "$older" | grep -vFx "$package")"
- # Request a package download.
- downloadManagerMsgRequest "$package"
- fi
- fi
- }
-}
-
-#
-# Checks whether packages depending on the packages to update require updating.
-#
-# @param 1
-# This is used to check the depending packages of newly added
-# dependencies.
-# @param older
-# The list of outdated packages. If pForce is set, this includes all
-# installed packages listed in the index.
-# @param upgrade
-# The primary list of packages to upgrade (read only).
-# @param upgradeDepending
-# The list of depending packages to upgrade.
-# @param pUpwardRecursive
-# If not set nothing is done.
-# @param pMoreUpwardRecursive
-# Also check the depending packages of depencencies.
-# @param pAll
-# If this is set do nothing.
-#
-pkgDepending() {
- # Without the upwardRecursive option this is completely
- # unnecessary.
- if [ -z "$pUpwardRecursive" ]; then
- return 0
- fi
-
- # If all packages are already going to be upgraded, there is no
- # need for this.
- if [ -n "$pAll" ]; then
- return 0
- fi
-
- # Only update depending packages of dependencies in thorough mode.
- if [ -n "$1" -a -z "$pMoreUpwardRecursive" ]; then
- return 0
- fi
-
- local package pkgname origin row depends escapedPkg upgradeList
-
- printStatus "Preparing upwards dependency checks ..."
-
- # In thorough mode the depencies of depending packages are updated, too.
- upgradeList="${1:-$upgrade}"
-
- # Do some prefiltering.
- rows="$(getIdxRowsEscaped $IDX_ORIGIN "$(
- echo "$older" | rs -TC\| | sed -E "s'([^;|]*);[^|]*'$idxports/\1'g"
- )")"
-
- # For each outdated package, check whether it depends on a package
- # to upgrade. In force mode outdated packages are all packages, so
- # the difference does not have to be made here.
- for package in $older; {
- # Skip this if this package is already scheduled for updating.
- if echo "$upgrade${upgradeDepends:+$IFS$upgradeDepends}${upgradeDepending:+$IFS$upgradeDepending}" | grep -qFx "$package"; then
- continue
- fi
-
- printStatus "Check for upwards dependency <${package#*;}>."
-
- origin="${package%;*}"
- row="$(getIdxRowsEscaped $IDX_ORIGIN "$idxports/$origin" "$rows")"
-
- # Ignore unindexed packages.
- if [ -z "$row" ]; then
- continue
- fi
-
- depends="$(getIdxColumn $IDX_DEPENDS "$row")"
-
- # It has no dependencies, so it cannot depend on anything
- # in the upgrade list.
- if [ -z "$depends" ]; then
- continue
- fi
-
- # Reformat dependencies.
- depends="$(echo "$depends" | sed -Ee "s/([^ ]+)/;\1/g" -e "s/ /\\$IFS/g")"
-
- # Check every dependency for matching the upgrade packages.
- if echo "$upgradeList" | grep -qF "$depends"; then
- upgradeDepending="$upgradeDepending${upgradeDepending:+$IFS}$package"
- older="$(echo "$older" | grep -vFx "$package")"
- downloadManagerMsgRequest "$package"
- fi
- }
-}
-
-#
-# This function calls pkgDepending and pkgDepends until no new packages
-# show up for updating. All the clever stuff happens in those functions.
-#
-# @param upgrade
-# The list of packages to upgrade.
-# @param upgradeDepends
-# The list of dependencies to add to the list of packages to upgrade.
-# @param upgradeDepending
-# The list of depending packages to add to the list of packages
-# to upgrade.
-#
-pkgDependencies() {
- test -z "$upgrade" && return 0
-
- verbose "Perform dependency checks."
-
- # Run the primary dependency checks.
- pkgDepending
- downloadManagerMsgRequest "$upgradeDepending"
- pkgDepends
- downloadManagerMsgRequest "$upgradeDepends"
-
- # The idea is to keep on checking until nothing new shows up.
- # Whether that is the case depends on the level of recursiveness.
- while [ -n "$upgradeDepends$upgradeDepending" ]; do
- if [ -n "$upgradeDepends" ]; then
- # Deal with packages depending on the updated packages.
- pkgDepending "$upgradeDepends"
- upgrade="$upgradeDepends$IFS$upgrade"
- upgradeDepends=
- fi
-
- if [ -n "$upgradeDepending" ]; then
- # Deal with missing or outdated dependencies.
- pkgDepends "$upgradeDepending"
- upgrade="$upgrade$IFS$upgradeDepending"
- upgradeDepending=
- fi
- done
-
- # Clear the status line.
- printStatus
-}
-
-#
-# Prints a progress message to the terminal device /dev/tty.
-#
-# @param 1
-# Total amount of operations to do.
-# @param 2
-# The amount of operations performed.
-# @param 3
-# The name of the package that is currently operated on.
-# @param 4
-# The text prepending the progress information.
-# @param status
-# The last printed message, used for clearing the status line before
-# printing a new status.
-# @param pClean
-# If set, do not print progress messages.
-#
-printProgress() {
- test -n "$pClean" && return 0
- printf "\r%${#status}s\r$4 %${#1}s of %${#1}s (%3s%%) <$3>.\r" '' "$2" "$1" "$(($2 * 100 / $1))" > /dev/tty
- status="$4 $1 of $1 (100%) <$3>."
-}
-
-#
-# Sorts the packages to upgrade by dependency.
-#
-# The trick is to have a list of already sorted packages. Each package added
-# to the list is inserted right behind its last dependency already present
-# there.
-# Packages without any dependencies in the sorted list are prepended. This
-# way it is ensured that they end up before all already sorted packages
-# that depend on them, without additional checking.
-#
-# @param upgrade
-# The list of packages to sort.
-# @param pParanoid
-# If set, make cyclic dependency checks.
-#
-pkgSort() {
- local rows sorted package row depends dependency pkgname
- local totalCount count
-
- test -z "$upgrade" && return 0
-
- verbose "Sort packages by dependency."
-
- printStatus "Prepare sorting of packages ..."
-
- # Limit rows to whatever is currently required.
- rows="$(getIdxRowsEscaped $IDX_ORIGIN "$(
- echo "$upgrade" | getIdxEscape -e 's/;.*//1' -e "s,^,$idxports/,1" | rs -TC\|
- )")"
-
- # The number of packages
- totalCount=$(($(echo "$upgrade" | wc -l)))
- count=0
-
- # Sort each package into the list of sorted packages.
- sorted=
- for package in $upgrade; {
- count=$(($count + 1))
- pkgname="${package#*;}"
- printProgress $totalCount $count "$pkgname" 'Sort'
-
- # Get the list of dependencies that should be updated before
- # the current package.
- row="$(getIdxRowsEscaped $IDX_PKG "$pkgname" "$rows")"
- depends="$(getIdxColumn $IDX_DEPENDS "$row" | sed -E "s/ /\\$IFS/g")"
-
- # Get the last matching dependency in the list.
- dependency="$(echo "$sorted" | grep -Fx "$depends" | tail -n 1)"
-
- # If there is no match, just prepend to the list.
- if [ -z "$dependency" ]; then
- sorted="$pkgname${sorted:+$IFS$sorted}"
- continue
- fi
-
- # Insert right behind the match.
- dependency="$(echo "$dependency" | getIdxEscape)"
- sorted="$(echo "$sorted" | sed -E "s/^$dependency$/$dependency\\$IFS$pkgname/1")"
- }
-
- # Perform optional cyclic dependency check.
- if [ -n "$pParanoid" ]; then
- printStatus "Validate sorting order ..."
-
- # Validate the sort order.
- count=0
- for pkgname in $sorted; {
- count=$(($count + 1))
- printProgress $totalCount $count "$pkgname" 'Validate'
-
- # Get the list of dependencies that should be updated before
- # the current package.
- row="$(getIdxRowsEscaped $IDX_PKG "$pkgname" "$rows")"
- depends="$(getIdxColumn $IDX_DEPENDS "$row" | sed -E "s/ /\\$IFS/g")"
-
- # Append the package to the list of dependencies to match.
- depends="${depends:+$depends$IFS}$pkgname"
-
- # Get the last match in the list.
- dependency="$(echo "$sorted" | grep -Fx "$depends" | tail -n 1)"
- # The last match has to be the package.
- if [ "$dependency" != "$pkgname" ]; then
- error $ERR_SORT "The package <$pkgname> was not sorted properly, a likely cause is a circular dependency."
- fi
- }
- fi
-
- printStatus "Assemble sorted packages ..."
-
- # Replace package names with <origin>;<package> pairs.
- for package in $upgrade; {
- pkgname="$(echo "${package#*;}" | getIdxEscape)"
- sorted="$(echo "$sorted" | sed -E "s'^$pkgname\$'$package'1")"
- }
-
- upgrade="$sorted"
- printStatus
-}
-
-#
-# Prints the update/replace/install task.
-#
-# @param 1
-# The package to upgrade/install.
-# @param replace
-# The list of packages to replace.
-#
-printTask() {
- local package newPkgname newOrigin oldPkgname oldOrigin
-
- # Get the name and origin of the new package.
- newPkgname="${1#*;}"
- newOrigin="${1%;*}"
-
- # Look for a package the new one replaces.
- package="$(echo "$replace" | grep -F "$1|")"
-
- # Look for a package this one replaces.
- # The current package actually replaces another one.
- if [ -n "$package" ]; then
- # Get the name and origin of the old package.
- package="${package#*|}"
- oldPkgname="${package#*;}"
- oldOrigin="${package%;*}"
-
- echo "Replace <$oldPkgname> ($oldOrigin) with <$newPkgname> ($newOrigin)"
- return 0
- fi
-
- # Check whether there's an old version of this package around.
- package="$(pkg_info -qO "$newOrigin")"
-
- # An older package with this origin is installed.
- if [ -n "$package" ]; then
- echo "Update <$package> to <$newPkgname> ($newOrigin)"
- return 0
- fi
-
- # Aparently this package will be newly installed.
- echo "Install <$newPkgname> ($newOrigin)"
-}
-
-#
-# List the packages that are going to be upgraded, installed and replaced.
-# If the 'no actions' mode is active.
-#
-# @param upgrade
-# The list of packages to upgrade.
-# @param pNoActions
-# Print the list of tasks.
-#
-pkgList() {
- # Only list packages in "no actions" mode.
- test -z "$pNoActions" && return 0
-
- test -z "$upgrade" && return 0
-
- local package
-
- verbose "The following packages will be updated:"
-
- for package in $upgrade; {
- printTask "$package"
- }
-}
-
-#
-# Wait for downloaded packages and validate them.
-#
-# @param upgrade
-# The list of packages to download.
-# @param pending
-# The list of pending downloads.
-# @param packagerepos
-# The location of the remote package repository (derived from
-# PACKAGESITE). If this is identical with the local repository,
-# the download manager was not started.
-# @param pNoActions
-# Do not download anything.
-#
-pkgDownload() {
- test -n "$pNoActions" && return 0
-
- test -z "$upgrade" && return 0
-
- local package total count line
-
- verbose "Validate downloaded packages."
-
- printStatus "Waiting for downloads ..."
-
- # Create a list of the package names to validate.
- # Entries are removed from this list by validatePackage().
- pending="$(echo "$upgrade" | sed 's/.*;//1')"
-
- # The total number of packages to validate.
- total="$(($(echo "$upgrade" | wc -l)))"
-
- # Check whether the download manager is available.
- if [ "$PACKAGES" = "$packagerepos" ]; then
- #
- # The local repository is identical with the remote repository
- # so the assumption is all packages should already be there.
- #
-
- # Validate all packages.
- for package in $pending; {
- count=$(($count + 1))
- printProgress $total $count "$package" "Validate"
- validatePackage "$package"
- }
- else
- #
- # The download manager is available, so hang on to its message
- # queue and proceed with validating as packages are finished.
- #
- count=0
-
- while [ -n "$pending" ]; do
- read line
- case "$line" in
- finished:*)
- count=$(($count + 1))
- package="${line##*;}"
- printProgress $total $count "$package" "Validate"
- validatePackage "$package"
- ;;
- esac
- done < "$queueMessages"
-
- # Stop the download manager.
- downloadManagerMsgExit
- fi
-
- # Clear the status line.
- printStatus
-}
-
-#
-# Upgrade each package.
-#
-# @param upgrade
-# The list of packages to upgrade.
-# @param conflictReplace
-# This list is reset for conflict handling.
-# @param pNoActions
-# Do not update anything.
-# @param pFetchOnly
-# Do not update anything.
-#
-pkgUpgrade() {
- test -n "$pNoActions" -o -n "$pFetchOnly" && return 0
-
- test -z "$upgrade" && return 0
-
- local package
-
- verbose "Install $(($(echo "$upgrade" | wc -l))) package(s)."
-
- for package in $upgrade; {
- upgradePackage "$package"
- }
-}
-
-#
-# To handle conflicts this function removes dependencies from a given package
-# and appends one or more new ones to take their place. Also the +REQUIRED_BY
-# files of the appended dependencies are updated.
-#
-# @param 1
-# The name of the package to which to apply the substitutions.
-# @param substituteDepends
-# The list of dependency substitutions that should take place.
-#
-substituteDepends() {
- # End here if there's nothing to substitute.
- test -z "$substituteDepends" && return 0
-
- local line originalOrigin originalPkgname newOrigin newPkgname
- local contents append remove requiredBy
-
- printStatus "Adjust the dependencies of <$1> ..."
-
- # Get the contents file.
- contents="$(cat "$PKG_DBDIR/$1/+CONTENTS")"
-
- # Because there can be several substitutions for a single package
- # the new ones will be added to the end of the +CONTENTS file and all
- # the matches will be removed later.
- append=
- remove=
- for line in $substituteDepends; {
- # Get original origin and package name from the line.
- originalOrigin="${line%%;*}"
- originalPkgname="${line%|*}"
- originalPkgname="${originalPkgname#*;}"
-
- # Continue with the next line if this one does not match.
- if ! echo "$contents" | grep -qFx "@pkgdep $originalPkgname"; then
- continue
- fi
-
- # Get new origin and package name from the line.
- newOrigin="${line#*|}"
- newPkgname="${newOrigin#*;}"
- newOrigin="${newOrigin%;*}"
-
- warn "Add dependency <$newPkgname> ($newOrigin)."
-
- # Remember what to append and what to remove.
- remove="${remove:+$remove$IFS}@pkgdep $originalPkgname$IFS@comment DEPORIGIN:$originalOrigin"
- # Just for the very unlikely case that two dependencies get
- # replaced for conflicting with the same package, check that
- # a dependency is not added twice.
- if ! echo "$append" | grep -qFx "@pkgdep $newPkgname"; then
- append="$append$IFS@pkgdep $newPkgname$IFS@comment DEPORIGIN:$newOrigin"
- fi
-
- # Make an entry for the package in the +REQUIRED_BY file of
- # of the dependency to append.
- requiredBy="$(cat "$PKG_DBDIR/$newPkgname/+REQUIRED_BY" 2> /dev/null)"
- requiredBy="${requiredBy:+$requiredBy$IFS}$1"
- echo "$requiredBy" | sort -u > "$PKG_DBDIR/$newPkgname/+REQUIRED_BY"
- }
-
- # Remove the original dependency entries.
- contents="$(echo "$contents" | grep -vFx "$remove")"
- # Write the new file. Note that $append always starts with a newline.
- echo "$contents$append" > "$PKG_DBDIR/$1/+CONTENTS"
-}
-
-#
-# Install the given package. This is where the magic happens.
-#
-# @param replace
-# The list of packages to replace (read only).
-# @param substituteDepends
-# A list of dependency substitutions that should take place for each
-# newly installed package to resolve conflicting packages.
-# @param packagebackup
-# The location for backup packages. This is derived from PACKAGES.
-# @param pNoBackup
-# If set, delete backups after successful completion.
-#
-upgradePackage() {
- local task targetPackage targetPkgname targetOrigin package replace
- local escapedPkg removePackages origin file conflict conflicting
- local replacePkgdep requiredBy count
- local signal
-
- # Get a string with the current upgrade task.
- task="$(printTask "$1")"
- echo "===> $task"
-
- targetPackage="$1"
- targetPkgname="${1#*;}"
- targetOrigin="${1%;*}"
-
- printStatus "Prepare installation of <$targetPkgname> ..."
-
- # Get the packages to replace with this one. Several packages can be
- # replaced with a single one.
- escapedPkg="$(echo "$targetPackage" | getIdxEscape)"
- replace="$(echo "$replace" | grep -Ex "$escapedPkg\|.*" | sed -E "s'^$escapedPkg\|''1")"
-
- # Append the current package to the list of packages to replace.
- replace="${replace:+$replace$IFS}$targetPackage"
-
- # Create the list of outdated packages that have to be backed up
- # and for which pkgdb adjustments have to be made after successful
- # installation of the new package.
- # Also create the necessary sed expressions to update the
- # package database.
- removePackages=
- replacePkgdep=
- for package in $replace; {
- origin="${package%;*}"
- package="$(pkg_info -qO "$origin")"
- test -z "$package" && continue
- removePackages="$removePackages${removePackages:+$IFS}$package"
- package="$(echo "$package" | getIdxEscape)"
- replacePkgdep="$replacePkgdep -e 's|^@pkgdep $package\$|@pkgdep $targetPkgname|1'"
- if [ "$origin" != "$targetOrigin" ]; then
- replacePkgdep="$replacePkgdep -e 's|^@comment DEPORIGIN: $origin\$|@comment DEPORIGIN:$targetOrigin|1'"
- fi
-
- }
-
- # Get a list of conflicting packages. The conflicts list is
- # provided by readContents().
- readContents "$PACKAGES/All/$targetPkgname.tbz"
- conflicting=
- for conflict in $conflicts; {
- # Match the conflict pattern against installed packages.
- for conflict in $(pkg_info -E "$conflict"); {
- escapedPkg="$(echo "$conflict" | getIdxEscape)"
- # Only add to the conflicting list if the conflicting
- # package is not in the list of packages to replace.
- if ! echo "$removePackages" | grep -qEx "$escapedPkg"; then
- conflicting="${conflicting:+$conflicting$IFS}$conflict"
- fi
- }
- }
- # Remove duplicated entries.
- conflicting="$(echo "$conflicting" | sort -u)"
-
- # Check whether any conflicts were found.
- if [ -n "$conflicting" ]; then
- # What happens now depends on the user preferences.
- if [ -n "$pExitOnConflict" ]; then
- # The user has chosen to bail out when a conflict
- # occurs.
- log $ERR_CONFLICT "$task"
- error $ERR_CONFLICT "The package <$targetPkgname> conflicts with the following packages:$IFS$conflicting"
- elif [ -n "$pReplaceConflicts" ]; then
- # The user has chosen that conflicting packages should
- # be replaced as if they were explicitly listed for
- # replacing.
- conflicts=
- for package in $conflicting; {
- warn "The package <$package> conflicts with <$targetPkgname> and will be replaced."
- removePackages="$removePackages${removePackages:+$IFS}$package"
- origin="$(pkg_info -qo "$package")"
- # The next line is just for prettier log output.
- conflicts="${conflicts:+$conflicts, }<$package> ($origin)"
- package="$(echo "$package" | getIdxEscape)"
- replacePkgdep="$replacePkgdep -e 's|^@pkgdep $package\$|@pkgdep $targetPkgname|1'"
- if [ "$origin" != "$targetOrigin" ]; then
- replacePkgdep="$replacePkgdep -e 's|^@comment DEPORIGIN: $origin\$|@comment DEPORIGIN:$targetOrigin|1'"
- fi
- }
- log 0 "Conflict <$targetPkgname> ($targetOrigin) remove package(s) $conflicts"
- else
- # The default action is to assume that the conflicting
- # packages fulfill the required functionality.
- conflicts=
- for package in $conflicting; {
- warn "The package <$targetPkgname> will not be installed in favour of <$package>, because they conflict."
- origin="$(pkg_info -qo "$package")"
- # Record the necessary substitutions.
- # TODO: Later versions will have to store this
- # for resume.
- substituteDepends="${substituteDepends:+$substituteDepends$IFS}$targetPackage|$origin;$package"
- # This is just for prettier log output.
- conflicts="${conflicts:+$conflicts, }<$package> ($origin)"
- }
- # Log the conflict resolution.
- log 0 "Conflict <$targetPkgname> ($targetOrigin) favour package(s) $conflicts"
- # Skip to the next package.
- return 0
- fi
- fi
-
- # Backup packages.
- mkdir -p "$packagebackup"
- for package in $removePackages; {
- printStatus "Backup <$package>."
- pkg_create -b "$package" "$packagebackup/$package"
- case $? in
- 0)
- # Everything went well.
- ;;
- 1)
- # If this happens someone's been messing with
- # the packages just milliseconds ago.
- log $ERR_BACKUP_MISS "$task"
- error $ERR_BACKUP_MISS "The backup of <$package> failed. The package is missing."
- ;;
- 2)
- # Fortunately pkg_create backs up as much as
- # as is possible. That the backup (and hence
- # the present package) is incomplete is all
- # the more reason to upgrade.
- # I do not understand why portmaster is
- # interactive in this case.
- warn "Ignoring incomplete backup of <$package>."
- ;;
- *)
- # Well, I've got no idea at all what else
- # could go wrong. Too bad the return codes
- # of pkg_create are not documented.
- log $ERR_BACKUP_UNKNOWN "$task"
- error $ERR_BACKUP_UNKNOWN "The backup of <$package> failed for unknown reasons."
- ;;
- esac
- }
-
- # Block SIGINT (CTRL-C), because that would really wrack havoc upon
- # the package database in the following section.
- signal=
- trap "signal=$ERR_USER" sigint
- trap "signal=$ERR_TERM" sigterm
-
- # Delete packages.
- requiredBy=
- count=-1
- for package in $removePackages; {
- printStatus "Delete <$package>."
- # Remember +REQUIRED_BY contents for roll-back.
- count=$(($count + 1))
- local "requiredBy$count"
- setvar "requiredBy$count" "$(cat "$PKG_DBDIR/$package/+REQUIRED_BY" 2> /dev/null)"
- # Remember +REQUIRED_BY contents for the new package.
- requiredBy="${requiredBy:+$requiredBy$IFS}$(cat "$PKG_DBDIR/$package/+REQUIRED_BY" 2> /dev/null)"
- # Finally delete the package.
- pkg_delete -f "$package"
- }
-
- # Update the package database.
- printStatus "Update package database for <$targetPkgname>."
- if [ -n "$replacePkgdep" ]; then
- for file in $(find "$PKG_DBDIR" -name '+CONTENTS'); {
- eval "sed -Ei '.$name' $replacePkgdep '$file'"
- }
- fi
-
- # If an old version of this package was favoured in a conflict,
- # the substituteDepends list has to be changed.
- substituteDepends="$(echo "$substituteDepends" | sed "s'\|$targetOrigin;.*'|$targetPackage'1")"
-
- # Try to install the new package.
- printStatus "Install <$targetPkgname>."
- if ! env PKG_PATH="$PACKAGES/All" pkg_add -f "$targetPkgname"; then
- # Installation went wrong, roll back!
- printStatus "Roll back changes for <$targetPkgname>."
- for file in $(find "$PKG_DBDIR" -name "*.$name"); {
- mv -f "$file" "${file%.$name}"
- }
- count=-1
- for package in $removePackages; {
- # Restore package.
- env PKG_PATH="$packagebackup" pkg_add -f "$package"
- # Recover +REQUIRED_BY file.
- count=$(($count + 1))
- eval "echo \"\$requiredBy$count\"" > "$PKG_DBDIR/$package/+REQUIRED_BY"
- # Remove the backup if set.
- test -n "$pNoBackup" && rm "$packagebackup/$package.tbz"
- }
- log $ERR_INSTALL "$task"
- error $ERR_INSTALL "The installation of <$targetPkgname> failed."
- fi
-
- # Add the +REQUIRED_BY contents of all deleted packages to the
- # +REQUIRED_BY file of the new one.
- requiredBy="$(echo "$(cat "$PKG_DBDIR/$targetPkgname/+REQUIRED_BY" 2> /dev/null)$IFS$requiredBy" | grep -vFx '' | sort -u)"
- echo "$requiredBy" > "$PKG_DBDIR/$targetPkgname/+REQUIRED_BY"
-
- # Make dependency substitutions from conflict resolving.
- substituteDepends "$targetPkgname"
-
- # Log successful completion of the task.
- log 0 "$task"
-
- # Remove backups if set.
- if [ -n "$pNoBackup" ]; then
- for package in $removePackages; {
- printStatus "Remove backup of <$package>."
- rm "$packagebackup/$package.tbz"
- }
- fi
-
- # Remove package database backups.
- # TODO: Later versions will instead store them to allow a rollback.
- printStatus "Remove database backups for <$targetPkgname>."
- find "$PKG_DBDIR" -name "*.$name" -exec rm \{\} \;
-
- # Clear the status line.
- printStatus
- echo "=> $task succeeded"
-
- # Bail out if SIGINT or SIGTERM were encountered.
- if [ -n "$signal" ]; then
- error $signal "The process was interrupted."
- fi
-
- # Reactivate default signal handlers.
- trap - sigint sigterm
-}
-
-#
-# Identify the package by a given string. Outputs the origin of all matched
-# packages, as well as the package name of the newest available package.
-# The output is in the following shape:
-# <origin>;<package>
-#
-# The shell wildcards '*' and '?' are supported.
-# Origin and package names with wildcards are matched against installed
-# packages. Unambiguous package names and origins are matched against the
-# index.
-#
-# @param 1
-# The package identifier to find matches for.
-#
-identifyPackage() {
- local packages package mangledPackage rows matchingRows mangledRows
- local origins origin guess escapedPkg
-
- # Check for wildcards.
- guess=
- if echo "$1" | grep -qE '\*|\?|\[.*]'; then
- guess=1
- fi
- package="$1"
-
- # Distuinguish between origins and packages.
- case "$package" in
- */*)
- # An origin has been given.
- if [ -n "$guess" ]; then
- # Wildcards present, match against installed
- # packages.
-
- # Get all matching packages.
- packages="$(pkg_info -qO "$package")"
-
- # Convert for use in a regular expression.
- package="$(echo "$package" | getIdxEscape -e 's/\*/[^|]*/g' -e 's/\?/[^|]/g')"
- # Get rows matching the given package origin.
- # This is a performance tweak, so the whole
- # index will not have to be parsed in the
- # following output loop.
- rows="$(getIdxRows $IDX_ORIGIN "$idxports/$package")"
-
- # Output all matching packages.
- for package in $packages; {
- # Get the origin.
- origin="$(pkg_info -qo "$package")"
-
- # Match this package origin against the
- # previously filtered rows.
- package="$(getIdxRowsEscaped $IDX_ORIGIN "$idxports/$origin" "$rows")"
- # Get the package name of the newest
- # package from the index.
- package="$(getIdxColumn $IDX_PKG "$package")"
- # Output origin/package pair.
- echo "$origin;$package"
- }
-
- # If no matches have been found, terminate.
- if [ -z "$packages" ]; then
- error $ERR_ARG "Package origin <$package> not matched by any installed package!" 1>&2
- fi
- else
- # There is an unambigious origin, match it
- # against the index.
- origin="$package"
- # Get the index row.
- rows="$(getIdxRowsEscaped $IDX_ORIGIN "$idxports/$origin")"
- # Get the package name column.
- package="$(getIdxColumn $IDX_PKG "$rows")"
- # Output origin/package pair, if a package for
- # the given origin was found.
- if [ -n "$package" ]; then
- # Output origin/package pair.
- echo "$origin;$package"
- else
- error $ERR_ARG "Package origin <$origin> not in index!" 1>&2
- fi
- fi
- ;;
- *)
- # A package name has been given.
- if [ -n "$guess" ]; then
- # Wildcards present, match against installed
- # packages.
-
- # Get the origins of matching packages.
- origins="$(pkg_info -qo "$package")"
-
- # Prepare the package name for use in a
- # regular expression.
- package="$(echo "$package" | getIdxEscape -e 's/\*/[^|]*/g' -e 's/\?/[^|]/g')"
- # Get rows matching the given package name.
- # This is a performance tweak, so the whole
- # index will not have to be parsed in the
- # following output loop.
- rows="$(getIdxRows $IDX_PKG "$package")"
- # Output all matching packages.
- for origin in $origins; {
- # Get the index row for this origin.
- package="$(getIdxRowsEscaped $IDX_ORIGIN "$idxports/$origin" "$rows")"
- # Get the latest package name from the
- # index.
- package="$(getIdxColumn $IDX_PKG "$package")"
- # Output origin/package pair.
- echo "$origin;$package"
- }
-
- # If no matches have been found, terminate.
- if [ -z "$origins" ]; then
- error $ERR_ARG "Package identifier <$package> not matched!" 1>&2
- fi
- else
- # A package name without wildcards has been
- # given. This is expected to either be an exact
- # package name or a LATEST_LINK name.
-
- # TODO: This would be much better if
- # LATEST_LINK was known. This is information
- # simply missing in the index.
- # To make up for this some guessing is done in
- # case of no matches or more than one match.
- # But this fails for apache13 and probably
- # other packages as well.
-
- # First try whether it is the current version
- # of a package.
- origin="$(pkg_info -qo "$package" 2> /dev/null)"
- if [ -n "$origin" ]; then
- # Get the matching index rows.
- rows="$(getIdxRowsEscaped $IDX_ORIGIN "$idxports/$origin")"
- fi
-
- # If it's not a current version, match against
- # the index.
- if [ -z "$rows" ]; then
- # Get the matching rows. This should be
- # only one, but it won't be for ports
- # that define a proprietary LATEST_LINK.
- escapedPkg="$(echo "$package" | getIdxEscape)"
- rows="$(getIdxRows $IDX_PKG "$escapedPkg(-[^-]+)?")"
- fi
-
- # No match, start some guessing.
- # This fails for packages with a version tail,
- # which is just what is wanted.
- if [ -z "$rows" ]; then
- # Assume this is a LATEST_LINK kind
- # package name and remove the trailing
- # numbers.
- mangledPackage="$(echo "$package" | sed -E 's/[0-9]+$//1')"
- # Get the matching rows, this is likely
- # to be too many (i.e. more than one).
- rows="$(getIdxRows $IDX_PKG "$mangledPackage-[^-]+")"
- fi
-
- # If there is more than one matching row,
- # try to match against the origin.
- if [ "$(($(echo "$rows" | wc -l)))" -gt "1" ]; then
- # Match against the origin.
- rows="$(getIdxRows $IDX_ORIGIN "[^|]*/$package" "$rows")"
-
- # If there is still more than one
- # match, match against the origins
- # of existing packages.
- if [ "$(($(echo "$rows" | wc -l)))" -gt "1" ]; then
- for origin in $(getIdxColumn $IDX_ORIGIN "$rows"); {
- test -n "$(pkg_info -qO "$origin")" \
- && matchingRows="$matchingRows${matchingRows:+$IFS}$(getIdxRowsEscaped $IDX_ORIGIN "$origin" "$rows")"
- }
- rows="$matchingRows"
- fi
-
- # Either a single origin is matched or
- # it's time to bail out and give up.
- if [ "$(($(echo "$rows" | wc -l)))" -ne "1" ]; then
- # The wrong amount of matches
- # has occured. Bail out.
- error $ERR_ARG "Package identifier <$package> not unambiguously matched!" 1>&2
- fi
- fi
-
- # Output if a package has been matched.
- if [ -n "$rows" ]; then
- # Get the origin of the given package.
- origin="$(getIdxColumn $IDX_ORIGIN "$rows")"
- # Geth the package name.
- package="$(getIdxColumn $IDX_PKG "$rows")"
- # Output origin/package pair.
- echo "${origin#$idxports/};$package"
- else
- error $ERR_ARG "Package identifier <$package> not in index!" 1>&2
- fi
- fi
- ;;
- esac
-}
-
-#
-# Prints the parameter list and terminates the program.
-#
-printHelp() {
- printf "$name v$version
-usage:
- $name -h
- $name -a [-b] [-bcCdfFlnpvX] [-o new existing] [update] [install]
- $name [-bcCdfFlnpvX] [-r [-r]] [-R [-R]] [-o new existing]
- %${#name}s [update] [install]\n" ''
- exit 0
-}
-
-#
-# Parse the command line parameters.
-#
-# @param upgrade
-# A list of packages to upgrade.
-# @param depth
-# This is used by the function to store the recursion depth and
-# should be unset when calling it.
-# @param origin
-# This is used by the function across differtent recursion depths to
-# remember whether a package origin is expected.
-# @param pAll
-# Is set if all packages should be update.
-# @param pNoBackup
-# Is set if backups could not be fetched.
-# @param pClean
-# Is set to turn off status messages.
-# @param pReplaceConflicts
-# Is set to replace conflicting packages with new ones instead of
-# leaving them alone.
-# @param pExitOnConflict
-# Is set to stop the program if a conflict is encountered.
-# @param pForce
-# Is set to force the update of packages that are not really updated.
-# @param pFetchOnly
-# Is set to only fetch packages instead of installing/upgrading them.
-# @param pInteractive
-# TODO: Reserved for future versions (resume/roll-back).
-# @param pJobs
-# TODO: Reserved for future versions (pkg_libchk tests).
-# @param pListDiscarded
-# Is set to activate the listing of packages that are ignored because
-# they are not set in the INDEX.
-# @param pNoActions
-# Is set if no actions should be performed but a list of what would have
-# been done should get printed.
-# @param pNoLogging
-# Turn off logging.
-# @param pParanoid
-# Is set to activate cyclic dependency checks.
-# @param pRecursive
-# Is set to activate updating of dependencies.
-# @param pMoreRecursive
-# Is set to activate updating of dependencies of depending packages.
-# @param pUpwardRecursive
-# Is set to activate updating of depending packages.
-# @param pMoreUpwardRecursive
-# Is set to activate updating of packages depending on dependencies.
-# @param pVerbose
-# Is set to activate informative output.
-#
-readParams() {
- local arg package escapedPkg depth
- # Store the recursion depth. Note that counting down is dealt with
- # by making depth local.
- depth=$((${depth:--1} + 1))
-
- # This is used to remember whether the next parameter should
- # be a replacing package or a packge to be replaced.
- origin=${origin:-0}
-
- for arg {
- #
- # Handle package replacements.
- #
- if [ $origin -eq 1 ]; then
- # Store the replacement.
- package="$(identifyPackage "$arg")" || exit $?
- if [ -z "$package" -o "$(($(echo "$package" | wc -l)))" -ne "1" ]; then
- error $ERR_ARG "The package identifier <$arg> is not unambiguous."
- fi
- upgrade="$upgrade${upgrade:+$IFS}$package"
- replace="$replace${replace:+$IFS}$package"
- origin=2
- # Request the download.
- downloadManagerMsgRequest "$package"
- continue
- fi
- if [ $origin -eq 2 ]; then
- # Store what to replace.
- # This is taken from the package database not the index.
-
- case "$arg" in
- */*)
- # Assume arg is an origin.
- package="$(pkg_info -qO "$arg")"
- package="$(pkg_info -qo "$package" 2> /dev/null);$package"
- ;;
- *)
- # Assume arg is a package identifier.
- package="$(pkg_info -qo "$arg" 2> /dev/null);$(pkg_info -E "$arg" 2> /dev/null)"
-
- # Maybe arg is a package identifier
- # without a version tail.
- if [ "$package" = ";" ]; then
- package="$(pkg_info -qo "$arg-*" 2> /dev/null);$(pkg_info -E "$arg-*" 2> /dev/null)"
- fi
- ;;
- esac
-
- # Arg is not installed.
- if [ "$package" = ";" ]; then
- error $ERR_ARG "The package <$arg> is not installed and thus cannot be replaced."
- fi
- # It appears arg is an identifier that is
- # not unambiguous.
- if [ "$(($(echo "$package" | wc -l)))" -ne "1" ]; then
- error $ERR_ARG "The package identifier <$arg> is not unambiguous."
- fi
- # A package can only be replaced once.
- escapedPkg="$(echo "$package" | getIdxEscape)"
- if echo "$replace" | grep -qEx ".*\|$escapedPkg"; then
- error $ERR_ARG "The package <$arg> is already listed for replacement."
- fi
- replace="$replace|$package"
- origin=0
- continue
- fi
-
- #
- # Identify arguments.
- #
- case "$arg" in
- "-a" | "--all")
- pAll=1
- if [ -n "$pRecursive" ]; then
- error $ERR_ARG "Recursiveness has no effect, because all packages are already selected for processing."
- fi
- if [ -n "$pUpwardRecursive" ]; then
- error $ERR_ARG "Upward recursiveness has no effect, because all packages are already selected for processing."
- fi
- ;;
- "-b" | "--no-backup")
- pNoBackup=1
- ;;
- "-c" | "--clean")
- pClean=-c
- ;;
- "-C" | "--replace-conflicts")
- if [ -n "$pExitOnConflict" ]; then
- error $ERR_ARG "The 'replace conflicts' and 'exit on conflict' modes are mutually exclusive."
- fi
- pReplaceConflicts=1
- ;;
- "-d" | "--list-discarded")
- pListDiscarded=1
- ;;
- "-f" | "--force")
- pForce=1
- ;;
- "-F" | "--fetch-only")
- if [ -n "$pNoActions" ]; then
- error $ERR_ARG "The 'no actions' and 'fetch only' modes are mutually exclusive."
- fi
- pFetchOnly=1
- ;;
- "-h" | "--help")
- printHelp
- ;;
- "-i" | "--interactive")
- # TODO: not yet used
- pInteractive=1
- ;;
- -j* | --jobs*)
- # TODO: not yet used
- pJobs="$arg"
- if ! pkg_libchk "$pJobs" DUMMY/DUMMY 1>&2; then
- exit $ERR_ARG
- fi
- ;;
- "-l" | "--no-logging")
- pNoLogging=1
- ;;
- "-n" | "--no-actions")
- if [ -n "$pFetchOnly" ]; then
- error $ERR_ARG "The 'no actions' and 'fetch only' modes are mutually exclusive."
- fi
- pNoActions=1
- ;;
- "-o" | "--origin")
- # Make sure the local index copy is up to date.
- getIndex
- origin=1
- ;;
- "-p" | "--paranoid")
- pParanoid=1
- ;;
- "-r" | "--recursive")
- if [ -n "$pMoreRecursive" ]; then
- error $ERR_ARG "There are only two levels of recursiveness."
- elif [ -n "$pRecursive" ]; then
- pMoreRecursive=1
- else
- pRecursive=1
- fi
- if [ -n "$pAll" ]; then
- error $ERR_ARG "Recursiveness has no effect, because all packages are already selected for processing."
- fi
- ;;
- "-R" | "--upward-recursive")
- if [ -n "$pMoreUpwardRecursive" ]; then
- error $ERR_ARG "There are only two levels of upward recursiveness."
- elif [ -n "$pUpwardRecursive" ]; then
- pMoreUpwardRecursive=1
- else
- pUpwardRecursive=1
- fi
- if [ -n "$pAll" ]; then
- error $ERR_ARG "Upward recursiveness has no effect, because all packages are already selected for processing."
- fi
- ;;
- "-v" | "--verbose")
- pVerbose=-v
- ;;
- "-X" | "--exit-on-conflict")
- if [ -n "$pReplaceConflicts" ]; then
- error $ERR_ARG "The 'exit on conflict' and 'replace conflicts' modes are mutually exclusive."
- fi
- pExitOnConflict=1
- ;;
- -? | --*)
- error $ERR_ARG "Unknown parameter \"$arg\"."
- ;;
- -*)
- # Split parmeters.
- readParams "${arg%%${arg#-?}}" "-${arg#-?}"
- ;;
- *)
- # Make sure the local index copy is up to date.
- getIndex
- # Add package to the list of packages to
- # upgrade/install.
- package="$(identifyPackage "$arg")" || exit $?
- upgrade="$upgrade${upgrade:+$IFS}$package"
- # Request the download.
- downloadManagerMsgRequest "$package"
- ;;
- esac
- }
-
- #
- # Only perform the following steps if this is the root call
- # to this function (recursion depth = 0).
- #
- if [ $depth -eq 0 ]; then
- #
- # Deal with missing parameters.
- #
- if [ $origin -eq 1 ]; then
- error $ERR_ARG "Incomplete parameters, missing origin."
- fi
- if [ $origin -eq 2 ]; then
- error $ERR_ARG "Incomplete parameters, missing package to replace."
- fi
-
- #
- # Deal with invalid levels of recursiveness.
- #
- if [ -n "$pMoreRecursive" -a -z "$pUpwardRecursive" ]; then
- error $ERR_ARG "Thorough recursiveness can only be used in conjunction with upwards recursiveness."
- fi
-
- #
- # Remove duplicates in the list of packages to upgrade.
- #
- upgrade="$(echo "$upgrade" | sort -u)"
- # Reset global variables.
- origin=
- fi
-}
-
-#
-# Reads all the required +CONTENTS information from a package.
-# The information is stored in variables.
-#
-# @param 1
-# The name of the package file.
-# @param pkgname
-# The name of the package.
-# @param origin
-# The origin of the package.
-# @param depends
-# The dependencies of the package in the format "<origin>;<package>",
-# in reverse order.
-# @param conflicts
-# A list of regular expressions that can be used to identify conflicting
-# packages.
-#
-readContents() {
- local contents line format
- contents="$(tar -xOf "$1" '+CONTENTS')"
- format=
-
- pkgname=
- origin=
- depends=
- conflicts=
- for line in $contents; {
- case "$line" in
- @name\ *)
- pkgname="${line#@name }"
- ;;
- @pkgdep\ *)
- depends=";${line#@pkgdep }${depends:+$IFS}$depends"
- ;;
- @comment\ *)
- line="${line#@comment }"
- case "$line" in
- DEPORIGIN:*)
- depends="${line#*:}$depends"
- ;;
- PKG_FORMAT_REVISION:*)
- format="${line#*:}"
- ;;
- ORIGIN:*)
- origin="${line#*:}"
- ;;
- esac
- ;;
- @conflicts\ *)
- conflicts="${conflicts:+$conflicts$IFS}${line#@conflicts }"
- ;;
- esac
- }
-
- if [ "$format" != "1.1" ]; then
- error $ERR_PACKAGE_FORMAT "Unknown package format in <$1>, bailing out!"
- fi
-
- return 0
-}
-
-#
-# Starts a download manager that can be instructed through a queue.
-# A process that wants to know what's going on with the download manager
-# can simply read from the queue as well.
-#
-# The download manager keeps as many downloads running as there are
-# PACKAGESITE_MIRRORS. Should a download fail, it is retried as soon
-# as no untried downloads remain. Every download is only retried once.
-# A download is never attempted from the master server.
-#
-# @param queueMessages
-# The queue to create and read from.
-# @param packagerepos
-# The location of the remote package repository (derived from
-# PACKAGESITE). If this is identical with the local repository,
-# the download manager will not be started.
-# @param pNoActions
-# If set, the download manager will not be started.
-#
-downloadManager() {
- # No actions mode, this includes no downloads.
- test -n "$pNoActions" && return 0
-
- # Packages are locally available, no downloads.
- test "$PACKAGES" = "$packagerepos" && return 0
-
- verbose "Start the download manager."
-
- # Initialize the queue.
- rm "$queueMessages" 2> /dev/null
- touch "$queueMessages"
-
- #
- # The following block is forked away.
- # Note that all variable assignments happen in a separate process
- # and hence have no effect on the outside.
- #
- (
- # Remove the queue when exiting and get rid of pending jobs.
- trap "
- kill \$(jobs -ls) > /dev/null 2>&1
- rm '$queueMessages' 2> /dev/null
- exit
- " EXIT sigint sigterm
-
- # The jobs yet to be done.
- jobs=
- # The available mirrors.
- mirrors="$PACKAGESITE_MIRRORS"
- # The jobs that should be retried.
- retry=
- # The jobs that have been retried.
- retried=
- # The last line read from the socket.
- line=
-
- # Keep on running as long as the father process is around.
- # Note that this while loop has the message queue as stdin.
- while kill -0 "$pid" 2> /dev/null; do
- # Check for a message in the queue.
- # There is nothing to be done, if there was no message,
- # none the less it times out to allow the terminal
- # to catch signals.
- read -t 2 line
- # Process messages.
- case "$line" in
- finished:*)
- # A download has been finished.
- # Add the mirror that was used to
- # the list of available mirrors.
- mirror="${line#finished:}"
- mirror="${mirror%;*}"
- mirrors="${mirrors:+$mirrors$IFS}$mirror"
- ;;
- retry:*)
- # A download was not finished
- # successfuly.
- mirror="${line#retry:}"
- job="${mirror##*;}"
- mirror="${mirror%;*}"
- if echo "$retried" | grep -qFx "$job"; then
- # If this package has already
- # had a retry, mark it as
- # finished to hand it over
- # to the package validation
- # that can fetch from the
- # master server.
- downloadManagerMsgFinished "$mirror" "$job"
- else
- # The first retry request.
- # Free the mirror and list
- # the package for retry.
- mirrors="${mirrors:+$mirrors$IFS}$mirror"
- retry="${retry:+$retry$IFS}$job"
- fi
- ;;
- request:*)
- # Append requested downloads to the
- # list of available jobs.
- jobs="${jobs:+$jobs$IFS}${line#request:}"
- ;;
- exit)
- # The download manager has been told
- # to terminate.
- break
- ;;
- esac
- # Delete the line, so it cannot be read again in the
- # next iteration, if reading from the queue has
- # timed out.
- line=
-
- # If any mirrors are available and there are jobs
- # in the queue, now is the time to dispatch them.
- while [ -n "$jobs" -a -n "$mirrors" ]; do
- mirror="${mirrors%%$IFS*}"
- mirrors="${mirrors#$mirror}"
- mirrors="${mirrors#$IFS}"
- job="${jobs%%$IFS*}"
- jobs="${jobs#$job}"
- jobs="${jobs#$IFS}"
- downloadManagerFetch "$mirror" "$job" &
- done
-
- # If we have run out of jobs, give the retry stuff.
- # a try.
- while [ -n "$retry" -a -n "$mirrors" ]; do
- mirror="${mirrors%%$IFS*}"
- mirrors="${mirrors#$mirror}"
- mirrors="${mirrors#$IFS}"
- job="${retry%%$IFS*}"
- retry="${retry#$job}"
- retry="${retry#$IFS}"
- # Remember that this job has been retried.
- retried="${retried:+$retried$IFS}$job"
- downloadManagerFetch "$mirror" "$job" &
- done
- done < "$queueMessages"
- ) &
-}
-
-#
-# This is forked off by the download manager to download a package from
-# a mirror.
-# If the package is already present a download is not attempted.
-#
-# @param 1
-# The mirror to download from.
-# @param 2
-# The name of the package to download.
-#
-downloadManagerFetch() {
- # Get rid of pending jobs.
- trap "
- kill \$(jobs -ls) > /dev/null 2>&1
- exit
- " EXIT sigint sigterm
-
- # Only do something if the package is not present.
- if ! [ -e "$PACKAGES/All/$2.tbz" ]; then
- # Create the download location.
- mkdir -p "$PACKAGES/All" 2> /dev/null
-
- # Attempt download from mirror.
- # This is forked off, to allow the shell to catch signals.
- fetch -qmo "$PACKAGES/All/$2.tbz" "${1%/*?}/All/$2.tbz" > /dev/null 2>&1 &
- if ! wait $!; then
- # Release the mirror and mark the package for a retry.
- downloadManagerMsgRetry "$1" "$2"
- return 0
- fi
- fi
-
- # Release the mirror and mark package finished.
- downloadManagerMsgFinished "$1" "$2"
-}
-
-#
-# Tells the download manager, that a download was unsuccessful.
-#
-# @param 1
-# The mirror that was used.
-# @param 2
-# The name of the package that was not downloaded.
-# @param queueMessages
-# The message queue to the download manager.
-#
-downloadManagerMsgRetry() {
- # Do not send anything without a queue.
- test ! -e "$queueMessages" && return 0
-
- lockf -k "$queueMessages" sh -c "echo 'retry:$1;$2' >> '$queueMessages'"
-}
-
-#
-# Tells the download manager, that a download has been finished.
-#
-# @param 1
-# The mirror that was used.
-# @param 2
-# The name of the downloaded package.
-# @param queueMessages
-# The message queue to the download manager.
-#
-downloadManagerMsgFinished() {
- # Do not send anything without a queue.
- test ! -e "$queueMessages" && return 0
-
- lockf -k "$queueMessages" sh -c "echo 'finished:$1;$2' >> '$queueMessages'"
-}
-
-#
-# Requests the download of packages from the download manager.
-#
-# @param 1
-# A list of packages for download.
-# @param queueMessages
-# The message queue to the download manager.
-#
-downloadManagerMsgRequest() {
- # Do not send anything without a queue.
- test ! -e "$queueMessages" && return 0
-
- local request
- for request in $1; {
- lockf -k "$queueMessages" sh -c "echo 'request:${request#*;}' >> '$queueMessages'"
- }
-}
-
-#
-# Instructs the download manager to terminate.
-#
-# @param queueMessages
-# The message queue to the download manager.
-#
-downloadManagerMsgExit() {
- # Do not send anything without a queue.
- test ! -e "$queueMessages" && return 0
-
- lockf -k "$queueMessages" sh -c "echo 'exit' >> '$queueMessages'"
-}
-
-#
-# Validates a single package. Validation means it checks whether a package
-# is a complete tar archive. Damaged or missing packages will be (re)downloaded
-# from the master server (the one named by PACKAGESITE).
-# If the package is a valid tar archive the +CONTENTS file will be checked,
-# as well.
-#
-# @param 1
-# The name of the package to validate.
-# @param packagerepos
-# The location of the remote package collection. This is derived from
-# PACKAGESITE.
-# @param pending
-# The list of pending packages.
-# @return
-# Return 0 on success.
-#
-validatePackage() {
- local package
- package="$1.tbz"
-
- # Check whether the package is intact and present.
- if ! tar -tf "$PACKAGES/All/$package" > /dev/null 2>&1; then
- # If the package repository and the local package collection
- # are identical, there's no chance to get the package if it's
- # not already there.
- if [ "$PACKAGES" = "$packagerepos" ]; then
- error $ERR_FETCH "The package <$package> is not present."
- fi
-
- # Clean up whatever crap is there.
- rm "$PACKAGES/All/$package" 2> /dev/null
-
- # Try to get the package from the master server.
- fetch -mo "$PACKAGES/All/$package" "$packagerepos/All/$package"
-
- # Check whether the package is present.
- if ! [ -e "$PACKAGES/All/$package" ]; then
- error $ERR_FETCH "The package <$package> could not be fetched."
- fi
-
- # Check whether the package is a valid tar archive.
- if ! tar -tf "$PACKAGES/All/$package" > /dev/null 2>&1; then
- error $ERR_FETCH "The package <$package> could not be read."
- fi
- fi
-
- # Check whether we can read the package +CONTENTS format.
- readContents "$PACKAGES/All/$package"
-
- # Remove this package from the list of pending packages.
- pending="$(echo "$pending" | grep -vFx "$1")"
-
- # The package is present and intact.
- return 0
-}
-
-#
-# Let's get it on! The declarative part is finally over.
-#
-
-# Ignore some signals that should not occur.
-trap 'warn "Discard signal SIGHUP."' sighup
-trap 'warn "Discard signal SIGUSR1."' sigusr1
-trap 'warn "Discard signal SIGUSR2."' sigusr2
-
-#
-# Parse command line parameters.
-#
-readParams "$@"
-
-# Make sure the index is available for the following operations.
-getIndex
-
-#
-# Populate the list of packages out of sync with the index.
-#
-pkgAll
-
-#
-# Perform dependency checking.
-#
-pkgDependencies
-
-#
-# Sort packages by their dependencies.
-#
-pkgSort
-
-#
-# Display tasks.
-#
-pkgList
-
-#
-# Download packages.
-#
-pkgDownload
-
-#
-# Upgrade packages.
-#
-pkgUpgrade
-
-exit 0
Index: head/sysutils/bsdadminscripts/files/uma.in
===================================================================
--- head/sysutils/bsdadminscripts/files/uma.in
+++ head/sysutils/bsdadminscripts/files/uma.in
@@ -1,436 +0,0 @@
-#!/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
-
Index: head/sysutils/bsdadminscripts/pkg-descr
===================================================================
--- head/sysutils/bsdadminscripts/pkg-descr
+++ head/sysutils/bsdadminscripts/pkg-descr
@@ -1,7 +0,0 @@
-This is a collection of administration scripts. At the moment it
-consists of a script to control rc.d scripts at runtime, a
-script that runs common make targets on batches of ports, scripts to set
-variables for make jobs (like portconf, but with more possibilities).
-And scripts to check for broken packages and missing libraries.
-
-WWW: https://sourceforge.net/projects/bsdadminscripts/
Index: head/sysutils/bsdadminscripts/pkg-plist
===================================================================
--- head/sysutils/bsdadminscripts/pkg-plist
+++ head/sysutils/bsdadminscripts/pkg-plist
@@ -1,35 +0,0 @@
-sbin/distviper
-sbin/pkg_libchk
-sbin/pkg_upgrade
-sbin/pkg_validate
-sbin/portconfig
-sbin/rcstart
-sbin/uma
-sbin/rcstatus
-sbin/rcstop
-sbin/rcrestart
-sbin/rconestart
-sbin/rconestatus
-sbin/rconestop
-sbin/rconerestart
-sbin/portbuild
-sbin/portclean
-sbin/portfetch
-sbin/portpackage
-sbin/portconfig-recursive
-sbin/portfetch-recursive
-man/man1/bsdadminscripts.1.gz
-man/man1/buildflags.awk.1.gz
-man/man1/buildflags.conf.1.gz
-man/man1/buildflags.mk.1.gz
-man/man1/distviper.1.gz
-man/man1/pkg_libchk.1.gz
-man/man1/pkg_upgrade.1.gz
-man/man1/pkg_validate.1.gz
-man/man1/portconfig.1.gz
-man/man1/rcstart.1.gz
-man/man1/uma.1.gz
-%%ETCDIR%%/buildflags.conf.sample
-%%ETCDIR%%/uma.conf.sample
-%%DATADIR%%/buildflags.awk
-%%DATADIR%%/buildflags.mk
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Mon, Mar 16, 8:12 PM (15 h, 43 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
29785388
Default Alt Text
D9434.diff (202 KB)
Attached To
Mode
D9434: new port: ports-mgmt/bsdadminscripts2
Attached
Detach File
Event Timeline
Log In to Comment