#!/bin/sh
#
#  Copyright (c) 1999 Michael Merten <mikemerten@yahoo.com>
#  Copyright (c) 1999-2000 Gregory T. Norris <adric@debian.org>
#  Copyright (c) 2000-2003 Herbert Xu <herbert@debian.org>
#
#  License:  This script is distributed under the terms of version 2
#            of the GNU GPL. See the LICENSE file included with the package.
#
#  $Id: apt-move,v 1.115 2006/01/14 04:05:23 herbert Exp $
#
#  The apt-move(8) manpage contains the most up-to-date documentation
#     for this script.  Also, see the README file.
#
#  Configuration for this script can be found in /etc/apt-move.conf
#
#  Requires GNU sed.
#
set -e

if [ -z "$APT_MOVE_REEXEC" ] && [ -n "$BASH" ]; then
	export APT_MOVE_REEXEC=1
	if type dash > /dev/null 2>&1; then
		exec dash $0 "$@"
	else
		exec ash $0 "$@"
	fi
fi

[ ${CDPATH+1} ] && unset CDPATH
if [ ${LC_ALL+1} ]; then
	export LC_MONETARY="$LC_ALL"
	export LC_RESPONSE="$LC_ALL"
	export LC_TIME="$LC_ALL"
	export LC_MESSAGES="$LC_ALL"
	unset LC_ALL
fi
export LC_CTYPE=C
export LC_COLLATE=C
export LC_NUMERIC=C

# set some defaults for conffile items, just in case someone tries to
# "clean up" the file
ARCH=`dpkg --print-installation-architecture`
LOCALDIR=/mirrors/debian
DIST=stable
PKGTYPE=binary
APTSITES=
FILECACHE=/var/cache/apt/archives
LISTSTATE=/var/lib/apt/lists
DELETE=no
MAXDELETE=20
COPYONLY=no
PKGCOMP=gzip
CONTENTS=no
GPGKEY=
LISTALL=

# Remember where we came from.
ORIGDIR=$PWD

# Global variables.
TEST=				# test run flag (-t)
FORCE=				# force delete flag (-f)
QUIET=				# quite (-q)
#
GET_BINARY=			# binary distribution flag
GET_SOURCE=			# source distribution flag

VERSION=0

FETCH=/usr/lib/apt-move/fetch	# crappy replacement for apt-get
SCRIPTS=$APTMOVE_SCRIPTS
: ${SCRIPTS:=/usr/share/apt-move}
awk="awk -f $SCRIPTS/cmpbignum.awk -f $SCRIPTS/cmpversion.awk -f"
awk="$awk $SCRIPTS/getdist.awk -f"
MOVE3=$SCRIPTS/move3
MOVE4="$awk $SCRIPTS/move4"
MOVE5="$awk $SCRIPTS/move5"
MOVE6="$awk $SCRIPTS/move6"
MOVE7="$awk $SCRIPTS/move7"
GET2="$awk $SCRIPTS/get2"
GET3="$awk $SCRIPTS/get3"
DEL1=$SCRIPTS/del1
PKG1=$SCRIPTS/pkg1
unset awk
# End Globals ---------------------------------------------------------------

info() {
	printf "%b\n" "$*" >&3
}

showusage() {
	revision='$Id: apt-move,v 1.115 2006/01/14 04:05:23 herbert Exp $'
	# display a 'usage' message.
	cat >&2 <<- EOF

	$revision

	Usage:    apt-move [-c conffile] [-d dist] [-afqt] COMMAND
	
	Commands:
	       get         - update your master files from local apt.
	       getlocal    - alias of get.
	       fsck        - fix broken repositories, use with caution.
	       move        - move cache files into mirror tree.
	       movefile    - move files specified on the command line.
	       delete      - delete obsolete packages.
	       packages    - create new local Packages files.
	       update      - alias for 'get move delete packages'.
	       local       - alias for 'move delete packages'.
	       localupdate - alias for 'getlocal move delete packages'.
	       mirror      - update your local mirror from remote site.
	       sync        - same as mirror, but only gets packages that
	                     you currently have installed on your system.
	       exclude     - prints a list of all packages EXCLUDED from the
	                     mirror by the .exclude file (ignores -t).
	       listbin     - prints lists of packages which can serve as the
	                     input to mirrorbin.  Takes the arguments mirror,
	                     sync, or repo.
	       listsrc     - same as listbin, but lists source packages.
	       mirrorbin   - same as mirror, but gets the packages specified
	                     on stdin.
	       mirrorsrc   - same as mirrorbin, but gets source packages.

	Options:
	  -a  Process all packages including those that are unchanged.
	  -c  Specify an alternative configuration file.
	  -d  Override the DIST setting.
	  -f  Override the MAXDELETE setting (use with caution).
	  -q  Be quiet; suppress normal output.
	  -t  Show what apt-move would do, but do not actually do anything.

	See the apt-move(8) manpage for further details.

	EOF
	exit 64
}

apt_move_stat() {
	perl -lpe '$_ = (stat)[7];'
}

checklist() {
	[ -d .apt-move ] || return 24
	if [ $GET_BINARY ]; then
		[ -f .apt-move/binary ] || return 24
	fi
	if [ $GET_SOURCE ]; then
		[ -f .apt-move/source ] || return 24
	fi
}

checkconf() {
	local i

	[ -z "$DIST" ] && getout apt-move 6

	case "$PKGTYPE" in
	binary)
		GET_BINARY=yes
		;;
	source)
		GET_SOURCE=yes
		;;
	both)
		GET_BINARY=yes
		GET_SOURCE=yes
		;;
	*)
		getout apt-move 18
	esac

	set -f
	set +f $PKGCOMP
	for i in $PKGCOMP; do
		case "$i" in
		none | gzip | bzip2)
			;;
		*)
			getout apt-move 29
			;;
		esac
	done

	case $CONTENTS in
	[yY]*)
		CONTENTS=yes
		;;
	*)
		CONTENTS=no
		;;
	esac

	case $APTSITES in
	/all/)
		APTSITES=[!_]*
		;;
	esac

	GPGKEY=${GPGKEY:-$SIGNINKEY}
}

waitall() {
	for i in $CHILDREN $!; do
		set +e
		wait $i
		status=$?
		set -e
		case $status in
		0 | 141)
			;;
		*)
			exit $status
			;;
		esac
	done
	unset CHILDREN
}

