#!/bin/sh

# Local version: 1.193
# $FreeBSD: ports/ports-mgmt/portmaster/files/portmaster.sh.in,v 1.26 2007/12/12 21:50:59 dougb Exp $

# Copyright (c) 2005-2007 Douglas Barton, All rights reserved
# Please see detailed copyright below

trap trap_exit INT

# Keep track of the parent process
if [ -z "$PARENT_PID" ]; then
	PARENT_PID=$$
	: ${TMPDIR:=/tmp}
	UPGRADE_TOOL=portmaster
	export PARENT_PID TMPDIR UPGRADE_TOOL
fi

# /usr/local and /usr/X11R6 are needed in path for make
PATH=/bin:/usr/bin:/sbin:/usr/sbin:/usr/local/bin:/usr/local/sbin:/usr/X11R6/bin
if [ -n "$CCACHE_PATH" ]; then
	if [ -z "$NOCCACHE" ]; then
		PATH="/usr/local/libexec/ccache:$PATH"
	fi
fi
export PATH

umask 022

usage () {
	echo "portmaster version `grep "[$]FreeBSD:" $0 | cut -d ' ' -f 4`"
	echo ''
	echo 'Usage:'
	echo "Common flags: [--force-config] [-CGgntvw B|b uf|i D|d]"
	echo "    [-m <arguments for make>]"
	echo "    [-x <glob pattern to exclude from building>]"
	echo "${0##*/} [Common flags] <full name of port directory in $pdb>"
	echo "${0##*/} [Common flags] <full path to $pd/foo/bar>"
	echo "${0##*/} [Common flags] Multiple full names/paths from $pdb|$pd"
	echo ''
	echo "${0##*/} [Common flags] <glob pattern of directory in $pdb>"
	echo "${0##*/} [Common flags] -p <port directory in $pd>"
	echo "${0##*/} [Common flags] . [Use in $pd/foo/bar to build that port]"
	echo ''
	echo "${0##*/} --show-work [-Gv] [-m <args for make>] <port, as above>"
	echo ''
	echo "${0##*/} [Common flags] -o <new port dir in $pd> <installed port>"
	echo "${0##*/} [Common flags] [-R] -r <name/glob of port directory in $pdb>"
	echo ''
	echo "${0##*/} -a [Common flags]"
	echo ''
	echo "${0##*/} -[l|L]"
	echo ''
	echo "${0##*/} [-b D|d] -e <full name of port directory in $pdb>"
	echo "${0##*/} [-b D|d] -s"
	echo ''
	echo "${0##*/} --clean-distfiles"
	echo "${0##*/} --clean-distfiles-all"
	echo ''
	echo "${0##*/} -h"
	echo ''
	echo "--force-config 'make config' for all ports (must be first option)"
	echo "-C prevents 'make clean' being run in port directory"
	echo "-G prevents recursive 'make config' (unsets --force-config)"
	echo '-B prevents creation of the backup package for the installed port'
	echo '-b create and keep a backup package of an installed port'
	echo '-g create a package of the new port'
	echo '-n do not actually make or install any ports'
	echo '-t recurse dependencies thoroughly, using all-depends-list'
	echo '-v verbose output'
	echo '-w save old shared libraries before deinstall'
	echo "-u unattended mode -- accept defaults for all but 'make config'"
	echo '[-R] -f always rebuild ports (overrides -i)'
	echo '-i interactive update mode'
	echo '-D prevents cleaning of distfiles'
	echo '-d always clean distfiles'
	echo "-m <arguments for the 'make' command line>"
	echo "-x <avoid building ports as dependencies that match this pattern>"
	echo ''
	echo '--show-work list what ports are and would be installed'
	echo ''
	echo '-o replace the installed port with a port from a different origin'
	echo '[-R] -r rebuild port, and all ports that depend on it'
	echo '-R restart an update, skipping ports already up to date'
	echo '-a check all ports, update as necessary'
	echo ''
	echo '-l list installed ports by category'
	echo '-L list installed ports by category, and search for updates'
	echo ''
	echo '-e expunge a port via pkg_delete, and remove its distfiles'
	echo '-s clean out stale ports that used to be depended on'
	echo ''
	echo '--clean-distfiles offer to delete stale distfiles'
	echo '--clean-distfiles-all delete stale distfiles without prompting'
	echo ''
	echo '-h display this help message'
	echo ''
	echo 'Please see the portmaster(8) man page for more information'
	exit ${1:-1}
}

fail () {
	echo ''
	echo "===>>> $1"
	echo "===>>> Aborting update"

	if [ "$$" -eq "$PARENT_PID" ]; then
		trap_exit fail
	else
		safe_exit 1
	fi
}

pmkill () {
	/bin/kill $1 >/dev/null 2>/dev/null
	return $?
}

kill_bad_children () {
	# Make parent_N global in case PIDs are random,
	# and we have to come back in here after them.
	local rc pid ppid command

	rc=0
	ps -axo pid,ppid,command | while read pid ppid command; do
		case "$ppid" in
		1)	case "$command" in
			*" $0 "*)	rc=1 ; parent_2=$pid ; pmkill $pid ;;
			*dialog*)	pmkill $pid ;;
			esac
			;;
		$PARENT_PID)
			case "$command" in
			# Don't kill this pipeline's subshell, but do chase it
			*" $0 "*)	rc=1 ; parent_2=$pid ;;
			*dialog*)	pmkill $pid ;;
			esac
			;;
		$parent_2)
			case "$command" in
			*" $0 "*)	rc=1 ; parent_3=$pid ; pmkill $pid ;;
			'make checksum') rc=1 ; parent_3=$pid ; pmkill $pid ;;
			*dialog*)	pmkill $pid ;;
			esac
			;;
		$parent_3|1)
			case "$command" in
			\[sh\]|*'/sh '*) rc=1 ; parent_4=$pid ; pmkill $pid ;;
			*dialog*)	pmkill $pid ;;
			esac
			;;
		$parent_4|1)
			case "$command" in
			\[sh\]|*'/sh '*) rc=1 ; parent_5=$pid ; pmkill $pid ;;
			*dialog*)	pmkill $pid ;;
			esac
			;;
		$parent_5|1)
			case "$command" in
			*'/fetch '*)	rc=1 ; pmkill $pid ;;
			*dialog*)	pmkill $pid ;;
			esac
			;;
		esac
	done

	return $rc
}

trap_exit () {
	local pid

	TRAP=yes

	if [ -n "$portdir" -a -z "$1" ]; then
		echo ''
		echo "===>>> Upgrade for $portdir exiting due to signal"
	elif [ -z "$1" ]; then
		echo "===>>> Exiting due to signal"
	fi

	if [ "$$" -eq "$PARENT_PID" ]; then
		for file in ${TMPDIR}/fetchlog-${PARENT_PID}-*; do
			pid=`awk '/^MCS_CHILD_PID / {print $2}' $file 2>/dev/null`
			test -n "$pid" || continue
			echo "===>>> Child process $pid:"
			if ! pmkill $pid ; then
				if ps -p $pid >/dev/null; then
					echo "Did not die!"
				fi
			fi
			rm -f $file
		done

		while ! kill_bad_children ; do
			# cheap way to keep it looping
		done
	fi

	safe_exit 1
}

safe_exit () {
	echo ''
	test -n "$grep_deps" && rm -f $grep_deps
	test -n "$req_deps" && rm -f $req_deps

	if [ "$$" -eq "$PARENT_PID" ]; then
		test -n "$NO_DEP_UPDATES" && rm -f $NO_DEP_UPDATES
		test -n "$IPC_SAVE" && rm -f $IPC_SAVE
		test -n "$DI_FILES" && rm -f $DI_FILES && kill_bad_children
		if [ -n "$MASTER_RB_LIST" ]; then
			case "$MASTER_RB_LIST" in
			*/+REQUIRED_BY) ;;
			*)	rm -f $MASTER_RB_LIST ;;
			esac
		fi

		if [ -z "$TRAP" -a \
		    -e "${TMPDIR}/f-${PARENT_PID}-package-flag" -a \
		    -n "$pkgrep" ]; then
