xref: /openbsd-src/usr.sbin/sysmerge/sysmerge.sh (revision 2b0358df1d88d06ef4139321dd05bd5e05d91eaf)
1#!/bin/sh -
2#
3# $OpenBSD: sysmerge.sh,v 1.34 2009/04/06 15:25:10 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 "MAKEDEV will be run"
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 "cap_mkdb will be run"
250			cap_mkdb ${DESTDIR}/etc/login.conf
251		fi
252		;;
253	/etc/mail/aliases)
254		echo -n "===> A new ${DESTDIR}/etc/mail/aliases file was installed, "
255		echo "newaliases will be run"
256		if [ "${DESTDIR}" ]; then
257			chroot ${DESTDIR} newaliases || NEED_NEWALIASES=1
258		else
259			newaliases
260		fi
261		;;
262	/etc/master.passwd)
263		echo -n "===> A new ${DESTDIR}/etc/master.passwd file was installed, "
264		echo "pwd_mkdb will be run"
265		pwd_mkdb -d ${DESTDIR}/etc -p ${DESTDIR}/etc/master.passwd
266		;;
267	esac
268}
269
270
271merge_loop() {
272	if [ "`expr "${MERGE_CMD}" : ^sdiff.*`" -gt 0 ]; then
273		echo "===> Type h at the sdiff prompt (%) to get usage help\n"
274	fi
275	MERGE_AGAIN=1
276	while [ "${MERGE_AGAIN}" ]; do
277		cp -p "${COMPFILE}" "${COMPFILE}.merged"
278		${MERGE_CMD} "${COMPFILE}.merged" \
279			"${DESTDIR}${COMPFILE#.}" "${COMPFILE}"
280		INSTALL_MERGED=v
281		while [ "${INSTALL_MERGED}" = "v" ]; do
282			echo ""
283			echo "  Use 'e' to edit the merged file"
284			echo "  Use 'i' to install the merged file"
285			echo "  Use 'n' to view a diff between the merged and new files"
286			echo "  Use 'o' to view a diff between the old and merged files"
287			echo "  Use 'r' to re-do the merge"
288			echo "  Use 'v' to view the merged file"
289			echo "  Default is to leave the temporary file to deal with by hand"
290			echo ""
291			echo -n "===> How should I deal with the merged file? [Leave it for later] "
292			read INSTALL_MERGED
293			case "${INSTALL_MERGED}" in
294			[eE])
295				echo "editing merged file...\n"
296				if [ -z "${VISUAL}" ]; then
297					EDIT="${EDITOR}"
298				else
299					EDIT="${VISUAL}"
300				fi
301				if which ${EDIT} > /dev/null 2>&1; then
302					${EDIT} ${COMPFILE}.merged
303				else
304					echo " *** Error: ${EDIT} can not be found or is not executable"
305				fi
306				INSTALL_MERGED=v
307				;;
308			[iI])
309				mv "${COMPFILE}.merged" "${COMPFILE}"
310				echo ""
311					if mm_install "${COMPFILE}"; then
312						echo "===> Merged version of ${COMPFILE} installed successfully"
313					else
314						echo " *** Warning: problem installing ${COMPFILE}, it will remain to merge by hand"
315					fi
316				unset MERGE_AGAIN
317				;;
318			[nN])
319				echo "comparison between merged and new files:\n"
320				diff -u ${COMPFILE}.merged ${COMPFILE}
321				INSTALL_MERGED=v
322				;;
323			[oO])
324				echo "comparison between old and merged files:\n"
325				diff -u ${DESTDIR}${COMPFILE#.} ${COMPFILE}.merged
326				INSTALL_MERGED=v
327				;;
328			[rR])
329				rm "${COMPFILE}.merged"
330				;;
331			[vV])
332				${PAGER} "${COMPFILE}.merged"
333				;;
334			'')
335				echo "===> ${COMPFILE} will remain for your consideration"
336				unset MERGE_AGAIN
337				;;
338			*)
339				echo "invalid choice: ${INSTALL_MERGED}"
340				INSTALL_MERGED=v
341				;;
342			esac
343		done
344	done
345}
346
347
348diff_loop() {
349	if [ "${BATCHMODE}" ]; then
350		HANDLE_COMPFILE=todo
351	else
352		HANDLE_COMPFILE=v
353	fi
354
355	while [ "${HANDLE_COMPFILE}" = "v" -o "${HANDLE_COMPFILE}" = "todo" ]; do
356		if [ "${HANDLE_COMPFILE}" = "v" ]; then
357			echo "\n========================================================================\n"
358		fi
359		if [ -f "${DESTDIR}${COMPFILE#.}" -a -f "${COMPFILE}" ]; then
360			# if current != new and current = old, auto-install new
361			if [ "${OTGZ}" -o "${OXTGZ}" ]; then
362				if diff -q "${DESTDIR}${COMPFILE#.}" "${OTEMPROOT}${COMPFILE#.}" > /dev/null 2>&1; then
363					echo "===> ${COMPFILE} has not been modified since previous release/snapshot,"
364					echo "     automatically installing new version"
365					if mm_install "${COMPFILE}"; then
366						echo "===> ${COMPFILE} installed successfully"
367						AUTO_INSTALLED_FILES="${AUTO_INSTALLED_FILES}${DESTDIR}${COMPFILE#.}\n"
368					else
369						echo " *** Warning: problem installing ${COMPFILE}, it will remain to merge by hand"
370					fi
371					return
372				fi
373			fi
374			if [ "${HANDLE_COMPFILE}" = "v" ]; then
375				(
376					echo "===> Displaying differences between ${COMPFILE} and installed version:"
377					echo ""
378					diff -u "${DESTDIR}${COMPFILE#.}" "${COMPFILE}"
379				) | ${PAGER}
380				echo ""
381			fi
382		else
383			echo "===> ${COMPFILE} was not found on the target system"
384			if [ -z "${AUTOMODE}" ]; then
385				echo ""
386				NO_INSTALLED=1
387			else
388				if mm_install "${COMPFILE}"; then
389					echo "===> ${COMPFILE} installed successfully"
390					AUTO_INSTALLED_FILES="${AUTO_INSTALLED_FILES}${DESTDIR}${COMPFILE#.}\n"
391				else
392					echo " *** Warning: problem installing ${COMPFILE}, it will remain to merge by hand"
393				fi
394				return
395			fi
396		fi
397
398		if [ -z "${BATCHMODE}" ]; then
399			echo "  Use 'd' to delete the temporary ${COMPFILE}"
400			if [ "${COMPFILE}" != "./etc/master.passwd" -a "${COMPFILE}" != "./etc/group" ]; then
401				echo "  Use 'i' to install the temporary ${COMPFILE}"
402			fi
403			if [ -z "${NO_INSTALLED}" -a -z "${IS_BINFILE}" ]; then
404				echo "  Use 'm' to merge the temporary and installed versions"
405				echo "  Use 'v' to view the diff results again"
406			fi
407			echo ""
408			echo "  Default is to leave the temporary file to deal with by hand"
409			echo ""
410			echo -n "How should I deal with this? [Leave it for later] "
411			read HANDLE_COMPFILE
412		else
413			unset HANDLE_COMPFILE
414		fi
415
416		case "${HANDLE_COMPFILE}" in
417		[dD])
418			rm "${COMPFILE}"
419			echo "\n===> Deleting ${COMPFILE}"
420			;;
421		[iI])
422			if [ "${COMPFILE}" != "./etc/master.passwd" -a "${COMPFILE}" != "./etc/group" ]; then
423				echo ""
424				if mm_install "${COMPFILE}"; then
425					echo "===> ${COMPFILE} installed successfully"
426				else
427					echo " *** Warning: problem installing ${COMPFILE}, it will remain to merge by hand"
428				fi
429			else
430				echo "invalid choice: ${HANDLE_COMPFILE}\n"
431				HANDLE_COMPFILE="todo"
432			fi
433
434			;;
435		[mM])
436			if [ -z "${NO_INSTALLED}" -a -z "${IS_BINFILE}" ]; then
437				merge_loop
438			else
439				echo "invalid choice: ${HANDLE_COMPFILE}\n"
440				HANDLE_COMPFILE="todo"
441			fi
442			;;
443		[vV])
444			if [ -z "${NO_INSTALLED}" -a -z "${IS_BINFILE}" ]; then
445				HANDLE_COMPFILE="v"
446			else
447				echo "invalid choice: ${HANDLE_COMPFILE}\n"
448				HANDLE_COMPFILE="todo"
449			fi
450			;;
451		'')
452			echo "\n===> ${COMPFILE} will remain for your consideration"
453			;;
454		*)
455			echo "invalid choice: ${HANDLE_COMPFILE}\n"
456			HANDLE_COMPFILE="todo"
457			continue
458			;;
459		esac
460	done
461
462	unset NO_INSTALLED
463}
464
465
466do_compare() {
467	echo "===> Starting comparison"
468
469	cd ${TEMPROOT} || error_rm_wrkdir
470
471	# use -size +0 to avoid comparing empty log files and device nodes
472	for COMPFILE in `find . -type f -size +0`; do
473		if [ ! -e "${DESTDIR}${COMPFILE#.}" ]; then
474			diff_loop
475			continue
476		fi
477
478		# compare CVS $Id's first so if the file hasn't been modified,
479		# it will be deleted from temproot and ignored from comparison.
480		# several files are generated from scripts so CVS ID is not a
481		# reliable way of detecting changes; leave for a full diff.
482		if [ "${AUTOMODE}" -a "${COMPFILE}" != "./etc/fbtab" \
483		    -a "${COMPFILE}" != "./etc/login.conf" \
484		    -a "${COMPFILE}" != "./etc/sysctl.conf" \
485		    -a "${COMPFILE}" != "./etc/ttys" ]; then
486			CVSID1=`grep "[$]OpenBSD:" ${DESTDIR}${COMPFILE#.} 2> /dev/null`
487			CVSID2=`grep "[$]OpenBSD:" ${COMPFILE} 2> /dev/null` || CVSID2=none
488			if [ "${CVSID2}" = "${CVSID1}" ]; then rm "${COMPFILE}"; fi
489		fi
490
491		if [ -f "${COMPFILE}" ]; then
492			# make sure files are different; if not, delete the one in temproot
493			if diff -q "${DESTDIR}${COMPFILE#.}" "${COMPFILE}" > /dev/null 2>&1; then
494				rm "${COMPFILE}"
495			# delete file in temproot if it has not changed since last release
496			elif [ "${OTGZ}" -o "${OXTGZ}" ] && diff -q "${COMPFILE}" "${OTEMPROOT}${COMPFILE#.}" > /dev/null 2>&1; then
497				rm "${COMPFILE}"
498			# xetcXX.tgz contains binary files; set IS_BINFILE to disable sdiff
499			elif diff -q "${DESTDIR}${COMPFILE#.}" "${COMPFILE}" | grep "Binary" > /dev/null 2>&1; then
500				IS_BINFILE=1
501				diff_loop
502			else
503				unset IS_BINFILE
504				diff_loop
505			fi
506		fi
507	done
508
509	echo "\n===> Comparison complete"
510}
511
512
513do_post() {
514	if [ "${NEED_NEWALIASES}" ]; then
515		echo "===> A new ${DESTDIR}/etc/mail/aliases file was installed."
516		echo "     However ${DESTDIR}/usr/bin/newaliases could not be run,"
517		echo "     you will need to rebuild your aliases database manually."
518        fi
519
520	clean_src
521	rm -rf ${OTEMPROOT}
522
523	echo "===> Making sure your directory hierarchy has correct perms, running mtree"
524	mtree -qdef ${DESTDIR}/etc/mtree/4.4BSD.dist -p ${DESTDIR:=/} -U > /dev/null
525
526	FILES_IN_TEMPROOT=`find ${TEMPROOT} -type f ! -name \*.merged -size +0 2> /dev/null`
527	FILES_IN_BKPDIR=`find ${BKPDIR} -type f -size +0 2> /dev/null`
528	if [ "${AUTO_INSTALLED_FILES}" ]; then
529		echo "===> Automatically installed file(s)" >> ${REPORT}
530		echo "${AUTO_INSTALLED_FILES}" >> ${REPORT}
531	fi
532	if [ "${FILES_IN_BKPDIR}" ]; then
533		echo "===> Backup of replaced file(s) can be found under" >> ${REPORT}
534		echo "${BKPDIR}\n" >> ${REPORT}
535	fi
536	if [ "${OBSOLETE_FILES}" ]; then
537		echo "===> File(s) removed from previous set (maybe obsolete)" >> ${REPORT}
538		echo "${OBSOLETE_FILES}" >> ${REPORT}
539	fi
540	if [ "${FILES_IN_TEMPROOT}" ]; then
541		echo "===> File(s) remaining for you to merge by hand" >> ${REPORT}
542		echo "${FILES_IN_TEMPROOT}" >> ${REPORT}
543	fi
544
545	if [ -e "${REPORT}" ]; then
546		echo "===> Manual intervention may be needed, see ${REPORT}"
547		echo "===> When done, ${WRKDIR} and its subdirectories should be removed"
548	else
549		echo "===> Removing ${WRKDIR}"
550		rm -rf "${WRKDIR}"
551	fi
552}
553
554
555while getopts abs:x:S:X: arg; do
556	case ${arg} in
557	a)
558		AUTOMODE=1
559		;;
560	b)
561		BATCHMODE=1
562		;;
563	s)
564		if [ -f "${OPTARG}/etc/Makefile" ]; then
565			SRCDIR=${OPTARG}
566		elif [ -f "${OPTARG}" ] && echo -n ${OPTARG} | \
567		    awk -F/ '{print $NF}' | \
568		    grep '^etc[0-9][0-9]\.tgz$' > /dev/null 2>&1 ; then
569			TGZ=${OPTARG}
570		elif echo ${OPTARG} | \
571		    grep -qE '^(http|ftp)://.*/etc[0-9][0-9]\.tgz$'; then
572			TGZ=${WRKDIR}/etc.tgz
573			TGZURL=${OPTARG}
574			if ! ${FETCH_CMD} -o ${TGZ} ${TGZURL}; then
575				echo " *** Error: could not retrieve ${TGZURL}"
576				error_rm_wrkdir
577			fi
578		else
579			echo " *** Error: ${OPTARG} is not a path to src nor etcXX.tgz"
580			error_rm_wrkdir
581		fi
582		;;
583	x)
584		if [ -f "${OPTARG}" ] && echo -n ${OPTARG} | \
585		    awk -F/ '{print $NF}' | \
586		    grep '^xetc[0-9][0-9]\.tgz$' > /dev/null 2>&1 ; then
587			XTGZ=${OPTARG}
588		elif echo ${OPTARG} | \
589		    grep -qE '^(http|ftp)://.*/xetc[0-9][0-9]\.tgz$'; then
590			XTGZ=${WRKDIR}/xetc.tgz
591			XTGZURL=${OPTARG}
592			if ! ${FETCH_CMD} -o ${XTGZ} ${XTGZURL}; then
593				echo " *** Error: could not retrieve ${XTGZURL}"
594				error_rm_wrkdir
595			fi
596		else
597			echo " *** Error: ${OPTARG} is not a path to xetcXX.tgz"
598			error_rm_wrkdir
599		fi
600		;;
601	S)
602		if [ -f "${OPTARG}" ] && echo -n ${OPTARG} | \
603		    awk -F/ '{print $NF}' | \
604		    grep '^etc[0-9][0-9]\.tgz$' > /dev/null 2>&1 ; then
605			OTGZ=${OPTARG}
606		elif echo ${OPTARG} | \
607		    grep -qE '^(http|ftp)://.*/etc[0-9][0-9]\.tgz$'; then
608			OTGZ=${WRKDIR}/etc.tgz
609			OTGZURL=${OPTARG}
610			if ! ${FETCH_CMD} -o ${OTGZ} ${OTGZURL}; then
611				echo " *** Error: could not retrieve ${OTGZURL}"
612				error_rm_wrkdir
613			fi
614		else
615			echo " *** Error: ${OPTARG} is not a path to etcXX.tgz"
616			error_rm_wrkdir
617		fi
618		;;
619	X)
620		if [ -f "${OPTARG}" ] && echo -n ${OPTARG} | \
621		    awk -F/ '{print $NF}' | \
622		    grep '^xetc[0-9][0-9]\.tgz$' > /dev/null 2>&1 ; then
623			OXTGZ=${OPTARG}
624		elif echo ${OPTARG} | \
625		    grep -qE '^(http|ftp)://.*/xetc[0-9][0-9]\.tgz$'; then
626			OXTGZ=${WRKDIR}/xetc.tgz
627			OXTGZURL=${OPTARG}
628			if ! ${FETCH_CMD} -o ${OXTGZ} ${OXTGZURL}; then
629				echo " *** Error: could not retrieve ${OXTGZURL}"
630				error_rm_wrkdir
631			fi
632		else
633			echo " *** Error: ${OPTARG} is not a path to xetcXX.tgz"
634			error_rm_wrkdir
635		fi
636		;;
637	*)
638		usage
639		error_rm_wrkdir
640		;;
641	esac
642done
643
644
645do_pre
646do_populate
647do_compare
648do_post
649