sortind() {
	awk '
		{
			file = $1
			n = split(file, a, /[_\/]/)
			m = 5
			dist = a[3]
			if (n == 10) {
				dist = dist "/" a[4]
				m++
			}
			src = a[m]
			bin = a[m + 2]
			ver = a[m + 3]
			arch = a[m + 4]
			name = dist "_" src (arch == "source" ? "" : "_" bin)
			print name " " ver " " arch " " $0
		}
	' | sort
}

createidx() {
	local pf
	pf=$TMPHOME/createidx

	$GET3 $1 > $pf-tmp
	< $pf-tmp sort
}

make_idx_local() {
	local dir i dist pf type
	pf=$TMPHOME/make_idx_local
	dir=$1
	type=$2

	set *.$type.local
	if [ $# -eq 1 ] && [ ! -e "$1" ]; then
		return
	fi

	if [ $type = binary ]; then
		cat <<- \EOF
			/^#/ || NF == 0 {
				next
			}

			{
				printf "%s_%s_%s %s %s %s %s\n",
					getdist($3), $4, $1, $2, $3,
					$6 != "" ? $6 : "-",
					$5 != "" ? $5 : "-"
			}
		EOF
	else
		cat <<- \EOF
			/^#/ || NF == 0 {
				next
			}

			{
				printf "%s_%s %s %s %s\n",
					getdist($3), $1, $2, $3,
					$4 != "" ? $4 : "-"
			}
		EOF
	fi > $pf-awk

	for i; do
		dist=${i%%.*}
		[ -d $dir/$dist ] || mkdir $dir/$dist
		awk -f $SCRIPTS/getdist.awk -f $pf-awk $i > $pf-tmp1
		< $pf-tmp1 sort -k 1,1 > $dir/$dist/local
	done
}

