diff options
Diffstat (limited to 'testing/source/pkgtools/scripts/upgradepkg')
-rw-r--r-- | testing/source/pkgtools/scripts/upgradepkg | 417 |
1 files changed, 417 insertions, 0 deletions
diff --git a/testing/source/pkgtools/scripts/upgradepkg b/testing/source/pkgtools/scripts/upgradepkg new file mode 100644 index 00000000..f53d21d9 --- /dev/null +++ b/testing/source/pkgtools/scripts/upgradepkg @@ -0,0 +1,417 @@ +#!/bin/bash +# Copyright 1999 Patrick Volkerding, Moorhead, Minnesota, USA +# Copyright 2001, 2002, 2003 Slackware Linux, Inc., Concord, California, USA +# Copyright 2009, 2015 Patrick J. Volkerding, Sebeka, MN, USA +# Copyright 2015 Michal Nazarewicz <mina86@mina86.com> +# All rights reserved. +# +# Redistribution and use of this script, with or without modification, is +# permitted provided that the following conditions are met: +# +# 1. Redistributions of this script 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. +# +# Mon Jun 4 21:17:58 UTC 2018 +# Use /var/lib/pkgtools, not /var/log. +# +# Thu May 24 20:23:55 UTC 2018 +# Added --terselength option to set the line length in --terse mode. +# Use a lockfile to prevent output collisions in --terse mode. +# +# Wed May 23 03:35:28 UTC 2018 +# Added --terse, which limits screen output to one line per package. +# +# Sat 17 Jan 16:21:32 UTC 2015 mina86 +# Various optimisation mostly resolving around avoiding having to fork +# and call cut, basename and other helper commands. Slight +# refactoring of code calling removepkg. +# +# Sat Apr 25 21:18:53 UTC 2009 +# Support new compression types and package extensions. +# Converted to use new pkgbase() function to remove pathname and +# valid package extensions. +# +# Added --dry-run, Sat Apr 26 18:13:29 PDT 2003 +# +# Added --install-new and --reinstall, Fri May 31 14:11:14 PDT 2002 volkerdi +# +# Rewritten to clean out _all_ old packages of a given basename, not just +# the first one found, Thu Apr 4 01:01:05 PST 2002 volkerdi +# +# Modified to handle either old 8.3 or new package-version-arch-build.tgz +# packages, Sat Nov 17 14:25:58 PST 2001 volkerdi + +# Return a package name that has been stripped of the dirname portion +# and any of the valid extensions (only): +pkgbase() { + PKGRETURN=${1##*/} + case "$PKGRETURN" in *.t[gblx]z) + PKGRETURN=${PKGRETURN%.*} + esac + echo "$PKGRETURN" +} + +usage() { + cat << EOF + +Usage: upgradepkg [options] <newpackage> ... + upgradepkg [options] <oldpackage%newpackage> ... + +Upgrade, install, or reinstall Slackware packages (.tgz, .tbz, .tlz, .txz). + +To operate on an alternate directory, such as /mnt: + ROOT=/mnt upgradepkg package.txz + +Options: + --dry-run only display what would be done + --install-new install new packages also + --reinstall upgrade packages of the same version + --terse display a single line for each package operation + --terselength <length> maximum line length of terse output + --verbose display all the gory details of the upgrade + --help display this help + +For more details see upgradepkg(8). +EOF +} + +# Set the prefix for the package database directories (packages, scripts). +ADM_DIR="$ROOT/var/lib/pkgtools" + +# Make sure there's a proper temp directory: +TMP=$ADM_DIR/setup/tmp +# If the $TMP directory doesn't exist, create it: +if [ ! -d $TMP ]; then + mkdir -p $TMP + chmod 700 $TMP # no need to leave it open +fi + +# This script expects an 022 umask: +umask 022 + +# $ROOT defined? +if [ -d "$ROOT" ]; then + export ROOT +else + unset ROOT +fi + +# --help or no args? +if [ "$1" = "" -o "$1" = "-help" -o "$1" = "--help" -o "$1" = "-?" ]; then + usage; + exit 1; +fi + +# Create a lockfile directory if it doesn't exist. We can use it to prevent +# output line collisions in --terse mode. +INSTLOCKDIR=${INSTLOCKDIR:-/run/lock/pkgtools} +if [ ! -d $INSTLOCKDIR ]; then + mkdir -p $INSTLOCKDIR +fi + +# Set default line length for terse mode: +if tty -s && which tput 1> /dev/null 2> /dev/null ; then + TERSELENGTH=$(tput cols) +else + TERSELENGTH=80 +fi + +# Arg processing loop. These must come before any packages are listed. +while [ 0 ]; do + if [ "$1" = "-no-paranoia" -o "$1" = "--no-paranoia" ]; then + # Enable --no-paranoia mode. This is so not-recommended that we're + # not even going to document it. ;) If a file used to be directly + # managed and now is moved into place, using --no-paranoia will cause + # it to improperly disappear. It does slightly speed things up, though. + # Don't use it. + NOT_PARANOID="true" + shift 1 + elif [ "$1" = "-install-new" -o "$1" = "--install-new" ]; then + # Install packages that do not already have an installed version. + # The usual default is to skip them. + INSTALL_NEW="yes" + shift 1 + elif [ "$1" = "-reinstall" -o "$1" = "--reinstall" ]; then + # Reinstall packages even if the installed one is the same version. + REINSTALL="true" + shift 1 + elif [ "$1" = "-verbose" -o "$1" = "--verbose" -o "$1" = "-v" ]; then + # We're adding a --verbose mode that doesn't filter removepkg as much + VERBOSE="verbose" + shift 1 + elif [ "$1" = "-dry-run" -o "$1" = "--dry-run" ]; then + # Output a report about which packages would be installed or upgraded + # but don't actually perform the upgrades. + DRY_RUN="true" + shift 1 + elif [ "$1" = "-terse" -o "$1" = "--terse" ]; then + # Output one line per installed/upgraded package by calling installpkg + # with --terse. Use TERSE=0 for true, so we can check with test. + TERSE=0 + shift 1 + elif [ "$1" = "-terselength" -o "$1" = "--terselength" ]; then + # Set line length in --terse mode: + TERSELENGTH=$2 + shift 2 + else # no more args + break; + fi +done # processing args + +# A couple not-really-documented features to adjust the behavior of --terse +# mode. These need to be used in addition to --terse, and passed in as +# environment variables. +# PLAINTERSE=0 (This outputs the standard terse line from installpkg, rather +# than prefixing it with "Upgrading:" or "Installing:") +# INFOBOX=0 (This outputs the installpkg --infobox instead of a terse line) + +# Here's a function to figure out the package name from one of those +# new long filenames. We'll need this to double check the name of the +# old package. + +package_name() { + STRING=$(pkgbase "$1") + case "$STRING" in + *-*-*-*) + # At least four segments, strip version arch and build and return name: + echo "${STRING%-*-*-*}" + # cruft for later ;) + # BUILD=${STRING##*-} + # STRING=${STRING%*-} + # ARCH=${STRING##*-} + # STRING=${STRING%*-} + # VER=${STRING%*-} + ;; + *) + # Old style package name with one segment or we don't have four + # segments: return the old-style (or out of spec) package name. + echo $STRING + esac +} + +ERRCODE=0 + +# Main processing loop: +for ARG; do + OLD=${ARG%'%'*} # first segment, = $ARG if no % + NEW=${ARG#*'%'} # second segment, = $ARG if no % + + # Simple package integrity check: + if ! [ -f "$NEW" ]; then + ERRCODE=4 + echo "Cannot install $NEW: file not found" + continue; + fi + + # Figure out the names of the old and new packages: + INCOMINGDIR=$(dirname $NEW) + # These are the package names with the extension: + NNAME=${NEW##*/} + ONAME=${OLD##*/} + # These are the package names without the extension: + OLD=$(pkgbase $OLD) + NEW=$(pkgbase $NEW) + + # Make sure the extension is valid: + if [ "$NNAME" = "$NEW" ]; then + # We won't throw an ERRCODE for this, but the package is skipped: + echo "Cannot install $OLD: invalid package extension" + continue; + fi + + # Check and fix the old package name: + SHORT="$(package_name $OLD)" + if [ ! -r $ADM_DIR/packages/$OLD ]; then + if ls $ADM_DIR/packages/$SHORT* 1> /dev/null 2> /dev/null ; then + for installed_package in $ADM_DIR/packages/$SHORT* ; do + if [ "$(package_name $installed_package)" = "$SHORT" ]; then # found one + OLD="${installed_package##*/}" + break + fi + done + fi + fi + + # Test to see if both the old and new packages are where we expect them + # to be - skip to the next package (or package pair) if anything's wrong: + + if [ ! -r $ADM_DIR/packages/$OLD ]; then + if [ ! "$INSTALL_NEW" = "yes" ]; then + if [ "$DRY_RUN" = "true" ]; then + echo "$OLD would not be upgraded (no installed package named $SHORT)." + else + ! [ $TERSE ] && echo + echo "Error: there is no installed package named $OLD." + ! [ $TERSE ] && echo " (looking for $ADM_DIR/packages/$OLD)" + ! [ $TERSE ] && echo + fi + ERRCODE=1 + else # --install-new was given, so install the new package: + if [ "$DRY_RUN" = "true" ]; then + echo "$NEW would be installed (new package)." + else + if [ $PLAINTERSE ]; then + /sbin/installpkg --terse --terselength $TERSELENGTH $INCOMINGDIR/$NNAME + elif [ $INFOBOX ]; then + /sbin/installpkg --infobox $INCOMINGDIR/$NNAME + elif [ $TERSE ]; then + OUTPUTLINE="$(/sbin/installpkg --terse --terselength $(expr $TERSELENGTH - 12) $INCOMINGDIR/$NNAME)" + ( flock 9 || exit 11 + echo "Installing: ${OUTPUTLINE}" + ) 9> $INSTLOCKDIR/outputline.lock + else + cat << EOF + ++============================================================================== +| Installing new package $INCOMINGDIR/$NNAME ++============================================================================== + +EOF + /sbin/installpkg $INCOMINGDIR/$NNAME + fi + fi + fi + continue; + elif [ ! -r "$INCOMINGDIR/$NNAME" ]; then + if [ "$DRY_RUN" = "true" ]; then + echo "$NEW incoming package not found (command line)." + else + ! [ $TERSE ] && echo + echo "Error: incoming package $INCOMINGDIR/$NNAME not found." + ! [ $TERSE ] && echo + fi + ERRCODE=1 + continue; + fi + + # Unless --reinstall was given, compare the package names + # and skip any exact matches: + if [ ! "$REINSTALL" = "true" ]; then + if [ "$OLD" = "$NEW" ]; then + if [ "$DRY_RUN" = "true" ]; then + echo "$NEW would be skipped (already installed)." + else + if ! [ $TERSE ]; then + cat << EOF + ++============================================================================== +| Skipping package $NEW (already installed) ++============================================================================== + +EOF + fi + fi + continue; + fi + fi + + # Showtime. Let's do the upgrade. First, we will rename all the + # installed packages with this basename to make them easy to remove later: + + TIMESTAMP=$(date +%Y-%m-%d,%T) + SHORT="$(package_name $OLD)" + if [ "$DRY_RUN" = "true" ]; then + echo -n "$NEW would upgrade: " + for installed_package in $ADM_DIR/packages/$SHORT* ; do + if [ "$(package_name $installed_package)" = "$SHORT" ]; then + echo -n "$(pkgbase $installed_package)" + fi + done + echo + continue + fi + for installed_package in $ADM_DIR/packages/$SHORT* ; do + if [ "$(package_name $installed_package)" = "$SHORT" ]; then + mv $installed_package ${installed_package}-upgraded-$TIMESTAMP + fi + done + for installed_script in $ADM_DIR/scripts/$SHORT* ; do + if [ "$(package_name $installed_script)" = "$SHORT" ]; then + if [ -r $installed_script ]; then + mv $installed_script ${installed_script}-upgraded-$TIMESTAMP + fi + fi + done + + # Print a banner for the current upgrade: + if ! [ $TERSE ]; then + cat << EOF + ++============================================================================== +| Upgrading $OLD package using $INCOMINGDIR/$NNAME ++============================================================================== +EOF + fi + # Next, the new package is pre-installed: + if [ "$VERBOSE" = "verbose" ]; then + if ! [ $TERSE ]; then + /sbin/installpkg $INCOMINGDIR/$NNAME + RETCODE=$? + else + /sbin/installpkg $INCOMINGDIR/$NNAME 1> /dev/null + RETCODE=$? + fi + else + if [ $PLAINTERSE ]; then + /sbin/installpkg --terse --terselength $TERSELENGTH $INCOMINGDIR/$NNAME + elif [ $INFOBOX ]; then + /sbin/installpkg --infobox $INCOMINGDIR/$NNAME + elif [ $TERSE ]; then + OUTPUTLINE="$(/sbin/installpkg --terse --terselength $(expr $TERSELENGTH - 12) $INCOMINGDIR/$NNAME)" + RETCODE=$? + ( flock 9 || exit 11 + echo "Upgrading: ${OUTPUTLINE}" + ) 9> $INSTLOCKDIR/outputline.lock + else + echo "Pre-installing package $NEW..." + /sbin/installpkg $INCOMINGDIR/$NNAME 1> /dev/null + RETCODE=$? + fi + fi + # Make sure that worked: + if [ ! $RETCODE = 0 ]; then + echo "ERROR: Package $INCOMINGDIR/$NNAME did not install" + echo "correctly. You may need to reinstall your old package" + echo "to avoid problems. Make sure the new package is not" + echo "corrupted." + sleep 15 + # Skip this package, but still try to proceed. Good luck... + continue; + fi + # Now, the leftovers from the old package(s) can go. Pretty simple, huh? :) + ( flock 9 || exit 11 + for rempkg in "$ADM_DIR/packages/"*"-$TIMESTAMP"; do + if [ "$VERBOSE" = "verbose" ]; then + /sbin/removepkg "${rempkg##*/}" + elif ! [ $TERSE ]; then + /sbin/removepkg "${rempkg##*/}" | grep -v 'Skipping\.\|Removing files:' + else + /sbin/removepkg "${rempkg##*/}" > /dev/null + fi + done + ) 9> $INSTLOCKDIR/removepkg.lock + # Again! Again! + # Seriously, the reinstalling of a package can be crucial if any files + # shift location, so we should always reinstall as the final step: + if [ ! "$NOT_PARANOID" = "true" ]; then + if ! [ $TERSE ]; then + /sbin/installpkg $INCOMINGDIR/$NNAME + else + /sbin/installpkg $INCOMINGDIR/$NNAME 1> /dev/null + fi + fi + ! [ $TERSE ] && echo "Package $OLD upgraded with new package $INCOMINGDIR/$NNAME." + ERRCODE=0 +done +exit $ERRCODE |