find ${pkgrep}/ -type f -newer ${TMPDIR}/f-${PARENT_PID}-package-flag -delete
		fi

		for file in ${TMPDIR}/f-${PARENT_PID}-*; do
			test -f $file && unlink $file
		done

		if [ -n "$RESTART" -o -n "$FORCE" ]; then
			if [ -z "$TRAP" ]; then
			find $pdb -type f -name PM_UPGRADE_DONE_FLAG -delete
			fi
		fi

		if [ -n "$DISPLAY_LIST" ]; then
			for f in $DISPLAY_LIST; do
				echo "===>>> pkg-message for ${f%/+DISPLAY}"
				cat $pdb/$f
				echo ''
			done

			echo "===>>> Done displaying pkg-message files"
		fi
	else
		# Save state for the parent process to read back in
		echo "CURRENT_DEPS_O='$CURRENT_DEPS_O'" >> $IPC_SAVE
		echo "CURRENT_DEPS_I='$CURRENT_DEPS_I'" >> $IPC_SAVE
		echo "IGNOREME_YES='$IGNOREME_YES'" >> $IPC_SAVE
		echo "DISPLAY_LIST='$DISPLAY_LIST'" >> $IPC_SAVE

		if [ -n "$INTERACTIVE_UPDATE" ]; then
			echo "INTERACTIVE_YES='$INTERACTIVE_YES'" >> $IPC_SAVE
			echo "INTERACTIVE_NO='$INTERACTIVE_NO'" >> $IPC_SAVE
		fi
		if [ -n "$URB_YES" ]; then
			echo "URB_DONE_LIST='$URB_DONE_LIST'" >> $IPC_SAVE
		fi
		if [ -n "$FORCE" ]; then
			echo "FORCE_DONE_LIST='$FORCE_DONE_LIST'" >> $IPC_SAVE
		fi
	fi

	exit ${1:-0}
}

update_contents () {
	local tempfile

	tempfile=`mktemp -t tempfile-${new_port}`

	sed "s/@pkgdep $1/@pkgdep $2/" $dep_port_contents > $tempfile &&
	    mv $tempfile $pdb/$dep_port/+CONTENTS
	    chmod 644 $pdb/$dep_port/+CONTENTS

	if [ -n "$oldportdir" ]; then
		sed "s%N:${oldportdir}\$%N:${newportdir}%" $dep_port_contents > $tempfile &&
		    mv $tempfile $pdb/$dep_port/+CONTENTS
		    chmod 644 $pdb/$dep_port/+CONTENTS

	fi
}