make_pkg_list() {
	local pf i type
	pf=$TMPHOME/make_pkg_list
	type=$1

	cd "$LISTSTATE"

	set -f
	set +f -- $APTSITES
	for i; do
		set -- ${i}_*_$type
		[ $# -eq 1 ] && [ ! -e "$1" ] && {
			info "APTSITES: $i does not exist"
			continue
		}
		printf '%s\n' "$@"
	done | sed 's:^\(.*\)_'$type'$:\1 &:' | sort -k 1,1 > $pf-tmp1

	if [ -z "$FORCE" ] && ! [ -s $pf-tmp1 ]; then
		return 32
	fi

	for i; do
		if [ $type = Packages ]; then
			set ${i}_*_binary-*_Release
		else
			set ${i}_*_source_Release
		fi
		[ $# -eq 1 ] && [ ! -e "$1" ] && continue
		printf '%s\n' "$@"
	done | xargs -r awk '
		function process() {
			if (name == "")
				return
			if (dist ~ /^updates\//) {
				rel = rel "-updates"
				dist = "-"
			} else if (dist ~ /\/debian-installer$/) {
				rel = rel "-debian-installer"
				dist = substr(dist, 1, length(dist) - 17)
			}
			if (arch == "")
				arch = "-"
			if (rel == "")
				rel = "-"
			if (dist == "")
				dist = "-"
			print name " " arch " " rel " " dist
			arch = rel = dist = ""
		}

		FNR == 1 {
			process()
			# Remove _Release suffix.
			name = substr(FILENAME, 1, length(FILENAME) - 8)
		}

		/^Architecture:/ { arch = $2 }
		/^Archive:/ { rel = $2 }
		/^Component:/ { dist = $2 }

		END {
			process()
		}
	' > $pf-tmp2 || return 27

	cd $OLDPWD
	< $pf-tmp2 sort -k 3,3 |
		join -a 1 -o 1.1,1.2,1.4,2.2,1.3 - $TMPHOME/code-alias |
		awk '{print $1 " " $2 " " $4 " " $3}' | sort -k 1,1 |
		join -a 1 -e - -o 2.2,2.3,2.4,1.2 $pf-tmp1 - |
		awk '
			$1 == "-" { $1 = "'$ARCH'" }
			$2 == "-" { $2 = "'$DIST'" }
			{ print }
		' | sort -k 1,2 | awk '
			{ key = $2 "." $1 }
			file != key {
				if (file && close(file)) {
					print "Failed to close " file \
						> "/dev/stderr"
					exit 1;
				}
				file = key
			}
			{ print $3 " '"$LISTSTATE"'/" $4 > file }
		'
}

make_bin_arch() {
	local dir pf i arch dist home
	dir=$1
	pf=$TMPHOME/make_bin_arch
	rm -rf $pf
	mkdir $pf

	home=$PWD
	cd $pf
	make_pkg_list Packages

	set *
	if [ $# -eq 1 ] && [ ! -e "$1" ]; then
		cd "$home"
		return
	fi

	for i; do
		dist=${i%.*}
		arch=${i##*.}
		[ -d $dir/$dist ] || mkdir $dir/$dist
		< $i createidx binary > $dir/$dist/arch.$arch
		> "$LOCALDIR"/.apt-move/$dist.arch.$arch
	done

	cd "$home"
}

make_src_debian() {
	local dir pf i dist home
	dir=$1
	pf=$TMPHOME/make_src_debian
	rm -rf $pf
	mkdir $pf

	home=$PWD
	cd $pf
	make_pkg_list Sources

	set *
	if [ $# -eq 1 ] && [ ! -e "$1" ]; then
		cd "$home"
		return
	fi

	for i; do
		dist=${i%.*}
		[ -d $dir/$dist ] || mkdir $dir/$dist
		< $i createidx source > $dir/$dist/debian
	done

	cd "$home"
}

getonebin() {
	local dir dist pf i
	dir=$1
	dist=${dir##*/}
	pf=$TMPHOME/getonebin

	[ -f $dir/local ] || > $dir/local

	set $dist.arch.*
	if [ $# -eq 1 ] && [ ! -e "$1" ]; then
		rm -f $dist.binary
		return
	fi

	if [ -f $dist.binary ]; then
		sort -um $dist.arch.* | join - $dist.binary
	else
		> $dist.binary
	fi > $pf-old

	set $dir/arch.*
	if [ $# -gt 1 ] || [ -e "$1" ]; then
		for i; do
			cut -d ' ' -f 1 $i | uniq > $dist.arch.${i##*/arch.}
		done
	else
		set --
	fi

	sort -k 1,1 -m $pf-old "$@" | $GET2 |
		sort -k 1,1 -sum $dir/local - |
		awk '{
			printf "%-30s\t%-9s\t%-15s\t%-9s\t%s\n",
				$1, $2, $3, $4, $5
		}' | unexpand -a > $dist.binary
}

getonesrc() {
	local dir dist pf i
	dir=$1
	dist=${dir##*/}
	pf=$TMPHOME/getonesrc

	[ -f $dir/local ] || > $dir/local
	[ -f $dir/debian ] || > $dir/debian

	< $dir/debian $GET2 |
		sort -k 1,1 -sum $dir/local - |
		awk '{
			printf "%-30s\t%-9s\t%-15s\t%s\n",
				$1, $2, $3, $4
		}' | unexpand -a > $dist.source
}

make_index() {
	local pf i
	pf=$TMPHOME/make_index

	for i in binary source; do
		set *.$i
		if [ $# -gt 1 ] || [ -e "$1" ]; then
			printf '%s\n' "$@" | awk '
				{
					f = $0
					d = substr(f, 1, length(f) - 7)
					while ((val = getline < f) > 0) {
						print $1 " " d " " $NF
					}
					if (val < 0) {
						print "Failed to read" f > \
							"/dev/stderr"
						exit 1
					}
					close(f)
				}
			' | sort
		fi > $i.new
	done

	{
		set *.arch.*
		if [ $# -gt 1 ] || [ -e "$1" ]; then
			for i; do
				IFS=.
				set $i
				unset IFS
				echo $1 binary-$3
			done
		fi
		set *.source
		if [ $# -gt 1 ] || [ -e "$1" ]; then
			printf '%s\n' "$@" | tr . ' '
		fi
	} | sort > arch.new
}

proc_idx_diff() {
	local pf i readlink binkey
	pf=$TMPHOME/proc_idx_diff
	rm -f $pf-fifo1 $pf-fifo2
	mkfifo $pf-fifo1 $pf-fifo2

	[ -f arch ] || > arch
	[ -f binary ] || > binary
	[ -f source ] || > source

	join -v 1 -o 1.1 arch arch.new | uniq | tee $pf-archold | {
		cd ../dists
		xargs -r rm -rf
	}
	cd dists
	< $pf-archold xargs -r rm -rf
	cd ..

	IFS='
'
	set -- $(join -v 2 $pf-archold arch | comm -23 - arch.new)
	unset IFS

	for i; do
		set $i
		[ -d dists/$1 ] &&
			find dists/$1 -type d -name $2
		[ -d ../dists/$1 ] &&
			find ../dists/$1 -type d -name $2
	done | xargs -r rm -r

	IFS='
'
	set -- $(
		join -v 2 -o 2.1 arch arch.new | uniq | join -v 2 - arch.new |
			comm -13 arch - | tee $pf-new
	)
	unset IFS

	for i; do
		set $i
		[ -d dists/$1 ] || continue
		[ $2 = source ] && continue
		find dists/$1 -type d -name binary-all \
			-printf "[ -d %h/$2 ] || cp -a %p %h/$2;"
	done | sh

	mv arch.new arch

	if
		! [ -s $pf-new ] &&
		cmp -s binary.new binary && cmp -s source.new source
	then
		rm binary.new source.new
		return
	fi

	< $pf-new cut -d ' ' -f 1 | awk '
		{ rel[$0] = 1 }
		END {
			file = "binary"
			while ((err = getline < file) > 0) {
				if (!($2 in rel)) {
					print
				}
			}
		}
	' | comm -13 - binary.new > $pf-diff
	comm -13 source source.new > $pf-srcdiff

	cd ..

	readlink='while (<>) {
		chop;
		print "$_ " . readlink() . "\n";
	}'

	binkey='s%^\(.apt-move/dists/\([^/]*\)/\(.*\)/binary-.*/'
	binkey="$binkey"'\.index/\(.*\)\) .*/\(.*\)/\.index/.*$%'
	binkey="$binkey"'\3_\5_\4 \2	\1%p'
	nice find .apt-move/dists -type l |
		perl -e "$readlink" | tee $pf-lnk | sed -n "$binkey" |
		sort > $pf-old

	cut -d ' ' -f -2 .apt-move/binary > $pf-fifo1&
	cut -d ' ' -f -2 .apt-move/binary.new | comm -23 $pf-fifo1 - |
		join -t '	' -o 2.2 - $pf-old | xargs -r rm
	waitall

	binkey='s%^\(.apt-move/dists/\([^/]*\)/\(.*\)/source/\.index/\(.*\)\)'
	binkey="$binkey"' .*%\3_\4 \2	\1%p'
	< $pf-lnk sed -n "$binkey" | sort > $pf-old

	cut -d ' ' -f -2 .apt-move/source > $pf-fifo1&
	cut -d ' ' -f -2 .apt-move/source.new | comm -23 $pf-fifo1 - |
		join -t '	' -o 2.2 - $pf-old | xargs -r rm
	waitall

	binkey='s%^\(.apt-move/dists/\([^/]*\)/.*/\([^/]*\)/.index/\(.*\)\)'
	binkey="$binkey"' [^_]*_\(.*\)_.*%\4/\3/\2 \1 \5%'
	< $pf-lnk sed "$binkey" | sort > $pf-old

	{
		nice find .apt-move/pool -path '*/.index/*' -type f \
			\( -name '*_source' -fprint $pf-src -o -print \) |
			sortind |
			$MOVE6 $pf-diff .apt-move/arch /dev/null
		< $pf-src sortind | $MOVE6 $pf-srcdiff .apt-move/arch /dev/null
	} > $pf-new
	< $pf-new sort | $MOVE7 $pf-old /dev/null /dev/null > $pf-cmd

	< $pf-cmd sort -u | cut -f 2- | $MOVE3

	cd .apt-move
	mv binary.new binary
	mv source.new source
}

getbin() {
	[ $GET_BINARY ] || return 0

	local pf dist
	pf=$TMPHOME/getbin
	rm -rf $pf
	mkdir $pf

	make_idx_local $pf binary
	make_bin_arch $pf

	set $pf/*
	if [ $# -gt 1 ] || [ -e "$1" ]; then
		for dist do
			getonebin $dist
		done
	fi
}

getsrc() (
	[ $GET_SOURCE ] || return 0

	local pf dist
	pf=$TMPHOME/getsrc
	rm -rf $pf
	mkdir $pf

	make_idx_local $pf source
	make_src_debian $pf

	set $pf/*
	if [ $# -gt 1 ] || [ -e "$1" ]; then
		for dist do
			getonesrc $dist
		done
	fi
)

pkgdir() {
	sed '
		s:^non-us :non-US/main :I
		s:^non-us\(/.*\) :non-US\1/ :I
		s:^[^/]* :main/&:
		s:\(non-US/.*\|.*/\)\(.*\) \(.*\):dists/'$DIST'/\1\3/\2:
		s:/$::
	'
}

getfiles() (
	info '\nUpdating from local Packages files...'

	[ $TEST ] && return

	mkdir -p .apt-move/dists .apt-move/pool dists pool || return 5

	cd .apt-move
	getbin
	getsrc

	make_index
	proc_idx_diff
	cd ..
)

link_new_files() {
	local readlink 

	readlink='while (<>) {
		chop;
		m%^.apt-move/dists/([^/]*)/.*/([^/]*)/.index/(.*)%;
		print "$3/$2/$1 $_";
		$_ = readlink;
		s/[^_]*_//;
		s/_.*//;
		print " $_\n";
	}'

	nice find .apt-move/dists -type l |
		perl -e "$readlink" | sort > $pf-old

	{
		if [ -f $pf-pkg ]; then
			< $pf-pkg sortind |
				$MOVE6 \
					.apt-move/binary .apt-move/arch \
					$pf-skip5
		fi

		if [ -f $pf-src ]; then
			< $pf-src sortind |
				$MOVE6 \
					.apt-move/source .apt-move/arch \
					$pf-skip7
		fi
	} | sort | $MOVE7 $pf-old $pf-skip6 $pf-move1 > $pf-lnk
}

movefiles() {
	checklist

	info '\nMoving files...'

	local pf i bif
	pf=$TMPHOME/movefiles
	rm -f $pf-fifo1 $pf-fifo2
	mkfifo $pf-fifo1 $pf-fifo2
	rm -rf $pf
	mkdir $pf

	bif='
		s/.*	//
		p
	'
	if [ $GET_BINARY ]; then
		bif='
			/\.u\?deb$/ {
				w '$pf-deb'
				b
			}
		'"$bif"
	fi

	if [ $GET_SOURCE ]; then
		bif='
			/\.dsc$/ {
				w '$pf-dsc'
				b
			}
		'"$bif"
	fi

	sed -n "$bif" > $pf-skip3

	mkdir $pf/deb $pf/dsc

	if [ $GET_BINARY ]; then
		< $pf-deb apt_move_stat > $pf-fifo1&
		< $pf-deb xargs -r md5sum |
			$MOVE4 $pf/deb $pf-fifo1 $pf-skip1 $pf-pkg $CONTENTS
		waitall
	fi > $pf-mvdeb

	if [ $GET_SOURCE ]; then
		< $pf-dsc apt_move_stat > $pf-fifo1&
		< $pf-dsc xargs -r md5sum |
			$MOVE4 $pf/dsc $pf-fifo1 $pf-skip2 > $pf-dsc1
		waitall

		sort -t _ -k 2 .apt-move/source > $pf-sdist
		sort -k 1,1 $pf-dsc1 | $MOVE5 $pf-sdist $pf-skip4 $pf-src
	fi > $pf-mvdsc

	link_new_files

	info 'Skipping files:'
	cat $pf-skip* - $pf-move* <<- EOF >&3
		Moving Files:
	EOF

	[ $TEST ] && return

	{
		for i in $pf-mvd?? $pf-lnk; do
			< $i sort -u
		done
	} | cut -f 2- | $MOVE3 || return 34

	if [ $COPYONLY = no ]; then
		sort -u $pf-move* | xargs -r rm -f || return 28
	fi

	return
}

domove() {
	local pf
	pf=$TMPHOME/domove
	rm -f $pf-fifo1
	mkfifo $pf-fifo1

	find $FILECACHE/ -maxdepth 1 -name '*.deb' -o -name '*.udeb' |
		movefiles
}

upgrade0() {
	[ -d backup ] && return 30

	mkdir backup || return 5
	for i in .apt-move dists pool; do
		[ -e $i ] && mv $i backup
	done

	info "Your old repository is now in $LOCALDIR/backup."

	mkdir -p .apt-move/dists .apt-move/pool dists pool || return 5
	echo $VERSION > .apt-move/version

	mkdir $pf/deb $pf/dsc

	find backup -type f \( \
		-name '*.udeb' -fprint $pf-deb -o \
		-name '*.deb' -fprint $pf-deb -o \
		-name '*.dsc' -fprint $pf-dsc \
	\)

	< $pf-deb apt_move_stat > $pf-fifo1&
	< $pf-deb xargs -r md5sum |
		$MOVE4 $pf/deb $pf-fifo1 $pf-skip1 $pf-pkg $CONTENTS \
		> $pf-mvdeb
	waitall

	< $pf-dsc apt_move_stat > $pf-fifo1&
	< $pf-dsc xargs -r md5sum |
		$MOVE4 $pf/dsc $pf-fifo1 $pf-skip2 > $pf-dsc1
	waitall

	cd .apt-move
	< $pf-pkg sortind | awk '
		{
			name = $1
			ver = $2
			arch = $3
			n = split($5, a, /\//)
			rel = "unknown"
			if ($5 ~ /^backup.dists/) {
				rel = a[3]
			}
			if (arch == "all") {
				arch = "'$ARCH'"
			}
			print name | "uniq > " rel ".arch." arch
			print name " - - - " ver | "'"$GET2"' > " rel ".binary"
		}
	'

	< $pf-dsc1 awk '
		{
			src = $1
			ver = $2
			n = split($4, a, /\//)
			rel = "unknown"
			m = 3
			if ($4 ~ /^backup.dists/) {
				rel = a[3]
				m++
			}
			dist = a[m]
			if (n == 7) {
				dist = dist "/" a[m + 1]
			}

			cmd = "sort | '"$GET2"' > " rel ".source"
			print dist "_" src " - - " ver | cmd
		}
	'

	make_index
	mv arch.new arch
	mv binary.new binary
	mv source.new source
	cd ..

	sort -t _ -k 2 .apt-move/source > $pf-sdist
	sort -k 1,1 $pf-dsc1 | $MOVE5 $pf-sdist $pf-skip4 $pf-src > $pf-mvdsc

	link_new_files

	{
		for i in $pf-mvd?? $pf-lnk; do
			< $i sort -u
		done
	} | cut -f 2- | $MOVE3 > /dev/null

	cat - $pf-skip* <<- EOF | tee .apt-move/backup.list >&3
		The following files need to be archived manually:
	EOF
	info "It is available in $LOCALDIR/.apt-move/backup.list"
	info "if you missed it."
}

dofsck() {
	local pf fifos i readlink bif overawk
	pf=$TMPHOME/dofsck
	rm -f $pf-fifo1 $pf-fifo2
	mkfifo $pf-fifo1 $pf-fifo2
	rm -rf $pf
	mkdir $pf

	info
	info "Rebuilding repository..."
	[ $TEST ] && return 0

	set .apt-move/version
	if [ ! -f $1 ] || [ $(cat $1) != $VERSION ]; then
		upgrade0
		return
	fi

	cd .apt-move
	find dists -type l | xargs -r rm
	if [ -f binary ]; then
		mv binary binary.new
	else
		> binary.new
	fi
	if [ -f source ]; then
		mv source source.new
	else
		> source.new
	fi
	cp arch arch.new
	proc_idx_diff
	cd ..
}

check_del_count() {
	# I do this just because a bug caused there to be a total of 0 files
	# in the distribution, and bc had a heart-attack.
	[ $loccount -eq 0 ] && return 0

	delcount=$(cat $pf-delcount)
	# check the results
	case `echo "scale=2; (($delcount/$loccount)*100) <= $MAXDELETE" | bc` in
	0)
		[ -z "$FORCE" ] && return 13
		info
		info "Too many files, but FORCE used... deleting anyway!"
		;;
	1) ;;
	*) return 12 ;;
	esac
}

dodeletes() {
	checklist

	local pf readlink expand sedp
	pf=$TMPHOME/dodeletes

	info
	if [ "$DELETE" != "yes" ]; then
		info "File deletes disabled, skipping."
		return 0
	fi
	info "Removing obsolete packages..."

	readlink='while (<>) {
		chop;
		$lnk = readlink();
		$lnk =~ s%^[./]*%%;
		print ".apt-move/$lnk\t$_\n";
	}'

	sedp='s%.*%&	&%'
	if [ $CONTENTS != no ]; then
		sedp='s%\(.*/\.\)content\(/.*\)%\1index\2	&%;t;'$sedp
	fi

	loccount=$(nice find pool -type f | sort | tee $pf-files | wc -l)

	nice find .apt-move/dists -path '*/.index/*' -type l |
		perl -e "$readlink" |
		sort | tee $pf-dists-map |
		cut -f 1 | uniq |
		$DEL1 |
		sort -u > $pf-idx-map

	join -v 2 -o 2.2 $pf-files $pf-idx-map | sort -u > $pf-idx-tmp

	nice find .apt-move/pool -type f | sed "$sedp" |
		sort | tee $pf-contents-map |
		cut -f 2 | sort -u > $pf-idx-list

	comm -23 $pf-idx-list $pf-idx-tmp |
		join -v 2 -o 2.2 - $pf-dists-map | sort > $pf-dists-del

	sort -k 2,2 $pf-dists-map | join -v 2 -2 2 -o 2.1 $pf-dists-del - |
		sort -u | join -v 2 -o 2.2 - $pf-contents-map > $pf-idx-del

	sort -k 2,2 $pf-idx-map | join -v 2 -2 2 -o 2.1 $pf-idx-del - |
		sort | comm -13 - $pf-files | tee $pf-files-del |
		wc -l > $pf-delcount

	check_del_count

	# we are either ok, or forced...
	sed 's/^/removing:  /' $pf-files-del >&3
	[ $TEST ] && return
	cat $pf-*-del | xargs -r rm
	find .apt-move/pool pool -type d -empty |
		xargs -r rmdir -p --ignore-fail-on-non-empty
}

listbin() {
	[ -f .apt-move/$DIST.arch.$ARCH ] || return 0

	local pf readlink
	pf=$TMPHOME/listbin

	readlink='while (<>) {
		chop;
		m%^.apt-move/dists/[^/]*/(.*)/.*/.index/(.*)%;
		$dist = $1;
		$bin = $2;
		$_ = readlink;
		s%^[./]*%%;
		m%^pool/.*/(.*)/.index/[^_]*_(.*)_%;
		print "${dist}_$1_$bin $2\n";
	}'

	if [ -d .apt-move/dists/$DIST ]; then
		nice find .apt-move/dists/$DIST \
			-path "*/binary-$ARCH/*" -type l |
			perl -e "$readlink" | sort
	fi > $pf-old

	local changed
	if ! [ $LISTALL ]; then
		changed='$3 != $4'
	fi

	join -o 2.1,2.3,2.5 .apt-move/$DIST.arch.$ARCH - |
		join -a 1 - $pf-old | awk "$changed"' { print $1 " " $2 }' |
		tee $pf-tmp1 | sed 's/^[^ ]*_\([^ ]*\) .*/\1_*/' > $pf-tmp2
	sed 's/.* \(.*\)$/\1 binary-'$ARCH'/' $pf-tmp1 | pkgdir |
		paste -d / - $pf-tmp2
}

listsrc() {
	local pf readlink
	pf=$TMPHOME/listbin

	readlink='while (<>) {
		chop;
		m%^.apt-move/dists/[^/]*/(.*)/.*/.index/(.*)%;
		print "$1_$2";
		$_ = readlink;
		s/[^_]*_//;
		s/_.*//;
		print " $_\n";
	}'

	if [ -d .apt-move/dists/$DIST ]; then
		nice find .apt-move/dists/$DIST -path "*/source/*" -type l |
			perl -e "$readlink" | sort > $pf-old
	fi

	local changed
	if ! [ $LISTALL ]; then
		changed='$3 != $4'
	fi

	join -o 1.1,1.3,1.4,2.2 -a 1 - $pf-old |
		awk "$changed"' { print $1 " " $2 }' | tee $pf-tmp1 |
		sed 's/^[^ ]*_\([^ ]*\) .*/\1_*/' > $pf-tmp2
	sed 's/.* \(.*\)/\1 source/' $pf-tmp1 | pkgdir |
		paste -d / - $pf-tmp2
}

excluded() {
	checklist

	local pf
	pf=$TMPHOME/excluded

	# print list of excluded files
	info "The following files are EXCLUDED from the mirror:"
	# if a $LOCALDIR/.exclude file exists, also find the files that
	# match one of the exclude patterns in that file.
	if [ -f $LOCALDIR/.exclude ]; then
		makeexcl
		{
			if [ $GET_BINARY ]; then
				< .apt-move/$DIST.binary listbin
			fi
			if [ $GET_SOURCE ]; then
				< .apt-move/$DIST.source listsrc
			fi
		} | grep -f $TMPHOME/makeexcl | sort
	fi
}

make_pkg_files() {
	local pf i dist sect suffix rel compo arch type lbl odist conj norel \
		contents
	pf=$TMPHOME/make_pkg_files
	rm -f $pf-fifo1 $pf-fifo2 $pf-fifogz $pf-fifobz
	mkfifo $pf-fifo1 $pf-fifo2 $pf-fifogz $pf-fifobz
	type=$1

	info "Creating $type files..." 
	set -- $(
		cd .apt-move/dists
		if [ $type = Packages ]; then
			nice find . \
				-type d -name binary-\* \
				! -name binary-all
		else
			nice find . -type d -name source
		fi
	)
	for i; do
		i=${i#./}
		odist=${i%%/*}
		compo=${i#*/}
		compo=${compo%/*}
		lbl=APT-Move
		arch=${i##*/}
		conj=
		norel=
		contents=

		case $odist in
		*-updates)
			case $compo in (non-US/*)
				continue
			esac
			conj=.apt-move/dists/$odist/non-US/$compo/$arch/.index
			dist=${odist%-updates}
			compo=updates/$compo
			lbl=$lbl-Security
			sect=dists/$dist/$compo/$arch
			;;
		*-debian-installer)
			dist=${odist%-debian-installer}
			compo=main/debian-installer
			sect=dists/$dist/$compo/$arch
			norel=yes
			;;
		*)
			dist=$odist
			sect=dists/$i
			if [ $type = Packages ] && [ $CONTENTS != no ]; then
				contents=$pf-contents/$i
				mkdir -p ${contents%/*}
				> $contents
			fi
			;;
		esac

		[ -h dists/$dist ] && continue

		info "Building: $dist $sect $type"

		[ $TEST ] && continue

		mkdir -p $sect || return 5
		rm -f $sect/$type*

		if [ -n "$conj" ] && [ -d $conj ]; then
			find $conj -type l -printf '%f %h/%l\n' |
				sort > $pf-non-US
		fi

		if [ $type = Packages ]; then
			sed 's%^[^[:blank:]]*_%%' .apt-move/$odist.binary
		else
			sed 's%^[^[:blank:]]*_%%' .apt-move/$odist.source
		fi | sort | $GET2 > $pf-fifo1&

		CHILDREN=$!
		find .apt-move/dists/$i/.index -type l -printf '%f %h/%l\n' |
			if [ -n "$conj" ] && [ -s $pf-non-US ]; then
				sort -u - $pf-non-US
			else
				sort
			fi | $PKG1 $pf-fifo1 $contents > $pf-fifo2&

		if [ $dogz ]; then
			CHILDREN="$CHILDREN $!"
			< $pf-fifogz gzip > $sect/$type.gz&
		fi
		if [ $dobz ]; then
			CHILDREN="$CHILDREN $!"
			< $pf-fifobz nice bzip2 -f \
				> $sect/$type.bz2&
		fi
		< $pf-fifo2 tee \
			${donone:+$sect/$type} \
			${dogz:+$pf-fifogz} \
			${dobz:+$pf-fifobz} > /dev/null
		waitall

		[ $norel ] && continue

		{
			echo "Archive: $dist"
			echo "Component: $compo"
			echo "Origin: APT-Move"
			echo "Label: $lbl"
			echo "Architecture: ${arch#binary-}"
		} > $sect/Release
	done
}

get_checksum() {
	for l; do
		[ -f $l ] || continue
		size=$(perl -le 'print ((stat($ARGV[0]))[7]);' $l)
		printf ' %32s%.s %16d %s\n' \
			$(md5sum $l) $size $j/$k/$l
		printf ' %40s%.s %16d %s\n' \
			$(sha1sum $l) $size $j/$k/$l >&3
	done
}

make_release() {
	local pf dir suite j dogz dobz donone codename origin label compo \
		nonus k arch l size desc prev
	pf=$TMPHOME/make_release
	dir=$1

	case $dir in
	*/non-US)
		suite=${dir%/*}
		nonus=non-US/
		;;
	*)
		suite=$dir
		nonus=
		;;
	esac

	codename=unknown
	desc=unknown
	origin=APT-Move
	label=APT-Move

	for j in codename desc origin label; do
		if [ -f .$j ]; then
			eval "$j=\$(cat .$j)"
		fi
	done

	compo=
	arch=
	for j in main contrib non-free main/debian-installer; do
		[ -d $j ] || continue
		if [ $j != main/debian-installer ]; then
			compo="$compo $nonus$j"
			prev=..
		else
			prev=../..
		fi
		cd $j

		for k in binary-*; do
			[ -d $k ] || continue
			arch="$arch ${k#*-}"
			cd $k
			get_checksum Packages Packages.gz Packages.bz2 Release
			cd ..
		done

		k=source
		if [ -d $k ]; then
			cd $k
			get_checksum Sources Sources.gz Sources.bz2 Release
			cd ..
		fi

		cd $prev
	done > $pf-md5sum 3> $pf-sha1sum

	[ -n "$compo" ] || return 0

	info "Building: $dir Release"

	[ $TEST ] && return

	exec > Release.new

	echo Origin: $origin
	echo Label: $label
	echo Suite: $suite
	echo Codename: $codename
	echo Date: $(TZ=UTC date '+%a, %d %b %Y %T %Z')
	echo Architectures: $(printf '%s\n' $arch | sort -u)
	echo Components:$compo
	echo Description: $desc
	echo MD5Sum:
	cat $pf-md5sum
	echo SHA1:
	cat $pf-sha1sum

	exec >&-

	if [ -n "$GPGKEY" ]; then
		gpg --detach-sign -ao Release.gpg --default-key "$GPGKEY" \
			--batch --yes --sign Release.new
	fi
	mv Release.new Release
}

make_contents() {
	local pf dir j k path
	pf=$TMPHOME/make_release
	dir=$1

	[ $CONTENTS != no ] || {
		[ $TEST ] || rm -f Contents-*
		return 0
	}

	info "Building: $dir Contents"

	[ $TEST ] && return

	rm -f Contents-*

	for j in main contrib non-free; do
		path=$TMPHOME/make_pkg_files-contents/$dir/$j
		[ -d $path ] || continue

		set -- "$path"/*
		[ $# -eq 1 ] && [ ! -e "$1" ] && continue
		for k; do
			cat $k >> Contents-${k##*-}
		done
	done

	set Contents-*
	[ $# -eq 1 ] && [ ! -e "$1" ] && return
	for j; do
		sort $j | awk '
			prev != $1 {
				if (prev != "") {
					printf "%-59s %s\n", prev, pkg
				}
				prev = $1
				pkg = $2
				next
			}
			{ pkg = pkg "," $2 }
			END {
				if (prev != "") {
					printf "%-59s %s\n", prev, pkg
				}
			}
		' | unexpand -a | cat $SCRIPTS/Contents.head - | gzip > $j.gz
		rm $j
	done
}

dopackages() {
	checklist

	local i dogz dobz donone

	dogz=
	dobz=
	donone=
	for i in $PKGCOMP; do
		case $i in
		gzip)
			dogz=yes
			;;
		bzip2)
			dobz=yes
			;;
		*)
			donone=yes
			;;
		esac
	done

	info
	# build our own local Packages.gz files
	# paths stored in packages files are relative to debian/
	if [ $GET_BINARY ]; then
		make_pkg_files Packages
	fi

	if [ $GET_SOURCE ]; then
		make_pkg_files Sources
	fi

	info "Creating Release files..." 
	cd dists
	for i in *; do
		[ ! -h $i ] && [ -d $i ] || continue
		cd $i
		make_release $i
		make_contents $i
		[ -d non-US ] || {
			cd ..
			continue
		}
		cd non-US
		make_release $i/non-US
		make_contents $i/non-US
		cd ../..
	done
}

procbin() {
	sed 's:.*/\(.*\)_\*$:\1:' | {
		if [ $TEST ]; then
			xargs -r $FETCH -t
			return 0
		fi
		xargs -r $FETCH
	}
	domove
}

procsrc() {
	sed 's:.*/\(.*\)_\*$:\1:' | {
		if [ $TEST ]; then
			xargs -r apt-get --print-uris source
			return 0
		fi
		if [ -d .apt-move/archive ]; then
			find .apt-move/archive -type l | xargs -r rm
		else
			mkdir .apt-move/archive || exit 5
		fi
		cd .apt-move/archive
		find ../../pool -name '*.orig.tar.gz' |
			xargs -r ln -s --target-directory=.
		xargs -r apt-get -d source
		cd ../..
	}
	find .apt-move/archive -name '*.dsc' | movefiles
}

runmirror() {
	# grab copy of all non-excluded files for the configured distribution.
	info
	info "Updating mirror..."

	local pf
	pf=$TMPHOME/runmirror
	rm -f $pf-fifo
	mkfifo $pf-fifo

	makeexcl

	listbinmirror > $pf-fifo&
	< $pf-fifo procbin
	waitall

	listsrcmirror > $pf-fifo&
	< $pf-fifo procsrc
	waitall
}

runsync() {
	# grab copy of all the packages you currently have installed
	info
	info "Syncing mirror..."

	local pf
	pf=$TMPHOME/runsync
	rm -f $pf-fifo
	mkfifo $pf-fifo

	makeexcl
	makeselect

	listbinsync > $pf-fifo&
	< $pf-fifo procbin
	waitall

	listsrcsync > $pf-fifo&
	< $pf-fifo procsrc
	waitall
}

listbinmirror() {
	[ $GET_BINARY ] || return 0
	[ -f .apt-move/$DIST.binary ] || return 31
	< .apt-move/$DIST.binary listbin | grep -v -f $TMPHOME/makeexcl |
		sed 's:.*/\(.*\)_\*$:\1:'
}

listsrcmirror() {
	[ $GET_SOURCE ] || return 0
	[ -f .apt-move/$DIST.source ] || return 31
	< .apt-move/$DIST.source listsrc | grep -v -f $TMPHOME/makeexcl |
		sed 's:.*/\(.*\)_\*$:\1:'
}

listbinsync() {
	[ $GET_BINARY ] || return 0
	[ -f .apt-move/$DIST.binary ] || return 31
	< .apt-move/$DIST.binary listbin | grep -v -f $TMPHOME/makeexcl |
		sed 's:.*/\(.*\)_\*$:\1:' | sort |
		comm -12 $TMPHOME/makeselect -
}

listsrcsync() {
	[ $GET_SOURCE ] || return 0
	[ -f .apt-move/$DIST.source ] || return 31
	< .apt-move/$DIST.source listsrc | grep -v -f $TMPHOME/makeexcl |
		sed 's:.*/\(.*\)_\*$:\1:' | sort |
		comm -12 $TMPHOME/makeselect-src -
}

listbinrepo() {
	[ $GET_BINARY ] || return 0
	[ -f .apt-move/$DIST.binary ] || return 31

	local pf
	pf=$TMPHOME/listbinrepo

	nice find pool -name '*.deb' -o -name '*.udeb' |
		sed 's%.*/%%; s/_.*//' | sort -u > $pf-old
	< .apt-move/$DIST.binary listbin | grep -v -f $TMPHOME/makeexcl |
		sed 's:.*/\(.*\)_\*$:\1:' | sort | comm -12 $pf-old -
}

listsrcrepo() {
	[ $GET_SOURCE ] || return 0
	[ -f .apt-move/$DIST.source ] || return 31

	local pf
	pf=$TMPHOME/listsrcrepo

	nice find .apt-move/pool -name '*_source' | sed 's%.*/%%; s/_.*//' |
		sort -u > $pf-old
	< .apt-move/$DIST.source listsrc | grep -v -f $TMPHOME/makeexcl |
		sed 's:.*/\(.*\)_\*$:\1:' | sort |
		comm -12 $pf-old -
}

makeexcl() {
	local f=$TMPHOME/makeexcl
	[ -f $f ] && return
	if [ -f .exclude ]; then
		sed '/^[#;]/d; /^$/d; s/\*//g' .exclude
	fi > $f
}

makeselect() {
	local f=$TMPHOME/makeselect pf
	[ -f $f ] && return

	pf=$TMPHOME/makeselect
	dpkg --get-selections | sort -sb -k 2,2 > $pf-tmp1
	echo install | join -j2 2 -o 2.1 - $pf-tmp1 > $f
	if [ -f .apt-move/$DIST.binary ]; then
		awk -F '[ \t_]' '{ print $3 " " $2 }' .apt-move/$DIST.binary |
			sort | join -o 1.2 - $f | sort -u
	fi > $f-src
}

printerr() {
	# print error message and exit with appropriate status
	case "$2" in
	0)
		;;
	5)
		echo "Error: $1: Could not create directory.  Aborting script."
		;;
	6)
		echo "Error: $1: You failed to select a distribution.  Check"
		echo "       the DIST setting in /etc/apt-move.conf.  Aborting"
		echo "       script."
		;;
	12)
		echo "Error: $1: bc calculation returned invalid result"
		;;
	13)
		echo "Error: $1: too many files to delete!  Your current limit"
		echo "       is set to $MAXDELETE%.  To change that, see the"
		echo "       MAXDELETE setting in /etc/apt-move.conf.  You can"
		echo "       override this safety using the 'force' parameter,"
		echo "       but be careful!  Aborting script."
		;;
	18)
		echo "Error: $1: You specified an invalid package type."
		echo "       See the PKGTYPE setting in /etc/apt-move.conf."
		echo "       Your current setting is:"
		echo "           PKGTYPE=$PKGTYPE"
		echo "       Aborting script."
		;;
	20)
		echo "Terminated by SIGINT (^C)..."
		;;
	21)
		echo "Terminated by SIGTERM..."
		;;
	22)
		echo "Terminated by SIGHUP..."
		;;
	23)
		echo "Error: $1: Your current mirror directory is incompatible"
		echo "       with this version of apt-move.  Please read"
		echo "       /usr/share/doc/apt-move/README[.gz] for"
		echo "       instructions on updating your mirror directory."
		;;
	24)
		echo "Error: $1: No master files exist!"
		echo "       You need to run apt-move get."
		;;
	25)
		echo "Error: $1: Could not read configuration.  Aborting."
		;;
	27)
		echo "Error: $1: Could not read Release files."
		;;
	28)
		echo "Error: $1: Failed to remove original files."
		;;
	29)
		echo "\
Error: $1: You specified an invalid Packages file compression list.
       See the PKGCOMP setting in /etc/apt-move.conf.
       Your current setting is:
           PKGCOMP='$PKGCOMP'
       Aborting script."
		;;
	30)
		echo "Error: $1: Please remove $LOCALDIR/backup."
		;;
	31)
		echo "Error: $1: Unknown DIST setting."
		echo "       Value must match Archive field in Release file."
		;;
	32)
		echo "Error: $1: Cannot find index files for APTSITES."
		echo "       Make sure that apt-get update has been run."
		;;
	33)
		echo "Error: $1: Configuration file has errors.  Aborting."
		;;
	34)
		echo "Error: $1: Failed to move files."
		;;
	64)
		# this is used by the 'usage' function... should get none of
		# these here.
		;;
	255 | *)
		echo "Unknown error: $1: $2."
		;;
	esac
}

