xref: /openbsd-src/usr.sbin/sysmerge/sysmerge.sh (revision 43003dfe3ad45d1698bed8a37f2b0f5b14f20d4f)
1#!/bin/sh -
2#
3# $OpenBSD: sysmerge.sh,v 1.52 2009/10/02 11:53:45 ajacoutot Exp $
4#
5# Copyright (c) 1998-2003 Douglas Barton <DougB@FreeBSD.org>
6# Copyright (c) 2008, 2009 Antoine Jacoutot <ajacoutot@openbsd.org>
7#
8# Permission to use, copy, modify, and distribute this software for any
9# purpose with or without fee is hereby granted, provided that the above
10# copyright notice and this permission notice appear in all copies.
11#
12# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
13# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
14# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
15# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
16# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
17# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
18# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
19#
20
21umask 0022
22
23unset AUTO_INSTALLED_FILES BATCHMODE DIFFMODE NEED_NEWALIASES
24unset OBSOLETE_FILES SRCDIR TGZ TGZURL XTGZ XTGZURL
25
26WRKDIR=`mktemp -d -p ${TMPDIR:=/var/tmp} sysmerge.XXXXX` || exit 1
27SWIDTH=`stty size | awk '{w=$2} END {if (w==0) {w=80} print w}'`
28MERGE_CMD="${MERGE_CMD:=sdiff -as -w ${SWIDTH} -o}"
29REPORT="${REPORT:=${WRKDIR}/sysmerge.log}"
30DBDIR="${DBDIR:=/var/db/sysmerge}"
31
32PAGER="${PAGER:=/usr/bin/more}"
33
34# clean leftovers created by make in src
35clean_src() {
36	if [ "${SRCDIR}" ]; then
37		cd ${SRCDIR}/gnu/usr.sbin/sendmail/cf/cf && make cleandir > /dev/null
38	fi
39}
40
41# restore files from backups
42restore_bak() {
43	for i in ${DESTDIR}/${DBDIR}/.*.bak; do
44		_i=`basename ${i} .bak`
45		if [ -f "${i}" ]; then
46			mv ${i} ${DESTDIR}/${DBDIR}/${_i#.}
47		fi
48	done
49}
50
51# remove newly created work directory and exit with status 1
52error_rm_wrkdir() {
53	rmdir ${WRKDIR} 2> /dev/null
54	exit 1
55}
56
57usage() {
58	echo "usage: ${0##*/} [-bd] [-s src | etcXX.tgz] [-x xetcXX.tgz]" >&2
59}
60
61trap "restore_bak; clean_src; rm -rf ${WRKDIR}; exit 1" 1 2 3 13 15
62
63if [ "`id -u`" -ne 0 ]; then
64	echo " *** Error: need root privileges to run this script"
65	usage
66	error_rm_wrkdir
67fi
68
69if [ -z "${FETCH_CMD}" ]; then
70	if [ -z "${FTP_KEEPALIVE}" ]; then
71		FTP_KEEPALIVE=0
72	fi
73	FETCH_CMD="/usr/bin/ftp -V -m -k ${FTP_KEEPALIVE}"
74fi
75
76
77do_pre() {
78	if [ -z "${SRCDIR}" -a -z "${TGZ}" -a -z "${XTGZ}" ]; then
79		if [ -f "/usr/src/etc/Makefile" ]; then
80			SRCDIR=/usr/src
81		else
82			echo " *** Error: please specify a valid path to src or (x)etcXX.tgz"
83			error_rm_wrkdir
84		fi
85	fi
86
87	TEMPROOT="${WRKDIR}/temproot"
88	BKPDIR="${WRKDIR}/backups"
89
90	if [ -z "${BATCHMODE}" -a -n "${DIFFMODE}" ]; then
91		echo "\n===> Running ${0##*/} with the following settings:\n"
92		if [ "${TGZURL}" ]; then
93			echo " etc source:          ${TGZURL}"
94			echo "                      (fetched in ${TGZ})"
95		elif [ "${TGZ}" ]; then
96			echo " etc source:          ${TGZ}"
97		elif [ "${SRCDIR}" ]; then
98			echo " etc source:          ${SRCDIR}"
99		fi
100		if [ "${XTGZURL}" ]; then
101			echo " xetc source:         ${XTGZURL}"
102			echo "                      (fetched in ${XTGZ})"
103		else
104			[ "${XTGZ}" ] && echo " xetc source:         ${XTGZ}"
105		fi
106		echo ""
107		echo " base work directory: ${WRKDIR}"
108		echo " temp root directory: ${TEMPROOT}"
109		echo " backup directory:    ${BKPDIR}"
110		echo ""
111		echo -n "Continue? (y|[n]) "
112		read ANSWER
113		case "${ANSWER}" in
114			y|Y)
115				echo ""
116				;;
117			*)
118				error_rm_wrkdir
119				;;
120		esac
121	fi
122}
123
124
125do_populate() {
126	mkdir -p ${DESTDIR}/${DBDIR} || error_rm_wrkdir
127	echo "===> Creating and populating temporary root under"
128	echo "     ${TEMPROOT}"
129	mkdir -p ${TEMPROOT}
130	local SRCSUM ETCSUM XETCSUM
131	if [ "${SRCDIR}" ]; then
132		SRCSUM=srcsum
133		cd ${SRCDIR}/etc
134		make DESTDIR=${TEMPROOT} distribution-etc-root-var > /dev/null 2>&1
135		(cd ${TEMPROOT} && find . -type f | xargs cksum >> ${WRKDIR}/${SRCSUM})
136	fi
137
138	if [ "${TGZ}" -o "${XTGZ}" ]; then
139		for i in ${TGZ} ${XTGZ}; do
140			tar -xzphf ${i} -C ${TEMPROOT};
141		done
142		if [ "${TGZ}" ]; then
143			ETCSUM=etcsum
144			_E=$(cd `dirname ${TGZ}` && pwd)/`basename ${TGZ}`
145			(cd ${TEMPROOT} && tar -tzf ${_E} | xargs cksum >> ${WRKDIR}/${ETCSUM})
146		fi
147		if [ "${XTGZ}" ]; then
148			XETCSUM=xetcsum
149			_X=$(cd `dirname ${XTGZ}` && pwd)/`basename ${XTGZ}`
150			(cd ${TEMPROOT} && tar -tzf ${_X} | xargs cksum >> ${WRKDIR}/${XETCSUM})
151		fi
152	fi
153
154	for i in ${SRCSUM} ${ETCSUM} ${XETCSUM}; do
155		if [ -f ${DESTDIR}/${DBDIR}/${i} ]; then
156			# delete file in temproot if it has not changed since last release
157			# and is present in current installation
158			if [ -z "${DIFFMODE}" ]; then
159				_R=$(cd ${TEMPROOT} && cksum -c ${DESTDIR}/${DBDIR}/${i} 2> /dev/null | grep OK | awk '{ print $2 }' | sed 's/[:]//')
160				for _r in ${_R}; do
161					if [ -f ${DESTDIR}/${_r} -a -f ${TEMPROOT}/${_r} ]; then
162						rm -f ${TEMPROOT}/${_r}
163					fi
164				done
165			fi
166
167			# set auto-upgradable files
168			_D=`diff -u ${WRKDIR}/${i} ${DESTDIR}/${DBDIR}/${i} | grep -E '^\+' | sed '1d' | awk '{print $3}'`
169			for _d in ${_D}; do
170				CURSUM=$(cd ${DESTDIR:=/} && cksum ${_d} 2> /dev/null)
171				if [ -n "`grep "${CURSUM}" ${DESTDIR}/${DBDIR}/${i}`" -a -z "`grep "${CURSUM}" ${WRKDIR}/${i}`" ]; then
172					local _array="${_array} ${_d}"
173				fi
174			done
175			if [ -n "${_array}" ]; then
176				set -A AUTO_UPG -- ${_array}
177			fi
178
179			# check for obsolete files
180			awk '{ print $3 }' ${DESTDIR}/${DBDIR}/${i} > ${WRKDIR}/new
181			awk '{ print $3 }' ${WRKDIR}/${i} > ${WRKDIR}/old
182			if [ -n "`diff -q ${WRKDIR}/old ${WRKDIR}/new`" ]; then
183				OBSOLETE_FILES="`diff -C 0 ${WRKDIR}/new ${WRKDIR}/old | grep -E '^- .' | sed -e 's,^- .,,g'`"
184			fi
185			rm ${WRKDIR}/new ${WRKDIR}/old
186
187			mv ${DESTDIR}/${DBDIR}/${i} ${DESTDIR}/${DBDIR}/.${i}.bak
188		fi
189		mv ${WRKDIR}/${i} ${DESTDIR}/${DBDIR}/${i}
190	done
191
192	# files we don't want/need to deal with
193	IGNORE_FILES="/etc/*.db /etc/mail/*.db /etc/passwd /etc/motd /etc/myname /var/mail/root"
194	CF_FILES="/etc/mail/localhost.cf /etc/mail/sendmail.cf /etc/mail/submit.cf"
195	for cf in ${CF_FILES}; do
196		CF_DIFF=`diff -q -I "##### " ${TEMPROOT}/${cf} ${DESTDIR}/${cf} 2> /dev/null`
197		if [ -z "${CF_DIFF}" ]; then
198			IGNORE_FILES="${IGNORE_FILES} ${cf}"
199		fi
200	done
201	if [ -r /etc/sysmerge.ignore ]; then
202		while read i; do \
203			IGNORE_FILES="${IGNORE_FILES} $(echo ${i} | sed -e 's,\.\.,,g' -e 's,#.*,,g')"
204		done < /etc/sysmerge.ignore
205	fi
206	for i in ${IGNORE_FILES}; do
207		rm -rf ${TEMPROOT}/${i};
208	done
209}
210
211
212do_install_and_rm() {
213	if [ -f "${5}/${4##*/}" ]; then
214		mkdir -p ${BKPDIR}/${4%/*}
215		cp ${5}/${4##*/} ${BKPDIR}/${4%/*}
216	fi
217
218	if ! install -m "${1}" -o "${2}" -g "${3}" "${4}" "${5}" 2> /dev/null; then
219		rm -f ${BKPDIR}/${4%/*}/${4##*/}
220		return 1
221	fi
222	rm -f "${4}"
223}
224
225
226mm_install() {
227	local INSTDIR
228	INSTDIR=${1#.}
229	INSTDIR=${INSTDIR%/*}
230
231	if [ -z "${INSTDIR}" ]; then INSTDIR=/; fi
232
233	DIR_MODE=`stat -f "%OMp%OLp" "${TEMPROOT}/${INSTDIR}"`
234	eval `stat -f "FILE_MODE=%OMp%OLp FILE_OWN=%Su FILE_GRP=%Sg" ${1}`
235
236	if [ "${DESTDIR}${INSTDIR}" -a ! -d "${DESTDIR}${INSTDIR}" ]; then
237		install -d -o root -g wheel -m "${DIR_MODE}" "${DESTDIR}${INSTDIR}"
238	fi
239
240	do_install_and_rm "${FILE_MODE}" "${FILE_OWN}" "${FILE_GRP}" "${1}" "${DESTDIR}${INSTDIR}" || return
241
242	case "${1#.}" in
243	/dev/MAKEDEV)
244		echo -n "===> A new ${DESTDIR%/}/dev/MAKEDEV script was installed, "
245		echo "running MAKEDEV"
246		(cd ${DESTDIR}/dev && /bin/sh MAKEDEV all)
247		;;
248	/etc/login.conf)
249		if [ -f ${DESTDIR}/etc/login.conf.db ]; then
250			echo -n "===> A new ${DESTDIR%/}/etc/login.conf file was installed, "
251			echo "running cap_mkdb"
252			cap_mkdb ${DESTDIR}/etc/login.conf
253		fi
254		;;
255	/etc/mail/access|/etc/mail/genericstable|/etc/mail/mailertable|/etc/mail/virtusertable)
256		DBFILE=`echo ${1} | sed -e 's,.*/,,'`
257		echo -n "===> A new ${DESTDIR%/}/${1#.} file was installed, "
258		echo "running makemap"
259		/usr/libexec/sendmail/makemap hash ${DESTDIR}/${1#.} < ${DESTDIR}/${1#.}
260		;;
261	/etc/mail/aliases)
262		echo -n "===> A new ${DESTDIR%/}/etc/mail/aliases file was installed, "
263		echo "running newaliases"
264		if [ "${DESTDIR}" ]; then
265			chroot ${DESTDIR} newaliases || export NEED_NEWALIASES=1
266		else
267			newaliases
268		fi
269		;;
270	/etc/master.passwd)
271		echo -n "===> A new ${DESTDIR%/}/etc/master.passwd file was installed, "
272		echo "running pwd_mkdb"
273		pwd_mkdb -d ${DESTDIR}/etc -p ${DESTDIR}/etc/master.passwd
274		;;
275	esac
276}
277
278mm_install_link() {
279	_LINKT=`readlink ${COMPFILE}`
280	_LINKF=`dirname ${DESTDIR}${COMPFILE#.}`
281	rm -f ${COMPFILE}
282	(cd ${_LINKF} && ln -sf ${_LINKT} .)
283	return
284}
285
286merge_loop() {
287	if [ "`expr "${MERGE_CMD}" : ^sdiff.*`" -gt 0 ]; then
288		echo "===> Type h at the sdiff prompt (%) to get usage help\n"
289	fi
290	MERGE_AGAIN=1
291	while [ "${MERGE_AGAIN}" ]; do
292		cp -p "${COMPFILE}" "${COMPFILE}.merged"
293		${MERGE_CMD} "${COMPFILE}.merged" \
294			"${DESTDIR}${COMPFILE#.}" "${COMPFILE}"
295		INSTALL_MERGED=v
296		while [ "${INSTALL_MERGED}" = "v" ]; do
297			echo ""
298			echo "  Use 'e' to edit the merged file"
299			echo "  Use 'i' to install the merged file"
300			echo "  Use 'n' to view a diff between the merged and new files"
301			echo "  Use 'o' to view a diff between the old and merged files"
302			echo "  Use 'r' to re-do the merge"
303			echo "  Use 'v' to view the merged file"
304			echo "  Use 'x' to delete the merged file and go back to previous menu"
305			echo "  Default is to leave the temporary file to deal with by hand"
306			echo ""
307			echo -n "===> How should I deal with the merged file? [Leave it for later] "
308			read INSTALL_MERGED
309			case "${INSTALL_MERGED}" in
310			[eE])
311				echo "editing merged file...\n"
312				if [ -z "${VISUAL}" ]; then
313					EDIT="${EDITOR:=/usr/bin/vi}"
314				else
315					EDIT="${VISUAL}"
316				fi
317				if which ${EDIT} > /dev/null 2>&1; then
318					${EDIT} ${COMPFILE}.merged
319				else
320					echo " *** Error: ${EDIT} can not be found or is not executable"
321				fi
322				INSTALL_MERGED=v
323				;;
324			[iI])
325				mv "${COMPFILE}.merged" "${COMPFILE}"
326				echo ""
327				if mm_install "${COMPFILE}"; then
328					echo "===> Merged version of ${COMPFILE} installed successfully"
329				else
330					echo " *** Warning: problem installing ${COMPFILE}, it will remain to merge by hand"
331				fi
332				unset MERGE_AGAIN
333				;;
334			[nN])
335				(
336					echo "comparison between merged and new files:\n"
337					diff -u ${COMPFILE}.merged ${COMPFILE}
338				) | ${PAGER}
339				INSTALL_MERGED=v
340				;;
341			[oO])
342				(
343					echo "comparison between old and merged files:\n"
344					diff -u ${DESTDIR}${COMPFILE#.} ${COMPFILE}.merged
345				) | ${PAGER}
346				INSTALL_MERGED=v
347				;;
348			[rR])
349				rm "${COMPFILE}.merged"
350				;;
351			[vV])
352				${PAGER} "${COMPFILE}.merged"
353				;;
354			[xX])
355				rm "${COMPFILE}.merged"
356				return 1
357				;;
358			'')
359				echo "===> ${COMPFILE} will remain for your consideration"
360				unset MERGE_AGAIN
361				;;
362			*)
363				echo "invalid choice: ${INSTALL_MERGED}"
364				INSTALL_MERGED=v
365				;;
366			esac
367		done
368	done
369}
370
371
372diff_loop() {
373	if [ "${BATCHMODE}" ]; then
374		HANDLE_COMPFILE=todo
375	else
376		HANDLE_COMPFILE=v
377	fi
378
379	unset NO_INSTALLED
380	unset CAN_INSTALL
381	unset FORCE_UPG
382
383	while [ "${HANDLE_COMPFILE}" = "v" -o "${HANDLE_COMPFILE}" = "todo" ]; do
384		if [ "${HANDLE_COMPFILE}" = "v" ]; then
385			echo "\n========================================================================\n"
386		fi
387		if [ -f "${DESTDIR}${COMPFILE#.}" -a -f "${COMPFILE}" -a -z "${IS_LINK}" ]; then
388			if [ -z "${DIFFMODE}" ]; then
389				# automatically install files if current != new and current = old
390				for i in "${AUTO_UPG[@]}"; do
391					if [ "${i}" = "${COMPFILE}" ]; then
392						FORCE_UPG=1
393					fi
394				done
395				# automatically install files which differ only by CVS Id or that are binaries
396				if [ -z "`diff -q -I'[$]OpenBSD:.*$' "${DESTDIR}${COMPFILE#.}" "${COMPFILE}"`" -o -n "${FORCE_UPG}" -o -n "${IS_BINFILE}" ]; then
397					if mm_install "${COMPFILE}"; then
398						echo "===> ${COMPFILE} installed successfully"
399						AUTO_INSTALLED_FILES="${AUTO_INSTALLED_FILES}${DESTDIR}${COMPFILE#.}\n"
400					else
401						echo " *** Warning: problem installing ${COMPFILE}, it will remain to merge by hand"
402					fi
403					return
404				fi
405			fi
406			if [ "${HANDLE_COMPFILE}" = "v" ]; then
407				(
408					echo "===> Displaying differences between ${COMPFILE} and installed version:"
409					echo ""
410					diff -u "${DESTDIR}${COMPFILE#.}" "${COMPFILE}"
411				) | ${PAGER}
412				echo ""
413			fi
414		else
415			echo "===> ${COMPFILE#.} was not found on the target system"
416			if [ "${IS_LINK}" ]; then
417				if [ -n "${DIFFMODE}" ]; then
418					echo ""
419					NO_INSTALLED=1
420				else
421					if mm_install_link; then
422						echo "===> ${COMPFILE#.} link created successfully"
423						AUTO_INSTALLED_FILES="${AUTO_INSTALLED_FILES}${DESTDIR}${COMPFILE#.}\n"
424					else
425						echo " *** Warning: problem creating ${COMPFILE#.} link, manual intervention will be needed"
426					fi
427					return
428				fi
429			fi
430			if [ -n "${DIFFMODE}" ]; then
431				echo ""
432				NO_INSTALLED=1
433			else
434				if mm_install "${COMPFILE}"; then
435					echo "===> ${COMPFILE} installed successfully"
436					AUTO_INSTALLED_FILES="${AUTO_INSTALLED_FILES}${DESTDIR}${COMPFILE#.}\n"
437				else
438					echo " *** Warning: problem installing ${COMPFILE}, it will remain to merge by hand"
439				fi
440				return
441			fi
442		fi
443
444		if [ -z "${BATCHMODE}" ]; then
445			echo "  Use 'd' to delete the temporary ${COMPFILE}"
446			if [ "${COMPFILE}" != "./etc/master.passwd" -a "${COMPFILE}" != "./etc/group" -a "${COMPFILE}" != "./etc/hosts" ]; then
447				CAN_INSTALL=1
448				echo "  Use 'i' to install the temporary ${COMPFILE}"
449			fi
450			if [ -z "${NO_INSTALLED}" -a -z "${IS_BINFILE}" -a -z "${IS_LINK}" ]; then
451				echo "  Use 'm' to merge the temporary and installed versions"
452				echo "  Use 'v' to view the diff results again"
453			fi
454			echo ""
455			echo "  Default is to leave the temporary file to deal with by hand"
456			echo ""
457			echo -n "How should I deal with this? [Leave it for later] "
458			read HANDLE_COMPFILE
459		else
460			unset HANDLE_COMPFILE
461		fi
462
463		case "${HANDLE_COMPFILE}" in
464		[dD])
465			rm "${COMPFILE}"
466			echo "\n===> Deleting ${COMPFILE}"
467			;;
468		[iI])
469			if [ -n "${CAN_INSTALL}" ]; then
470				echo ""
471				if [ -n "${IS_LINK}" ]; then
472					if mm_install_link; then
473						echo "===> ${COMPFILE#.} link created successfully"
474						AUTO_INSTALLED_FILES="${AUTO_INSTALLED_FILES}${DESTDIR}${COMPFILE#.}\n"
475					else
476						echo " *** Warning: problem creating ${COMPFILE#.} link, manual intervention will be needed"
477					fi
478				else
479					if mm_install "${COMPFILE}"; then
480						echo "===> ${COMPFILE} installed successfully"
481					else
482						echo " *** Warning: problem installing ${COMPFILE}, it will remain to merge by hand"
483					fi
484				fi
485			else
486				echo "invalid choice: ${HANDLE_COMPFILE}\n"
487				HANDLE_COMPFILE="todo"
488			fi
489
490			;;
491		[mM])
492			if [ -z "${NO_INSTALLED}" -a -z "${IS_BINFILE}" -a -z "${IS_LINK}" ]; then
493				merge_loop || HANDLE_COMPFILE="todo"
494			else
495				echo "invalid choice: ${HANDLE_COMPFILE}\n"
496				HANDLE_COMPFILE="todo"
497			fi
498			;;
499		[vV])
500			if [ -z "${NO_INSTALLED}" -a -z "${IS_BINFILE}" -a -z "${IS_LINK}" ]; then
501				HANDLE_COMPFILE="v"
502			else
503				echo "invalid choice: ${HANDLE_COMPFILE}\n"
504				HANDLE_COMPFILE="todo"
505			fi
506			;;
507		'')
508			echo "\n===> ${COMPFILE} will remain for your consideration"
509			;;
510		*)
511			echo "invalid choice: ${HANDLE_COMPFILE}\n"
512			HANDLE_COMPFILE="todo"
513			continue
514			;;
515		esac
516	done
517}
518
519
520do_compare() {
521	echo "===> Starting comparison"
522
523	cd ${TEMPROOT} || error_rm_wrkdir
524
525	# use -size +0 to avoid comparing empty log files and device nodes;
526	# however, we want to keep the symlinks
527	for COMPFILE in `find . -type f -size +0 -or -type l`; do
528		unset IS_BINFILE
529		unset IS_LINK
530		# links need to be treated in a different way
531		if [ -h "${COMPFILE}" ]; then
532			IS_LINK=1
533		fi
534		if [ ! -e "${DESTDIR}${COMPFILE#.}" ]; then
535			diff_loop
536			continue
537		fi
538
539		# compare CVS $Id's first so if the file hasn't been modified,
540		# it will be deleted from temproot and ignored from comparison.
541		# several files are generated from scripts so CVS ID is not a
542		# reliable way of detecting changes; leave for a full diff.
543		if [ -z "${DIFFMODE}" -a "${COMPFILE}" != "./etc/fbtab" \
544		    -a "${COMPFILE}" != "./etc/login.conf" \
545		    -a "${COMPFILE}" != "./etc/sysctl.conf" \
546		    -a "${COMPFILE}" != "./etc/ttys" -a -z "${IS_LINK}" ]; then
547			CVSID1=`grep "[$]OpenBSD:" ${DESTDIR}${COMPFILE#.} 2> /dev/null`
548			CVSID2=`grep "[$]OpenBSD:" ${COMPFILE} 2> /dev/null` || CVSID2=none
549			if [ "${CVSID2}" = "${CVSID1}" ]; then rm "${COMPFILE}"; fi
550		fi
551
552		if [ -f "${COMPFILE}" -a -z "${IS_LINK}" ]; then
553			# make sure files are different; if not, delete the one in temproot
554			if diff -q "${DESTDIR}${COMPFILE#.}" "${COMPFILE}" > /dev/null 2>&1; then
555				rm "${COMPFILE}"
556			# xetcXX.tgz contains binary files; set IS_BINFILE to disable sdiff
557			elif diff -q "${DESTDIR}${COMPFILE#.}" "${COMPFILE}" | grep "Binary" > /dev/null 2>&1; then
558				IS_BINFILE=1
559				diff_loop
560			else
561				diff_loop
562			fi
563		fi
564	done
565
566	echo "\n===> Comparison complete"
567}
568
569
570do_post() {
571	echo "===> Making sure your directory hierarchy has correct perms, running mtree"
572	mtree -qdef ${DESTDIR}/etc/mtree/4.4BSD.dist -p ${DESTDIR:=/} -U > /dev/null
573	if [ -n "${XTGZ}" ]; then
574		mtree -qdef ${DESTDIR}/etc/mtree/BSD.x11.dist -p ${DESTDIR:=/} -U > /dev/null
575	fi
576
577	if [ "${NEED_NEWALIASES}" ]; then
578		echo "===> A new ${DESTDIR}/etc/mail/aliases file was installed." >> ${REPORT}
579		echo "However ${DESTDIR}/usr/bin/newaliases could not be run," >> ${REPORT}
580		echo "you will need to rebuild your aliases database manually.\n" >> ${REPORT}
581		unset NEED_NEWALIASES
582	fi
583
584	FILES_IN_TEMPROOT=`find ${TEMPROOT} -type f ! -name \*.merged -size +0 2> /dev/null`
585	FILES_IN_BKPDIR=`find ${BKPDIR} -type f -size +0 2> /dev/null`
586	if [ "${AUTO_INSTALLED_FILES}" ]; then
587		echo "===> Automatically installed file(s)" >> ${REPORT}
588		echo "${AUTO_INSTALLED_FILES}" >> ${REPORT}
589	fi
590	if [ "${FILES_IN_BKPDIR}" ]; then
591		echo "===> Backup of replaced file(s) can be found under" >> ${REPORT}
592		echo "${BKPDIR}\n" >> ${REPORT}
593	fi
594	if [ "${OBSOLETE_FILES}" ]; then
595		echo "===> File(s) removed from previous source (maybe obsolete)" >> ${REPORT}
596		echo "${OBSOLETE_FILES}" >> ${REPORT}
597	fi
598	if [ "${FILES_IN_TEMPROOT}" ]; then
599		echo "===> File(s) remaining for you to merge by hand" >> ${REPORT}
600		echo "${FILES_IN_TEMPROOT}" >> ${REPORT}
601	fi
602
603	if [ -e "${REPORT}" ]; then
604		if [ "${OBSOLETE_FILES}" -o "${FILES_IN_TEMPROOT}" ]; then
605			echo "===> Manual intervention may be needed, see ${REPORT}"
606		else
607			echo "===> Output log available at ${REPORT}"
608		fi
609		echo "===> When done, ${WRKDIR} and its subdirectories should be removed"
610	else
611		echo "===> Removing ${WRKDIR}"
612		rm -rf "${WRKDIR}"
613	fi
614
615	clean_src
616	rm -f ${DESTDIR}/${DBDIR}/.*.bak
617}
618
619
620while getopts bds:x: arg; do
621	case ${arg} in
622	b)
623		BATCHMODE=1
624		;;
625	d)
626		DIFFMODE=1
627		;;
628	s)
629		if [ -f "${OPTARG}/etc/Makefile" ]; then
630			SRCDIR=${OPTARG}
631		elif [ -f "${OPTARG}" ] && echo -n ${OPTARG} | \
632		    awk -F/ '{print $NF}' | \
633		    grep '^etc[0-9][0-9]\.tgz$' > /dev/null 2>&1 ; then
634			TGZ=${OPTARG}
635		elif echo ${OPTARG} | \
636		    grep -qE '^(http|ftp)://.*/etc[0-9][0-9]\.tgz$'; then
637			TGZ=${WRKDIR}/etc.tgz
638			TGZURL=${OPTARG}
639			if ! ${FETCH_CMD} -o ${TGZ} ${TGZURL}; then
640				echo " *** Error: could not retrieve ${TGZURL}"
641				error_rm_wrkdir
642			fi
643		else
644			echo " *** Error: ${OPTARG} is not a path to src nor etcXX.tgz"
645			error_rm_wrkdir
646		fi
647		;;
648	x)
649		if [ -f "${OPTARG}" ] && echo -n ${OPTARG} | \
650		    awk -F/ '{print $NF}' | \
651		    grep '^xetc[0-9][0-9]\.tgz$' > /dev/null 2>&1 ; then
652			XTGZ=${OPTARG}
653		elif echo ${OPTARG} | \
654		    grep -qE '^(http|ftp)://.*/xetc[0-9][0-9]\.tgz$'; then
655			XTGZ=${WRKDIR}/xetc.tgz
656			XTGZURL=${OPTARG}
657			if ! ${FETCH_CMD} -o ${XTGZ} ${XTGZURL}; then
658				echo " *** Error: could not retrieve ${XTGZURL}"
659				error_rm_wrkdir
660			fi
661		else
662			echo " *** Error: ${OPTARG} is not a path to xetcXX.tgz"
663			error_rm_wrkdir
664		fi
665		;;
666	*)
667		usage
668		error_rm_wrkdir
669		;;
670	esac
671done
672
673
674do_pre
675do_populate
676do_compare
677do_post
678