1473 lines
33 KiB
Bash
Executable File
1473 lines
33 KiB
Bash
Executable File
#!/bin/sh
|
|
#
|
|
# $NetBSD: postinstall,v 1.58 2008/02/13 12:55:56 tron Exp $
|
|
#
|
|
# Copyright (c) 2002-2006 The NetBSD Foundation, Inc.
|
|
# All rights reserved.
|
|
#
|
|
# This code is derived from software contributed to The NetBSD Foundation
|
|
# by Luke Mewburn.
|
|
#
|
|
# 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.
|
|
# 3. All advertising materials mentioning features or use of this software
|
|
# must display the following acknowledgement:
|
|
# This product includes software developed by the NetBSD
|
|
# Foundation, Inc. and its contributors.
|
|
# 4. Neither the name of The NetBSD Foundation nor the names of its
|
|
# contributors may be used to endorse or promote products derived
|
|
# from this software without specific prior written permission.
|
|
#
|
|
# 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.
|
|
#
|
|
# postinstall
|
|
# Check for or fix configuration changes that occur
|
|
# over time as NetBSD evolves.
|
|
#
|
|
|
|
#
|
|
# checks to add:
|
|
# - sysctl(8) renames (net.inet6.ip6.bindv6only -> net.inet6.ip6.v6only)
|
|
# - de* -> tlp* migration (/etc/ifconfig.de*, $ifconfig_de*,
|
|
# dhclient.conf, ...) ?
|
|
# - support quiet/verbose mode ?
|
|
# - differentiate between failures caused by missing source
|
|
# and real failures
|
|
# - install moduli into usr/share/examples/ssh and use from there?
|
|
# - differentiate between "needs fix" versus "can't fix" issues
|
|
#
|
|
|
|
#
|
|
# helper functions
|
|
#
|
|
|
|
err()
|
|
{
|
|
exitval=$1
|
|
shift
|
|
echo 1>&2 "${PROGNAME}: $@"
|
|
if [ -n "${SCRATCHDIR}" ]; then
|
|
/bin/rm -rf ${SCRATCHDIR}
|
|
fi
|
|
exit ${exitval}
|
|
}
|
|
|
|
warn()
|
|
{
|
|
echo 1>&2 "${PROGNAME}: $@"
|
|
}
|
|
|
|
msg()
|
|
{
|
|
echo " $@"
|
|
}
|
|
|
|
mkdtemp()
|
|
{
|
|
# Make sure we don't loop forever if mkdir will always fail.
|
|
[ -d /tmp ] || err 2 /tmp is not a directory
|
|
[ -w /tmp ] || err 2 /tmp is not writable
|
|
|
|
_base=/tmp/_postinstall.$$
|
|
_serial=0
|
|
|
|
while true; do
|
|
_dir=${_base}.${_serial}
|
|
mkdir -m 0700 ${_dir} && break
|
|
_serial=$((${_serial} + 1))
|
|
done
|
|
echo ${_dir}
|
|
}
|
|
|
|
# additem item description
|
|
# Add item to list of supported items to check/fix,
|
|
# which are checked/fixed by default if no item is requested by user.
|
|
#
|
|
additem()
|
|
{
|
|
[ $# -eq 2 ] || err 3 "USAGE: additem item description"
|
|
defaultitems="${defaultitems}${defaultitems:+ }$1"
|
|
eval desc_$1=\"$2\"
|
|
}
|
|
|
|
# adddisableditem item description
|
|
# Add item to list of supported items to check/fix,
|
|
# but execute the item only if the user asks for it explicitely.
|
|
#
|
|
adddisableditem()
|
|
{
|
|
[ $# -eq 2 ] || err 3 "USAGE: adddisableditem item description"
|
|
otheritems="${otheritems}${otheritems:+ }$1"
|
|
eval desc_$1=\"$2\"
|
|
}
|
|
|
|
# checkdir op dir mode
|
|
# Ensure dir exists, and if not, create it with the appropriate mode.
|
|
# Returns 0 if ok, 1 otherwise.
|
|
#
|
|
check_dir()
|
|
{
|
|
[ $# -eq 3 ] || err 3 "USAGE: check_dir op dir mode"
|
|
_cdop=$1
|
|
_cddir=$2
|
|
_cdmode=$3
|
|
[ -d "${_cddir}" ] && return 0
|
|
if [ "${_cdop}" = "check" ]; then
|
|
msg "${_cddir} is not a directory"
|
|
return 1
|
|
elif ! mkdir -m "${_cdmode}" "${_cddir}" ; then
|
|
msg "Can't create missing ${_cddir}"
|
|
return 1
|
|
else
|
|
msg "Missing ${_cddir} created"
|
|
fi
|
|
return 0
|
|
}
|
|
|
|
# check_ids op type file id [...]
|
|
# Check if file of type "users" or "groups" contains the relevant IDs
|
|
# Returns 0 if ok, 1 otherwise.
|
|
#
|
|
check_ids()
|
|
{
|
|
[ $# -ge 4 ] || err 3 "USAGE: checks_ids op type file id [...]"
|
|
_op=$1
|
|
_type=$2
|
|
_file=$3
|
|
shift 3
|
|
_ids="$@"
|
|
|
|
if [ ! -f "${_file}" ]; then
|
|
msg "${_file} doesn't exist; can't check for missing ${_type}"
|
|
return 1
|
|
fi
|
|
if [ ! -r "${_file}" ]; then
|
|
msg "${_file} is not readable; can't check for missing ${_type}"
|
|
return 1
|
|
fi
|
|
_notfixed=""
|
|
if [ "${_op}" = "fix" ]; then
|
|
_notfixed=${NOT_FIXED}
|
|
fi
|
|
_missing=$(awk -F: '
|
|
BEGIN {
|
|
for (x = 1; x < ARGC; x++)
|
|
idlist[ARGV[x]]++
|
|
ARGC=1
|
|
}
|
|
{
|
|
found[$1]++
|
|
}
|
|
END {
|
|
for (id in idlist) {
|
|
if (! (id in found))
|
|
print id
|
|
}
|
|
}
|
|
' ${_ids} < ${_file}) || return 1
|
|
if [ -n "${_missing}" ]; then
|
|
msg "Missing ${_type}${_notfixed}:" $(echo ${_missing})
|
|
return 1
|
|
fi
|
|
return 0
|
|
}
|
|
|
|
# populate_dir op onlynew src dest mode file [file ...]
|
|
# Perform op ("check" or "fix") on files in src/ against dest/
|
|
# If op = "check" display missing or changed files, optionally with diffs.
|
|
# If op != "check" copies any missing or changed files.
|
|
# If onlynew evaluates to true, changed files are ignored.
|
|
# Returns 0 if ok, 1 otherwise.
|
|
#
|
|
populate_dir()
|
|
{
|
|
[ $# -ge 5 ] || err 3 "USAGE: populate_dir op onlynew src dest mode file [...]"
|
|
_op=$1
|
|
_onlynew=$2
|
|
_src=$3
|
|
_dest=$4
|
|
_mode=$5
|
|
shift 5
|
|
_files="$@"
|
|
|
|
if [ ! -d "${_src}" ]; then
|
|
msg "${_src} is not a directory; skipping check"
|
|
return 1
|
|
fi
|
|
check_dir ${_op} ${_dest} 755 || return 1
|
|
|
|
_cmpdir_rv=0
|
|
for f in ${_files}; do
|
|
fs=${_src}/${f}
|
|
fd=${_dest}/${f}
|
|
_error=""
|
|
if [ ! -f "${fd}" ]; then
|
|
_error="${fd} does not exist"
|
|
elif ! cmp -s ${fs} ${fd} ; then
|
|
if $_onlynew; then # leave existing ${fd} alone
|
|
continue;
|
|
fi
|
|
_error="${fs} != ${fd}"
|
|
else
|
|
continue
|
|
fi
|
|
if [ "${_op}" = "check" ]; then
|
|
msg ${_error}
|
|
if [ -n "${DIFF_STYLE}" -a -f "${fd}" ]; then
|
|
diff -${DIFF_STYLE} ${DIFF_OPT} ${fd} ${fs}
|
|
fi
|
|
_cmpdir_rv=1
|
|
elif ! rm -f ${fd} ||
|
|
! cp -f ${fs} ${fd}; then
|
|
msg "Can't copy ${fs} to ${fd}"
|
|
_cmpdir_rv=1
|
|
elif ! chmod ${_mode} ${fd}; then
|
|
msg "Can't change mode of ${fd} to ${_mode}"
|
|
_cmpdir_rv=1
|
|
else
|
|
msg "Copied ${fs} to ${fd}"
|
|
fi
|
|
done
|
|
return ${_cmpdir_rv}
|
|
}
|
|
|
|
# compare_dir op src dest mode file [file ...]
|
|
# Perform op ("check" or "fix") on files in src/ against dest/
|
|
# If op = "check" display missing or changed files, optionally with diffs.
|
|
# If op != "check" copies any missing or changed files.
|
|
# Returns 0 if ok, 1 otherwise.
|
|
#
|
|
compare_dir()
|
|
{
|
|
[ $# -ge 4 ] || err 3 "USAGE: compare_dir op src dest mode file [...]"
|
|
_op=$1
|
|
_src=$2
|
|
_dest=$3
|
|
_mode=$4
|
|
shift 4
|
|
_files="$@"
|
|
|
|
populate_dir $_op false $_src $_dest $_mode $_files
|
|
}
|
|
|
|
# move_file op src dest --
|
|
# Check (op == "check") or move (op != "check") from src to dest.
|
|
# Returns 0 if ok, 1 otherwise.
|
|
#
|
|
move_file()
|
|
{
|
|
[ $# -eq 3 ] || err 3 "USAGE: move_file op src dest"
|
|
_fm_op=$1
|
|
_fm_src=$2
|
|
_fm_dest=$3
|
|
|
|
if [ -f "${_fm_src}" -a ! -f "${_fm_dest}" ]; then
|
|
if [ "${_fm_op}" = "check" ]; then
|
|
msg "Move ${_fm_src} to ${_fm_dest}"
|
|
return 1
|
|
fi
|
|
if ! mv ${_fm_src} ${_fm_dest}; then
|
|
msg "Can't move ${_fm_src} to ${_fm_dest}"
|
|
return 1
|
|
fi
|
|
msg "Moved ${_fm_src} to ${_fm_dest}"
|
|
fi
|
|
return 0
|
|
}
|
|
|
|
# rcconf_is_set op name var [verbose] --
|
|
# Load the rcconf for name, and check if obsolete rc.conf(5) variable
|
|
# var is defined or not.
|
|
# Returns 0 if defined (even to ""), otherwise 1.
|
|
# If verbose != "", print an obsolete warning if the var is defined.
|
|
#
|
|
rcconf_is_set()
|
|
{
|
|
[ $# -ge 3 ] || err 3 "USAGE: rcconf_is_set op name var [verbose]"
|
|
_rcis_op=$1
|
|
_rcis_name=$2
|
|
_rcis_var=$3
|
|
_rcis_verbose=$4
|
|
_rcis_notfixed=""
|
|
if [ "${_rcis_op}" = "fix" ]; then
|
|
_rcis_notfixed=${NOT_FIXED}
|
|
fi
|
|
(
|
|
for f in \
|
|
${DEST_DIR}/etc/rc.conf \
|
|
${DEST_DIR}/etc/rc.conf.d/${_rcis_name}; do
|
|
[ -f "${f}" ] && . "${f}"
|
|
done
|
|
eval echo -n \"\${${_rcis_var}}\" 1>&3
|
|
if eval "[ -n \"\${${_rcis_var}}\" \
|
|
-o \"\${${_rcis_var}-UNSET}\" != \"UNSET\" ]"; then
|
|
if [ -n "${_rcis_verbose}" ]; then
|
|
msg \
|
|
"Obsolete rc.conf(5) variable '\$${_rcis_var}' found.${_rcis_notfixed}"
|
|
fi
|
|
exit 0
|
|
else
|
|
exit 1
|
|
fi
|
|
)
|
|
}
|
|
|
|
# find_file_in_dirlist() file message dir1 [...] --
|
|
# Find which directory file is in, and sets ${dir} to match.
|
|
# Returns 0 if matched, otherwise 1 (and sets ${dir} to "").
|
|
#
|
|
# Generally, check the directory for the "checking from source" case,
|
|
# and then the directory for the "checking from extracted etc.tgz" case.
|
|
#
|
|
find_file_in_dirlist()
|
|
{
|
|
[ $# -ge 3 ] || err 3 "USAGE: find_file_in_dirlist file msg dir1 [...]"
|
|
|
|
_file=$1 ; shift
|
|
_msg=$1 ; shift
|
|
_dir1st=
|
|
for dir in $*; do
|
|
: ${_dir1st:=${dir}}
|
|
if [ -f "${dir}/${_file}" ]; then
|
|
if [ "${_dir1st}" != "${dir}" ]; then
|
|
msg \
|
|
"(Checking for ${_msg} from ${dir} instead of ${_dir1st})"
|
|
fi
|
|
return 0
|
|
fi
|
|
done
|
|
msg "Can't find source directory for ${_msg}"
|
|
return 1
|
|
}
|
|
|
|
# stat op format target value
|
|
# Call stat(1) on the given target according to the given format,
|
|
# if stat(1) is available (it is presumed to live in /usr/bin).
|
|
# If it is not available, this routine will always succeed, otherwise
|
|
# it returns 0 or 1, depending on whether or not the output from
|
|
# stat(1) matches the expected value.
|
|
#
|
|
stat()
|
|
{
|
|
_stop=$1
|
|
_stfmt=$2
|
|
_sttgt=$3
|
|
_stval=$4
|
|
|
|
if [ ! -x /usr/bin/stat ]; then
|
|
msg \
|
|
"(/usr/bin/stat not available; skipping ${_stop} on ${_sttgt})"
|
|
return 0
|
|
fi
|
|
|
|
_stres=$(/usr/bin/stat -q -f "${_stfmt}" "${_sttgt}")
|
|
[ "${_stres}" = "${_stval}" ]
|
|
return $?
|
|
}
|
|
|
|
# file_exists_exact path
|
|
# Returns true if file exists matching exact case for path
|
|
# Each path is relative to ${DEST_DIR}, and should
|
|
# be an absolute path or start with `./'.
|
|
#
|
|
file_exists_exact()
|
|
{
|
|
[ -n "1" ] || err 3 "USAGE: file_exists_exact path"
|
|
_path=${1#.}
|
|
[ -h "${DEST_DIR}${_path}" ] || \
|
|
[ -e "${DEST_DIR}${_path}" ] || return 1
|
|
while [ "${_path}" != "/" ] ; do
|
|
_dirname=$(dirname "${_path}" 2>/dev/null)
|
|
_basename=$(basename "${_path}" 2>/dev/null)
|
|
ls -fa "${DEST_DIR}${_dirname}" 2> /dev/null \
|
|
| grep -q -x -F "${_basename}" \
|
|
|| return 1
|
|
_path=${_dirname}
|
|
done
|
|
return 0
|
|
}
|
|
|
|
# obsolete_paths op
|
|
# Obsolete the list of paths provided on stdin.
|
|
# Each path is relative to ${DEST_DIR}, and should
|
|
# be an absolute path or start with `./'.
|
|
#
|
|
obsolete_paths()
|
|
{
|
|
[ -n "$1" ] || err 3 "USAGE: obsolete_paths fix|check"
|
|
op=$1
|
|
|
|
failed=0
|
|
while read ofile; do
|
|
if ! file_exists_exact "${ofile}"; then
|
|
continue
|
|
fi
|
|
ofile=${DEST_DIR}${ofile#.}
|
|
cmd="rm"
|
|
ftype="file"
|
|
if [ -h "${ofile}" ]; then
|
|
ftype="link"
|
|
elif [ -d "${ofile}" ]; then
|
|
ftype="directory"
|
|
cmd="rmdir"
|
|
fi
|
|
if [ "${op}" = "check" ]; then
|
|
msg "Remove obsolete ${ftype} ${ofile}"
|
|
failed=1
|
|
elif ! eval ${cmd} ${ofile}; then
|
|
msg "Can't remove obsolete ${ftype} ${ofile}"
|
|
failed=1
|
|
else
|
|
msg "Removed obsolete ${ftype} ${ofile}"
|
|
fi
|
|
done
|
|
return ${failed}
|
|
}
|
|
|
|
# obsolete_libs dir
|
|
# Display the minor/teeny shared libraries in dir that are considered
|
|
# to be obsolete.
|
|
#
|
|
# The implementation supports removing obsolete major libraries
|
|
# if the awk variable AllLibs is set, although there is no way to
|
|
# enable that in the enclosing shell function as this time.
|
|
#
|
|
obsolete_libs()
|
|
{
|
|
[ $# -eq 1 ] || err 3 "USAGE: obsolete_libs dir"
|
|
dir=$1
|
|
|
|
(
|
|
|
|
if [ ! -e "${DEST_DIR}/${dir}" ]
|
|
then
|
|
return 0
|
|
fi
|
|
|
|
cd "${DEST_DIR}/${dir}" || err 2 "can't cd to ${DEST_DIR}/${dir}"
|
|
echo lib*.so.* \
|
|
| tr ' ' '\n' \
|
|
| awk -v LibDir="${dir}/" '
|
|
#{
|
|
|
|
function digit(v, c, n) { return (n <= c) ? v[n] : 0 }
|
|
|
|
function checklib(results, line, regex) {
|
|
if (! match(line, regex))
|
|
return
|
|
lib = substr(line, RSTART, RLENGTH)
|
|
rev = substr($0, RLENGTH+1)
|
|
if (! (lib in results)) {
|
|
results[lib] = rev
|
|
return
|
|
}
|
|
orevc = split(results[lib], orev, ".")
|
|
nrevc = split(rev, nrev, ".")
|
|
maxc = (orevc > nrevc) ? orevc : nrevc
|
|
for (i = 1; i <= maxc; i++) {
|
|
res = digit(orev, orevc, i) - digit(nrev, nrevc, i)
|
|
if (res < 0) {
|
|
print LibDir lib results[lib]
|
|
results[lib] = rev
|
|
return
|
|
} else if (res > 0) {
|
|
print LibDir lib rev
|
|
return
|
|
}
|
|
}
|
|
}
|
|
|
|
/^lib.*\.so\.[0-9]+\.[0-9]+(\.[0-9]+)?$/ {
|
|
if (AllLibs)
|
|
checklib(minor, $0, "^lib.*\.so\.")
|
|
else
|
|
checklib(found, $0, "^lib.*\.so\.[0-9]+\.")
|
|
}
|
|
|
|
/^lib.*\.so\.[0-9]+$/ {
|
|
if (AllLibs)
|
|
checklib(major, $0, "^lib.*\.so\.")
|
|
}
|
|
|
|
#}'
|
|
|
|
)
|
|
}
|
|
|
|
# modify_file op srcfile scratchfile awkprog
|
|
# Apply awkprog to srcfile sending output to scratchfile, and
|
|
# if appropriate replace srcfile with scratchfile.
|
|
#
|
|
modify_file()
|
|
{
|
|
[ $# -eq 4 ] || err 3 "USAGE: modify_file op file scratch awkprog"
|
|
|
|
_mfop=$1
|
|
_mffile=$2
|
|
_mfscratch=$3
|
|
_mfprog=$4
|
|
_mffailed=0
|
|
|
|
awk "${_mfprog}" < "${_mffile}" > "${_mfscratch}"
|
|
if ! cmp -s "${_mffile}" "${_mfscratch}"; then
|
|
diff "${_mffile}" "${_mfscratch}" > "${_mfscratch}.diffs"
|
|
if [ "${_mfop}" = "check" ]; then
|
|
msg "${_mffile} needs the following changes:"
|
|
_mffailed=1
|
|
elif ! rm -f "${_mffile}" ||
|
|
! cp -f "${_mfscratch}" "${_mffile}"; then
|
|
msg "${_mffile} changes not applied:"
|
|
_mffailed=1
|
|
else
|
|
msg "${_mffile} changes applied:"
|
|
fi
|
|
while read _line; do
|
|
msg " ${_line}"
|
|
done < "${_mfscratch}.diffs"
|
|
fi
|
|
return ${_mffailed}
|
|
}
|
|
|
|
|
|
# contents_owner op directory user group
|
|
# Make sure directory and contents are owned (and group-owned)
|
|
# as specified.
|
|
#
|
|
contents_owner()
|
|
{
|
|
[ $# -eq 4 ] || err 3 "USAGE: contents_owner op dir user group"
|
|
|
|
_op=$1
|
|
_dir=$2
|
|
_user=$3
|
|
_grp=$4
|
|
|
|
if [ "${_op}" = "check" ]; then
|
|
if [ ! -z "`find ${_dir} \( ! -user ${_user} \) -o \
|
|
\( ! -group ${_grp} \)`" ]; then
|
|
msg \
|
|
"${_dir} and contents not all owned by ${_user}:${_grp}"
|
|
return 1
|
|
else
|
|
return 0
|
|
fi
|
|
elif [ "${_op}" = "fix" ]; then
|
|
find ${_dir} \( \( ! -user ${_user} \) -o \
|
|
\( ! -group ${_grp} \) \) -a -print0 \
|
|
| xargs -0 chown ${_user}:${_grp}
|
|
fi
|
|
}
|
|
|
|
|
|
#
|
|
# items
|
|
# -----
|
|
#
|
|
|
|
#
|
|
# bluetooth
|
|
#
|
|
additem bluetooth "bluetooth configuration is up to date"
|
|
do_bluetooth()
|
|
{
|
|
[ -n "$1" ] || err 3 "USAGE: do_bluetooth fix|check"
|
|
op=$1
|
|
failed=0
|
|
|
|
populate_dir ${op} true \
|
|
${SRC_DIR}/etc/bluetooth ${DEST_DIR}/etc/bluetooth 644 \
|
|
hosts protocols btdevctl.conf btuartd.conf
|
|
failed=$(( ${failed} + $? ))
|
|
|
|
move_file ${op} ${DEST_DIR}/var/db/btdev.xml \
|
|
${DEST_DIR}/var/db/btdevctl.plist
|
|
failed=$(( ${failed} + $? ))
|
|
|
|
return ${failed}
|
|
}
|
|
|
|
#
|
|
# defaults
|
|
#
|
|
additem defaults "/etc/defaults/ being up to date"
|
|
do_defaults()
|
|
{
|
|
[ -n "$1" ] || err 3 "USAGE: do_defaults fix|check"
|
|
op=$1
|
|
failed=0
|
|
|
|
compare_dir $op ${SRC_DIR}/etc/defaults ${DEST_DIR}/etc/defaults 444 \
|
|
daily.conf monthly.conf rc.conf security.conf weekly.conf
|
|
failed=$(( ${failed} + $? ))
|
|
|
|
find_file_in_dirlist pf.boot.conf "pf.boot.conf" \
|
|
${SRC_DIR}/usr.sbin/pf/etc/defaults ${SRC_DIR}/etc/defaults \
|
|
|| return 1
|
|
# ${dir} is set by find_file_in_dirlist()
|
|
compare_dir $op ${dir} ${DEST_DIR}/etc/defaults 444 pf.boot.conf
|
|
failed=$(( ${failed} + $? ))
|
|
|
|
return ${failed}
|
|
}
|
|
|
|
#
|
|
# envsys
|
|
#
|
|
additem envsys "envsys configuration is up to date"
|
|
do_envsys()
|
|
{
|
|
[ -n "$1" ] || err 3 "USAGE: do_envsys fix|check"
|
|
op=$1
|
|
failed=0
|
|
|
|
populate_dir $op true ${SRC_DIR}/etc ${DEST_DIR}/etc 644 envsys.conf
|
|
failed=$(( ${failed} + $? ))
|
|
|
|
populate_dir $op true ${SRC_DIR}/etc/powerd/scripts \
|
|
${DEST_DIR}/etc/powerd/scripts 555 sensor_battery \
|
|
sensor_drive sensor_fan sensor_indicator sensor_power \
|
|
sensor_resistance sensor_temperature sensor_voltage
|
|
failed=$(( ${failed} + $? ))
|
|
|
|
return ${failed}
|
|
}
|
|
|
|
#
|
|
# gid
|
|
#
|
|
additem gid "required groups in /etc/group"
|
|
do_gid()
|
|
{
|
|
[ -n "$1" ] || err 3 "USAGE: do_gid fix|check"
|
|
|
|
check_ids $1 groups "${DEST_DIR}/etc/group" \
|
|
named ntpd postfix sshd authpf _pflogd _rwhod _proxy _timedc \
|
|
_sdpd _httpd
|
|
}
|
|
|
|
#
|
|
# hosts
|
|
#
|
|
additem hosts "/etc/hosts being up to date"
|
|
do_hosts()
|
|
{
|
|
[ -n "$1" ] || err 3 "USAGE: do_hosts fix|check"
|
|
|
|
modify_file "$1" ${DEST_DIR}/etc/hosts ${SCRATCHDIR}/hosts '
|
|
/^(127\.0\.0\.1|::1)[ ]+[^\.]*$/ {
|
|
print $0, "localhost."
|
|
next
|
|
}
|
|
{ print }
|
|
'
|
|
return $?
|
|
}
|
|
|
|
#
|
|
# iscsi
|
|
#
|
|
additem iscsi "/etc/iscsi is populated"
|
|
do_iscsi()
|
|
{
|
|
[ -n "$1" ] || err 3 "USAGE: do_iscsi fix|check"
|
|
|
|
populate_dir ${op} true \
|
|
${SRC_DIR}/etc/iscsi ${DEST_DIR}/etc/iscsi 600 auths
|
|
populate_dir ${op} true \
|
|
${SRC_DIR}/etc/iscsi ${DEST_DIR}/etc/iscsi 644 targets
|
|
return $?
|
|
}
|
|
|
|
#
|
|
# makedev
|
|
#
|
|
additem makedev "/dev/MAKEDEV being up to date"
|
|
do_makedev()
|
|
{
|
|
[ -n "$1" ] || err 3 "USAGE: do_makedev fix|check"
|
|
|
|
if [ -f "${SRC_DIR}/etc/MAKEDEV.tmpl" ]; then
|
|
# generate MAKEDEV from source if source is available
|
|
env MACHINE=${MACHINE} \
|
|
MACHINE_ARCH=${MACHINE_ARCH} \
|
|
NETBSDSRCDIR="${SRC_DIR}" \
|
|
awk -f ${SRC_DIR}/etc/MAKEDEV.awk \
|
|
${SRC_DIR}/etc/MAKEDEV.tmpl > ${SCRATCHDIR}/MAKEDEV
|
|
fi
|
|
|
|
find_file_in_dirlist MAKEDEV "MAKEDEV" \
|
|
${SCRATCHDIR} ${SRC_DIR}/dev \
|
|
|| return 1
|
|
# ${dir} is set by find_file_in_dirlist()
|
|
compare_dir $1 ${dir} ${DEST_DIR}/dev 555 MAKEDEV
|
|
}
|
|
|
|
#
|
|
# motd
|
|
#
|
|
additem motd "contents of motd"
|
|
do_motd()
|
|
{
|
|
[ -n "$1" ] || err 3 "USAGE: do_motd fix|check"
|
|
|
|
if grep -i 'http://www.NetBSD.org/Misc/send-pr.html' ${DEST_DIR}/etc/motd \
|
|
>/dev/null 2>&1 || \
|
|
grep -i 'http://www.NetBSD.org/support/send-pr.html' ${DEST_DIR}/etc/motd \
|
|
>/dev/null 2>&1; then
|
|
tmp1=$(mktemp /tmp/postinstall.motd.XXXXXXXX)
|
|
tmp2=$(mktemp /tmp/postinstall.motd.XXXXXXXX)
|
|
sed '1,2d' <${SRC_DIR}/etc/motd >${tmp1}
|
|
sed '1,2d' <${DEST_DIR}/etc/motd >${tmp2}
|
|
|
|
if [ "$1" = check ]; then
|
|
cmp -s ${tmp1} ${tmp2}
|
|
result=$?
|
|
if [ ${result} -ne 0 ]; then
|
|
msg \
|
|
"Bug reporting messages do not seem to match the installed release"
|
|
fi
|
|
else
|
|
head -n 2 ${DEST_DIR}/etc/motd >${tmp1}
|
|
sed '1,2d' <${SRC_DIR}/etc/motd >>${tmp1}
|
|
cp ${tmp1} ${DEST_DIR}/etc/motd
|
|
result=0
|
|
fi
|
|
|
|
rm -f ${tmp1} ${tmp2}
|
|
else
|
|
result=0
|
|
fi
|
|
|
|
return ${result}
|
|
}
|
|
|
|
#
|
|
# mtree
|
|
#
|
|
additem mtree "/etc/mtree/ being up to date"
|
|
do_mtree()
|
|
{
|
|
[ -n "$1" ] || err 3 "USAGE: do_mtree fix|check"
|
|
|
|
compare_dir $1 ${SRC_DIR}/etc/mtree ${DEST_DIR}/etc/mtree 444 \
|
|
NetBSD.dist special
|
|
}
|
|
|
|
#
|
|
# named
|
|
#
|
|
additem named "named configuration update"
|
|
do_named()
|
|
{
|
|
[ -n "$1" ] || err 3 "USAGE: do_named fix|check"
|
|
op=$1
|
|
|
|
move_file ${op} \
|
|
${DEST_DIR}/etc/namedb/named.conf \
|
|
${DEST_DIR}/etc/named.conf
|
|
}
|
|
|
|
#
|
|
# pam
|
|
#
|
|
additem pam "/etc/pam.d is populated"
|
|
do_pam()
|
|
{
|
|
[ -n "$1" ] || err 3 "USAGE: do_pam fix|check"
|
|
op=$1
|
|
failed=0
|
|
|
|
populate_dir ${op} true ${SRC_DIR}/etc/pam.d ${DEST_DIR}/etc/pam.d 644 \
|
|
README display_manager ftpd gdm imap kde login other passwd \
|
|
pop3 ppp rexecd rsh sshd su system telnetd xdm xserver
|
|
|
|
failed=$(( ${failed} + $? ))
|
|
|
|
return ${failed}
|
|
}
|
|
|
|
#
|
|
# periodic
|
|
#
|
|
additem periodic "/etc/{daily,weekly,monthly,security} being up to date"
|
|
do_periodic()
|
|
{
|
|
[ -n "$1" ] || err 3 "USAGE: do_periodic fix|check"
|
|
|
|
compare_dir $1 ${SRC_DIR}/etc ${DEST_DIR}/etc 644 \
|
|
daily weekly monthly security
|
|
}
|
|
|
|
#
|
|
# pf
|
|
#
|
|
additem pf "pf configuration being up to date"
|
|
do_pf()
|
|
{
|
|
[ -n "$1" ] || err 3 "USAGE: do_pf fix|check"
|
|
op=$1
|
|
failed=0
|
|
|
|
find_file_in_dirlist pf.os "pf.os" \
|
|
${SRC_DIR}/dist/pf/etc ${SRC_DIR}/etc \
|
|
|| return 1
|
|
# ${dir} is set by find_file_in_dirlist()
|
|
populate_dir ${op} true \
|
|
${dir} ${DEST_DIR}/etc 644 \
|
|
pf.conf pf.os
|
|
failed=$(( ${failed} + $? ))
|
|
|
|
return ${failed}
|
|
}
|
|
|
|
#
|
|
# postfix
|
|
#
|
|
additem postfix "/etc/postfix/ being up to date"
|
|
do_postfix()
|
|
{
|
|
[ -n "$1" ] || err 3 "USAGE: do_postfix fix|check"
|
|
op=$1
|
|
failed=0
|
|
|
|
find_file_in_dirlist postfix-script "postfix scripts" \
|
|
${SRC_DIR}/gnu/dist/postfix/conf \
|
|
${DEST_DIR}/usr/share/examples/postfix \
|
|
|| return 1
|
|
# ${dir} is set by find_file_in_dirlist()
|
|
compare_dir ${op} ${dir} ${DEST_DIR}/etc/postfix 555 \
|
|
post-install postfix-script
|
|
failed=$(( ${failed} + $? ))
|
|
compare_dir ${op} ${dir} ${DEST_DIR}/etc/postfix 444 postfix-files
|
|
failed=$(( ${failed} + $? ))
|
|
|
|
return ${failed}
|
|
}
|
|
|
|
#
|
|
# rc
|
|
#
|
|
additem rc "/etc/rc* and /etc/rc.d/ being up to date"
|
|
do_rc()
|
|
{
|
|
[ -n "$1" ] || err 3 "USAGE: do_rc fix|check"
|
|
op=$1
|
|
failed=0
|
|
|
|
compare_dir ${op} ${SRC_DIR}/etc ${DEST_DIR}/etc 644 \
|
|
rc rc.subr rc.shutdown
|
|
failed=$(( ${failed} + $? ))
|
|
|
|
compare_dir ${op} ${SRC_DIR}/etc/rc.d ${DEST_DIR}/etc/rc.d 555 \
|
|
DAEMON LOGIN NETWORKING SERVERS \
|
|
accounting altqd amd apmd \
|
|
bootconf.sh bootparams btconfig btdevctl bthcid btuartd \
|
|
ccd cgd cleartmp cron \
|
|
dhclient dhcpd dhcrelay dmesg downinterfaces envsys \
|
|
fsck ftpd \
|
|
hostapd \
|
|
identd ifwatchd inetd ipfilter ipfs ipmon ipnat ipsec \
|
|
irdaattach iscsi_target isdnd \
|
|
kdc \
|
|
ldconfig lkm1 lkm2 lkm3 local lpd \
|
|
mixerctl mopd motd mountall mountcritlocal mountcritremote \
|
|
mountd moused mrouted \
|
|
named ndbootd network newsyslog nfsd nfslocking ntpd ntpdate \
|
|
perusertmp pf pf_boot pflogd poffd postfix powerd ppp pwcheck \
|
|
quota \
|
|
racoon rpcbind raidframe raidframeparity rarpd rbootd root \
|
|
route6d routed rtadvd rtclocaltime rtsold rwho \
|
|
savecore screenblank sdpd securelevel sshd \
|
|
staticroute swap1 swap2 sysctl sysdb syslogd \
|
|
timed tpctl ttys \
|
|
veriexec virecover wdogctl wpa_supplicant wscons wsmoused \
|
|
xdm xfs \
|
|
ypbind yppasswdd ypserv
|
|
failed=$(( ${failed} + $? ))
|
|
|
|
# check for obsolete rc.d files
|
|
for f in NETWORK btcontrol fsck.sh kerberos nfsiod servers \
|
|
systemfs daemon gated login portmap sunndd xntpd; do
|
|
fd=/etc/rc.d/${f}
|
|
[ -e "${DEST_DIR}${fd}" ] && echo "${fd}"
|
|
done | obsolete_paths ${op}
|
|
failed=$(( ${failed} + $? ))
|
|
|
|
# check for obsolete rc.conf(5) variables
|
|
set -- amd amd_master \
|
|
btcontrol btcontrol_devices \
|
|
critical_filesystems critical_filesystems_beforenet \
|
|
defcorename \
|
|
ip6forwarding \
|
|
mountcritlocal mountcritremote \
|
|
network nfsiod_flags \
|
|
sdpd sdpd_control \
|
|
sdpd sdpd_groupname \
|
|
sdpd sdpd_username \
|
|
sysctl
|
|
while [ $# -gt 1 ]; do
|
|
if rcconf_is_set ${op} $1 $2 1; then
|
|
failed=1
|
|
fi
|
|
shift 2
|
|
done
|
|
|
|
return ${failed}
|
|
}
|
|
|
|
#
|
|
# sendmail
|
|
#
|
|
adddisableditem sendmail "remove obsolete sendmail configuration files and scripts"
|
|
do_sendmail()
|
|
{
|
|
[ -n "$1" ] || err 3 "USAGE: do_sendmail fix|check"
|
|
op=$1
|
|
failed=0
|
|
|
|
# Don't complain if the "sendmail" package is installed because the
|
|
# files might still be in use.
|
|
if /usr/sbin/pkg_info -qe sendmail >/dev/null 2>&1; then
|
|
return 0
|
|
fi
|
|
|
|
for f in /etc/mail/helpfile /etc/mail/local-host-names \
|
|
/etc/mail/sendmail.cf /etc/mail/submit.cf /etc/rc.d/sendmail \
|
|
/etc/rc.d/smmsp /usr/share/misc/sendmail.hf \
|
|
$(find /usr/share/sendmail -type f) \
|
|
$(find /usr/share/sendmail -type d) /var/log/sendmail.st \
|
|
/var/spool/clientmqueue /var/spool/mqueue; do
|
|
[ -e "${DEST_DIR}${f}" ] && echo "${f}"
|
|
done | obsolete_paths ${op}
|
|
failed=$(( ${failed} + $? ))
|
|
|
|
return ${failed}
|
|
}
|
|
|
|
#
|
|
# mailerconf
|
|
#
|
|
adddisableditem mailerconf "update /etc/mailer.conf after sendmail removal"
|
|
do_mailerconf()
|
|
{
|
|
[ -n "$1" ] || err 3 "USAGE: do_mailterconf fix|check"
|
|
op=$1
|
|
|
|
failed=0
|
|
mta_path=$(awk '/^sendmail[ \t]/{print$2}' /etc/mailer.conf)
|
|
old_sendmail_path="/usr/libexec/sendmail/sendmail"
|
|
if [ "${mta_path}" = "${old_sendmail_path}" ]; then
|
|
if [ "$op" = check ]; then
|
|
msg "mailer.conf points to obsolete ${old_sendmail_path}"
|
|
failed=1;
|
|
else
|
|
populate_dir ${op} false \
|
|
${SRC_DIR}/etc ${DEST_DIR}/etc 644 mailer.conf
|
|
failed=$?
|
|
fi
|
|
fi
|
|
|
|
return ${failed}
|
|
}
|
|
|
|
#
|
|
# ssh
|
|
#
|
|
additem ssh "ssh configuration update"
|
|
do_ssh()
|
|
{
|
|
[ -n "$1" ] || err 3 "USAGE: do_ssh fix|check"
|
|
op=$1
|
|
|
|
failed=0
|
|
_etcssh=${DEST_DIR}/etc/ssh
|
|
if ! check_dir ${op} ${_etcssh} 755; then
|
|
failed=1
|
|
fi
|
|
|
|
if [ ${failed} -eq 0 ]; then
|
|
for f in \
|
|
ssh_known_hosts ssh_known_hosts2 \
|
|
ssh_host_dsa_key ssh_host_dsa_key.pub \
|
|
ssh_host_rsa_key ssh_host_rsa_key.pub \
|
|
ssh_host_key ssh_host_key.pub \
|
|
; do
|
|
if ! move_file ${op} \
|
|
${DEST_DIR}/etc/${f} ${_etcssh}/${f} ; then
|
|
failed=1
|
|
fi
|
|
done
|
|
for f in sshd.conf ssh.conf ; do
|
|
# /etc/ssh/ssh{,d}.conf -> ssh{,d}_config
|
|
#
|
|
if ! move_file ${op} \
|
|
${_etcssh}/${f} ${_etcssh}/${f%.conf}_config ; then
|
|
failed=1
|
|
fi
|
|
# /etc/ssh{,d}.conf -> /etc/ssh/ssh{,d}_config
|
|
#
|
|
if ! move_file ${op} \
|
|
${DEST_DIR}/etc/${f} ${_etcssh}/${f%.conf}_config ;
|
|
then
|
|
failed=1
|
|
fi
|
|
done
|
|
fi
|
|
|
|
sshdconf=""
|
|
for f in \
|
|
${_etcssh}/sshd_config \
|
|
${_etcssh}/sshd.conf \
|
|
${DEST_DIR}/etc/sshd.conf ; do
|
|
if [ -f "${f}" ]; then
|
|
sshdconf=${f}
|
|
break
|
|
fi
|
|
done
|
|
if [ -n "${sshdconf}" ]; then
|
|
modify_file ${op} "${sshdconf}" "${SCRATCHDIR}/sshdconf" '
|
|
/^[^#$]/ {
|
|
kw = tolower($1)
|
|
if (kw == "hostkey" &&
|
|
$2 ~ /^\/etc\/+ssh_host(_[dr]sa)?_key$/ ) {
|
|
sub(/\/etc\/+/, "/etc/ssh/")
|
|
}
|
|
if (kw == "rhostsauthentication" ||
|
|
kw == "verifyreversemapping" ||
|
|
kw == "reversemappingcheck") {
|
|
sub(/^/, "# DEPRECATED:\t")
|
|
}
|
|
}
|
|
{ print }
|
|
'
|
|
failed=$(( ${failed} + $? ))
|
|
fi
|
|
|
|
if ! find_file_in_dirlist moduli "moduli" \
|
|
${SRC_DIR}/crypto/dist/ssh ${SRC_DIR}/etc ; then
|
|
failed=1
|
|
# ${dir} is set by find_file_in_dirlist()
|
|
elif ! compare_dir ${op} ${dir} ${DEST_DIR}/etc 444 moduli; then
|
|
failed=1
|
|
fi
|
|
|
|
if ! check_dir "${op}" "${DEST_DIR}/var/chroot/sshd" 755 ; then
|
|
failed=1
|
|
fi
|
|
|
|
if rcconf_is_set ${op} sshd sshd_conf_dir 1; then
|
|
failed=1
|
|
fi
|
|
|
|
return ${failed}
|
|
}
|
|
|
|
#
|
|
# wscons
|
|
#
|
|
additem wscons "wscons configuration file update"
|
|
do_wscons()
|
|
{
|
|
[ -n "$1" ] || err 3 "USAGE: do_wscons fix|check"
|
|
op=$1
|
|
|
|
[ -f ${DEST_DIR}/etc/wscons.conf ] || return 0
|
|
|
|
failed=0
|
|
notfixed=""
|
|
if [ "${op}" = "fix" ]; then
|
|
notfixed=${NOT_FIXED}
|
|
fi
|
|
while read _type _arg1 _rest; do
|
|
if [ "${_type}" = "mux" -a "${_arg1}" = "1" ]; then
|
|
msg \
|
|
"Obsolete wscons.conf(5) entry \""${_type} ${_arg1}"\" found.${notfixed}"
|
|
failed=1
|
|
fi
|
|
done < ${DEST_DIR}/etc/wscons.conf
|
|
|
|
return ${failed}
|
|
}
|
|
|
|
#
|
|
# X11
|
|
#
|
|
additem x11 "x11 configuration update"
|
|
do_x11()
|
|
{
|
|
[ -n "$1" ] || err 3 "USAGE: do_x11 fix|check"
|
|
op=$1
|
|
|
|
failed=0
|
|
_etcx11=${DEST_DIR}/etc/X11
|
|
if [ ! -d "${_etcx11}" ]; then
|
|
msg "${_etcx11} is not a directory; skipping check"
|
|
return 0
|
|
fi
|
|
_libx11=${DEST_DIR}/usr/X11R6/lib/X11
|
|
if [ ! -d "${_libx11}" ]; then
|
|
msg "${_libx11} is not a directory; skipping check"
|
|
return 0
|
|
fi
|
|
|
|
_notfixed=""
|
|
if [ "${op}" = "fix" ]; then
|
|
_notfixed=${NOT_FIXED}
|
|
fi
|
|
|
|
for d in \
|
|
fs lbxproxy proxymngr rstart twm xdm xinit xserver xsm \
|
|
; do
|
|
sd=${_libx11}/${d}
|
|
ld=/etc/X11/${d}
|
|
td=${DEST_DIR}${ld}
|
|
if [ -h ${sd} ]; then
|
|
continue
|
|
elif [ -d ${sd} ]; then
|
|
tdfiles=$(find ${td} \! -type d)
|
|
if [ -n "${tdfiles}" ]; then
|
|
msg "${sd} exists yet ${td} already" \
|
|
"contains files${_notfixed}"
|
|
else
|
|
msg "Migrate ${sd} to ${td}${_notfixed}"
|
|
fi
|
|
failed=1
|
|
elif [ -e ${sd} ]; then
|
|
msg "Unexpected file ${sd}${_notfixed}"
|
|
continue
|
|
else
|
|
continue
|
|
fi
|
|
done
|
|
|
|
return ${failed}
|
|
}
|
|
|
|
#
|
|
# uid
|
|
#
|
|
additem uid "required users in /etc/master.passwd"
|
|
do_uid()
|
|
{
|
|
[ -n "$1" ] || err 3 "USAGE: do_uid fix|check"
|
|
|
|
check_ids $1 users "${DEST_DIR}/etc/master.passwd" \
|
|
named ntpd postfix sshd _pflogd _rwhod _proxy _timedc \
|
|
_sdpd _httpd
|
|
}
|
|
|
|
|
|
#
|
|
# varrwho
|
|
#
|
|
additem varrwho "required ownership of files in /var/rwho"
|
|
do_varrwho()
|
|
{
|
|
[ -n "$1" ] || err 3 "USAGE: do_varrwho fix|check"
|
|
|
|
contents_owner $1 "${DEST_DIR}/var/rwho" _rwhod _rwhod
|
|
}
|
|
|
|
|
|
#
|
|
# obsolete
|
|
# (this item is last to allow other items to move obsolete files)
|
|
#
|
|
additem obsolete "remove obsolete file sets and minor libraries"
|
|
do_obsolete()
|
|
{
|
|
[ -n "$1" ] || err 3 "USAGE: do_obsolete fix|check"
|
|
op=$1
|
|
failed=0
|
|
|
|
sort -ru ${DEST_DIR}/var/db/obsolete/* | obsolete_paths ${op}
|
|
failed=$(( ${failed} + $? ))
|
|
|
|
(
|
|
obsolete_libs /lib
|
|
obsolete_libs /usr/lib
|
|
obsolete_libs /usr/lib/i18n
|
|
obsolete_libs /usr/X11R6/lib
|
|
) | obsolete_paths ${op}
|
|
failed=$(( ${failed} + $? ))
|
|
|
|
return ${failed}
|
|
}
|
|
|
|
|
|
#
|
|
# end of items
|
|
# ------------
|
|
#
|
|
|
|
|
|
usage()
|
|
{
|
|
cat 1>&2 << _USAGE_
|
|
Usage: ${PROGNAME} [-s srcdir] [-d destdir] [-m mach] [-a arch] op [item [...]]
|
|
Perform post-installation checks and/or fixes on a system's
|
|
configuration files.
|
|
If no items are provided, a default set of checks or fixes is applied.
|
|
|
|
Options:
|
|
-s {srcdir|tgzfile|tempdir}
|
|
Location of the source files. This may be any
|
|
of the following:
|
|
* A directory that contains a NetBSD source tree;
|
|
* A distribution set file such as "etc.tgz" or
|
|
"xetc.tgz", or a colon-separated list of such
|
|
files;
|
|
* A temporary directory in which one or both of
|
|
"etc.tgz" and "xetc.tgz" have been extracted.
|
|
[${SRC_DIR:-/}]
|
|
-d destdir Destination directory to check. [${DEST_DIR:-/}]
|
|
-m mach MACHINE. [${MACHINE}]
|
|
-a arch MACHINE_ARCH. [${MACHINE_ARCH}]
|
|
|
|
Operation may be one of:
|
|
help Display this help.
|
|
list List available items.
|
|
check Perform post-installation checks on items.
|
|
diff [diff(1) options ...]
|
|
Similar to 'check' but also output difference of files.
|
|
fix Apply fixes that 'check' determines need to be applied.
|
|
usage Display this usage.
|
|
_USAGE_
|
|
exit 2
|
|
}
|
|
|
|
|
|
list()
|
|
{
|
|
echo "Default set of items (to apply if no items are provided by user):"
|
|
echo " Item Description"
|
|
echo " ---- -----------"
|
|
for i in ${defaultitems}; do
|
|
eval desc="\${desc_${i}}"
|
|
printf " %-12s %s\n" "${i}" "${desc}"
|
|
done
|
|
echo "Items disabled by default (must be requested explicitely):"
|
|
echo " Item Description"
|
|
echo " ---- -----------"
|
|
for i in ${otheritems}; do
|
|
eval desc="\${desc_${i}}"
|
|
printf " %-12s %s\n" "${i}" "${desc}"
|
|
done
|
|
|
|
}
|
|
|
|
|
|
main()
|
|
{
|
|
while getopts s:d:m:a: ch; do
|
|
case ${ch} in
|
|
s)
|
|
if [ -f "${OPTARG%%:*}" ]; then
|
|
# arg refers to a *.tgz file, or a
|
|
# colon-separated list.
|
|
# This may happen twice, for both etc.tgz and
|
|
# xetc.tgz, so we build up a colon-separated
|
|
# list in TGZLIST.
|
|
TGZLIST="${TGZLIST}${TGZLIST:+:}${OPTARG}"
|
|
SRC_ARG="${TGZLIST}"
|
|
elif [ -d "${OPTARG}" ]; then
|
|
SRC_ARG=${OPTARG}
|
|
else
|
|
err 2 "Invalid argument for -s option"
|
|
fi
|
|
;;
|
|
d)
|
|
DEST_DIR=${OPTARG}
|
|
;;
|
|
m)
|
|
MACHINE=${OPTARG}
|
|
;;
|
|
a)
|
|
MACHINE_ARCH=${OPTARG}
|
|
;;
|
|
*)
|
|
usage
|
|
;;
|
|
esac
|
|
done
|
|
shift $((${OPTIND} - 1))
|
|
[ $# -gt 0 ] || usage
|
|
|
|
#
|
|
# If '-s etc.tgz' or '-s etc.tgz:xetc.tgz', extract tgz files
|
|
# to a scratch directory.
|
|
#
|
|
if [ -n "${TGZLIST}" ]; then
|
|
ETCTGZDIR="${SCRATCHDIR}/etc.tgz"
|
|
echo "Note: -s ${SRC_ARG} is a file,"
|
|
echo " temporarily extracting to ${ETCTGZDIR}"
|
|
if ! mkdir "${ETCTGZDIR}"; then
|
|
err 2 "Can't create ${ETCTGZDIR}"
|
|
fi
|
|
oldIFS="${IFS}"
|
|
IFS=:
|
|
for tgz in ${TGZLIST}; do
|
|
cat "${tgz}" | (
|
|
cd "${ETCTGZDIR}" &&
|
|
tar -zxf -
|
|
) || err 2 "Can't extract ${tgz}"
|
|
done
|
|
IFS="${oldIFS}"
|
|
SRC_DIR="${ETCTGZDIR}"
|
|
else
|
|
SRC_DIR="${SRC_ARG}"
|
|
fi
|
|
|
|
[ -d "${SRC_DIR}" ] || err 2 "${SRC_DIR} is not a directory"
|
|
[ -d "${DEST_DIR}" ] || err 2 "${DEST_DIR} is not a directory"
|
|
[ -n "${MACHINE}" ] || err 2 "\${MACHINE} is not defined"
|
|
[ -n "${MACHINE_ARCH}" ] || err 2 "\${MACHINE_ARCH} is not defined"
|
|
|
|
# If directories are /, clear them, so various messages
|
|
# don't have leading "//". However, this requires
|
|
# the use of ${foo:-/} to display the variables.
|
|
#
|
|
[ "${SRC_DIR}" = "/" ] && SRC_DIR=""
|
|
[ "${DEST_DIR}" = "/" ] && DEST_DIR=""
|
|
|
|
op=$1
|
|
shift
|
|
|
|
case "${op}" in
|
|
diff)
|
|
op=check
|
|
DIFF_STYLE=n # default style is RCS
|
|
OPTIND=1
|
|
while getopts bcenpuw ch; do
|
|
case ${ch} in
|
|
c|e|n|u)
|
|
if [ ${DIFF_STYLE} != n -a \
|
|
${DIFF_STYLE} != ${ch} ]; then
|
|
err 2 "conflicting output style: ${ch}"
|
|
fi
|
|
DIFF_STYLE=${ch}
|
|
;;
|
|
b|p|w)
|
|
DIFF_OPT="${DIFF_OPT} -${ch}"
|
|
;;
|
|
*)
|
|
err 2 "unknown diff option"
|
|
;;
|
|
esac
|
|
done
|
|
shift $((${OPTIND} - 1))
|
|
;;
|
|
esac
|
|
|
|
case "${op}" in
|
|
|
|
usage|help)
|
|
usage
|
|
;;
|
|
|
|
list)
|
|
echo "Source directory: ${SRC_DIR:-/}"
|
|
echo "Target directory: ${DEST_DIR:-/}"
|
|
if [ "${SRC_DIR}" != "${SRC_ARG}" ]; then
|
|
echo " (extracted from: ${SRC_ARG})"
|
|
fi
|
|
list
|
|
;;
|
|
|
|
check|fix)
|
|
todo="$@"
|
|
: ${todo:=${defaultitems}}
|
|
|
|
# ensure that all supplied items are valid
|
|
#
|
|
for i in ${todo}; do
|
|
eval desc=\"\${desc_${i}}\"
|
|
[ -n "${desc}" ] || err 2 "Unsupported ${op} '"${i}"'"
|
|
done
|
|
|
|
# perform each check/fix
|
|
#
|
|
echo "Source directory: ${SRC_DIR:-/}"
|
|
if [ "${SRC_DIR}" != "${SRC_ARG}" ]; then
|
|
echo " (extracted from: ${SRC_ARG})"
|
|
fi
|
|
echo "Target directory: ${DEST_DIR:-/}"
|
|
items_passed=
|
|
items_failed=
|
|
for i in ${todo}; do
|
|
echo "${i} ${op}:"
|
|
( eval do_${i} ${op} )
|
|
if [ $? -eq 0 ]; then
|
|
items_passed="${items_passed} ${i}"
|
|
else
|
|
items_failed="${items_failed} ${i}"
|
|
fi
|
|
done
|
|
|
|
if [ "${op}" = "check" ]; then
|
|
plural="checks"
|
|
else
|
|
plural="fixes"
|
|
fi
|
|
|
|
echo "${PROGNAME} ${plural} passed:${items_passed}"
|
|
echo "${PROGNAME} ${plural} failed:${items_failed}"
|
|
if [ -n "${items_failed}" ]; then
|
|
exitstatus=1;
|
|
if [ "${op}" = "check" ]; then
|
|
[ "$MACHINE" = "$(uname -m)" ] && m= || m=" -m $MACHINE"
|
|
cat <<_Fix_me_
|
|
To fix, run:
|
|
${0} -s ${SRC_ARG} -d ${DEST_DIR:-/}$m fix${items_failed}
|
|
_Fix_me_
|
|
fi
|
|
fi
|
|
|
|
;;
|
|
|
|
*)
|
|
warn "Unknown operation '"${op}"'"
|
|
usage
|
|
;;
|
|
|
|
esac
|
|
}
|
|
|
|
# defaults
|
|
#
|
|
PROGNAME=${0##*/}
|
|
SRC_ARG="/usr/src"
|
|
DEST_DIR="/"
|
|
: ${MACHINE:=$( uname -m )} # assume native build if $MACHINE is not set
|
|
: ${MACHINE_ARCH:=$( uname -p )}# assume native build if not set
|
|
|
|
DIFF_STYLE=
|
|
NOT_FIXED=" (FIX MANUALLY)"
|
|
SCRATCHDIR=$( mkdtemp ) || err 2 "Can't create scratch directory"
|
|
trap "/bin/rm -rf ${SCRATCHDIR} ; exit 0" 1 2 3 15 # HUP INT QUIT TERM
|
|
|
|
umask 022
|
|
exec 3>/dev/null
|
|
exec 4>/dev/null
|
|
exitstatus=0
|
|
|
|
main "$@"
|
|
/bin/rm -rf ${SCRATCHDIR}
|
|
exit $exitstatus
|