#!/bin/bash # # apt-fast v1.9 # Use this just like aptitude or apt-get for faster package downloading. # # Copyright: 2008-2012 Matt Parnell, http://www.mattparnell.com # Improvements, maintenance, revisions - 2012, 2017-2018 Dominique Lasserre # # You may distribute this file under the terms of the GNU General # Public License as published by the Free Software Foundation; either # version 3 of the License, or (at your option) any later version. # [ -n "$DEBUG" ] && set -xv # Print colored messages. # Usage: msg "message text" "message type" "optional: err" # Message types are 'normal', 'hint' or 'warning'. Warnings and messages with a # third argument are piped to stderr. msg(){ msg_options=() case "$2" in normal) beginColor="$cGreen";; hint) beginColor="$cBlue";; warning) beginColor="$cRed";; question) beginColor="$cRed"; msg_options=(-n);; *) beginColor= ;; esac if [ -z "$3" ] && [ "$2" != "warning" ]; then echo -e "${msg_options[@]}" "${aptfast_prefix}${beginColor}$1${endColor}" else echo -e "${msg_options[@]}" "${aptfast_prefix}${beginColor}$1${endColor}" >&2 fi } # Search for known options and decide if root privileges are needed. root=1 # default value: we need root privileges option= for argument in "$@"; do case "$argument" in upgrade | full-upgrade | install | dist-upgrade | build-dep) option="install" ;; clean | autoclean) option="clean" ;; download) option="download" root=0 ;; source) option="source" root=0 ;; changelog) root=0 ;; esac done # To handle priority of options correctly (environment over config file vars) # we need to preserve all interesting env variables. As this wouldn't be # difficult enough we have to preserve complete env vars (especially if value # ist set (even empty) or not) when changing context (sudo)... # Set a 'random' string to all unset variables. TMP_RANDOM="13979853562951413" TMP_LCK_FILE="${LCK_FILE-${TMP_RANDOM}}" TMP_DOWNLOADBEFORE="${DOWNLOADBEFORE-${TMP_RANDOM}}" TMP__APTMGR="${_APTMGR-${TMP_RANDOM}}" TMP_APTCACHE="${APTCACHE-${TMP_RANDOM}}" TMP_DLDIR="${DLDIR-${TMP_RANDOM}}" TMP_DLLIST="${DLLIST-${TMP_RANDOM}}" TMP_LISTDIR="${LISTDIR-${TMP_RANDOM}}" TMP__MAXNUM="${MAXNUM-${TMP_RANDOM}}" TMP__MAXCONPERSRV="${MAXCONPERSRV-${TMP_RANDOM}}" TMP__SPLITCON="${SPLITCON-${TMP_RANDOM}}" TMP__MINSPLITSZ=${MINSPLITSZ-${TMP_RANDOM}} TMP__PIECEALGO=${PIECEALGO-${TMP_RANDOM}} TMP_aptfast_prefix="${aptfast_prefix-${TMP_RANDOM}}" TMP_APT_FAST_TIMEOUT="${APT_FAST_TIMEOUT-${TMP_RANDOM}}" TMP_VERBOSE_OUTPUT="${VERBOSE_OUTPUT-${TMP_RANDOM}}" TMP_ftp_proxy="${ftp_proxy-${TMP_RANDOM}}" TMP_http_proxy="${http_proxy-${TMP_RANDOM}}" TMP_https_proxy="${https_proxy-${TMP_RANDOM}}" # Check for proper privileges. # Call explicitly with environment variables to get them into root conext. if [ "$root" = 1 ] && [ "$UID" != 0 ]; then exec sudo DEBUG="$DEBUG" \ LCK_FILE="$TMP_LCK_FILE" \ DOWNLOADBEFORE="$TMP_DOWNLOADBEFORE" \ _APTMGR="$TMP__APTMGR" \ APTCACHE="$TMP_APTCACHE" \ DLDIR="$TMP_DLDIR" \ DLLIST="$TMP_DLLIST" \ LISTDIR="$TMP_LISTDIR" \ _MAXNUM="$TMP__MAXNUM" \ _MAXCONPERSRV="$TMP__MAXCONPERSRV" \ _SPLITCON="$TMP__SPLITCON" \ _MINSPLITSZ="$TMP__MINSPLITSZ" \ _PIECEALGO="$TMP__PIECEALGO" \ aptfast_prefix="$TMP_aptfast_prefix" \ APT_FAST_TIMEOUT="$TMP_APT_FAST_TIMEOUT" \ VERBOSE_OUTPUT="$TMP_VERBOSE_OUTPUT" \ ftp_proxy="$TMP_ftp_proxy" \ http_proxy="$TMP_http_proxy" \ https_proxy="$TMP_https_proxy" \ "$0" "$@" fi # Define lockfile. # Use /tmp as directory because everybody (not only root) has to have write # permissions. # We need lock for non-root commands too, because we only have one download # list file. LCK_FILE="/tmp/apt-fast" LCK_FD=99 # Set default package manager, APT cache, temporary download dir, # temporary download list file, and maximal parallel downloads _APTMGR=apt-get eval "$(apt-config shell APTCACHE Dir::Cache::archives/d)" # Check if APT config option Dir::Cache::archives::apt-fast-partial is set. eval "$(apt-config shell apt_fast_partial Dir::Cache::archives::apt-fast-partial/d)" if [ -z "$apt_fast_partial" ]; then eval "$(apt-config -o Dir::Cache::archives::apt-fast-partial=apt-fast shell DLDIR Dir::Cache::archives::apt-fast-partial/d)" else eval "$(apt-config shell DLDIR Dir::Cache::archives::apt-fast-partial/d)" fi # Currently not needed. eval "$(apt-config shell LISTDIR Dir::State::lists/d)" DLLIST="/tmp/apt-fast.list" _MAXNUM=5 _MAXCONPERSRV=10 _SPLITCON=8 _MINSPLITSZ="1M" _PIECEALGO="default" # Prefix in front of apt-fast output: aptfast_prefix= # aptfast_prefix="$(date '+%b %_d %T.%N') apt-fast: " # Set color variables. cGreen='\e[0;32m' cRed='\e[0;31m' cBlue='\e[0;34m' endColor='\e[0m' # Set timout value for apt-fast download confirmation dialog. # Value is in seconds. APT_FAST_TIMEOUT=60 # Ask for download confirmation if unset DOWNLOADBEFORE= # Formatted package list in download confirmation if unset VERBOSE_OUTPUT= # Download command. _DOWNLOADER='aria2c --no-conf -c -j ${_MAXNUM} -x ${_MAXCONPERSRV} -s ${_SPLITCON} -i ${DLLIST} --min-split-size=${_MINSPLITSZ} --stream-piece-selector=${_PIECEALGO} --connect-timeout=600 --timeout=600 -m0' # Load config file. CONFFILE="/etc/apt-fast.conf" if [ -e "$CONFFILE" ]; then source "$CONFFILE" fi # no proxy as default ftp_proxy= http_proxy= https_proxy= # Now overwrite with preserved values if values were set before (compare with # 'random' string). [ "$TMP_LCK_FILE" = "$TMP_RANDOM" ] || LCK_FILE="$TMP_LCK_FILE" [ "$TMP_DOWNLOADBEFORE" = "$TMP_RANDOM" ] || DOWNLOADBEFORE="$TMP_DOWNLOADBEFORE" [ "$TMP__APTMGR" = "$TMP_RANDOM" ] || _APTMGR="$TMP__APTMGR" [ "$TMP_APTCACHE" = "$TMP_RANDOM" ] || APTCACHE="$TMP_APTCACHE" [ "$TMP_DLDIR" = "$TMP_RANDOM" ] || DLDIR="$TMP_DLDIR" [ "$TMP_DLLIST" = "$TMP_RANDOM" ] || DLLIST="$TMP_DLLIST" [ "$TMP_LISTDIR" = "$TMP_RANDOM" ] || LISTDIR="$TMP_LISTDIR" [ "$TMP__MAXNUM" = "$TMP_RANDOM" ] || _MAXNUM="$TMP__MAXNUM" [ "$TMP__MAXCONPERSRV" = "$TMP_RANDOM" ] || _MAXCONPERSRV="$TMP__MAXCONPERSRV" [ "$TMP__SPLITCON" = "$TMP_RANDOM" ] || _SPLITCON="$TMP__SPLITCON" [ "$TMP__MINSPLITSZ" = "$TMP_RANDOM" ] || _MINSPLITSZ="$TMP__MINSPLITSZ" [ "$TMP__PIECEALGO" = "$TMP_RANDOM" ] || _PIECEALGO="$TMP__PIECEALGO" [ "$TMP_aptfast_prefix" = "$TMP_RANDOM" ] || aptfast_prefix="$TMP_aptfast_prefix" [ "$TMP_APT_FAST_TIMEOUT" = "$TMP_RANDOM" ] || APT_FAST_TIMEOUT="$TMP_APT_FAST_TIMEOUT" [ "$TMP_VERBOSE_OUTPUT" = "$TMP_RANDOM" ] || VERBOSE_OUTPUT="$TMP_VERBOSE_OUTPUT" [ "$TMP_ftp_proxy" = "$TMP_RANDOM" ] || ftp_proxy="$TMP_ftp_proxy" [ "$TMP_http_proxy" = "$TMP_RANDOM" ] || http_proxy="$TMP_http_proxy" [ "$TMP_https_proxy" = "$TMP_RANDOM" ] || https_proxy="$TMP_https_proxy" # Disable colors if not executed in terminal. if [ ! -t 1 ]; then cGreen= cRed= cBlue= endColor= #FIXME: Time not updated. [ -z "$aptfast_prefix" ] && aptfast_prefix="[apt-fast $(date +"%T")]" fi msg_already_running() { msg "apt-fast already running!" "warning" msg "Verify that all apt-fast processes are finished then remove $LCK_FILE.lock and try again." "hint" } # Check if a lock file exists. if [ -f "$LCK_FILE.lock" ]; then msg_already_running exit 1 fi # create the lock file and lock it, die on failure _create_lock() { eval "exec $LCK_FD>\"$LCK_FILE.lock\"" trap "cleanup_aptfast; exit_cleanup_state" EXIT trap "cleanup_aptfast; exit 1" INT TERM flock -n $LCK_FD || { msg_already_running; exit 1; } } # unlock and remove the lock file _remove_lock() { flock -u "$LCK_FD" 2>/dev/null rm -f "$LCK_FILE.lock" } # Move download file away so missing permissions won't stop usage. CLEANUP_STATE=0 cleanup_dllist() { if [ -f "$DLLIST" ] then if ! mv -- "$DLLIST{,.old}" 2>/dev/null then if ! rm -f -- "$DLLIST" 2>/dev/null then msg "Could not clean up download list file." "warning" CLEANUP_STATE=1 fi fi fi } cleanup_aptfast() { [ "$CLEANUP_STATE" -eq 0 ] && CLEANUP_STATE=$? cleanup_dllist _remove_lock } exit_cleanup_state() { exit $CLEANUP_STATE } # decode url string # translates %xx but must not convert '+' in spaces urldecode() { printf '%b' "${1//%/\\x}" } # Check if mirrors are available. And if so add all mirrors to download list. get_mirrors(){ # Check all mirror lists. for mirrorstr in "${MIRRORS[@]}"; do # Build mirrors array from comma separated string. IFS=", " read -r -a mirrors <<< "$mirrorstr" # Check for all mirrors if URI of $1 is from mirror. If so add all other # mirrors to (resmirror) list and break all loops. for mirror in "${mirrors[@]}"; do # Real expension. if [[ "$1" == "$mirror"* ]]; then filepath=${1#${mirror}} # Build list for aria download list. list="${mirrors[*]}" echo -e "${list// /${filepath}\\t}$filepath\n" return 0 fi done done # No other mirrors found. echo "$1" } # Globals to save package name, version, size and overall size. DOWNLOAD_DISPLAY= DOWNLOAD_SIZE=0 # Get the package URLs. get_uris(){ if [ ! -d "$(dirname "$DLLIST")" ] then if ! mkdir -p -- "$(dirname "$DLLIST")" then msg "Could not create download file directory." "warning" exit 1 fi elif [ -f "$DLLIST" ]; then if ! rm -f -- "$DLLIST" 2>/dev/null && ! touch -- "$DLLIST" 2>/dev/null then msg "Unable to write to download file. Try restarting with root permissions or run 'apt-fast clean' first." "warning" exit 1 fi fi # Add header to overwrite file. echo "# apt-fast mirror list: $(date)" > "$DLLIST" #NOTE: aptitude doesn't have this functionality, so we use apt-get to get # package URIs. case "$_APTMGR" in apt|apt-get) uri_mgr=$_APTMGR;; *) uri_mgr=apt-get;; esac uris_full="$("$uri_mgr" "${APT_SCRIPT_WARNING[@]}" -y --print-uris "$@")" uris_full_ret="$?" if [ "$uris_full_ret" -ne 0 ] then msg "Package manager quit with exit code." "warning" exit "$uris_full_ret" fi while read -r pkg_uri_info do [ -z "$pkg_uri_info" ] && continue ## --print-uris format is: # 'fileurl' filename filesize checksum_hint:filechecksum uri="$(echo "$pkg_uri_info" | cut -d' ' -f1 | tr -d "'")" filename="$(echo "$pkg_uri_info" | cut -d' ' -f2)" filesize="$(echo "$pkg_uri_info" | cut -d' ' -f3)" checksum_string="$(echo "$pkg_uri_info" | cut -d' ' -f4)" hash_algo="$(echo "$checksum_string" | cut -d':' -f1)" checksum="$(echo "$checksum_string" | cut -d':' -f2)" filename_decoded="$(urldecode "$filename")" DOWNLOAD_DISPLAY="${DOWNLOAD_DISPLAY}$(echo "$filename_decoded" | cut -d'_' -f1)" DOWNLOAD_DISPLAY="${DOWNLOAD_DISPLAY} $(echo "$filename_decoded" | cut -d'_' -f2)" DOWNLOAD_DISPLAY="${DOWNLOAD_DISPLAY} $(echo "$filesize" | numfmt --to=iec-i --suffix=B)\n" DOWNLOAD_SIZE=$((DOWNLOAD_SIZE + filesize)) ## whole uri comes encoded (urlencoded). Filename must NOT be decoded because # plain aptitude do not decode it when download and install it. Therefore, we # will have ugly named packages at /var/cache/apt/archives but is the standard # behavior. # But package version must be decoded, otherways package=version calls will # not work. if [ -n "$HASH_SUPPORTED" ]; then case "$hash_algo" in SHA512) [ -z "$SHA512_SUPPORTED" ] && hash_algo= || hash_algo=sha-512 ;; SHA256) [ -z "$SHA256_SUPPORTED" ] && hash_algo= || hash_algo=sha-256 ;; SHA1) [ -z "$SHA1_SUPPORTED" ] && hash_algo= || hash_algo=sha-1 ;; MD5Sum) [ -z "$MD5sum_SUPPORTED" ] && hash_algo= || hash_algo=md5 ;; *) hash_algo= esac # Using apt-cache show package=version to ensure recover single and # correct package version. # Warning: assuming that package naming uses '_' as field separator. # Therefore, this code expects package-name_version_arch.deb Otherways # below code will fail resoundingly if [ -z "$hash_algo" ]; then pkg_name="$(echo "$filename" | cut -d'_' -f1)" pkg_version="$(echo "$filename" | cut -d'_' -f2)" pkg_version="$(urldecode "$pkg_version")" package_info="$(apt-cache show "$pkg_name=$pkg_version")" patch_checksum= if [ -n "$SHA512_SUPPORTED" ]; then patch_checksum="$(echo "$package_info" | grep SHA512 | head -n 1)" [ -n "$patch_checksum" ] && hash_algo="sha-512" fi if [ -z "$patch_checksum" ] && [ -n "$SHA256_SUPPORTED" ]; then patch_checksum="$(echo "$package_info" | grep SHA256 | head -n 1)" [ -n "$patch_checksum" ] && hash_algo="sha-256" fi if [ -z "$patch_checksum" ] && [ -n "$SHA1_SUPPORTED" ]; then patch_checksum="$(echo "$package_info" | grep SHA1 | head -n 1)" [ -n "$patch_checksum" ] && hash_algo="sha-1" fi if [ -z "$patch_checksum" ] && [ -n "$MD5sum_SUPPORTED" ]; then patch_checksum="$(echo "$package_info" | grep MD5sum | head -n 1)" [ -n "$patch_checksum" ] && hash_algo="md5" fi if [ -n "$patch_checksum" ]; then checksum="$(echo "$patch_checksum" | cut -d' ' -f2)" else msg "Couldn't get supported checksum for $pkg_name ($pkg_version)." "warning" REMOVE_WORKING_MESSAGE= fi fi else hash_algo= fi { get_mirrors "$uri" #echo " dir=$DLDIR" if [ -n "$hash_algo" ]; then echo " checksum=$hash_algo=$checksum" fi echo " out=$filename" } >> "$DLLIST" done <<<"$(echo "$uris_full" | grep -E "^'(http(s|)|(s|)ftp)://")" #cat "$DLLIST" #LCK_RM #exit } display_downloadfile(){ if [ -n "$VERBOSE_OUTPUT" ]; then cat "$DLLIST" else DISPLAY_SORT_OPTIONS=(-k 1,1) # Sort output after package download size (decreasing): #DISPLAY_SORT_OPTIONS=(-k 3,3 -hr) while read -r line; do [ -z "$line" ] && continue pkg="$(echo "$line" | cut -d' ' -f1)" ver="$(echo "$line" | cut -d' ' -f2)" size="$(echo "$line" | cut -d' ' -f3)" printf '%s%-40s %-20s %10s\n' "$aptfast_prefix" "$pkg" "$ver" "$size" done <<<"$(echo -e "$DOWNLOAD_DISPLAY" | sort "${DISPLAY_SORT_OPTIONS[@]}")" fi msg "Download size: $(echo "$DOWNLOAD_SIZE" | numfmt --to=iec-i --suffix=B)" "normal" } # Create and insert a PID number to lockfile. _create_lock # Make sure aria2c (in general first parameter from _DOWNLOADER) is available. CMD="$(echo "$_DOWNLOADER" | sed 's/^\s*\([^ ]\+\).*$/\1/')" if [ ! "$(command -v "$CMD")" ]; then msg "Command not found: $CMD" "normal" "err" msg "You must configure $CONFFILE to use aria2c or another supported download manager" "normal" "err" exit 1 fi # Make sure package manager is available. if [ ! "$(command -v "$_APTMGR")" ]; then msg "\`$_APTMGR\` command not available." "warning" msg "You must configure $CONFFILE to use either apt-get or aptitude." "normal" "err" exit 1 fi # Disable script warning if apt is used. APT_SCRIPT_WARNING=() if [ "$_APTMGR" == "apt" ]; then APT_SCRIPT_WARNING=(-o "Apt::Cmd::Disable-Script-Warning=true") fi # Set supported hash algorithms by aria2c (and also by Debian repository). SHA512_SUPPORTED= SHA256_SUPPORTED= SHA1_SUPPORTED= MD5sum_SUPPORTED= HASH_SUPPORTED= if [ "$CMD" == "aria2c" ]; then for supported_hash in $(LC_ALL=C aria2c -v | sed '/^Hash Algorithms:/!d; s/\(^Hash Algorithms: \|,\)\+//g'); do case "$supported_hash" in sha-512) SHA512_SUPPORTED=y; HASH_SUPPORTED=y ;; sha-256) SHA256_SUPPORTED=y; HASH_SUPPORTED=y ;; sha-1) SHA1_SUPPORTED=y; HASH_SUPPORTED=y ;; md5) MD5sum_SUPPORTED=y; HASH_SUPPORTED=y ;; esac done if [ -z "$HASH_SUPPORTED" ]; then msg "Couldn't find supported checksum algorithm from aria2c. Checksums disabled." "warning" fi fi # Check if "assume yes" switch is enabled and if yes enable $DOWNLOADBEFORE. # Also check if "download only" switch is enabled. #TODO: Get real value over APT items APT::Get::Assume-Yes and # APT::Get::Assume-No . # Respectively Aptitude::CmdLine::Download-Only and APT::Get::Download-Only. DOWNLOAD_ONLY= while true; do while getopts ":dy-:" optchar; do case "${optchar}" in -) case "${OPTARG}" in yes | assume-yes) DOWNLOADBEFORE=true ;; assume-no) DOWNLOADBEFORE= ;; download-only) DOWNLOAD_ONLY=true ;; esac ;; y) DOWNLOADBEFORE=true ;; d) DOWNLOAD_ONLY=true ;; esac done ((OPTIND++)) [ $OPTIND -gt $# ] && break done # Configure proxies. Use apt values over environment variables. # Note: If proxy setting is not set, there is no apt-config output. # Therefore variable doesn't get overriden, which is intended. # Export the variables to make them available in subshells (aka the # downloader command). eval "$(apt-config shell ftp_proxy Acquire::ftp::proxy)" export ftp_proxy eval "$(apt-config shell http_proxy Acquire::http::proxy)" export http_proxy eval "$(apt-config shell https_proxy Acquire::https::proxy)" export https_proxy # aria2 has no socks support (see https://github.com/aria2/aria2/issues/153) if echo "$http_proxy" | grep -q "^socks5h://" || echo "$https_proxy" | grep -q "^socks5h://"; then msg "Socks proxy detected. Falling back to ${_APTMGR}" "hint" "${_APTMGR}" "${APT_SCRIPT_WARNING[@]}" "$@" exit 0 fi # Run actions. if [ "$option" == "install" ]; then msg msg "Working... this may take a while." "normal" REMOVE_WORKING_MESSAGE=y get_uris "$@" [ -t 1 ] && [ -n "$REMOVE_WORKING_MESSAGE" ] && tput cuu 1 && tput el && tput cuu 1 # Test /tmp/apt-fast.list file exists and not just the apt-fast comment line. # Then download all files from the list. if [ -f "$DLLIST" ] && [ "$(wc -l "$DLLIST" | cut -d' ' -f1)" -gt 1 ] && [ ! "$DOWNLOADBEFORE" ]; then display_downloadfile msg msg "Do you want to download the packages? [Y/n] " "question" while ((!updsys)); do read -r -sn1 -t "$APT_FAST_TIMEOUT" answer || { msg; msg "Timed out." "warning"; exit 1; } case "$answer" in [JjYy]) result=1; updsys=1 ;; [Nn]) result=0; updsys=1 ;; "") result=1; updsys=1 ;; *) updsys=0 ;; esac done else result=1 fi if ((DOWNLOAD_SIZE)); then msg # Continue if answer was right or DOWNLOADBEFORE is enabled. if ((result)); then if [ -s "$DLLIST" ]; then # Test if apt-fast directory is present where we put packages. if [ ! -d "$DLDIR" ]; then mkdir -p -- "$DLDIR" fi cd "$DLDIR" &>/dev/null || exit 1 eval "${_DOWNLOADER}" # execute downloadhelper command if [ "$(find "$DLDIR" -printf . | wc -c)" -gt 1 ]; then # Move all packages to the apt install directory by force to ensure # already existing debs which may be incomplete are replaced find . -type f -name "*.deb" -execdir mv -ft "$APTCACHE" {} \+ fi cd - &>/dev/null || msg "Failed to change back directory" "warning" fi else exit 1 fi else [ -t 1 ] && tput el fi if [ -z "$DOWNLOAD_ONLY" ] || [ "$_APTMGR" == "aptitude" ]; then "${_APTMGR}" "${APT_SCRIPT_WARNING[@]}" "$@" fi elif [ "$option" == "clean" ]; then "${_APTMGR}" "${APT_SCRIPT_WARNING[@]}" "$@" && { find "$DLDIR" -maxdepth 1 -type f -delete CLEANUP_STATE="$?" [ -f "$DLLIST" ] && rm -f -- "$DLLIST"* || true } elif [ "$option" == "download" ]; then msg msg "Working... this may take a while." "normal" REMOVE_WORKING_MESSAGE=y get_uris "$@" [ -t 1 ] && [ -n "$REMOVE_WORKING_MESSAGE" ] && tput cuu 1 && tput el && tput cuu 1 if [ -f "$DLLIST" ] && [ "$(wc -l "$DLLIST" | cut -d' ' -f1)" -gt 1 ]; then display_downloadfile eval "${_DOWNLOADER}" fi if [ "$_APTMGR" == "aptitude" ]; then "${_APTMGR}" "$@" fi elif [ "$option" == "source" ]; then msg msg "Working... this may take a while." "normal" REMOVE_WORKING_MESSAGE=y get_uris "$@" [ -t 1 ] && [ -n "$REMOVE_WORKING_MESSAGE" ] && tput cuu 1 && tput el && tput cuu 1 if [ -f "$DLLIST" ] && [ "$(wc -l "$DLLIST" | cut -d' ' -f1)" -gt 1 ]; then display_downloadfile eval "${_DOWNLOADER}" fi # We use APT manager here to provide more verbose output. This method is # slightly slower then extractiong packages manually after download but also # more hardened (e.g. some options like --compile are available). "${_APTMGR}" "${APT_SCRIPT_WARNING[@]}" "$@" # Uncomment following snippet to extract source directly and comment # both lines before. #while read srcfile; do # # extract only .dsc files # echo "$srcfile" | grep -q '\.dsc$' || continue # dpkg-source -x "$(basename "$srcfile")" #done < "$DLLIST" # Execute package manager directly if unknown options are passed. else "${_APTMGR}" "${APT_SCRIPT_WARNING[@]}" "$@" fi # After error or all done remove our lockfile (done with EXIT trap)