From owner-svn-ports-head@FreeBSD.ORG Tue Aug 26 18:57:58 2014 Return-Path: Delivered-To: svn-ports-head@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:1900:2254:206a::19:1]) (using TLSv1 with cipher ADH-AES256-SHA (256/256 bits)) (No client certificate requested) by hub.freebsd.org (Postfix) with ESMTPS id 02F936A6; Tue, 26 Aug 2014 18:57:58 +0000 (UTC) Received: from svn.freebsd.org (svn.freebsd.org [IPv6:2001:1900:2254:2068::e6a:0]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (Client did not present a certificate) by mx1.freebsd.org (Postfix) with ESMTPS id E18DB3A9C; Tue, 26 Aug 2014 18:57:57 +0000 (UTC) Received: from svn.freebsd.org ([127.0.1.70]) by svn.freebsd.org (8.14.9/8.14.9) with ESMTP id s7QIvvPX051127; Tue, 26 Aug 2014 18:57:57 GMT (envelope-from rene@FreeBSD.org) Received: (from rene@localhost) by svn.freebsd.org (8.14.9/8.14.9/Submit) id s7QIvvxJ051123; Tue, 26 Aug 2014 18:57:57 GMT (envelope-from rene@FreeBSD.org) Message-Id: <201408261857.s7QIvvxJ051123@svn.freebsd.org> X-Authentication-Warning: svn.freebsd.org: rene set sender to rene@FreeBSD.org using -f From: Rene Ladan Date: Tue, 26 Aug 2014 18:57:57 +0000 (UTC) To: ports-committers@freebsd.org, svn-ports-all@freebsd.org, svn-ports-head@freebsd.org Subject: svn commit: r366248 - in head/sysutils/bsdadminscripts: . files X-SVN-Group: ports-head MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-BeenThere: svn-ports-head@freebsd.org X-Mailman-Version: 2.1.18-1 Precedence: list List-Id: SVN commit messages for the ports tree for head List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Tue, 26 Aug 2014 18:57:58 -0000 Author: rene Date: Tue Aug 26 18:57:57 2014 New Revision: 366248 URL: http://svnweb.freebsd.org/changeset/ports/366248 QAT: https://qat.redports.org/buildarchive/r366248/ Log: sysutils/bsdadminscripts: fix scripts at runtime. Previously, pkg_libchk, pkg_upgrade, and uma failed to run. Bump PORTREVISION PR: 193003 Submitted by: Carlos Jacobo Puga Medina Reviewed by: marino Added: head/sysutils/bsdadminscripts/files/pkg_libchk.in (contents, props changed) head/sysutils/bsdadminscripts/files/pkg_upgrade.in (contents, props changed) head/sysutils/bsdadminscripts/files/uma.in (contents, props changed) Deleted: head/sysutils/bsdadminscripts/files/patch-pkg_libchk Modified: head/sysutils/bsdadminscripts/Makefile Modified: head/sysutils/bsdadminscripts/Makefile ============================================================================== --- head/sysutils/bsdadminscripts/Makefile Tue Aug 26 18:55:22 2014 (r366247) +++ head/sysutils/bsdadminscripts/Makefile Tue Aug 26 18:57:57 2014 (r366248) @@ -3,7 +3,7 @@ PORTNAME= bsdadminscripts PORTVERSION= 6.1.1 -PORTREVISION= 6 +PORTREVISION= 7 CATEGORIES= sysutils ports-mgmt MASTER_SITES= SF/${PORTNAME}/${PORTNAME} @@ -13,10 +13,17 @@ COMMENT= Collection of administration sc LICENSE= BSD2CLAUSE NO_BUILD= yes + +TMP?= /tmp +VAR?= /var + PORTDOCS= ABOUT CHANGES INSTALL NOTES THANKS OPTIONS_DEFINE= DOCS +SUB_FILES= pkg_libchk pkg_upgrade uma +SUB_LIST= TMP=${TMP} PREFIX=${PREFIX} VAR=${VAR} PORTS=${PORTSDIR} + .include .if ! ${PORT_OPTIONS:MDOCS} @@ -31,12 +38,14 @@ do-install: -datadir=${STAGEDIR}${DATADIR} \ ${EVALDOCS} .for n in 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 @@ -46,6 +55,7 @@ post-install: ${MKDIR} ${STAGEDIR}${ETCDIR} ${MV} ${STAGEDIR}${PREFIX}/etc/*.sample ${STAGEDIR}${ETCDIR} ${RM} -rf ${STAGEDIR}${PREFIX}/etc/*.sample + .if ${PORT_OPTIONS:MDOCS} ${MKDIR} ${STAGEDIR}${DOCSDIR} cd ${WRKSRC} && ${INSTALL_DATA} ${PORTDOCS} ${STAGEDIR}${DOCSDIR} Added: head/sysutils/bsdadminscripts/files/pkg_libchk.in ============================================================================== --- /dev/null 00:00:00 1970 (empty, because file is newly added) +++ head/sysutils/bsdadminscripts/files/pkg_libchk.in Tue Aug 26 18:57:57 2014 (r366248) @@ -0,0 +1,484 @@ +#!/bin/sh -f +# +# Copyright (c) 2007-2009 +# Dominic Fandrey +# +# 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 Added: head/sysutils/bsdadminscripts/files/pkg_upgrade.in ============================================================================== --- /dev/null 00:00:00 1970 (empty, because file is newly added) +++ head/sysutils/bsdadminscripts/files/pkg_upgrade.in Tue Aug 26 18:57:57 2014 (r366248) @@ -0,0 +1,2239 @@ +#!/bin/sh -f +# +# Copyright (c) 2009 +# Dominic Fandrey +# +# 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. +# + +# ; +upgrade= +upgradeDepends= +upgradeDepending= + +# The ; part can also be found in $upgrade. +# ;|; +replace= + +# A list of dependency substitutions for new packages. +# ;|; +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. +# +# - - (|DONE): +# +# 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 *** DIFF OUTPUT TRUNCATED AT 1000 LINES ***