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