# called when one of the main functions returns an error.
# display the appropriate message
# $1 should be the function name, and $2 should be the error code
getout() {
	[ $GETOUT ] || printerr $1 $2 >&2
	GETOUT=yes
	exit $2
}

# START main program logic -----------------------------------------------

umask 022

CONFFILE=/etc/apt-move.conf
unset dist

# read the options
while getopts "ac:d:fqt" flag; do
	case $flag in
	a)
		LISTALL=yes
		;;
	c)
		CONFFILE="$OPTARG"
		[ -n "${CONFFILE##/*}" ] && CONFFILE="$ORIGDIR/$CONFFILE"
		;;
	d)
		dist="$OPTARG"
		;;
	t)
		TEST=yes
		;;
	f)
		FORCE=yes
		;;
	q)
		QUIET=yes
		;;
	*)
		showusage
		;;
	esac
done
shift $(($OPTIND - 1))

# if nothing on command line, 
[ $# -eq 0 ] && showusage

# source the conffile
[ -f "$CONFFILE" ] || getout apt-move 25
trap 'getout apt-move 33' EXIT
. "$CONFFILE"
trap - EXIT

if [ ${dist+1} ]; then
	DIST=$dist
	unset dist
fi

checkconf

# set the working directory - create it if required
[ -d $LOCALDIR ] || install -d $LOCALDIR || getout apt-move 5
cd $LOCALDIR

if [ -d .apt-move ] || [ -d dists ] || [ -d pool ]; then
	if [ "$1" != fsck ]; then
		[ -f .apt-move/version ] || getout apt-move 23
		[ $(cat .apt-move/version) = $VERSION ] || getout apt-move 23
	fi
else
	mkdir .apt-move || get-out apt-move 5
	echo $VERSION > .apt-move/version
fi

trap "SIG=INT; getout apt-move 20" INT
trap "SIG=TERM; getout apt-move 21" TERM
trap "SIG=HUP; getout apt-move 22" HUP

# make sure that tempfile always get cleaned up
trap '
	err=$?
	set +e
	CHILDREN="$CHILDREN${!:+ $!}"
	[ -n "$CHILDREN" ] && kill $CHILDREN 2> /dev/null
	wait
	rm -rf $TMPHOME
	if [ $SIG ]; then
		trap - $SIG
		kill -$SIG $$
	else
		getout ${PROGNAME:-apt-move} $err
	fi
' EXIT

TMPHOME=$(
	d=`mktemp -u ${TMPDIR:-/tmp}/MOVE_XXXXXX` && mkdir -m 700 $d &&
		echo $d
) || getout apt-move 5

if [ $QUIET ]; then
	exec 3> /dev/null
else
	exec 3>&1
fi

if [ -d dists ]; then
	find dists -maxdepth 1 -type l -printf '%f %l\n' | sort
fi > $TMPHOME/code-alias

if [ -h $DIST ]; then
	DIST=$(echo $DIST | join -o 2.2 - $TMPHOME/code-alias)
fi

# Put together the basic functions for each option
case "$1" in
get | getlocal)
	FUNCT="getfiles"
	shift
	if [ $# -gt 0 ]; then
		LISTSTATE=$1
		[ -n "${LISTSTATE##/*}" ] && LISTSTATE="$ORIGDIR/$LISTSTATE"
	fi
	;;
move)
	FUNCT="domove"
	;;