dep_warn () {
	local num_ports1

	echo ''
	echo "===>>> Warning! Potential unrecorded dependencies on $new_port"
	echo "===>>> From existing +CONTENTS files:"
	grep -B1 DEPORIGIN:$upg_origin$ $pdb/*/+CONTENTS |
	    sort -u | sed -e "s#$pdb/##" -e 1d | less -F
	num_ports1=`grep DEPORIGIN:$upg_origin$ $pdb/*/+CONTENTS |
	    sort -u | wc -l | awk '{print $1}'`
	echo "===>>> $num_ports1 ports"
	echo ''
}

update_reqfile () {
	local num_ports2 sdiff_deps

	dep_warn
	num_ports2=`wc -l $req_deps | awk '{print $1}'`
	echo "===>>> From $pdb/$upg_port/+REQUIRED_BY:"
	less -F $req_deps
	echo "===>>> $num_ports2 ports"
	echo ''
	echo "===>>> Use dependencies from existing +CONTENTS files	[c]"
	echo "===>>> Use dependencies from existing +REQUIRED_BY file	[r]"
	echo "===>>> Use sdiff to edit both files into a new file	[s]"
	echo ''
	if [ -z "$UNATTENDED" ]; then
		echo -n "===>>> Update dependency list? [r] "
		read DEPUPDATE

		case "$DEPUPDATE" in
		[cC])	mv $grep_deps $req_deps ; unset grep_deps ;;
		[sS])	sdiff_deps=`mktemp -t sdiff-deps-${short_port}`
			sdiff -o $sdiff_deps --text --suppress-common-lines \
			    --width=`tput columns` $req_deps $grep_deps
			mv $sdiff_deps $req_deps
			;;
		esac
	else
		echo "===>>> Default (use +REQUIRED_BY file) in unattended mode"
	fi
}

update_port () {
	local upd upd_origin

	if [ -n "$NO_DEP_UPDATES" ]; then
		rm -f $NO_DEP_UPDATES
		unset NO_DEP_UPDATES
	fi

	case "$1" in
	-p)	upd=$2
		test -n "$URB_YES" && upd_origin=${2#$pd/}
		;;
	*)	upd=$1
		test -n "$URB_YES" && upd_origin=`origin_from_pdb $pdb/$1`
		;;
	esac

	echo "===>>> Launching child to update ${upd#$pd/}"
	echo ''
	if [ -z "$NO_ACTION" ]; then
		($0 $ARGS $@) || fail "Update for $upd failed"
		. $IPC_SAVE

		# Only do this if we are in the +REQUIRED_BY code to
		# avoid nasty (potential) circular dependencies
		if [ -n "$URB_YES" ]; then
			URB_DONE_LIST="${URB_DONE_LIST}${upd_origin}:"
		fi
	else
		test -n "$VERBOSE" &&
		    echo "===>>> Build canceled due to -n flag"
	fi

	if [ -n "$UPDATE_ALL" ]; then
		echo "===>>> Returning to update check of installed ports"
	elif [ -n "$UPDATE_REQ_BYS" ]; then
		return 0
	elif [ -n "$CONFIG_ONLY" ]; then
		echo "===>>> Continuing 'make config' dependency check for $portdir"
	else
		echo "===>>> Returning to dependency check for $portdir"
	fi

	return 0
}

check_interactive () {
	local UPD_OR_NOT

	if [ -n "$INTERACTIVE_UPDATE" ]; then
		case "$INTERACTIVE_YES" in
		*:${1}:*)	return 0 ;;
		esac

		case "$INTERACTIVE_NO" in
		*:${1}:*)	return 1 ;;
		esac

		echo -n "===>>> Update ${1}? [y] "
		read UPD_OR_NOT
		case "$UPD_OR_NOT" in
		[nN]*)	INTERACTIVE_NO="${INTERACTIVE_NO}${1}:"
			return 1
			;;
		*)	INTERACTIVE_YES="${INTERACTIVE_YES}${1}:" ;;
		esac
	fi

	return 0
}

iport_from_origin () {
	local dir

	dir=`grep -l "@comment ORIGIN:${1}$" $pdb/*/+CONTENTS`

	# It should not happen that more than one port meets this
	# requirement, but it can if the pkg data is corrupted.
	dir="${dir%%/+CONTENTS*}"
	dir="${dir#$pdb/}"

	echo $dir
}

origin_from_pdb () {
	grep '@comment ORIGIN' ${1}/+CONTENTS 2>/dev/null | cut -f2 -d':'
}

check_for_updates () {
	local upd_port port_ver do_update

	upd_port=`origin_from_pdb $pdb/$1`
	if [ -z "$upd_port" ]; then
		if [ -n "$VERBOSE" ]; then
			echo "===>>> No ORIGIN in $pdb/$1/+CONTENTS"
			echo ''
		fi
		return 0
	fi

	if [ -d "$pd/$upd_port" ]; then
		if ! cd $pd/$upd_port 2>/dev/null; then
			if [ -e "$pdb/$1/+IGNOREME" ]; then
			echo "===>>> Warning: Unable to cd to $pd/$upd_port"
			echo "===>>> Continuing due to $pdb/$1/+IGNOREME"
				return 0
			else
			    fail "Cannot cd to port directory: $pd/$upd_port"
			fi
		fi
		port_ver=`make $PM_MAKE_ARGS -V PKGNAME`

		[ -z "$port_ver" ] && fail "Is $pd/$upd_port/Makefile missing?"

		if [ "$1" = "$port_ver" ]; then
			if [ -z "$LIST" -a -z "$LIST_PLUS" ]; then
				# Keep list both ways to increase performance
				CURRENT_DEPS_O="${CURRENT_DEPS_O}${upd_port}:"
				CURRENT_DEPS_I="${CURRENT_DEPS_I}${1}:"
			fi

			if [ -n "$FORCE" ]; then
				if [ ! -e "$pdb/$1/PM_UPGRADE_DONE_FLAG" ]; then
					do_update=yes
				fi
			elif [ -n "$URB_YES" -a -n "$RESTART" ]; then
				if [ ! -e "$pdb/$1/PM_UPGRADE_DONE_FLAG" ]; then
					if grep -q $1 $MASTER_RB_LIST; then
						do_update=yes
					fi
				else
					return 0
				fi
			else
				return 0
			fi
		else
			case `pkg_version -t $1 $port_ver` in
			\<)	do_update=yes ;;
			=)	;;	# Should not be reached
			*) if [ -n "$VERBOSE" ]; then
				echo ''
				echo "	===>>> Port version $port_ver does not"
				echo "	===>>> seem newer than installed $1"
				echo ''
			   fi
			   ;;
			esac
		fi
	else
		# This will fail if it doesn't exist anymore
		# It will return 1 if we know nothing about the port
		find_moved_port $upd_port || return 0

		# If the port has moved, we have to update it
		do_update=yes
	fi

	if [ -n "$do_update" ]; then
		case "$2" in
		list)	if [ -z "$newportdir" ]; then
				echo "	===>>> New version available: $port_ver"
				if [ -e "$pdb/$1/+IGNOREME" ]; then
				echo "	===>>> +IGNOREME file is present for $1"
				fi
				num_updates=$(( $num_updates + 1 ))
			else
				unset newportdir
			fi
			return 0
			;;
		esac

		if ! check_interactive $1 ; then
			return 0
		fi

		update_port $1 || return 1
	fi

	return 0
}

find_moved_port () {
	# newportdir and oldportdir are used globally
	local sf IFS l

	sf=$1

	# To avoid having each word of the reason treated separately
	IFS='
'
	for l in `grep "^$sf" $pd/MOVED`; do
		case "$l" in
		${sf}\|\|*)	fail "The $sf port has been deleted: ${l##*|}"
				;;
		${sf}\|*)	newportdir=${l#*\|}
				newportdir=${newportdir%%\|*}
				echo ''
				echo "===>>> The $sf port moved to $newportdir"
				echo "===>>> Reason: ${l##*|}"
				echo ''
				find_moved_port $newportdir
				;;
		esac
	done

	if [ -z "$newportdir" ]; then
		echo ''
		echo "===>>> No $pd/$1 exists, and no information"
		echo "===>>> about $1 can be found in $pd/MOVED"
		echo ''
		return 1
	fi

	oldportdir=$1

	return 0
}

ports_by_category () {
	local pkg

	for pkg in $pdb/*; do
		if [ -s "$pkg/+REQUIRED_BY" ]; then
			if grep -q '^@pkgdep ' $pkg/+CONTENTS 2>/dev/null; then
				branches="$branches $pkg"
			else
				trunks="$trunks $pkg"
			fi
		else
			if grep -q '^@pkgdep ' $pkg/+CONTENTS 2>/dev/null; then
				leaves="$leaves $pkg"
			else
				test -s $pkg/+CONTENTS && roots="$roots $pkg"
			fi
		fi
	done
}

dependency_check () {
	local dep_port_list dep_port ign_p cur_p upd_args p op old_p conflicts glob conflict_port

	# Print a message here because sometimes list generation takes
	# a long time to return.
	echo "===>>> Gathering dependency list for $portdir from ports"
	dep_port_list=`make $PM_MAKE_ARGS $1 | sort -u`

	if [ -z "$dep_port_list" ]; then
		echo "===>>> No dependencies for $portdir"
		[ -n "$SHOW_WORK" ] && safe_exit
		return 0
	else
		if [ -n "$CONFIG_ONLY" ]; then
			echo "===>>> Starting recursive 'make config' check"
		else
			echo "===>>> Starting dependency check"
		fi
	fi

	for dep_port in $dep_port_list; do
		case "$dep_port" in
		*${EXCL}*) test -n "$VERBOSE" &&
echo "===>>> Skipping ${dep_port#$pd/} because it matches the pattern: *${EXCL}*"
			continue
			;;
		esac

		if [ -n "$SHOW_WORK" ]; then
			orig=${dep_port#$pd/}
			dir=`iport_from_origin $orig`
			case "$dir" in
			'') echo "===>>> NOT INSTALLED		$orig" ;;
			*)  echo "===>>> Installed $orig" ;;
			esac

			continue
		fi

		test -n "$VERBOSE" &&
		    echo "===>>> Checking dependency: $dep_port"

		# Do this first to catch out of date dependencies
		if [ -n "$CONFIG_ONLY" ]; then
			case "$CONFIG_SEEN_LIST" in
			*:${dep_port#$pd/}:*)	continue ;;
			esac
			CONFIG_SEEN_LIST="${CONFIG_SEEN_LIST}${dep_port#$pd/}:"
		fi

		case "$CURRENT_DEPS_O" in
		*:${dep_port#$pd/}:*)	continue ;;
		esac

		case "$FORCE_DONE_LIST" in
		*:${dep_port#$pd/}:*)	continue ;;
		esac

		cd $dep_port &&
		conflicts=`make BEFOREPORTMK=yes $PM_MAKE_ARGS -V CONFLICTS`
		for glob in $conflicts; do
			conflict_port=`pkg_info -I $glob 2>/dev/null |
			    cut -f1 -d' '`
			if [ -n "$conflict_port" ]; then
				echo ''
				echo "===>>> The dependency for ${dep_port#$pd/}"
				echo "       seems to be handled by $conflict_port"
				echo ''
				dep_port="$pd/`origin_from_pdb $pdb/$conflict_port`"
			fi
		done

		ign_p=''
		cur_p=`iport_from_origin ${dep_port#$pd/}`
		if [ -n "$cur_p" ]; then
			upd_args=$cur_p
			ign_p=$cur_p
		else
			upd_args="-p $dep_port"		# Sensible default

			# Check to see if the dependency has moved because
			# if so, we need to update the old port to fix it
			p=${dep_port#$pd/}
			op=`sed -ne "s#\([^|]*\)|$p|.*#\1#p" $pd/MOVED`

			# In case there is more than one match, use the latest
			op=${op##* }

			if [ -n "$op" ]; then
				old_p=`iport_from_origin ${op}`
				if [ -n "$old_p" ]; then
					upd_args=$old_p
					ign_p=$old_p
				fi
			fi
		fi

		if [ -e "$pdb/$ign_p/+IGNOREME" ]; then
			if [ -n "$VERBOSE" ]; then
				echo ''
				echo "===>>> Skipping $ign_p due to +IGNOREME file"
				echo ''
			fi
			continue
		fi

		if [ -n "$FORCE" ]; then
			if [ ! -e "$pdb/$cur_p/PM_UPGRADE_DONE_FLAG" ]; then
				echo "===>>> Forcing update for $dep_port"
				update_port $upd_args
				continue
			fi
		fi

		if [ -z "$cur_p" -a -n "$old_p" ]; then
			cur_p=$old_p
		fi

		if [ -n "$URB_YES" -a -n "$cur_p" ]; then
			case "$URB_DONE_LIST" in
			*:${dep_port#$pd/}:*) continue ;;
			esac

			if grep -q $cur_p $MASTER_RB_LIST; then
				if ! check_interactive $cur_p ; then
					continue
				fi

				if [ -z "$RESTART" -a -z "$FORCE" ]; then
					update_port $cur_p || return 1
				else
					check_for_updates $cur_p || return 1
				fi
				continue
			fi
		fi

		if [ -n "$cur_p" ]; then
			check_for_updates $cur_p
		else
			if ! check_interactive $dep_port ; then
				continue
			fi

			update_port -p $dep_port
		fi
	done
	if [ -n "$CONFIG_ONLY" ]; then
		echo "===>>> Recursive 'make config' check complete for $portdir"
	else
		echo "===>>> Dependency check complete for $portdir"
		echo ''
	fi

	[ -n "$SHOW_WORK" ] && safe_exit
}

unset_recursive_config () {
	unset CONFIG_SEEN_LIST CONFIG_ONLY
}

req_by_error () {
	local DISCARD

	echo "===>>> WARNING! $pdb/$1/+REQUIRED_BY "
	echo "===>>> shows that $2 requires $1, but "
	echo "===>>> $2 does not seem to be installed"
	echo -n "===>>> Press Enter to proceed "
	read DISCARD
}

find_and_delete_distfiles () {
	# old_distpattern is used for subsequent invocations of the function
	# distfiles_checked is used globally
	local distpattern file DELORNOT

	distpattern=${1%[_-]*}
	[ "$distpattern" = "$old_distpattern" ] && return 0
	for file in ${distpattern}*; do
		# This generally means the pattern did not match
		case "$file" in
		*\*)	old_distpattern=$distpattern
			find_and_delete_distfiles ${distpattern}
			continue
			;;
		esac

		case "$distfiles_checked" in
		*${file}*) continue ;;
		esac

		case "$distfiles" in
		*${file}*)
			distfiles_checked="$file $distfiles_checked"
			if [ -n "$VERBOSE" -a -z "$do_delete" ]; then
				echo "===>>> Keeping current distfile: $file"
			fi
			continue	# Do not delete current version
			;;
		*)	[ ! -d "$file" ] || continue
			if [ -e "$DI_FILES" ]; then
				grep -q \(${file}\) $DI_FILES && continue
			fi

			if [ -n "$ALWAYS_SCRUB_DISTFILES" ]; then
				echo "===>>> Deleting stale distfile: $file"
				rm -f $file
				continue
			fi

			echo -n "===>>> Delete $file? [n] "
			read DELORNOT
			case "$DELORNOT" in
			[yY])	rm -f $file ;;
			esac
			;;
		esac
	done
}

delete_stale_distfiles () {
	# distfiles is used globally
	# distfiles_checked is used globally
	# inherit distdir from the environment, but only modify our copy
	local distdir dist_subdir file DELORNOT distfile

	dist_subdir=`make BEFOREPORTMK=yes $PM_MAKE_ARGS -V DIST_SUBDIR`
	test -n "$dist_subdir" && distdir="${distdir}/${dist_subdir}/"

	# Also used in find_and_delete_distfiles() to make sure
	# we do not delete the current set of distfiles
	distfiles=`make $PM_MAKE_ARGS -V ALLFILES`

	if [ -d "$distdir" ]; then
		cd $distdir || fail "cd to $distdir failed!"
	else
		echo '' ; echo ''
		echo "===>>> $distdir does not exist, therefore we"
		echo "       will assume that all relevant distfiles are gone."
		echo ''
		return 0
	fi

	# If these two match, it means that the distfiles in the +CONTENTS
	# file are the current set, so do not delete them.
	if [ ! "$dist_list_files" = "${distfiles% }" ]; then
		for file in $dist_list_files; do
			[ -f $file ] || continue

			case "$distfiles" in
			*${file}*)
				distfiles_checked="$file $distfiles_checked"
				if [ -n "$VERBOSE" ]; then
				echo "===>>> Keeping current distfile: $file"
				fi
				continue # Do not delete current version
				;;
			esac

			if [ -n "$ALWAYS_SCRUB_DISTFILES" ]; then
				echo "===>>> Deleting stale distfile: $file"
				rm -f $file
				continue
			fi

			echo -n "===>>> Delete $file? [n] "
			read DELORNOT
			case "$DELORNOT" in
			[yY])	rm -f $file ;;
			esac
		done
	fi

	# Eventually we will hide this behind an "aggressive distfile purge"
	# flag, but until the DISTFILE stuff is well populated in PORT_DBDIR,
	# keep doing it both ways.
	for distfile in $distfiles; do
		find_and_delete_distfiles $distfile
	done
}

delete_all_distfiles () {
	# do_delete is used globally
	local DELORNOT

	if ! cd $pd/$1 2>/dev/null; then
		echo ''
		echo "===>>> No $pd/$1 to cd to in order to delete"
		echo "       old distfiles, remove by hand if desired"
	else
		if [ -n "$ALWAYS_SCRUB_DISTFILES" ]; then
			echo "===>>> Deleting all distfiles for $1"
			do_delete=1
		else
			echo -n "===>>> Delete all distfiles for ${1}? [n] "
			read DELORNOT
			case "$DELORNOT" in
			[yY])	do_delete=1 ;;
			*)	delete_stale_distfiles ;;
			esac
		fi

		if [ -n "$do_delete" ]; then
			delete_stale_distfiles
			rm -f $distfiles
			find $distdir -type d -empty -delete
		fi
	fi
}

init_pkgrep () {
	pkgrep=`make $PM_MAKE_ARGS -f/usr/share/mk/bsd.port.mk -VPKGREPOSITORY`
	[ -n "$pkgrep" ] || fail 'The value of PKGREPOSITORY cannot be empty'
	export pkgrep
	mkdir -p $pkgrep
}

backup_package () {
	echo "===>>> Creating a backup package for old version $1"
	cd $pkgrep || fail "Cannot cd into the $pkgrep directory for backup"
	if pkg_create -b $1; then
		echo "	===>>> Package can be found in $pkgrep"
	else
		local PROCEED

		if [ -z "$UNATTENDED" ]; then
			echo ''
			echo "===>>> Backup package creation failed for ${1}!"
			echo ''
			echo "===>>> Ignore this error	[i]"
			echo "===>>> Abort update		[a]"
			echo ''
			echo -n "===>>> How would you like to proceed? [i] "
			read PROCEED
			case "$PROCEED" in
			a)	fail "Backup package creation failed for $1" ;;
			esac
		else
			fail "Backup package creation failed for $1"
		fi
	fi
}

# Read a global rc file first
if [ -r /etc/portmaster.rc ]; then
	. /etc/portmaster.rc
fi

# Read a local one next, and allow the command line to override
if [ -r "$HOME/.portmasterrc" ]; then
	. $HOME/.portmasterrc
fi

# Set default values here so that they can be overriden above
if [ -z "$pd" ]; then
	pd=`make BEFOREPORTMK=yes -f/usr/share/mk/bsd.port.mk -V PORTSDIR`
	[ -n "$pd" ] || fail 'The value of PORTSDIR cannot be empty'
	export pd
fi
if [ -z "$pdb" ]; then
	pdb=`make -f/usr/share/mk/bsd.port.mk -V PKG_DBDIR`
	[ -n "$pdb" ] || fail 'The value of PKG_DBDIR cannot be empty'
	export pdb
fi
if [ -z "$distdir" ]; then
	distdir=`make BEFOREPORTMK=yes -f/usr/share/mk/bsd.port.mk -V DISTDIR`
	[ -n "$distdir" ] || fail 'The value of DISTDIR cannot be empty'
	# In case it is a symlink
	distdir="${distdir}/"
	export distdir
fi

case "$1" in
--clean-distfiles)	CLEAN_DISTFILES=yes ;;
--clean-distfiles-all)	CLEAN_DISTFILES=yes ; ALL=yes ;;
--show-work)		SHOW_WORK=yes ; RECURSE_THOROUGH=yes ; shift ;;
--force-config)		FORCE_CONFIG=yes ; export FORCE_CONFIG ; shift ;;
esac

read_distinfos () {
	local ugp pkg origin distinfo disc1 file disc2

	echo "===>>> Gathering distinfo list for installed ports"
	[ -n "$upg_port" ] && upg="${pdb}/$upg_port"

	for pkg in $upg ${pdb}/*; do
		[ -d $pkg ] || continue
		origin=`origin_from_pdb $pkg`

		if [ ! -d "$pd/$origin" ]; then
			find_moved_port $origin >/dev/null || continue
			origin=$newportdir
		fi

		cd $pd/$origin 2>/dev/null || continue
		distinfo=`make $PM_MAKE_ARGS -V MD5_FILE`
		if [ -s "$distinfo" ]; then
			grep '^MD5' $distinfo | while read disc1 file disc2; do
				echo $file >> $DI_FILES
			done
		fi
	done
}

if [ -n "$CLEAN_DISTFILES" ]; then
	# Set the file name here because this function is
	# usually called in a subshell.
	DI_FILES=`mktemp -t DI-FILES-$PARENT_PID`
	export DI_FILES
	read_distinfos

	echo "===>>> Checking for stale distfiles"
	for df in `find $distdir -type f`; do
		f=${df#$distdir}
		if ! grep -q \(${f}\) $DI_FILES; then
			if [ -n "$ALL" ]; then
				echo "===>>> Deleting $f"
				rm $df
			else
				echo -n "===>>> Delete stale file: ${f}? [y] "
				read DEL_OR_NOT
				case "$DEL_OR_NOT" in
				[nN]*)	continue ;;
				*)	rm $df ;;
				esac
			fi
		fi
	done

	safe_exit
fi

# Save switches for potential child processes
while getopts 'BCDGLRabde:fghilm:nop:r:stuvwx:' COMMAND_LINE_ARGUMENT ; do
	case "${COMMAND_LINE_ARGUMENT}" in
	B)	NO_BACKUP=yes; ARGS="-B $ARGS" ;;
	C)	DONT_PRE_CLEAN=yes; ARGS="-C $ARGS" ;;
	D)	DONT_SCRUB_DISTFILES=yes; ARGS="-D $ARGS" ;;
	G)	NO_RECURSIVE_CONFIG=yes; unset FORCE_CONFIG ; ARGS="-G $ARGS" ;;
	L)	LIST_PLUS=yes ;;
	R)	RESTART=yes ; ARGS="-R $ARGS" ;;
	a)	UPDATE_ALL=yes ;;
	b)	BACKUP=yes; ARGS="-b $ARGS" ;;
	d)	ALWAYS_SCRUB_DISTFILES=yes; ARGS="-d $ARGS" ;;
	e)	EXPUNGE=$OPTARG ;;
	f)	FORCE=yes
		FORCE_DONE_LIST=':'
		export FORCE FORCE_DONE_LIST
		;;
	g)	MAKE_PACKAGE=yes; ARGS="-g $ARGS" ;;
	h)	usage 0 ;;
	i)	INTERACTIVE_UPDATE=yes; ARGS="-i $ARGS" ;;
	l)	LIST=yes ;;
	m)	PM_MAKE_ARGS=$OPTARG
		export PM_MAKE_ARGS	# For 'make checksum'
		ARGS="-m $PM_MAKE_ARGS $ARGS"
		;;
	n)	NO_ACTION=yes; ARGS="-n $ARGS" ;;
	o)	REPLACE_ORIGIN=yes ;;
	p)	portdir="${OPTARG#$pd/}" ; portdir=${portdir%/} ;;
	r)	UPDATE_REQ_BYS=yes; upg_port=$OPTARG ;;
	s)	CLEAN_STALE=yes ;;
	t)	RECURSE_THOROUGH=yes; ARGS="-t $ARGS" ;;
	u)	UNATTENDED=yes; ARGS="-u $ARGS" ;;
	v)	VERBOSE=yes; ARGS="-v $ARGS" ;;
	w)	SAVE_SHARED=yes; ARGS="-w $ARGS" ;;
	x)	EXCL=$OPTARG ; ARGS="-x $EXCL $ARGS" ;;
	*)	usage ;;
	esac
done
shift $(( $OPTIND - 1 ))

: ${EXCL:=Ishouldthinkofsomethingclevertosayhere}

if [ -n "$LIST" -o -n "$LIST_PLUS" ]; then
	ports_by_category

	num_roots=0
	num_trunks=0
	num_branches=0
	num_leaves=0
	num_updates=0

	echo "===>>> Root ports (No dependencies, not depended on)"
	for port in $roots; do
		echo "===>>> ${port##*/}"
		[ -n "$LIST_PLUS" ] && check_for_updates ${port##*/} list
		num_roots=$(( $num_roots + 1 ))
	done
	echo "===>>> $num_roots root ports"
	echo ''
	echo "===>>> Trunk ports (No dependencies, are depended on)"
	for port in $trunks; do
		echo "===>>> ${port##*/}"
		[ -n "$LIST_PLUS" ] && check_for_updates ${port##*/} list
		num_trunks=$(( $num_trunks + 1 ))
	done
	echo "===>>> $num_trunks trunk ports"
	echo ''
	echo "===>>> Branch ports (Have dependencies, are depended on)"
	for port in $branches; do
		echo "===>>> ${port##*/}"
		[ -n "$LIST_PLUS" ] && check_for_updates ${port##*/} list
		num_branches=$(( $num_branches + 1 ))
	done
	echo "===>>> $num_branches branch ports"
	echo ''
	echo "===>>> Leaf ports (Have dependencies, not depended on)"
	for port in $leaves; do
		echo "===>>> ${port##*/}"
		[ -n "$LIST_PLUS" ] && check_for_updates ${port##*/} list
		num_leaves=$(( $num_leaves + 1 ))
	done
	echo "===>>> $num_leaves leaf ports"
	echo ''
	num_ports=$(( $num_roots + $num_trunks + $num_branches + $num_leaves ))
	echo "===>>> $num_ports total installed ports"

	if [ "$num_updates" -gt 1 ]; then
		echo "	===>>> $num_updates have new versions available"
	elif [ "$num_updates" -eq 1 ]; then
		echo "	===>>> 1 has a new version available"
	elif [ -n "$LIST_PLUS" ]; then
		echo "	===>>> There are no new versions available"
	fi

	exit 0
fi

find_dl_distfiles () {
	# dist_list and dist_list_files are used globally

	# We need to define this for use in the deletion/update process.
	# Do it relative to OPTIONSFILE so we can be sure that they end
	# up in the same place without having to derive it ourselves.
	cd $pd/$1
	dist_list=`make BEFOREPORTMK=yes $PM_MAKE_ARGS -V OPTIONSFILE`
	dist_list="${dist_list%options}distfiles"

	[ -n "$DONT_SCRUB_DISTFILES" ] && return 0
	[ -s "$dist_list" ] || return 0

	# The grep is needed to allow for comments, etc.
	local file
	for file in `grep ^DISTFILE $dist_list | cut -f2 -d:`; do
		dist_list_files="${dist_list_files} ${file#*/}"
	done

	dist_list_files=${dist_list_files# }
}

delete_dist_list () {
	test -e "$dist_list" && unlink $dist_list
	rmdir ${dist_list%/distfiles} 2>/dev/null
}

if [ -n "$EXPUNGE" ]; then
	if [ -d "$pdb/$EXPUNGE" ]; then
		origin=`origin_from_pdb $pdb/$EXPUNGE`
		deplist=`grep -l DEPORIGIN:$origin$ $pdb/*/+CONTENTS`
		if [ -n "$deplist" ]; then
		echo "===>>> Warning: ports with dependencies on ${EXPUNGE}:"
			for dep in $deplist; do echo ${dep%/+CON*}; done
			exit 1
		fi

		if [ -n "$BACKUP" ]; then
			init_pkgrep
			backup_package $EXPUNGE
		fi

		find_dl_distfiles $origin

		echo "===>>> Running pkg_delete -f $EXPUNGE"
		pkg_delete -f $EXPUNGE
		delete_dist_list
		if [ -z "$DONT_SCRUB_DISTFILES" ]; then
			delete_all_distfiles $origin
		fi
		exec $0 -s $ARGS
	else
		fail "No such directory/port: $pdb/$EXPUNGE"
	fi

	exit 0	# Should not be reached
fi

if [ -n "$CLEAN_STALE" ]; then
	if [ -z "$do_not_delete" ]; then
		do_not_delete=':'
		export do_not_delete
	fi

	for file in `find $pdb/ -name \+REQUIRED_BY -empty` ; do
		dir="${file%/+REQUIRED_BY}"
		iport=${dir#$pdb/}

		case "$do_not_delete" in
		*:${iport}:*)	continue ;;
		esac

		echo ''

		origin=`origin_from_pdb $dir`
		deplist=`grep -l DEPORIGIN:$origin$ $pdb/*/+CONTENTS`
		if [ -n "$deplist" ]; then
		echo "===>>> Warning: unrecorded dependencies on ${iport}:"
			for dep in $deplist; do echo ${dep%/+CON*}; done
			continue
		fi

		pkg_info $iport

		echo -n "===>>> ${iport} is no longer depended on, delete? [n] "
		read YESNO
		case "$YESNO" in
		[yY])	if [ -n "$BACKUP" ]; then
				[ -z "$pkgrep" ] && init_pkgrep
				backup_package $iport
			fi

			find_dl_distfiles $origin

			echo "===>>> Running pkg_delete -f $iport"
			pkg_delete -f ${iport}
			delete_dist_list
			if [ -z "$DONT_SCRUB_DISTFILES" ]; then
				delete_all_distfiles $origin
			fi
			exec $0 -s $ARGS
			;;
		*) echo -n "	===>>> Remove empty +REQUIRED_BY file? [n] "
			read DELORNOT
			case "$DELORNOT" in
			[yY])	rm -f $file ;;
			*)	do_not_delete="${do_not_delete}${iport}:" ;;
			esac
			;;
		esac
	done

	exit 0
fi

test -n "$FORCE" && unset INTERACTIVE_UPDATE
if [ -n "$UNATTENDED" ]; then
	unset INTERACTIVE_UPDATE

	if [ -z "$DONT_SCRUB_DISTFILES" -a -z "$ALWAYS_SCRUB_DISTFILES" ]; then
		ALWAYS_SCRUB_DISTFILES=yes
		ARGS="-d $ARGS"
	fi
fi

if [ "$$" -eq "$PARENT_PID" ]; then
	CURRENT_DEPS_O=':'
	CURRENT_DEPS_I=':'
	IGNOREME_YES=':'
	DISPLAY_LIST=''
	IPC_SAVE=`mktemp -t ipc_save-$PARENT_PID`
	export CURRENT_DEPS_O CURRENT_DEPS_I IGNOREME_YES DISPLAY_LIST IPC_SAVE

	PORTS_PREFIX=`make BEFOREPORTMK=yes $PM_MAKE_ARGS -f/usr/share/mk/bsd.port.mk -VPREFIX`
	[ -n "$PORTS_PREFIX" ] || fail 'The value of PREFIX cannot be empty'
	export PORTS_PREFIX

	if [ -n "$INTERACTIVE_UPDATE" ]; then
		INTERACTIVE_YES=':'
		INTERACTIVE_NO=':'
		export INTERACTIVE_YES INTERACTIVE_NO
	fi

	if [ -n "$UPDATE_REQ_BYS" ]; then
		URB_DONE_LIST=':'
		export URB_DONE_LIST
	fi

	if [ -n "$UPDATE_REQ_BYS" -o -n "$FORCE" ]; then
		if [ -z "$RESTART" ]; then
			find $pdb -type f -name PM_UPGRADE_DONE_FLAG -delete
		fi
	fi

	if [ -z "$CONFIG_ONLY" -a -z "$NO_RECURSIVE_CONFIG" ]; then
		NO_DEP_UPDATES=`mktemp -t no_dep_updates-$PARENT_PID`

		CONFIG_SEEN_LIST=':'
		CONFIG_ONLY=yes
		export CONFIG_SEEN_LIST CONFIG_ONLY
	fi

	if [ -z "$NO_BACKUP" ]; then
		init_pkgrep
		if [ -z "$BACKUP" ]; then
			touch ${TMPDIR}/f-${PARENT_PID}-package-flag
		fi
	fi

	if [ -z "$SHOW_WORK" -a -z "$DONT_SCRUB_DISTFILES" ]; then
		# Set the file name here so it's visible to the children
		DI_FILES=`mktemp -t DI-FILES-$PARENT_PID`
		export DI_FILES
	fi

	if [ $# -gt 1 -a -z "$REPLACE_ORIGIN" ]; then
		# This has to be done here because the children
		# will never be PARENT_PID for the test below.
		if [ -z "$SHOW_WORK" -a -z "$DONT_SCRUB_DISTFILES" ]; then
			(read_distinfos)&
		fi

		if [ -z "$NO_RECURSIVE_CONFIG" ]; then
			for port in $@; do
				($0 $ARGS $port) ||
				    fail "Update for $port failed"
				. $IPC_SAVE
			done
			unset_recursive_config
			echo ''
			echo "===>>> Starting build for ports:        <<<==="
			echo "===>>> $@ <<<==="
			echo ''
		fi
		for port in $@; do
			($0 $ARGS $port) || fail "Update for $port failed"
			. $IPC_SAVE
		done
		safe_exit
	fi
else
	# Zero out this file so that we can save our data to it safely
	> $IPC_SAVE
fi

if [ -n "$UPDATE_ALL" ]; then
	if [ -z "$DONT_SCRUB_DISTFILES" ]; then
		(read_distinfos)&
	fi

	echo "===>>> Starting check of installed ports for available updates"
	ports_by_category

	if [ -n "$CONFIG_ONLY" ]; then
		echo "===>>> Checking ports for recursive 'make config'"
		for pkg in $roots $trunks $branches $leaves; do
			test -n "$VERBOSE" &&
			    echo "===>>> Checking installed port: ${pkg#$pdb/}"

			case "$pkg" in
			*${EXCL}*) test -n "$VERBOSE" &&
echo "===>>> Skipping ${pkg#$pdb/} because it matches the pattern: *${EXCL}*"
				continue
				;;
			esac

			case "$CURRENT_DEPS_I" in
			*:${pkg#$pdb/}:*)	continue ;;
			esac

			orig=`origin_from_pdb $pkg`
			case "$CONFIG_SEEN_LIST" in
			*:${orig}:*)	continue ;;
			esac
			CONFIG_SEEN_LIST="${CONFIG_SEEN_LIST}${orig}:"
			check_for_updates ${pkg#$pdb/} || fail 'Update failed'
		done

		if [ -e "$NO_DEP_UPDATES" ]; then
			echo "===>>> The 'make config' check revealed no ports to update"
			safe_exit
		fi

		unset_recursive_config
		echo ''
		echo "===>>> Starting build for ports that need updating <<<==="
		echo ''
	fi

	BUILDING=yes
	export BUILDING

	for pkg in $roots $trunks $branches $leaves; do
		case "$pkg" in
		*${EXCL}*) test -n "$VERBOSE" &&
echo "===>>> Skipping ${pkg#$pdb/} because it matches the pattern: *${EXCL}*"
			continue
			;;
		esac

		if [ ! -d "$pkg" ]; then
			# This port probably got updated as a dependency
			# for something else
			continue
		fi
		if [ -n "$FORCE" ]; then
			p=`origin_from_pdb $pkg`
			case "$FORCE_DONE_LIST" in
			*:${p}:*) test -n "$VERBOSE" &&
				    echo "===>>> Update for $p already done"
				  continue
				  ;;
			esac

			if [ -e "${pkg}/PM_UPGRADE_DONE_FLAG" ]; then
				test -n "$VERBOSE" &&
				    echo "===>>> Update for $p already done"
				continue
			fi

			echo "===>>> Forcing update for ${pkg#$pdb/}"
			update_port ${pkg#$pdb/}
			continue
		else
			test -n "$VERBOSE" &&
			    echo "===>>> Checking installed port: ${pkg#$pdb/}"
		fi

		case "$CURRENT_DEPS_I" in
		*:${pkg#$pdb/}:*)	continue ;;
		esac
		check_for_updates ${pkg#$pdb/} || fail 'Update failed'
	done
	echo "===>>> Update check of installed ports complete"
	safe_exit
fi

if [ -n "$REPLACE_ORIGIN" ]; then
	portdir="${1#$pd/}"
	portdir="${portdir%/}"
	newportdir=$portdir

	if [ -d "$pdb/$2" ]; then
		# Handle the portmaster'ish way to specify the port
		upg_port=$2
	else
		# Handle existing portupgrade syntax
		upg_port=`grep -l " ORIGIN:${2#$pd/}$" $pdb/*/+CONTENTS`
		[ -n "$upg_port" ] ||
		    upg_port=`grep -l " ORIGIN:${2#$pd/}" $pdb/*/+CONTENTS`
		[ -n "$upg_port" ] ||
		    fail "Cannot find an installed port with ORIGIN $2"
		upg_port="${upg_port%/+CONTENTS}"
		upg_port="${upg_port#$pdb/}"
	fi

	oldportdir=`origin_from_pdb $pdb/$upg_port`
fi

# Exercised in the common case of not using -p option
case "$portdir" in
'')	argv=${1%/}
	case "$argv" in
	'')	test -z "$UPDATE_REQ_BYS" && usage ;;
	${pd}/*)	portdir="${argv#$pd/}" ;;
	/*)	upg_port="${argv##*/}" ;;
	\.)	portdir="${PWD##*/ports/}" ;;
	*)	if [ -d "${pd}/${argv}" ]; then
			portdir=$argv
		else
			upg_port=$argv
		fi
		;;
	esac
