856 lines
22 KiB
Bash
856 lines
22 KiB
Bash
#!/bin/sh
|
|
#
|
|
# $NetBSD: etcupdate,v 1.65 2022/01/17 08:47:03 lukem Exp $
|
|
#
|
|
# Copyright (c) 2001-2022 The NetBSD Foundation, Inc.
|
|
# All rights reserved.
|
|
#
|
|
# This code is derived from software contributed to The NetBSD Foundation
|
|
# by Martti Kuparinen.
|
|
#
|
|
# Redistribution and use in source and binary forms, with or without
|
|
# modification, are permitted provided that the following conditions
|
|
# are met:
|
|
# 1. Redistributions of source code must retain the above copyright
|
|
# notice, this list of conditions and the following disclaimer.
|
|
# 2. Redistributions in binary form must reproduce the above copyright
|
|
# notice, this list of conditions and the following disclaimer in the
|
|
# documentation and/or other materials provided with the distribution.
|
|
#
|
|
# THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
|
|
# ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
|
# TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
|
# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
|
|
# BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
|
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
|
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
|
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
|
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
|
# POSSIBILITY OF SUCH DAMAGE.
|
|
#
|
|
#
|
|
# This script helps you to update the configuration files in /etc
|
|
# after an operating system upgrade. Instead of running "make distribution"
|
|
# in /usr/src/etc (and losing your current configuration) you can easily
|
|
# see the modifications and either install the new version or merge the
|
|
# changes in to your current configuration files.
|
|
#
|
|
# This script was written by Martti Kuparinen <martti@NetBSD.org> and
|
|
# improved by several other NetBSD users.
|
|
#
|
|
# The idea for this script (including code fragments, variable names etc.)
|
|
# came from the FreeBSD mergemaster (by Douglas Barton).
|
|
#
|
|
PATH="/sbin:/usr/sbin:/bin:/usr/bin:${PATH}"
|
|
|
|
# Default settings
|
|
PROG="${0##*/}"
|
|
DESTDIR="" # must not have a trailing slash
|
|
DESTDIR_BRE="" # basic regex to match ${DESTDIR}
|
|
TEMPROOT="${TEMPROOT:=/tmp/temproot}"
|
|
PAGER="${PAGER:=/usr/bin/more}"
|
|
SWIDTH="$(stty size | awk '{w=$2}END{if(w==0){w=80}print w}')"
|
|
WIDTH="${WIDTH:="${SWIDTH}"}"
|
|
DIFF_COMMAND="diff -u"
|
|
VERBOSE=false
|
|
CONTINUE=false
|
|
SOURCEMODE=false # true for "-s source_dir"
|
|
SRCDIR= # directory for SOURCEMODE
|
|
BINARYMODE=false # true for both BINARYDIRMODE and BINARYTGZMODE
|
|
BINARYDIRMODE=false # true for "-s extracted_dir"
|
|
BINARYDIR= # directory name for BINARYDIRMODE
|
|
BINARYTGZMODE=false # true for "-s etc.tgz"
|
|
TGZLIST= # quoted list list of files for BINARYTGZMODE
|
|
SRC_ARGLIST= # quoted list of "-s" args
|
|
N_SRC_ARGS=0 # number of "-s" args
|
|
AUTOMATIC=false
|
|
LOCALSKIP=false
|
|
MACHINE="${MACHINE:="$(uname -m)"}"
|
|
export MACHINE
|
|
MACHINE_ARCH="${MACHINE_ARCH:="$(uname -p)"}"
|
|
export MACHINE_ARCH
|
|
|
|
# Settings for post-installation procedures
|
|
NEED_ANYTHING=false
|
|
NEED_MAKEDEV=false
|
|
NEED_MTREE=false
|
|
NEED_NEWALIASES=false
|
|
NEED_PWD_MKDB=false
|
|
NEED_SERVICES_MKDB=false
|
|
|
|
|
|
help()
|
|
{
|
|
cat << EOF
|
|
|
|
Usage: ${PROG} [-alv] [-d DESTDIR] [-p PAGER] [-s SRC_ARG] [-t TEMPROOT] [-w WIDTH]
|
|
${PROG} ( -h | -? )
|
|
|
|
Options:
|
|
|
|
-a Automatically update unmodified files.
|
|
-d DESTDIR Destination directory to check. [/]
|
|
-h Display this help, and exit.
|
|
-l Automatically skip files with strictly local changes
|
|
(this option has no effect on files lacking RCS Ids).
|
|
-p PAGER Which pager to use [/usr/bin/more]
|
|
-s SRC_ARG Location of the source files. [/usr/src]
|
|
This may be any of the following:
|
|
-s SRC_DIR A directory that contains a NetBSD
|
|
source tree.
|
|
-s TGZ_DIR A directory in which one or both of
|
|
"etc.tgz" and "xetc.tgz" have been extracted.
|
|
-s TGZ_FILE A distribution set file such as "etc.tgz" or
|
|
"xetc.tgz". May be specified multiple times.
|
|
-t TEMPROOT Where to store temporary files. [/tmp/temproot]
|
|
-w WIDTH Screen width. [80]
|
|
-v Be more verbose.
|
|
-? Display this help, and exit.
|
|
|
|
EOF
|
|
}
|
|
|
|
usage()
|
|
{
|
|
help 1>&2
|
|
exit 1
|
|
}
|
|
|
|
verbose()
|
|
{
|
|
# $* = message to display if in verbose mode
|
|
|
|
${VERBOSE} && echo "${@}"
|
|
}
|
|
|
|
yesno()
|
|
{
|
|
# $* = message to display
|
|
|
|
echo -n "${@}? (y/[n]) "
|
|
read ANSWER
|
|
case "${ANSWER}" in
|
|
y|Y)
|
|
return 0
|
|
;;
|
|
*)
|
|
return 1
|
|
;;
|
|
esac
|
|
}
|
|
|
|
# Quote args to make them safe in the shell.
|
|
# Usage: quotedlist="$(shell_quote args...)"
|
|
#
|
|
# After building up a quoted list, use it by evaling it inside
|
|
# double quotes, like this:
|
|
# eval "set -- $quotedlist"
|
|
# or like this:
|
|
# eval "\$command $quotedlist \$filename"
|
|
#
|
|
shell_quote()
|
|
{(
|
|
local result=''
|
|
local arg qarg
|
|
LC_COLLATE=C ; export LC_COLLATE # so [a-zA-Z0-9] works in ASCII
|
|
for arg in "$@" ; do
|
|
case "${arg}" in
|
|
'')
|
|
qarg="''"
|
|
;;
|
|
*[!-./a-zA-Z0-9]*)
|
|
# Convert each embedded ' to '\'',
|
|
# then insert ' at the beginning of the first line,
|
|
# and append ' at the end of the last line.
|
|
# Finally, elide unnecessary '' pairs at the
|
|
# beginning and end of the result and as part of
|
|
# '\'''\'' sequences that result from multiple
|
|
# adjacent quotes in he input.
|
|
qarg="$(printf "%s\n" "$arg" | \
|
|
${SED:-sed} -e "s/'/'\\\\''/g" \
|
|
-e "1s/^/'/" -e "\$s/\$/'/" \
|
|
-e "1s/^''//" -e "\$s/''\$//" \
|
|
-e "s/'''/'/g"
|
|
)"
|
|
;;
|
|
*)
|
|
# Arg is not the empty string, and does not contain
|
|
# any unsafe characters. Leave it unchanged for
|
|
# readability.
|
|
qarg="${arg}"
|
|
;;
|
|
esac
|
|
result="${result}${result:+ }${qarg}"
|
|
done
|
|
printf "%s\n" "$result"
|
|
)}
|
|
|
|
# Convert arg $1 to a basic regular expression (as in sed)
|
|
# that will match the arg. This works by inserting backslashes
|
|
# before characters that are special in basic regular expressions.
|
|
# It also inserts backslashes before the extra characters specified
|
|
# in $2 (which defaults to "/,").
|
|
# XXX: Does not handle embedded newlines.
|
|
# Usage: regex="$(bre_quote "${string}")"
|
|
bre_quote()
|
|
{
|
|
local arg="$1"
|
|
local extra="${2-/,}"
|
|
printf "%s\n" "${arg}" | sed -e 's/[][^$.*\\'"${extra}"']/\\&/g'
|
|
}
|
|
|
|
install_dir()
|
|
{
|
|
# $1 = target directory (relative to ${DESTDIR})
|
|
|
|
NEED_ANYTHING=true
|
|
if yesno "Create ${DESTDIR}${1}"; then
|
|
verbose "Creating ${DESTDIR}${1}"
|
|
mkdir -p "${DESTDIR}${1}" || exit 1
|
|
NEED_MTREE=true
|
|
fi
|
|
}
|
|
|
|
install_file()
|
|
{
|
|
# $1 = target file (relative to ${DESTDIR})
|
|
|
|
NEED_ANYTHING=true
|
|
# Install the new file
|
|
verbose "Installing ${DESTDIR}${1}"
|
|
cp -p "${TEMPROOT}${1}" "${DESTDIR}${1}" && rm -f "${TEMPROOT}${1}"
|
|
|
|
# Check if this was a special file
|
|
case "${1}" in
|
|
/dev/MAKEDEV)
|
|
NEED_MAKEDEV=true
|
|
;;
|
|
/dev/MAKEDEV.local)
|
|
NEED_MAKEDEV=true
|
|
;;
|
|
/etc/mail/aliases)
|
|
NEED_NEWALIASES=true
|
|
;;
|
|
/etc/master.passwd)
|
|
NEED_PWD_MKDB=true
|
|
;;
|
|
/etc/services)
|
|
NEED_SERVICES_MKDB=true
|
|
;;
|
|
esac
|
|
}
|
|
|
|
install_checksum()
|
|
{
|
|
# $1 = target file (relative to ${DESTDIR})
|
|
|
|
${AUTOMATIC} || return
|
|
|
|
NEED_ANYTHING=true
|
|
D="$(dirname "${1}")"
|
|
mkdir -p "${DESTDIR}/var/etcupdate/${D}"
|
|
verbose "Saving MD5 checksum for ${DESTDIR}${1} to" \
|
|
"${DESTDIR}/var/etcupdate/${1}"
|
|
# The sed part of the following pipeline changes things like
|
|
# "MD5 (/path/to/dest/dir/etc/filename) = abc123" to
|
|
# "MD5 (/etc/filename) = abc123".
|
|
md5 "${DESTDIR}${1}" | sed -e "s,(${DESTDIR_BRE},(," \
|
|
> "${DESTDIR}/var/etcupdate/${1}"
|
|
}
|
|
|
|
# Initialise the DIFF_EXTRA_OPTIONS variable.
|
|
init_diff_extra_options()
|
|
{
|
|
#
|
|
# Start with a few options that are always available.
|
|
#
|
|
DIFF_EXTRA_OPTIONS=\
|
|
" su Show differences in unified format (\"diff -u\")
|
|
sc Show differences in context format (\"diff -c\")
|
|
ss Show differences side by side (\"sdiff -w${WIDTH}\")"
|
|
#
|
|
# wdiff is not part of the base system, but the
|
|
# user might have installed it from pkgsrc. It is
|
|
# useful to show differences on a word by word basis
|
|
# instead of line by line. If it is executable
|
|
# then offer to use it in the menu.
|
|
#
|
|
if (wdiff /dev/null /dev/null) >/dev/null 2>&1 ; then
|
|
DIFF_EXTRA_OPTIONS="${DIFF_EXTRA_OPTIONS}
|
|
sw Show differences word by word (\"wdiff -n -l\")"
|
|
fi
|
|
#
|
|
# End with an option to use a user-specified diff-like command.
|
|
#
|
|
DIFF_EXTRA_OPTIONS="${DIFF_EXTRA_OPTIONS}
|
|
scommand Show differences using the specified diff-like command"
|
|
}
|
|
|
|
diff_and_merge_file()
|
|
{
|
|
# $1 = target file (relative to ${DESTDIR})
|
|
|
|
if cmp -s "${TEMPROOT}${1}" "${DESTDIR}${1}"; then
|
|
verbose "===> ${1} (ok)"
|
|
rm -f "${TEMPROOT}${1}"
|
|
install_checksum "${1}"
|
|
return
|
|
fi
|
|
|
|
if ${AUTOMATIC} && [ -f "${DESTDIR}/var/etcupdate/${1}" ]; then
|
|
SUM1="$(md5 "${1}")"
|
|
SUM2="$(cat "${DESTDIR}/var/etcupdate/${1}")"
|
|
if [ "${SUM1}" = "${SUM2}" ]; then
|
|
install_file "${1}"
|
|
install_checksum "${1}"
|
|
return
|
|
fi
|
|
fi
|
|
|
|
if ${LOCALSKIP}; then
|
|
ID1="$(ident -q "${TEMPROOT}${1}" | sed -n 2p)"
|
|
ID1="${ID1:-0}"
|
|
ID2="$(ident -q "${DESTDIR}${1}" | sed -n 2p)"
|
|
ID2="${ID2:-1}"
|
|
if [ "${ID1}" = "${ID2}" ]; then
|
|
verbose "===> ${1} (ok:RCS)"
|
|
rm -f "${TEMPROOT}${1}"
|
|
return
|
|
fi
|
|
fi
|
|
|
|
clear
|
|
if [ ! -f "${DESTDIR}${1}" ]; then
|
|
verbose "===> ${DESTDIR}${1} (missing)"
|
|
DOES_EXIST=false
|
|
else
|
|
verbose "===> ${DESTDIR}${1} (modified)"
|
|
verbose ""
|
|
DOES_EXIST=true
|
|
diff -u "${DESTDIR}${1}" "${TEMPROOT}${1}" | ${PAGER}
|
|
fi
|
|
|
|
STAY_HERE=true
|
|
ALREADY_MERGED=false
|
|
|
|
# Determine name for the backup file (/foo/._etcupdate.bar)
|
|
D="$(dirname "${TEMPROOT}${1}")"
|
|
F="$(basename "${TEMPROOT}${1}")"
|
|
B="${D}/.etcupdate.${F}"
|
|
F="${D}/${F}"
|
|
|
|
while ${STAY_HERE}; do
|
|
|
|
# Ask the user if (s)he wants to install the new
|
|
# version or perform a more complicated manual work.
|
|
echo ""
|
|
echo -n "File: ${DESTDIR}${1}"
|
|
if [ ! -f "${DESTDIR}${1}" ]; then
|
|
echo -n " (missing)"
|
|
else
|
|
echo -n " (modified)"
|
|
fi
|
|
echo ""
|
|
echo ""
|
|
echo "Please select one of the following operations:"
|
|
echo ""
|
|
if ! ${DOES_EXIST}; then
|
|
cat << EOF
|
|
d Don't install the missing file
|
|
i Install the missing file
|
|
v Show the missing file
|
|
|
|
EOF
|
|
elif ! ${ALREADY_MERGED}; then
|
|
cat << EOF
|
|
d Don't install the new file (keep your old file)
|
|
i Install the new file (overwrites your local modifications!)
|
|
m Merge the currently installed and new files
|
|
s Show the differences between the currently installed and new files
|
|
${DIFF_EXTRA_OPTIONS}
|
|
v Show the new file
|
|
|
|
EOF
|
|
else
|
|
cat << EOF
|
|
d Don't install the merged file (keep your old file)
|
|
i Install the merged file (overwrites your old file)
|
|
m Merge again (your old file against the result from the previous merge)
|
|
s Show the differences between the currently installed and new merged files
|
|
${DIFF_EXTRA_OPTIONS}
|
|
u Undo merge (start again with the original version of the new file)
|
|
v Show the merged file
|
|
|
|
EOF
|
|
fi
|
|
echo -n "What do you want to do? [Leave it for later] "
|
|
read ANSWER
|
|
case "${ANSWER}" in
|
|
|
|
[dD])
|
|
verbose "Removing ${TEMPROOT}${1}"
|
|
rm -f "${TEMPROOT}${1}"
|
|
STAY_HERE=false
|
|
;;
|
|
[iI])
|
|
install_file "${1}"
|
|
if ! ${ALREADY_MERGED}; then
|
|
install_checksum "${1}"
|
|
fi
|
|
STAY_HERE=false
|
|
;;
|
|
[mM])
|
|
${DOES_EXIST} || continue
|
|
[ ! -f "${B}" ] && cp "${F}" "${B}"
|
|
cp "${TEMPROOT}${1}" "${TEMPROOT}${1}.merged"
|
|
sdiff -o "${TEMPROOT}${1}.merged" \
|
|
--width=${WIDTH} \
|
|
--suppress-common-lines --text \
|
|
"${DESTDIR}${1}" "${TEMPROOT}${1}"
|
|
mv -f "${TEMPROOT}${1}.merged" "${TEMPROOT}${1}"
|
|
ALREADY_MERGED=true
|
|
;;
|
|
[sS]*)
|
|
${DOES_EXIST} || continue
|
|
case "${ANSWER}" in
|
|
[sS]) : no change ;;
|
|
[sS]u) DIFF_COMMAND="diff -u" ;;
|
|
[sS]c) DIFF_COMMAND="diff -c" ;;
|
|
[sS]s) DIFF_COMMAND="sdiff -w${WIDTH}" ;;
|
|
[sS]w) DIFF_COMMAND="wdiff -n -l" ;;
|
|
[sS]*) DIFF_COMMAND="${ANSWER#?}" ;;
|
|
esac
|
|
${DIFF_COMMAND} "${DESTDIR}${1}" "${TEMPROOT}${1}" \
|
|
| ${PAGER}
|
|
;;
|
|
[uU])
|
|
if [ -f "${B}" ]; then
|
|
echo "*** Restoring ${F}"
|
|
mv -f "${B}" "${F}"
|
|
fi
|
|
ALREADY_MERGED=false
|
|
;;
|
|
[vV])
|
|
${PAGER} "${TEMPROOT}${1}"
|
|
;;
|
|
"")
|
|
STAY_HERE=false
|
|
;;
|
|
*)
|
|
echo "*** Invalid selection!"
|
|
;;
|
|
esac
|
|
done
|
|
rm -f "$B"
|
|
}
|
|
|
|
# Set the environment for make.
|
|
set_makeenv()
|
|
{
|
|
#
|
|
# INSTALL_DONE=1 prevents installation of unwanted
|
|
# files (things that are not part of the etc set).
|
|
# BUILD=1 allows building of files that are wanted.
|
|
#
|
|
MAKE_ENV=" \
|
|
NETBSDSRCDIR=$(shell_quote "${SRCDIR}") \
|
|
DESTDIR=$(shell_quote "${TEMPROOT}") \
|
|
MAKE=make \
|
|
MTREE=mtree \
|
|
TOOL_MTREE=mtree \
|
|
INSTALL_DONE=1 \
|
|
BUILD=1 \
|
|
USETOOLS=never"
|
|
}
|
|
|
|
#
|
|
# main()
|
|
#
|
|
|
|
# Read global configuration
|
|
GLOBALRC="/etc/${PROG}.conf"
|
|
[ -r ${GLOBALRC} ] && . ${GLOBALRC}
|
|
|
|
# Read user configuration
|
|
USERRC="${HOME}/.{PROG}rc"
|
|
[ -r ${USERRC} ] && . ${USERRC}
|
|
|
|
# Read command line arguments
|
|
while getopts :ad:hlp:s:t:vw: i
|
|
do
|
|
case "${i}" in
|
|
a)
|
|
AUTOMATIC=true
|
|
;;
|
|
d)
|
|
DESTDIR="${OPTARG}"
|
|
;;
|
|
h)
|
|
help
|
|
exit 0
|
|
;;
|
|
l)
|
|
LOCALSKIP=true
|
|
;;
|
|
p)
|
|
PAGER="${OPTARG}"
|
|
;;
|
|
s)
|
|
# Three cases:
|
|
# -s tgzfile (may be repeated)
|
|
# -s srcdir (may not be repeated)
|
|
# -s extracted_dir (may not be repeated)
|
|
arg="${OPTARG}"
|
|
qarg="$(shell_quote "${OPTARG}")"
|
|
N_SRC_ARGS=$(( N_SRC_ARGS + 1 ))
|
|
SRC_ARGLIST="${SRC_ARGLIST}${SRC_ARGLIST:+ }-s ${qarg}"
|
|
if [ -f "${arg}" ]; then
|
|
# arg refers to a *.tgz file.
|
|
# This may happen twice, for both etc.tgz and
|
|
# xetc.tgz, so we build up a list in TGZLIST.
|
|
BINARYMODE=true
|
|
BINARYTGZMODE=true
|
|
TGZLIST="${TGZLIST}${TGZLIST:+ }${qarg}"
|
|
elif [ -d "${arg}" ] && [ -f "${arg}/etc/Makefile" ]; then
|
|
# arg refers to a source directory
|
|
SOURCEMODE=true
|
|
SRCDIR="${arg}"
|
|
elif [ -d "${arg}" ] && [ -d "${arg}/etc" ] \
|
|
&& ! [ -f "${arg}/etc/Makefile" ]
|
|
then
|
|
# arg refers to a directory where the
|
|
# sets have already been extracted
|
|
BINARYMODE=true
|
|
BINARYDIRMODE=true
|
|
BINARYDIR="${arg}"
|
|
else
|
|
echo "*** Nonexistent or invalid file or directory" \
|
|
"for -s ${arg}"
|
|
usage
|
|
fi
|
|
;;
|
|
t)
|
|
TEMPROOT="${OPTARG}"
|
|
;;
|
|
v)
|
|
VERBOSE=true
|
|
;;
|
|
w)
|
|
WIDTH="${OPTARG}"
|
|
;;
|
|
"?")
|
|
if [ "${OPTARG}" = "?" ]; then
|
|
help
|
|
exit 0
|
|
fi
|
|
echo 1>&2 "${PROG}: Unknown option -${OPTARG}"
|
|
usage
|
|
;;
|
|
|
|
:)
|
|
echo 1>&2 "${PROG}: Missing argument for option -${OPTARG}"
|
|
usage
|
|
;;
|
|
|
|
*)
|
|
echo 1>&2 "${PROG}: Unimplemented option -${i}"
|
|
exit 3
|
|
;;
|
|
esac
|
|
done
|
|
shift $((${OPTIND} - 1))
|
|
if [ $# -ne 0 ] ; then
|
|
echo 1>&2 "${PROG}: Unknown extra arguments"
|
|
usage
|
|
fi
|
|
|
|
# Last minute sanity checks
|
|
if [ "$(id -u)" -ne 0 ]; then
|
|
echo "*** ERROR: You MUST be root"
|
|
exit 1
|
|
fi
|
|
DESTDIR="${DESTDIR%/}" # remove trailing slash, if any. result might be "".
|
|
DESTDIR_BRE="$(bre_quote "${DESTDIR}")"
|
|
if [ "${N_SRC_ARGS}" -gt 1 ] && ( ${SOURCEMODE} || ${BINARYDIRMODE} ); then
|
|
echo 1>&2 "${PROG}: Multiple -s args are allowed only with tgz files"
|
|
usage
|
|
fi
|
|
case "${TEMPROOT}" in
|
|
/*) : OK ;;
|
|
*) new="${PWD:-$(pwd)}/${TEMPROOT}"
|
|
echo "*** NOTE: Using TEMPROOT \"${new}\" instead of \"${TEMPROOT}\""
|
|
TEMPROOT="${new}"
|
|
;;
|
|
esac
|
|
if ${BINARYDIRMODE}; then
|
|
SRCDIR="${TEMPROOT}"
|
|
fi
|
|
if ${BINARYTGZMODE}; then
|
|
SRCDIR="${TEMPROOT}"
|
|
fi
|
|
if [ "${N_SRC_ARGS}" -eq 0 ]; then
|
|
# default if no "-s" option was specified
|
|
SOURCEMODE=true
|
|
SRCDIR="/usr/src"
|
|
SRC_ARGLIST="-s $(shell_quote "${SRCDIR}")"
|
|
fi
|
|
if [ -z "${SRCDIR}" -o -z "${TEMPROOT}" ]; then
|
|
echo "*** ERROR: One of the following variables is undefined"
|
|
echo ""
|
|
echo "SRCDIR=\"${SRCDIR}\""
|
|
echo "TEMPROOT=\"${TEMPROOT}\""
|
|
echo ""
|
|
exit 1
|
|
fi
|
|
if [ -r "${TEMPROOT}" ]; then
|
|
echo ""
|
|
echo "*** WARNING: ${TEMPROOT} already exists"
|
|
echo ""
|
|
if yesno "Continue previously aborted update"; then
|
|
CONTINUE=true
|
|
elif yesno "Remove the old ${TEMPROOT}"; then
|
|
echo "*** Removing ${TEMPROOT}"
|
|
rm -rf "${TEMPROOT}"
|
|
fi
|
|
fi
|
|
|
|
if ! ${CONTINUE}; then
|
|
# Create the temporary root directory
|
|
echo "*** Creating ${TEMPROOT}"
|
|
mkdir -p "${TEMPROOT}"
|
|
if [ ! -d "${TEMPROOT}" ]; then
|
|
echo "*** ERROR: Unable to create ${TEMPROOT}"
|
|
exit 1
|
|
fi
|
|
# Are we using the sources or binaries?
|
|
if ${BINARYTGZMODE}; then
|
|
# Populate ${TEMPROOT} from ${TGZLIST}
|
|
eval "set -- ${TGZLIST}"
|
|
for tgz in "$@"; do
|
|
if [ ! -f "${tgz}" ]; then
|
|
echo "*** ERROR: Unable to find ${tgz}"
|
|
exit 1
|
|
fi
|
|
echo "*** Populating ${TEMPROOT} from ${tgz}"
|
|
tar -zxpf "${tgz}" -C "${TEMPROOT}"
|
|
[ $? -ne 0 ] && exit 1
|
|
done
|
|
elif ${BINARYDIRMODE}; then
|
|
# Populate ${TEMPROOT} from ${SRCDIR} by copying.
|
|
# Copy only the files that belong to the etc and xetc sets.
|
|
echo "*** Populating ${TEMPROOT} from ${BINARYDIR} (copying)"
|
|
for setname in etc xetc; do
|
|
mtreefile="${BINARYDIR}/etc/mtree/set.${setname}"
|
|
if ${VERBOSE}; then vflag="-v"; else vflag=""; fi
|
|
if [ -f "${mtreefile}" ]; then
|
|
echo "*** Copying files belonging to" \
|
|
"${setname} set"
|
|
(cd "${BINARYDIR}" \
|
|
&& pax -rwdM ${vflag} "${TEMPROOT%/}/."
|
|
) <"${mtreefile}"
|
|
[ $? -ne 0 ] && exit 1
|
|
else
|
|
echo "*** Not copying files belonging to" \
|
|
"${setname} set: ${mtreefile} not found"
|
|
fi
|
|
done
|
|
elif ${SOURCEMODE}; then
|
|
# Populate ${TEMPROOT} from ${SRCDIR} by running make
|
|
if [ ! -f "${SRCDIR}/etc/Makefile" ]; then
|
|
echo "*** ERROR: Unable to find ${SRCDIR}/etc/Makefile"
|
|
exit 1
|
|
fi
|
|
set_makeenv
|
|
echo "*** Populating ${TEMPROOT} from ${SRCDIR} (make distribution)"
|
|
cd ${SRCDIR}/etc
|
|
if ! ${VERBOSE}; then
|
|
eval "${MAKE_ENV} make distribution > /dev/null"
|
|
else
|
|
eval "${MAKE_ENV} make distribution"
|
|
fi
|
|
[ $? -ne 0 ] && exit 1
|
|
fi
|
|
if ! [ -f "${TEMPROOT}/etc/mtree/set.etc" ]; then
|
|
echo "*** ERROR: Files from the etc.tgz set are missing"
|
|
exit 1
|
|
fi
|
|
if [ ! -f "${TEMPROOT}/dev/MAKEDEV" ]; then
|
|
echo ""
|
|
echo "*** WARNING: ${TEMPROOT}/dev/MAKEDEV not found"
|
|
echo "Make sure you update /dev/MAKEDEV later and run"
|
|
echo "(cd /dev && ./MAKEDEV all) to rebuild the device nodes"
|
|
echo ""
|
|
fi
|
|
|
|
# Ignore the following files during comparison
|
|
rm -f "${TEMPROOT}"/etc/passwd
|
|
rm -f "${TEMPROOT}"/etc/pwd.db
|
|
rm -f "${TEMPROOT}"/etc/spwd.db
|
|
find "${TEMPROOT}" -type f -size 0 -exec rm {} \;
|
|
|
|
# Ignore files we're told to ignore
|
|
if [ ! -z "${IGNOREFILES}" ]; then
|
|
echo "*** Ignoring files: ${IGNOREFILES}"
|
|
for file in ${IGNOREFILES}; do
|
|
rm -f "${TEMPROOT}"${file}
|
|
done
|
|
fi
|
|
|
|
# Are there any new directories?
|
|
echo "*** Checking for new directories"
|
|
exec 3<&0
|
|
find "${TEMPROOT}" -type d | \
|
|
while read i; do
|
|
D="${i#"${TEMPROOT}"}"
|
|
[ "x${i}" = "x${TEMPROOT}" ] && continue
|
|
[ ! -d "${D}" ] && install_dir "${D}" <&3
|
|
done
|
|
fi
|
|
|
|
# Start the comparison
|
|
echo "*** Checking for added/modified files"
|
|
init_diff_extra_options
|
|
exec 3<&0
|
|
find "${TEMPROOT}" -type f -a ! -name \*.etcupdate.\* | \
|
|
while read i; do
|
|
D="${i#"${TEMPROOT}"}"
|
|
diff_and_merge_file "${D}" <&3
|
|
done
|
|
|
|
# Do we have files which were not processed?
|
|
REMAINING="$(find "${TEMPROOT}" -type f -a ! -name \*.etcupdate.\*)"
|
|
if [ ! -z "${REMAINING}" ]; then
|
|
echo ""
|
|
echo "*** The following files need your attention:"
|
|
echo ""
|
|
echo "${REMAINING}" | sed -e 's/^/ /'
|
|
echo ""
|
|
elif ! ${NEED_ANYTHING}; then
|
|
echo ""
|
|
echo "*** No changes were needed"
|
|
echo ""
|
|
fi
|
|
if yesno "Remove ${TEMPROOT}"; then
|
|
echo "*** Removing ${TEMPROOT}"
|
|
rm -rf "${TEMPROOT}"
|
|
else
|
|
echo "*** Keeping ${TEMPROOT}"
|
|
fi
|
|
|
|
# Clean up after "make distribution"
|
|
if ${SOURCEMODE}; then
|
|
echo "*** Cleaning up in ${SRCDIR}/etc"
|
|
set_makeenv
|
|
cd ${SRCDIR}/etc
|
|
if ! ${VERBOSE}; then
|
|
eval "${MAKE_ENV} make clean > /dev/null"
|
|
else
|
|
eval "${MAKE_ENV} make clean"
|
|
fi
|
|
fi
|
|
|
|
# Do some post-installation tasks
|
|
if ${NEED_PWD_MKDB}; then
|
|
pwd_mkdb_cmd="$(shell_quote \
|
|
pwd_mkdb ${DESTDIR:+-d "${DESTDIR}"} \
|
|
-p "${DESTDIR}/etc/master.passwd")"
|
|
if yesno "Do you want to rebuild the password databases from the" \
|
|
"new ${DESTDIR}/etc/master.passwd"
|
|
then
|
|
verbose "Running pwd_mkdb"
|
|
eval "${pwd_mkdb_cmd}"
|
|
else
|
|
echo ""
|
|
echo "*** You MUST rebuild the password databases to make" \
|
|
"the changes visible"
|
|
echo "*** This is done by running \"${pwd_mkdb_cmd}\" as root"
|
|
echo ""
|
|
fi
|
|
fi
|
|
|
|
if ! ${NEED_SERVICES_MKDB}; then
|
|
if test -e "${DESTDIR}/var/db/services.db" \
|
|
-a ! -e "${DESTDIR}/var/db/services.cdb"
|
|
then
|
|
NEED_SERVICES_MKDB=true
|
|
fi
|
|
fi
|
|
|
|
if ${NEED_SERVICES_MKDB}; then
|
|
services_mkdb_cmd="$(shell_quote services_mkdb -V cdb \
|
|
-o "${DESTDIR}/var/db/services.cdb" \
|
|
"${DESTDIR}/etc/services")"
|
|
if yesno "Do you want to rebuild the services databases from the" \
|
|
"new ${DESTDIR}/etc/services"
|
|
then
|
|
verbose "Running services_mkdb"
|
|
eval "${services_mkdb_cmd}"
|
|
else
|
|
echo ""
|
|
echo "*** You SHOULD rebuild the services databases to make" \
|
|
"the changes visible"
|
|
echo "*** This is done by running \"${services_mkdb_cmd}\"" \
|
|
"as root"
|
|
echo ""
|
|
fi
|
|
fi
|
|
if ${NEED_MTREE}; then
|
|
if yesno "You have created new directories. Run mtree to set" \
|
|
"permissions"
|
|
then
|
|
(cd "${DESTDIR:-/}" && \
|
|
mtree -Udef "${DESTDIR}/etc/mtree/NetBSD.dist")
|
|
fi
|
|
fi
|
|
if ${NEED_MAKEDEV}; then
|
|
makedev_cmd="($(shell_quote cd "${DESTDIR}/dev") && ./MAKEDEV all)"
|
|
if yesno "Do you want to rebuild the device nodes in ${DESTDIR}/dev"
|
|
then
|
|
verbose "Running MAKEDEV in /dev"
|
|
eval "${makedev_cmd}"
|
|
else
|
|
echo ""
|
|
echo "*** You SHOULD rebuild the device nodes in" \
|
|
"${DESTDIR}/dev"
|
|
echo "*** This is done by running \"${makedev_cmd}\" as root."
|
|
echo ""
|
|
fi
|
|
fi
|
|
if ${NEED_NEWALIASES}; then
|
|
newaliases_cmd="newaliases"
|
|
# XXX newaliases doesn't work with DESTDIR.
|
|
# We could check whether the system configuration is
|
|
# sufficiently standard, and then run postalias(1) with the
|
|
# right args to make it work, but changes to /etc/mail/aliases
|
|
# are so rare that it doesn't seem worth the effort of checking
|
|
# that the system's mail configuration is standard.
|
|
if [ -z "${DESTDIR}" ] && \
|
|
yesno "Do you want to rebuild the mail alias database"
|
|
then
|
|
verbose "Running newaliases"
|
|
eval "${newaliases_cmd}"
|
|
else
|
|
echo ""
|
|
echo "*** You MUST rebuild the mail alias database to make" \
|
|
"the changes visible"
|
|
echo "*** This is done by running \"${newaliases_cmd}\" as root"
|
|
if [ -n "${DESTDIR}" ]; then
|
|
postalias_cmd="$(shell_quote \
|
|
postalias "hash:${DESTDIR}/etc/mail/aliases")"
|
|
echo "*** but it won't work with DESTDIR=${DESTDIR}."
|
|
echo "*** If you use postfix(1) with the default" \
|
|
"configuration, then you can try"
|
|
echo "*** running \"${postalias_cmd}\" as root."
|
|
fi
|
|
echo ""
|
|
fi
|
|
fi
|
|
if [ -x "${DESTDIR}/usr/sbin/postinstall" ]; then
|
|
postinstall_cmd="$(shell_quote "${DESTDIR}/usr/sbin/postinstall" \
|
|
${DESTDIR:+-d "${DESTDIR}"}) ${SRC_ARGLIST} check"
|
|
echo "*** Running ${DESTDIR}/usr/sbin/postinstall"
|
|
eval "${postinstall_cmd}"
|
|
fi
|
|
echo "*** All done"
|