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