delete)
	FUNCT="dodeletes"
	;;
packages)
	FUNCT="dopackages"
	;;
update | localupdate)
	FUNCT="getfiles domove dodeletes dopackages"
	;;
local)
	FUNCT="domove dodeletes dopackages"
	;;
mirror)
	FUNCT="getfiles runmirror dodeletes dopackages"
	;;
sync)
	FUNCT="getfiles runsync dodeletes dopackages"
	;;
exclude)
	FUNCT="excluded"
	;;
fsck)
	FUNCT="dofsck"
	;;
mirrorbin)
	FUNCT="getfiles procbin dodeletes dopackages"
	;;
mirrorsrc)
	FUNCT="getfiles procsrc dodeletes dopackages"
	;;

movefile)
	shift
	if [ -z "$*" ]; then
		showusage
	fi
	PROGNAME=movefile
	echo $* | tr " " "\n" | sed "/^[^/]/s:^:$ORIGDIR/:" | movefiles

	;;

listbin | listsrc)
	case "$2" in
	mirror | repo)
		;;
	sync)
		makeselect
		;;
	*)
		showusage
		;;
	esac
	makeexcl
	$1$2
	;;

*)
	showusage
	;;
esac

if [ -n "$FUNCT" ]; then
	if [ $# -gt 1 ]; then
		showusage
	fi
	for PROGNAME in $FUNCT; do
		$PROGNAME
	done
fi
#
# normal exit
# done (I think)
info "\nAll done, exiting." 
exit 0