esac

case "$upg_port" in
'')	test -n "$portdir" || usage
	old_port_dir=`iport_from_origin ${portdir}`
	if [ -n "$old_port_dir" ]; then
		upg_port="${old_port_dir}"
	fi
	;;
*)	if [ ! -d "$pdb/$upg_port" ]; then
		glob_dirs=`find $pdb -type d -name ${upg_port}\*`
		case "$glob_dirs" in
		*\*)	fail "$upg_port did not match an installed port" ;;
		*)	for dir in $glob_dirs; do
				echo -n "===>>> Update ${dir#$pdb/}? [n] "
				read GLOB_DIR
				case "$GLOB_DIR" in
				[yY])	upg_port=${dir#$pdb/}
					selected=yes
					break
					;;
				esac
			done
			test -n "$selected" || usage
			;;
		esac
	fi
	echo "===>>> Port to upgrade: $upg_port"
	if [ -z "$portdir" ]; then
		portdir=`origin_from_pdb $pdb/$upg_port`
		[ -n "$portdir" ] ||
		    fail "No ORIGIN in $pdb/$upg_port/+CONTENTS"
	fi
	;;
esac

if [ -e "$pdb/$upg_port/+IGNOREME" ]; then
	echo ''
	if [ -z "$UNATTENDED" ]; then
		if [ -z "$BUILDING" ]; then
			echo "===>>> $upg_port has an +IGNOREME file"
			echo -n "===>>> Update anyway? [n] "
			read UPD_OR_NOT
			case "$UPD_OR_NOT" in
			[yY]*)	IGNOREME_YES="${IGNOREME_YES}${upg_port}:" ;;
			*)	safe_exit ;;
			esac
		else
			case "$IGNOREME_YES" in
			*:${upg_port}:*)	;;
			*)	safe_exit ;;
			esac
		fi
	else
		echo "===>>> $upg_port has an +IGNOREME file, ignoring"
		safe_exit
	fi
