xref: /netbsd/usr.sbin/etcupdate/etcupdate (revision bf9ec67e)
1#!/bin/sh
2#
3# $NetBSD: etcupdate,v 1.3 2002/05/15 08:17:56 martti Exp $
4#
5# Copyright (c) 2001 The NetBSD Foundation, Inc.
6# All rights reserved.
7#
8# This code is derived from software contributed to The NetBSD Foundation
9# by Martti Kuparinen.
10#
11# Redistribution and use in source and binary forms, with or without
12# modification, are permitted provided that the following conditions
13# are met:
14# 1. Redistributions of source code must retain the above copyright
15#    notice, this list of conditions and the following disclaimer.
16# 2. Redistributions in binary form must reproduce the above copyright
17#    notice, this list of conditions and the following disclaimer in the
18#    documentation and/or other materials provided with the distribution.
19# 3. All advertising materials mentioning features or use of this software
20#    must display the following acknowledgement:
21#        This product includes software developed by the NetBSD
22#        Foundation, Inc. and its contributors.
23# 4. Neither the name of The NetBSD Foundation nor the names of its
24#    contributors may be used to endorse or promote products derived
25#    from this software without specific prior written permission.
26#
27# THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
28# ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
29# TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
30# PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
31# BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
32# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
33# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
34# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
35# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
36# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
37# POSSIBILITY OF SUCH DAMAGE.
38#
39#
40# This script helps you to update the configuration files in /etc
41# after an operating system upgrade. Instead of running "make distribution"
42# in /usr/src/etc (and losing your current configuration) you can easily
43# see the modifications and either install the new version or merge the
44# changes in to your current configuration files.
45#
46# This script was written by Martti Kuparinen <martti@netbsd.org> and
47# improved by several other NetBSD users.
48#
49# The idea for this script (including code fragments, variable names etc.)
50# came from the FreeBSD mergemaster (by Douglas Barton).
51#
52PATH="/sbin:/usr/sbin:/bin:/usr/bin:${PATH}"
53
54# Default settings
55TEMPROOT="${TEMPROOT:=/tmp/temproot}"
56SRCDIR="${SRCDIR:=/usr/src/etc}"
57PAGER="${PAGER:=/usr/bin/more}"
58WIDTH="${WIDTH:=80}"
59VERBOSE=
60CONTINUE=
61BINARY=
62
63# Settings for post-installlation procedures
64NEED_MTREE=
65NEED_MAKEDEV=
66NEED_NEWALIASES=
67NEED_PWD_MKDB=
68
69usage() {
70	cat << EOF
71
72Usage: `basename $0` [options]
73
74Options:
75
76  -b srcdir    Location of the extracted sets
77  -p pager     Which pager to use              (default: /usr/bin/more)
78  -s srcdir    Location of the source files    (default: /usr/src)
79  -t temproot  Where to store temporary files  (default: /tmp/temproot)
80  -w width     Screen width                    (default: 80)
81
82  -h           This help text
83  -v           Be more verbose
84
85EOF
86	exit 1
87}
88
89verbose() {
90	# $* = message to display if in verbose mode
91
92	[ ! -z "${VERBOSE}" ] && echo ${*}
93}
94
95yesno() {
96	# $* = message to display
97
98	echo -n "${*} (y/[n]) "
99	read ANSWER
100	case "${ANSWER}" in
101		y|Y)
102			return 0
103			;;
104		*)
105			return 1
106			;;
107	esac
108}
109
110install_dir() {
111	# $1 = target directory
112
113	if yesno "Create ${1}"; then
114		verbose "Creating ${1}"
115		mkdir -p "${1}" || exit 1
116		NEED_MTREE=YES
117	fi
118}
119
120install_file() {
121	# $1 = target file
122
123	# Install the new file
124	verbose "Installing ${1}"
125	cp -p "${TEMPROOT}${1}" "${1}" && rm -f "${TEMPROOT}${1}"
126
127	# Check if this was a special file
128	case "${1}" in
129	/dev/MAKEDEV)
130		NEED_MAKEDEV=YES
131		;;
132	/dev/MAKEDEV.local)
133		NEED_MAKEDEV=YES
134		;;
135	/etc/mail/aliases)
136		NEED_NEWALIASES=YES
137		;;
138	/etc/master.passwd)
139		NEED_PWD_MKDB=YES
140		;;
141	esac
142}
143
144diff_and_merge_file() {
145	# $1 = target file
146
147	if cmp -s "${TEMPROOT}${1}" "${1}"; then
148		verbose "===> ${1} (ok)"
149		rm -f "${TEMPROOT}${1}"
150		return
151	fi
152
153	clear
154	if [ ! -f "${1}" ]; then
155		verbose "===> ${1} (missing)"
156		DOES_EXIST=
157	else
158		verbose "===> ${1} (modified)"
159		verbose ""
160		DOES_EXIST=YES
161		diff -u "${1}" "${TEMPROOT}${1}" | ${PAGER}
162	fi
163
164	STAY_HERE=YES
165	ALREADY_MERGED=
166
167	# Determine name for the backup file (/foo/._etcupdate.bar)
168	D=`dirname  "${TEMPROOT}${1}"`
169	F=`basename "${TEMPROOT}${1}"`
170	B="${D}/.etcupdate.${F}"
171	F="${D}/${F}"
172
173	while [ "x${STAY_HERE}" = "xYES" ]; do
174
175		# Ask the user if (s)he wants to install the new
176		# version or perform a more complicated manual work.
177		echo ""
178		echo -n "File: ${1}"
179		if [ ! -f "${1}" ]; then
180			echo -n " (missing)"
181		else
182			echo -n " (modified)"
183		fi
184		echo ""
185		echo ""
186		echo "Please select one of the following operations:"
187		echo ""
188		if [ -z "${DOES_EXIST}" ]; then
189			cat << EOF
190  d  Don't install the missing file
191  i  Install the missing file
192  v  Show the missing file
193
194EOF
195		elif [ -z "${ALREADY_MERGED}" ]; then
196			cat << EOF
197  d  Don't install the new file
198  i  Install the new file (overwrites your modifications!)
199  m  Merge the currently installed and new files
200  s  Show the differences between the currently installed and new files
201  v  Show the new file
202
203EOF
204		else
205			cat << EOF
206  d  Don't install the new file
207  i  Install the new file (overwrites your modifications!)
208  m  Merge again the currently installed and new files
209  s  Show the differences between the currently installed and new files
210  u  Undo merge and restore the temporary file from backup
211  v  Show the merged file
212
213EOF
214		fi
215		echo -n "What do you want to do? [Leave it for later] "
216		read ANSWER
217		case "${ANSWER}" in
218
219		[dD])
220			verbose "Removing ${TEMPROOT}${1}"
221			rm -f "${TEMPROOT}${1}"
222			STAY_HERE=NO
223			;;
224		[iI])
225			install_file "${1}"
226			STAY_HERE=NO
227			;;
228		[mM])
229			[ -z "${DOES_EXIST}" ] && continue
230			[ ! -f "${B}" ] && cp "${F}" "${B}"
231			cp "${TEMPROOT}${1}" "${TEMPROOT}${1}.merged"
232			sdiff -o "${TEMPROOT}${1}.merged"	\
233				--width=${WIDTH}		\
234				--suppress-common-lines --text	\
235				"${1}" "${TEMPROOT}${1}"
236			mv -f "${TEMPROOT}${1}.merged" "${TEMPROOT}${1}"
237			ALREADY_MERGED=YES
238			;;
239		[sS])
240			[ -z "${DOES_EXIST}" ] && continue
241			diff -u "${1}" "${TEMPROOT}${1}" | ${PAGER}
242			;;
243		[uU])
244			if [ -f "${B}" ]; then
245				echo "*** Restoring ${F}"
246				mv -f "${B}" "${F}"
247			fi
248			ALREADY_MERGED=
249			;;
250		[vV])
251			${PAGER} "${TEMPROOT}${1}"
252			;;
253		"")
254			STAY_HERE=NO
255			;;
256		*)
257			echo "*** Invalid selection!"
258			;;
259		esac
260	done
261	rm -f "._etcupdate_${TEMPROOT}${1}"
262}
263
264#
265# main()
266#
267
268# Read global configuration
269GLOBALRC="/etc/`basename $0`.conf"
270[ -r ${GLOBALRC} ] && . ${GLOBALRC}
271
272# Read user configuration
273USERRC="${HOME}/.`basename $0`rc"
274[ -r ${USERRC} ] && . ${USERRC}
275
276# Read command line arguments
277ARGV=`getopt b:hp:s:t:vw: $*`
278[ $? != 0 ] && usage
279set -- ${ARGV}
280for i; do
281	case "${i}" in
282	-b)
283		BINARY=YES
284		SRCDIR="${2}"
285		shift 2
286		;;
287	-h)
288		usage
289		;;
290	-p)
291		PAGER="${2}"
292		shift 2
293		;;
294	-s)
295		SRCDIR="${2}"
296		shift 2
297		;;
298	-t)
299		TEMPROOT="${2}"
300		shift 2
301		;;
302	-v)
303		VERBOSE=YES
304		shift
305		;;
306	-w)
307		WIDTH="${2}"
308		shift 2
309		;;
310	--)
311		shift
312		break
313		;;
314	esac
315done
316
317# Last minute sanity checks
318if [ `id -u` -ne 0 ]; then
319	echo "*** ERROR: You MUST be root"
320	exit 1
321fi
322if [ ! -z "${BINARY}" ]; then
323	TEMPROOT="${SRCDIR}"
324fi
325if [ -z "${SRCDIR}" -o -z "${TEMPROOT}" ]; then
326	echo "*** ERROR: One of the following variables is undefined"
327	echo ""
328	echo "SRCDIR=\"${SRCDIR}\""
329	echo "TEMPROOT=\"${TEMPROOT}\""
330	echo ""
331	exit 1
332fi
333if [ -z "${BINARY}" -a -r "${TEMPROOT}" ]; then
334	echo ""
335	echo "*** WARNING: ${TEMPROOT} already exists"
336	echo ""
337	if yesno "Continue previously aborted update"; then
338		CONTINUE=YES
339	elif yesno "Remove the old ${TEMPROOT}"; then
340		echo "*** Removing ${TEMPROOT}"
341		rm -rf "${TEMPROOT}"
342	fi
343fi
344
345if [ -z "${CONTINUE}" ]; then
346	# Are we using the sources or binaries?
347	if [ -z "${BINARY}" ]; then
348		# Create the temporary root directory
349		echo "*** Creating ${TEMPROOT}"
350		mkdir -p "${TEMPROOT}"
351		if [ ! -d "${TEMPROOT}" ]; then
352			echo "*** ERROR: Unable to create ${TEMPROOT}"
353			exit 1
354		fi
355
356		# Populate ${TEMPROOT} from ${SRCDIR}
357		if [ ! -f "${SRCDIR}/Makefile" ]; then
358			echo "*** ERROR: Unable to find ${SRCDIR}/Makefile"
359			exit 1
360		fi
361		# Set the environment for make
362		MAKE_ENV=" 			\
363			DESTDIR=${TEMPROOT}	\
364			MAKE=make		\
365			MTREE=mtree		\
366			INSTALL_DONE=1		\
367			NO_SENDMAIL=1"
368		echo "*** Populating ${TEMPROOT} from ${SRCDIR}"
369		cd ${SRCDIR}
370		if [ -z "${VERBOSE}" ]; then
371			eval ${MAKE_ENV} make distribution > /dev/null
372		else
373			eval ${MAKE_ENV} make distribution
374		fi
375		[ $? -ne 0 ] && exit 1
376	elif [ ! -f "${TEMPROOT}/dev/MAKEDEV" ]; then
377		echo ""
378		echo "*** WARNING: ${TEMPROOT}/dev/MAKEDEV not found"
379		echo "Make sure you update /dev/MAKEDEV later and run"
380		echo "(cd /dev && ./MAKEDEV all) to rebuild the device nodes"
381		echo ""
382	fi
383
384	# Ignore the following files during comparision
385	rm -f "${TEMPROOT}"/etc/passwd
386	rm -f "${TEMPROOT}"/etc/pwd.db
387	rm -f "${TEMPROOT}"/etc/spwd.db
388	find "${TEMPROOT}" -type f -size 0 -exec rm {} \;
389
390	# Are there any new directories?
391	echo "*** Checking for new directories"
392	for i in `find ${TEMPROOT} -type d`; do
393		D=`echo ${i} | sed "s#${TEMPROOT}##"`
394		[ "x${i}" = "x${TEMPROOT}" ] && continue
395		[ ! -d "${D}" ] && install_dir "${D}"
396	done
397fi
398
399# Start the comparision
400echo "*** Checking for added/modified files"
401for i in `find ${TEMPROOT} -type f  -a ! -name \*.etcupdate.\*`; do
402	D=`echo ${i} | sed "s#${TEMPROOT}##"`
403	diff_and_merge_file "${D}"
404done
405
406# Do we have files which were not processed?
407REMAINING=`find "${TEMPROOT}" -type f -a ! -name \*.etcupdate.\*`
408if [ ! -z "${REMAINING}" ]; then
409	echo ""
410	echo "*** The following files need your attention:"
411	echo ""
412	for i in ${REMAINING}; do
413		echo "  ${i}"
414	done
415	echo ""
416fi
417if yesno "Remove ${TEMPROOT}"; then
418	echo "*** Removing ${TEMPROOT}"
419	rm -rf "${TEMPROOT}"
420else
421	echo "*** Keeping ${TEMPROOT}"
422fi
423
424# Do some post-installation tasks
425if [ ! -z "${NEED_MTREE}" ]; then
426	if yesno "You have created new directories. Run mtree to set" \
427	         "permissions"
428	then
429		(cd / && mtree -Udef /etc/mtree/NetBSD.dist)
430	fi
431fi
432if [ ! -z "${NEED_MAKEDEV}" ]; then
433	if yesno "Do you want to rebuild the device nodes in /dev"; then
434		verbose "Running MAKEDEV in /dev"
435		(cd "/dev" && ./MAKEDEV all)
436	else
437		echo ""
438		echo "*** You SHOULD rebuild the device nodes in /dev"
439		echo "*** This is done by running \"(cd /dev &&" \
440		     "./MAKEDEV all)\" as root".
441		echo ""
442	fi
443fi
444if [ ! -z "${NEED_NEWALIASES}" ]; then
445	if yesno "Do you want to rebuild the mail alias database"; then
446		verbose "Running newaliases"
447		newaliases
448	else
449		echo ""
450		echo "*** You MUST rebuild the mail alias database to make" \
451		     "the changes visible"
452		echo "*** This is done by running \"newaliases\" as root"
453		echo ""
454	fi
455fi
456if [ ! -z "${NEED_PWD_MKDB}" ]; then
457	if yesno "Do you want to rebuild the password databases from the" \
458	         "new master.passwd"
459	then
460		verbose "Running pwd_mkdb"
461		pwd_mkdb -p "/etc/master.passwd"
462	else
463		echo ""
464		echo "*** Do MUST rebuild the password databases to make" \
465		     "the changes visible"
466		echo "*** This is done by running \"pwd_mkdb -p" \
467		     "/etc/master.passwd\" as root"
468		echo ""
469	fi
470fi
471if [ -x /etc/postinstall ]; then
472	S=`echo ${SRCDIR} | sed 's+/etc++'`
473	echo "*** Running /etc/postinstall"
474	/etc/postinstall -s "${S}" check
475fi
476echo "*** All done"
477