fi

if [ -d "$pd/$portdir" ]; then
	echo "===>>> Port directory: $pd/$portdir"
else
	find_moved_port $portdir || usage
	portdir=$newportdir
fi

cd $pd/$portdir || usage

for state in FORBIDDEN BROKEN IGNORE; do
	state_set=`make -V $state`
	if [ -n "$state_set" ]; then
		echo "===>>> This port is marked $state:"
		printf "===>>> $state_set"
		echo "===>>> If you are sure you can build it, remove the"
		echo "       $state line in the Makefile and try again."
		safe_exit 1
	fi
done

# Since this task is non-trivial, when only one port is supplied on the
# command line do not start this process until we are sure that we are
# going to (at least try to) build the port.
if [ "$$" -eq "$PARENT_PID" -a -z "$SHOW_WORK" \
    -a -z "$DONT_SCRUB_DISTFILES" ]; then
	(read_distinfos)&
fi

# Do these things first time through, with or without 'make config'
if [ -z "$BUILDING" -a -z "$SHOW_WORK" ]; then
dofetch () {
	echo "===>>> Launching 'make checksum' for $portdir in background"
	fetchlog=`mktemp -t fetchlog-${PARENT_PID}-${portdir##*/}`
	(make -DBATCH $PM_MAKE_ARGS checksum >> $fetchlog 2>&1 &&
	    { rm -f $fetchlog; \
	    rm -f ${TMPDIR}/f-${PARENT_PID}-*-${portdir##*/}.*; exit 0;}
	    allfiles=`make $PM_MAKE_ARGS -V ALLFILES`
	    make $PM_MAKE_ARGS delete-distfiles RESTRICTED_FILES="${allfiles}" \
		>> $fetchlog 2>&1 &&
	    echo "===>>> RE-STARTING FETCH <<<===" >> $fetchlog
	    make $PM_MAKE_ARGS checksum >> $fetchlog 2>&1; \
	    rm -f ${TMPDIR}/f-${PARENT_PID}-*-${portdir##*/}.*; \
	    rm -f $fetchlog)&
	echo "MCS_CHILD_PID $!" >> $fetchlog
}

	distfiles=`make $PM_MAKE_ARGS -V ALLFILES`
	for file in $distfiles; do
		flag_file=f-${PARENT_PID}-${file}
		if ! ls ${TMPDIR}/${flag_file}-* >/dev/null 2>&1; then
			mktemp -t ${flag_file}-${portdir##*/} >/dev/null
		else
			DONT_FETCH=yes
			break
		fi
	done

	test -z "$DONT_FETCH" && dofetch

	TESTINT=`make -V IS_INTERACTIVE`
	if [ -n "$TESTINT" ]; then
		echo ''
		echo "===>>> Warning: $portdir is interactive, and will likely"
		echo "       require attention during the build"
		echo ''
		echo -n "===>>> Press the [Enter] or [Return] key to continue "
		read DISCARD
		echo ''
	fi

	if [ -n "$UPDATE_REQ_BYS" ]; then
		MASTER_RB_LIST=`mktemp -t master_rb_list-${PARENT_PID}`
		export MASTER_RB_LIST
		if [ -s "$pdb/$upg_port/+REQUIRED_BY" ]; then
			old_rb=$pdb/$upg_port/+REQUIRED_BY
		fi
		upg_origin=`origin_from_pdb $pdb/$upg_port`
		grep -l DEPORIGIN:$upg_origin$ $pdb/*/+CONTENTS |
		    cut -f 5 -d '/' | sort -u - $old_rb > $MASTER_RB_LIST
	fi
fi

if [ -n "$CONFIG_ONLY" ]; then
	config_type=config-conditional
	test -n "$FORCE_CONFIG" && config_type=config
	make $PM_MAKE_ARGS $config_type

	CONFIG_SEEN_LIST="${CONFIG_SEEN_LIST}${portdir}:"

	if [ -z "$RECURSE_THOROUGH" ]; then
		dependency_check 'build-depends-list run-depends-list'
	else
		dependency_check all-depends-list
	fi

	if [ ! "$$" -eq "$PARENT_PID" ]; then
		# Save state for the parent process to read back in
		echo "CONFIG_SEEN_LIST='$CONFIG_SEEN_LIST'" > $IPC_SAVE
		safe_exit
	else
		if [ -n "$UPDATE_REQ_BYS" ]; then
			URB_YES=yes ; export URB_YES
			echo ''
			echo "===>>> Checking ports that depend on $upg_port"
			for req_by in `cat $MASTER_RB_LIST`; do
				case "$req_by" in
				*${EXCL}*) test -n "$VERBOSE" &&
	echo "===>>> Skipping $req_by because it matches the pattern: *${EXCL}*"
				continue
				;;
				esac

				rb_origin=`origin_from_pdb $pdb/$req_by`
				case "$URB_DONE_LIST" in
				*:${rb_origin}:*) continue ;;
				esac

				test -n "$VERBOSE" &&
				  echo "===>>> $upg_port is required by $req_by"
				if [ ! -d "$pdb/$req_by" ]; then
					# A failure here is probably just a
					# stale dependency, but warn the user.
					req_by_error $upg_port $req_by
					continue
				fi
				if ! check_interactive ${req_by} ; then
					continue
				fi

				if [ -z "$RESTART" -a -z "$FORCE" ]; then
					update_port $req_by
				else
					check_for_updates $req_by
				fi
			done
			rm -f $MASTER_RB_LIST
			echo "===>>> Done checking ports that depend on $upg_port"
			unset URB_YES
			URB_DONE_LIST=':'
		fi

		unset_recursive_config
	fi
	echo ''
	echo "===>>> Starting build for $portdir <<<==="
	echo ''
fi

BUILDING=yes
export BUILDING

cd $pd/$portdir

if [ ! -e "$NO_DEP_UPDATES" ]; then
	if [ -z "$RECURSE_THOROUGH" ]; then
		echo "===>>> Starting check for build dependencies"
		dependency_check build-depends-list
	else
		echo "===>>> Starting check for all dependencies"
		dependency_check all-depends-list
	fi
else
	if [ -z "$NO_RECURSIVE_CONFIG" ]; then
		echo "===>>> The 'make config' check revealed no dependencies to update"
		echo ''
	fi
fi

if [ -n "$NO_ACTION" ]; then
	test -n "$VERBOSE" &&
	    echo "===>>> Build canceled due to -n flag"
	safe_exit
fi

# In case we went elsewhere in the dependency check
cd $pd/$portdir

case "$DONT_PRE_CLEAN" in
'')	make $PM_MAKE_ARGS clean NOCLEANDEPENDS=yes || fail 'make clean failed' ;;
esac

fl_read=`echo ${TMPDIR}/fetchlog-${PARENT_PID}-${portdir##*/}.*`
while [ -f "$fl_read" ]; do
	echo ''
	echo "===>>> Waiting on fetch & checksum for $portdir <<<==="
	tail -10 $fl_read 2>/dev/null | egrep -v '^$|MCS_CHILD_PID'
	echo ''
	echo "===>>> Waiting on fetch & checksum for $portdir <<<==="
	sleep 5
done

make $PM_MAKE_ARGS || fail "make failed for $portdir"

new_port=`make $PM_MAKE_ARGS -V PKGNAME`
prefix=`make $PM_MAKE_ARGS -V PKGNAMEPREFIX`
portname=`make $PM_MAKE_ARGS -V PORTNAME`
suffix=`make $PM_MAKE_ARGS -V PKGNAMESUFFIX`
short_port="${prefix}${portname}${suffix}"

# Check for dependencies here in case +REQUIRED_BY is not up to date or missing
grep_deps=`mktemp -t grep-deps-${short_port}`

upg_origin=$portdir
if [ -n "$upg_port" ]; then
	upg_origin=`origin_from_pdb $pdb/$upg_port`
fi
grep -l DEPORIGIN:$upg_origin$ $pdb/*/+CONTENTS | cut -f 5 -d '/' |
    sort -u > $grep_deps

if [ -s "$pdb/$upg_port/+REQUIRED_BY" ]; then
	req_deps=`mktemp -t req-deps-${short_port}`
	sort -u $pdb/$upg_port/+REQUIRED_BY > $req_deps
fi

if [ ! -s "$grep_deps" -a ! -s "$req_deps" ]; then
	if [ -n "$upg_port" ]; then
		echo "===>>> $upg_port is not depended on by any other ports"
	fi
elif [ -s "$grep_deps" -a -s "$req_deps" ]; then
	if ! cmp -s $grep_deps $req_deps; then
		update_reqfile
	fi
elif [ -s "$grep_deps" -a ! -s "$req_deps" ]; then
	dep_warn
	echo -n "===>>> Install these as the new +REQUIRED_BY file? [n] "
	if [ -z "$UNATTENDED" ]; then
		read INSTALLDEPS

		case "$INSTALLDEPS" in
		[yY])	req_deps=`mktemp -t req-deps-${short_port}`
			mv $grep_deps $req_deps ; unset grep_deps
			;;
		esac
	else
		echo "===>>> Default (no) in unattended mode"
	fi
else
	# It should not happen that req_deps exist but grep_deps does not
	echo ''
	echo "===>>> $pdb/$upg_port/+REQUIRED_BY indicates"
	echo "       a dependency on this port, but no other ports have"
	echo "       it recorded.  If that file does not contain any valid"
	echo "       dependency data, try removing it and then start again."
	fail "Stale dependency data in $pdb/$upg_port/+REQUIRED_BY"
fi

# Ignore if no old port exists
if [ -n "$upg_port" ]; then
	find_dl_distfiles $portdir

	UPGRADE_PORT=$upg_port
	UPGRADE_PORT_VER=`echo $UPGRADE_PORT | sed 's#.*-\(.*\)#\1#'`
	export UPGRADE_PORT UPGRADE_PORT_VER

	if [ -z "$NO_BACKUP" ]; then
		backup_package $upg_port
	fi

	if [ -n "$SAVE_SHARED" ]; then
		ldconfig_out=`mktemp -t f-${PARENT_PID}-ldconfig`
		ldconfig -r | sed 's#.* ##' |
		    grep -v ^${PORTS_PREFIX}/lib/compat > $ldconfig_out

		mkdir -p ${PORTS_PREFIX}/lib/compat/pkg

		for file in `pkg_info -q -L $upg_port | sort - $ldconfig_out | \
		    uniq -d`; do
			cp -p $file ${PORTS_PREFIX}/lib/compat/pkg/
		done
		ldconfig -m ${PORTS_PREFIX}/lib/compat/pkg
	fi

	pkg_delete -f $upg_port || fail 'pkg_delete failed'
	delete_dist_list

	if [ -n "$REPLACE_ORIGIN" ]; then
		installed_newport=`iport_from_origin ${newportdir}`
		if [ -n "$installed_newport" ]; then
			pkg_delete -f $installed_newport
			delete_dist_list
		fi
	fi
fi

# In case we went elsewhere to create a backup package
cd $pd/$portdir

# Do the install here in case a run dependency has a build dependency on us.
# Defining NO_DEPENDS ensures that we will control the installation of the
# run depends, not bsd.port.mk.
make -DNO_DEPENDS $PM_MAKE_ARGS install || {
    if [ -z "$NO_BACKUP" -a -n "$upg_port" ]; then
	echo ''
	echo "===>>> A backup package for $portdir should be located in $pkgrep"
    fi
    fail "Installation of new port failed";}

# Remove saved libs that match newly installed files
pkg_info -q -L $new_port | while read file; do
	if [ -e "${PORTS_PREFIX}/lib/compat/pkg/${file##*/}" ]; then
		unlink ${PORTS_PREFIX}/lib/compat/pkg/${file##*/}
	fi
done
test -d "${PORTS_PREFIX}/lib/compat/pkg" &&
    ldconfig -m ${PORTS_PREFIX}/lib/compat/pkg

allfiles=`make $PM_MAKE_ARGS -V ALLFILES`
if [ ! "$allfiles" = ' ' ]; then
	# Implement storage of distfile information in the way that
	# it will (hopefully, soon?) be implemented in bsd.port.mk
	# See http://www.freebsd.org/cgi/query-pr.cgi?pr=106483
	dist_list=`make BEFOREPORTMK=yes $PM_MAKE_ARGS -V OPTIONSFILE`
	dist_list="${dist_list%options}distfiles"
	mkdir -p ${dist_list%/distfiles}
	ds=`make BEFOREPORTMK=yes $PM_MAKE_ARGS -V DIST_SUBDIR`
	test -n "$ds" && ds="${ds}/"
	distinfo=`make $PM_MAKE_ARGS -V MD5_FILE`
	echo '# Added by portmaster' > $dist_list
	for file in $allfiles; do
		size=`grep "^SIZE (${ds}${file})" $distinfo | cut -f4 -d' '`
		sha256=`grep "^SHA256 (${ds}${file})" $distinfo | cut -f4 -d' '`
		md5=`grep "^MD5 (${ds}${file})" $distinfo | cut -f4 -d' '`
		echo "DISTFILE:${ds}${file}:SIZE=${size}:SHA256=${sha256}:MD5=${md5}" >> $dist_list
	done
fi

if [ -z "$RECURSE_THOROUGH" -a ! -e "$NO_DEP_UPDATES" ]; then
	echo ''
	echo "===>>> Starting check for runtime dependencies"
	dependency_check run-depends-list
fi

# In case we went elsewhere in the dependency check
cd $pd/$portdir

if [ -n "$MAKE_PACKAGE" ]; then
	echo "===>>> Creating a package for new version $new_port"
	make $PM_MAKE_ARGS package || fail 'Package creation of new port failed'
	echo "	===>>> Package can be found in $pkgrep"
fi

make $PM_MAKE_ARGS clean NOCLEANDEPENDS=yes

# By now, if this file exists, it should be authoritative
if [ -s "$req_deps" ]; then

update_dep_entries () {
	local upg_port

	test -n "$1" && upg_port=$1

	echo "===>>> Updating package dependency entry for each dependent port"
	while read dep_port; do
		dep_port_contents="$pdb/$dep_port/+CONTENTS"
		[ -e "$pdb/$dep_port/+CONTENTS" ] || continue
		if grep -q "@pkgdep $upg_port" $dep_port_contents; then
			update_contents $upg_port $new_port
		else
			echo -n "===>>> In ${dep_port}"
			echo " no entry for $upg_port, trying $short_port"
			update_contents "$short_port.*" $new_port
		fi
	done < $req_deps
}
	update_dep_entries
	mv $req_deps $pdb/$new_port/+REQUIRED_BY
	unset req_deps
	chmod 644 $pdb/$new_port/+REQUIRED_BY

	if [ -n "$REPLACE_ORIGIN" ]; then
		req_deps=`mktemp -t req-deps-${short_port}`

		grep -l DEPORIGIN:$newportdir$ $pdb/*/+CONTENTS |
		    cut -f 5 -d '/' | sort -u > $req_deps
		update_dep_entries $new_port
		cat $req_deps >> $pdb/$new_port/+REQUIRED_BY
	fi
fi

echo ''
test -z "$upg_port" && upg_port=$portdir
echo "===>>> Upgrade for $upg_port to $new_port succeeded"
echo ''

test -n "$FORCE" && FORCE_DONE_LIST="${FORCE_DONE_LIST}${portdir}:"
test -e "$pdb/$new_port/+DISPLAY" &&
    DISPLAY_LIST="${DISPLAY_LIST}$new_port/+DISPLAY "

if [ -n "$URB_YES" -o -n "$UPDATE_REQ_BYS" -o -n "$FORCE" ]; then
	touch $pdb/$new_port/PM_UPGRADE_DONE_FLAG
fi

if [ -z "$DONT_SCRUB_DISTFILES" ]; then
	# Make sure any new distfiles get added to the list
	cd $pd/$portdir 2>/dev/null ||
	    fail "Cannot cd to $pd/$portdir for distfile update"
	distinfo=`make $PM_MAKE_ARGS -V MD5_FILE`
	if [ -s "$distinfo" ]; then
		grep '^MD5' $distinfo | while read disc1 file disc2; do
			echo $file >> $DI_FILES
		done
	fi

	if [ -z "$oldportdir" ]; then
		delete_stale_distfiles
	else
		delete_all_distfiles ${oldportdir}
		cd $pd/$newportdir && delete_stale_distfiles
	fi
fi

if [ -n "$UPDATE_REQ_BYS" -a -s "$pdb/$new_port/+REQUIRED_BY" ]; then
	URB_YES=yes ; export URB_YES
	MASTER_RB_LIST=$pdb/$new_port/+REQUIRED_BY
	echo "===>>> Updating ports that depend on $new_port"
	for req_by in `cat $pdb/$new_port/+REQUIRED_BY`; do
		if [ ! -d "$pdb/$req_by" ]; then
			# Since the dependency list was probably updated as
			# a result of updating the parent port, a missing
			# directory here is likely the result of the port
			# being updated as a dependency for something else.
			continue
		fi

		case "$req_by" in
		*${EXCL}*) test -n "$VERBOSE" &&
	echo "===>>> Skipping $req_by because it matches the pattern: *${EXCL}*"
			continue
			;;
		esac

		p=`origin_from_pdb $pdb/$req_by`
		case "$URB_DONE_LIST" in
		*:${p}:*) continue ;;
		esac

		case "$FORCE_DONE_LIST" in
		*:${p}:*) test -n "$VERBOSE" &&
			    echo "===>>> Update for $p already done"
			  continue
			  ;;
		esac

		if ! check_interactive ${req_by} ; then
			continue
		fi

		test -n "$VERBOSE" &&
		    echo "===>>> $new_port is required by $req_by"

		if [ -z "$RESTART" -a -z "$FORCE" ]; then
			update_port $req_by
		else
			check_for_updates $req_by
		fi
	done
	echo "===>>> Done updating ports that depend on $new_port"
fi

safe_exit

#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

#  Copyright (c) 2005-2007 Douglas Barton
#  All rights reserved.
#
#  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.
#  2. Redistributions in binary form must reproduce the above copyright
#     notice, this list of conditions and the following disclaimer in the
#     documentation and/or other materials provided with the distribution.
#
#  THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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.


syntax highlighted by Code2HTML, v. 0.9.1