--- /dev/null
+#!/bin/sh
+#
+# $NetBSD: postinstall,v 1.147 2012/09/22 09:20:06 ast Exp $
+#
+# Copyright (c) 2002-2008 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.
+#
+# 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.
+#
+
+#
+# XXX BE SURE TO USE ${DEST_DIR} PREFIX BEFORE ALL REAL FILE OPERATIONS XXX
+#
+
+#
+# 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
+#
+
+# This script is executed as part of a cross build. Allow the build
+# environment to override the locations of some tools.
+: ${AWK:=awk}
+: ${DB:=db}
+: ${GREP:=grep}
+: ${HOST_SH:=sh}
+: ${MAKE:=make}
+: ${PWD_MKDB:=/usr/sbin/pwd_mkdb}
+: ${STAT:=stat}
+
+#
+# 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}"
+}
+
+# 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
+ for arg in "$@" ; do
+ # Append a space if necessary
+ result="${result}${result:+ }"
+ # Convert each embedded ' to '\'',
+ # then insert ' at the beginning of the first line,
+ # and append ' at the end of the last line.
+ result="${result}$(printf "%s\n" "$arg" | \
+ sed -e "s/'/'\\\\''/g" -e "1s/^/'/" -e "\$s/\$/'/")"
+ done
+ printf "%s\n" "$result"
+}
+
+
+# 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 explicitly.
+#
+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
+ }
+ }
+ ' "$@" < "${_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 "$@"; 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" "$@"
+}
+
+# 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
+ )
+}
+
+# rcvar_is_enabled var
+# Check if rcvar is enabled
+#
+rcvar_is_enabled()
+{
+ [ $# -eq 1 ] || err 3 "USAGE: rcvar_is_enabled var"
+ _rcie_var="$1"
+ (
+ [ -f "${DEST_DIR}/etc/rc.conf" ] && . "${DEST_DIR}/etc/rc.conf"
+ eval _rcie_val="\${${_rcie_var}}"
+ case $_rcie_val in
+ # "yes", "true", "on", or "1"
+ [Yy][Ee][Ss]|[Tt][Rr][Uu][Ee]|[Oo][Nn]|1)
+ exit 0
+ ;;
+
+ *)
+ exit 1
+ ;;
+ esac
+ )
+}
+
+# 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= # first dir in list
+ 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
+}
+
+# file_exists_exact path
+# Returns true if a file exists in the ${DEST_DIR} whose name
+# is exactly ${path}, interpreted in a case-sensitive way
+# even if the underlying file system is case-insensitive.
+#
+# The path must begin with '/' or './', and is interpreted as
+# being relative to ${DEST_DIR}.
+#
+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} -F -x "${_basename}" >/dev/null \
+ || 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"
+
+ _obsolete_libs "${dir}"
+ _obsolete_libs "/usr/libdata/debug/${dir}"
+}
+
+_obsolete_libs()
+{
+ 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]+)?(\.debug)?$/ {
+ 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
+}
+
+# get_makevar var [var ...]
+# Retrieve the value of a user-settable system make variable
+get_makevar()
+{
+ $SOURCEMODE || err 3 "get_makevar must be used in source mode"
+ [ $# -eq 0 ] && err 3 "USAGE: get_makevar var [var ...]"
+
+ for _var in "$@"; do
+ _value="$(echo '.include <bsd.own.mk>' | \
+ ${MAKE} -f - -V "${_var}")"
+
+ eval ${_var}=\"${_value}\"
+ done
+}
+
+# detect_x11
+# Detect if X11 components should be analysed and set values of
+# relevant variables.
+detect_x11()
+{
+ if $SOURCEMODE; then
+ get_makevar MKX11 X11ROOTDIR X11SRCDIR
+ else
+ if [ -f "${SRC_DIR}/etc/mtree/set.xetc" ]; then
+ MKX11=yes
+ X11ROOTDIR=/this/value/isnt/used/yet
+ else
+ MKX11=no
+ X11ROOTDIR=
+ fi
+ X11SRCDIR=/nonexistent/xsrc
+ 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 btattach.conf btdevctl.conf
+ failed=$(( ${failed} + $? ))
+
+ move_file "${op}" "${DEST_DIR}/var/db/btdev.xml" \
+ "${DEST_DIR}/var/db/btdevctl.plist"
+ failed=$(( ${failed} + $? ))
+
+ notfixed=""
+ if [ "${op}" = "fix" ]; then
+ notfixed="${NOT_FIXED}"
+ fi
+ for _v in btattach btconfig btdevctl; do
+ if rcvar_is_enabled "${_v}"; then
+ msg \
+ "${_v} is obsolete in rc.conf(5)${notfixed}: use bluetooth=YES"
+ failed=$(( ${failed} + 1 ))
+ fi
+ done
+
+ return ${failed}
+}
+
+#
+# ddbonpanic
+#
+additem ddbonpanic "verify ddb.onpanic is configured in sysctl.conf"
+do_ddbonpanic()
+{
+ [ -n "$1" ] || err 3 "USAGE: do_ddbonpanic fix|check"
+
+ if ${GREP} -E '^#*[[:space:]]*ddb\.onpanic[[:space:]]*\??=[[:space:]]*[[:digit:]]+' \
+ "${DEST_DIR}/etc/sysctl.conf" >/dev/null 2>&1
+ then
+ result=0
+ else
+ if [ "$1" = check ]; then
+ msg \
+ "The ddb.onpanic behaviour is not explicitly specified in /etc/sysctl.conf"
+ result=1
+ else
+ echo >> "${DEST_DIR}/etc/sysctl.conf"
+ sed < "${SRC_DIR}/etc/sysctl.conf" \
+ -e '/^ddb\.onpanic/q' | \
+ sed -e '1,/^$/d' >> \
+ "${DEST_DIR}/etc/sysctl.conf"
+ result=$?
+ fi
+ fi
+ return ${result}
+}
+
+#
+# defaults
+#
+additem defaults "/etc/defaults/ being up to date"
+do_defaults()
+{
+ [ -n "$1" ] || err 3 "USAGE: do_defaults fix|check"
+ op="$1"
+ failed=0
+
+ # Except for i386 and amd64, rc.conf(5) should be the same as the
+ # one obtained from a source directory
+ extra_scripts="rc.conf"
+ if [ "$MACHINE" = "i386" -o "$MACHINE" = "amd64" ]; then
+ if $SOURCEMODE; then
+ extra_scripts= # clear
+
+ # Generate and compare the correct rc.conf(5) file
+ mkdir "${SCRATCHDIR}/defaults"
+
+ cat "${SRC_DIR}/etc/defaults/rc.conf" \
+ "${SRC_DIR}/etc/etc.${MACHINE}/rc.conf.append" \
+ > "${SCRATCHDIR}/defaults/rc.conf"
+
+ compare_dir "${op}" "${SCRATCHDIR}/defaults" \
+ "${DEST_DIR}/etc/defaults" \
+ 444 \
+ "rc.conf"
+ failed=$(( ${failed} + $? ))
+ fi
+ fi
+
+ compare_dir "$op" "${SRC_DIR}/etc/defaults" "${DEST_DIR}/etc/defaults" \
+ 444 \
+ daily.conf monthly.conf security.conf \
+ weekly.conf ${extra_scripts}
+ 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}
+}
+
+#
+# dhcpcd
+#
+additem dhcpcd "dhcpcd configuration is up to date"
+do_dhcpcd()
+{
+ [ -n "$1" ] || err 3 "USAGE: do_dhcpcd fix|check"
+ op="$1"
+ failed=0
+
+ find_file_in_dirlist dhcpcd.conf "dhcpcd.conf" \
+ "${SRC_DIR}/external/bsd/dhcpcd/dist" "${SRC_DIR}/etc" || return 1
+ # ${dir} is set by find_file_in_dirlist()
+ populate_dir "$op" true "${dir}" "${DEST_DIR}/etc" 644 dhcpcd.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}
+}
+
+#
+# X11 fontconfig
+#
+additem fontconfig "X11 font configuration is up to date"
+do_fontconfig()
+{
+ [ -n "$1" ] || err 3 "USAGE: do_fontconfig fix|check"
+ op="$1"
+ failed=0
+
+ if [ -f "${DEST_DIR}/etc/fonts/conf.d/10-unhinted.conf" -a \
+ -f "${DEST_DIR}/etc/fonts/conf.d/10-autohint.conf" ]; then
+ failed=1
+ fi
+
+ if [ "$failed" = 1 ]; then
+ msg \
+ "Broken fontconfig configuration found; please delete these files"
+ msg \
+ "in the ${DESTDIR}/etc/fonts/conf.d/ subdirectory:"
+ msg \
+ " 10-autohint.conf 10-no-sub-pixel.conf 10-sub-pixel-bgr.conf"
+ msg \
+ " 10-sub-pixel-rgb.conf 10-sub-pixel-vbgr.conf"
+ msg \
+ " 10-sub-pixel-vrgb.conf 10-unhinted.conf 25-unhint-nonlatin.conf"
+ msg \
+ " 65-khmer.conf 70-no-bitmaps.conf 70-yes-bitmaps.conf"
+ msg \
+ "(This warning only appears if both the 10-unhinted.conf and"
+ msg \
+ "10-autohint.conf files are present."
+ fi
+
+ 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 sshd authpf _pflogd _rwhod _proxy _timedc \
+ _sdpd _httpd _mdnsd _tests _tcpdump _tss
+}
+
+#
+# gpio
+#
+additem gpio "gpio configuration is up to date"
+do_gpio()
+{
+ [ -n "$1" ] || err 3 "USAGE: do_gpio fix|check"
+ op="$1"
+ failed=0
+
+ populate_dir "$op" true "${SRC_DIR}/etc" "${DEST_DIR}/etc" 644 \
+ gpio.conf
+ failed=$(( ${failed} + $? ))
+
+ return ${failed}
+}
+
+#
+# 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"
+ failed=0
+
+ 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
+ failed=$(( ${failed} + $? ))
+
+ find_file_in_dirlist MAKEDEV.local "MAKEDEV.local" \
+ "${SRC_DIR}/etc" "${SRC_DIR}/dev" \
+ || return 1
+ # ${dir} is set by find_file_in_dirlist()
+ compare_dir "$1" "${dir}" "${DEST_DIR}/dev" 555 MAKEDEV.local
+ failed=$(( ${failed} + $? ))
+
+ return ${failed}
+}
+
+#
+# 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"
+ failed=0
+
+ compare_dir "$1" "${SRC_DIR}/etc/mtree" "${DEST_DIR}/etc/mtree" 444 special
+ failed=$(( ${failed} + $? ))
+
+ if ! $SOURCEMODE; then
+ MTREE_DIR="${SRC_DIR}/etc/mtree"
+ else
+ ${MAKE} -C "${SRC_DIR}/etc/mtree" emit_dist_file > \
+ "${SCRATCHDIR}/NetBSD.dist"
+ MTREE_DIR="${SCRATCHDIR}"
+ fi
+ compare_dir "$1" "${MTREE_DIR}" "${DEST_DIR}/etc/mtree" 444 NetBSD.dist
+ failed=$(( ${failed} + $? ))
+
+ return ${failed}
+}
+
+#
+# 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"
+
+ compare_dir "${op}" "${SRC_DIR}/etc/namedb" "${DEST_DIR}/etc/namedb" \
+ 644 \
+ root.cache
+}
+
+#
+# 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
+ failed=$(( ${failed} + $? ))
+
+ compare_dir "${op}" "${dir}" "${DEST_DIR}/etc" 444 pf.os
+ failed=$(( ${failed} + $? ))
+
+ return ${failed}
+}
+
+#
+# pwd_mkdb
+#
+additem pwd_mkdb "passwd database version"
+do_pwd_mkdb()
+{
+ [ -n "$1" ] || err 3 "USAGE: do_pwd_mkdb fix|check"
+ op="$1"
+ failed=0
+
+ # XXX Ideally, we should figure out the endianness of the
+ # target machine, and add "-E B"/"-E L" to the db(1) flags,
+ # and "-B"/"-L" to the pwd_mkdb(8) flags if the target is not
+ # the same as the host machine. It probably doesn't matter,
+ # because we don't expect "postinstall fix pwd_mkdb" to be
+ # invoked during a cross build.
+
+ set -- $(${DB} -q -Sb -Ub -To -N hash "${DEST_DIR}/etc/pwd.db" \
+ 'VERSION\0')
+ case "$2" in
+ '\001\000\000\000') return 0 ;; # version 1, little-endian
+ '\000\000\000\001') return 0 ;; # version 1, big-endian
+ esac
+
+ if [ "${op}" = "check" ]; then
+ msg "Update format of passwd database"
+ failed=1
+ elif ! ${PWD_MKDB} -V 1 -d "${DEST_DIR:-/}" \
+ "${DEST_DIR}/etc/master.passwd";
+ then
+ msg "Can't update format of passwd database"
+ failed=1
+ else
+ msg "Updated format of passwd database"
+ fi
+
+ 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
+ generated_scripts=""
+ if [ "${MKX11}" != "no" ]; then
+ generated_scripts="${generated_scripts} xdm xfs"
+ fi
+
+ compare_dir "${op}" "${SRC_DIR}/etc" "${DEST_DIR}/etc" 644 \
+ rc rc.subr rc.shutdown
+ failed=$(( ${failed} + $? ))
+
+ if ! $SOURCEMODE; then
+ extra_scripts="${generated_scripts}"
+ else
+ extra_scripts=""
+ fi
+
+ compare_dir "${op}" "${SRC_DIR}/etc/rc.d" "${DEST_DIR}/etc/rc.d" 555 \
+ DAEMON DISKS LOGIN NETWORKING SERVERS \
+ accounting altqd amd apmd \
+ bluetooth bootconf.sh bootparams \
+ ccd cgd cleartmp cron \
+ dhclient dhcpcd dhcpd dhcrelay dmesg downinterfaces envsys \
+ fsck fsck_root ftp_proxy ftpd \
+ gpio \
+ hostapd httpd \
+ identd ifwatchd inetd ipfilter ipfs ipmon ipnat ipsec \
+ irdaattach iscsi_target isdnd isibootd \
+ kdc \
+ ldconfig ldpd local lpd lvm\
+ makemandb mdnsd mixerctl mopd motd mountall mountcritlocal \
+ mountcritremote mountd moused mrouted \
+ named ndbootd network newsyslog nfsd nfslocking npf \
+ ntpd ntpdate \
+ perusertmp pf pf_boot pflogd postfix powerd ppp pwcheck \
+ quota \
+ racoon rpcbind raidframe raidframeparity random_seed \
+ rarpd rbootd rndctl \
+ root route6d routed rtadvd rtclocaltime rtsold rwho \
+ savecore screenblank securelevel sshd \
+ staticroute swap1 swap2 sysctl sysdb syslogd \
+ timed tpctl ttys \
+ veriexec virecover wdogctl wpa_supplicant wscons wsmoused \
+ ypbind yppasswdd ypserv \
+ ${extra_scripts}
+ failed=$(( ${failed} + $? ))
+
+ if $SOURCEMODE && [ -n "${generated_scripts}" ]; then
+ # generate scripts
+ mkdir "${SCRATCHDIR}/rc"
+ for f in ${generated_scripts}; do
+ sed -e "s,@X11ROOTDIR@,${X11ROOTDIR},g" \
+ < "${SRC_DIR}/etc/rc.d/${f}.in" \
+ > "${SCRATCHDIR}/rc/${f}"
+ done
+ compare_dir "${op}" "${SCRATCHDIR}/rc" \
+ "${DEST_DIR}/etc/rc.d" 555 \
+ ${generated_scripts}
+ failed=$(( ${failed} + $? ))
+ fi
+
+ # check for obsolete rc.d files
+ for f in NETWORK btattach btconfig btcontrol btdevctl bthcid btuartd \
+ fsck.sh kerberos nfsiod sdpd servers \
+ systemfs daemon gated login poffd 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 \
+ mountcritlocal mountcritremote \
+ network ip6forwarding \
+ network nfsiod_flags \
+ sdpd sdpd_control \
+ sdpd sdpd_groupname \
+ sdpd sdpd_username \
+ sysctl defcorename
+ 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 "${DEST_DIR}/usr/share/sendmail" -type f) \
+ $(find "${DEST_DIR}/usr/share/sendmail" -type d) \
+ "${DEST_DIR}/var/log/sendmail.st" \
+ "${DEST_DIR}/var/spool/clientmqueue" \
+ "${DEST_DIR}/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}' \
+ "${DEST_DIR}/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/external/bsd/openssh/dist" "${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
+ if [ -d "${DEST_DIR}/usr/X11R6/." ]
+ then
+ _libx11="${DEST_DIR}/usr/X11R6/lib/X11"
+ if [ ! -d "${_libx11}" ]; then
+ msg "${_libx11} is not a directory; skipping check"
+ return 0
+ fi
+ 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}
+}
+
+#
+# xkb
+#
+# /usr/X11R7/lib/X11/xkb/symbols/pc used to be a directory, but changed
+# to a file on 2009-06-12. Fixing this requires removing the directory
+# (which we can do) and re-extracting the xbase set (which we can't do),
+# or at least adding that one file (which we may be able to do if X11SRCDIR
+# is available).
+#
+additem xkb "clean up for xkbdata to xkeyboard-config upgrade"
+do_xkb()
+{
+ [ -n "$1" ] || err 3 "USAGE: do_xkb fix|check"
+ op="$1"
+ failed=0
+
+ pcpath="/usr/X11R7/lib/X11/xkb/symbols/pc"
+ pcsrcdir="${X11SRCDIR}/external/mit/xkeyboard-config/dist/symbols"
+
+ filemsg="\
+${pcpath} was a directory, should be a file.
+ To fix, extract the xbase set again."
+
+ _notfixed=""
+ if [ "${op}" = "fix" ]; then
+ _notfixed="${NOT_FIXED}"
+ fi
+
+ if [ ! -d "${DESTDIR}${pcpath}" ]; then
+ return 0
+ fi
+
+ # Delete obsolete files in the directory, and the directory
+ # itself. If the directory contains unexpected extra files
+ # then it will not be deleted.
+ ( [ -f "${DEST_DIR}"/var/db/obsolete/xbase ] \
+ && sort -ru "${DEST_DIR}"/var/db/obsolete/xbase \
+ | ${GREP} -E "^\\.?${pcpath}/" ;
+ echo "${pcpath}" ) \
+ | obsolete_paths "${op}"
+ failed=$(( ${failed} + $? ))
+
+ # If the directory was removed above, then try to replace it with
+ # a file.
+ if [ -d "${DESTDIR}${pcpath}" ]; then
+ msg "${filemsg}${_notfixed}"
+ failed=$(( ${failed} + 1 ))
+ else
+ if ! find_file_in_dirlist pc "${pcpath}" \
+ "${pcsrcdir}" "${SRC_DIR}${pcpath%/*}"
+ then
+ msg "${filemsg}${_notfixed}"
+ failed=$(( ${failed} + 1 ))
+ else
+ # ${dir} is set by find_file_in_dirlist()
+ populate_dir "${op}" true \
+ "${dir}" "${DEST_DIR}${pcpath%/*}" 444 \
+ pc
+ failed=$(( ${failed} + $? ))
+ fi
+ fi
+
+ 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 _mdnsd _tests _tcpdump _tss
+}
+
+
+#
+# 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
+}
+
+
+#
+# tcpdumpchroot
+#
+additem tcpdumpchroot "remove /var/chroot/tcpdump/etc/protocols"
+do_tcpdumpchroot()
+{
+ [ -n "$1" ] || err 3 "USAGE: do_tcpdumpchroot fix|check"
+
+ failed=0;
+ if [ -r "${DEST_DIR}/var/chroot/tcpdump/etc/protocols" ]; then
+ if [ "$1" = "fix" ]; then
+ rm "${DEST_DIR}/var/chroot/tcpdump/etc/protocols"
+ failed=$(( ${failed} + $? ))
+ rmdir "${DEST_DIR}/var/chroot/tcpdump/etc"
+ failed=$(( ${failed} + $? ))
+ else
+ failed=1
+ fi
+ fi
+ return ${failed}
+}
+
+
+#
+# atf
+#
+additem atf "install missing atf configuration files and validate them"
+do_atf()
+{
+ [ -n "$1" ] || err 3 "USAGE: do_atf fix|check"
+ op="$1"
+ failed=0
+
+ # Ensure atf configuration files are in place.
+ if find_file_in_dirlist NetBSD.conf "NetBSD.conf" \
+ "${SRC_DIR}/external/bsd/atf/etc/atf" \
+ "${SRC_DIR}/etc/atf"; then
+ # ${dir} is set by find_file_in_dirlist()
+ populate_dir "${op}" true "${dir}" "${DEST_DIR}/etc/atf" 644 \
+ NetBSD.conf common.conf || failed=1
+ else
+ failed=1
+ fi
+ if find_file_in_dirlist atf-run.hooks "atf-run.hooks" \
+ "${SRC_DIR}/external/bsd/atf/dist/atf-run/sample" \
+ "${SRC_DIR}/etc/atf"; then
+ # ${dir} is set by find_file_in_dirlist()
+ populate_dir "${op}" true "${dir}" "${DEST_DIR}/etc/atf" 644 \
+ atf-run.hooks || failed=1
+ else
+ failed=1
+ fi
+
+ # Validate the _atf to _tests user/group renaming.
+ if [ -f "${DEST_DIR}/etc/atf/common.conf" ]; then
+ handle_atf_user "${op}" || failed=1
+ else
+ failed=1
+ fi
+
+ return ${failed}
+}
+
+handle_atf_user()
+{
+ local op="$1"
+ local failed=0
+
+ local conf="${DEST_DIR}/etc/atf/common.conf"
+ if grep '[^#]*unprivileged-user[ \t]*=.*_atf' "${conf}" >/dev/null
+ then
+ if [ "$1" = "fix" ]; then
+ sed -e \
+ "/[^#]*unprivileged-user[\ t]*=/s/_atf/_tests/" \
+ "${conf}" >"${conf}.new"
+ failed=$(( ${failed} + $? ))
+ mv "${conf}.new" "${conf}"
+ failed=$(( ${failed} + $? ))
+ msg "Set unprivileged-user=_tests in ${conf}"
+ else
+ msg "unprivileged-user=_atf in ${conf} should be" \
+ "unprivileged-user=_tests"
+ failed=1
+ fi
+ fi
+
+ return ${failed}
+}
+
+#
+# catpages
+#
+obsolete_catpages()
+{
+ basedir="$2"
+ section="$3"
+ mandir="${basedir}/man${section}"
+ catdir="${basedir}/cat${section}"
+ test -d "$mandir" || return 0
+ test -d "$catdir" || return 0
+ (cd "$mandir" && find . -type f) | {
+ failed=0
+ while read manpage; do
+ manpage="${manpage#./}"
+ case "$manpage" in
+ *.Z)
+ catname="$catdir/${manpage%.*.Z}.0"
+ ;;
+ *.gz)
+ catname="$catdir/${manpage%.*.gz}.0"
+ ;;
+ *)
+ catname="$catdir/${manpage%.*}.0"
+ ;;
+ esac
+ test -e "$catname" -a "$catname" -ot "$mandir/$manpage" || continue
+ if [ "$1" = "fix" ]; then
+ rm "$catname"
+ failed=$(( ${failed} + $? ))
+ msg "Removed obsolete cat page $catname"
+ else
+ msg "Obsolete cat page $catname"
+ failed=1
+ fi
+ done
+ exit $failed
+ }
+}
+
+additem catpages "remove outdated cat pages"
+do_catpages()
+{
+ failed=0
+ for manbase in /usr/share/man /usr/X11R6/man /usr/X11R7/man; do
+ for sec in 1 2 3 4 5 6 7 8 9; do
+ obsolete_catpages "$1" "${DEST_DIR}${manbase}" "${sec}"
+ failed=$(( ${failed} + $? ))
+ if [ "$1" = "fix" ]; then
+ rmdir "${DEST_DIR}${manbase}/cat${sec}"/* \
+ 2>/dev/null
+ rmdir "${DEST_DIR}${manbase}/cat${sec}" \
+ 2>/dev/null
+ fi
+ done
+ done
+ return $failed
+}
+
+#
+# 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_libs /usr/X11R7/lib
+ [ "$MACHINE" = "amd64" ] && obsolete_libs /usr/lib/i386
+ [ "$MACHINE" = "sparc64" ] && obsolete_libs /usr/lib/sparc
+ ) | obsolete_paths "${op}"
+ failed=$(( ${failed} + $? ))
+
+ return ${failed}
+}
+
+
+#
+# ptyfsoldnodes
+#
+additem ptyfsoldnodes "remove legacy device nodes when using ptyfs"
+do_ptyfsoldnodes()
+{
+ [ -n "$1" ] || err 3 "USAGE: do_ptyfsoldnodes fix|check"
+ _ptyfs_op="$1"
+
+ # Check whether ptyfs is in use
+ failed=0;
+ if ! ${GREP} -E "^ptyfs" "${DEST_DIR}/etc/fstab" > /dev/null; then
+ msg "ptyfs is not in use"
+ return 0
+ fi
+
+ # Find the device major numbers for the pty master and slave
+ # devices, by parsing the output from "MAKEDEV -s pty0".
+ #
+ # Output from MAKEDEV looks like this:
+ # ./ttyp0 type=char device=netbsd,5,0 mode=666 gid=0 uid=0
+ # ./ptyp0 type=char device=netbsd,6,0 mode=666 gid=0 uid=0
+ #
+ # Output from awk, used in the eval statement, looks like this:
+ # maj_ptym=6; maj_ptys=5;
+ #
+ eval "$(
+ ${HOST_SH} "${DEST_DIR}/dev/MAKEDEV" -s pty0 2>/dev/null \
+ | ${AWK} '\
+ BEGIN { before_re = ".*device=[a-zA-Z]*,"; after_re = ",.*"; }
+ /ptyp0/ { maj_ptym = gensub(before_re, "", 1, $0);
+ maj_ptym = gensub(after_re, "", 1, maj_ptym); }
+ /ttyp0/ { maj_ptys = gensub(before_re, "", 1, $0);
+ maj_ptys = gensub(after_re, "", 1, maj_ptys); }
+ END { print "maj_ptym=" maj_ptym "; maj_ptys=" maj_ptys ";"; }
+ '
+ )"
+ #msg "Major numbers are maj_ptym=${maj_ptym} maj_ptys=${maj_ptys}"
+ if [ -z "$maj_ptym" ] || [ -z "$maj_ptys" ]; then
+ msg "Cannot find device major numbers for pty master and slave"
+ return 1
+ fi
+
+ # look for /dev/[pt]ty[p-zP-T][0-9a-zA-Z], and check that they
+ # have the expected device major numbers. ttyv* is typically not a
+ # pty device, but we check it anyway.
+ #
+ # The "for d1" loop is intended to avoid overflowing ARG_MAX;
+ # otherwise we could have used a single glob pattern.
+ #
+ # If there are no files that match a particular pattern,
+ # then stat prints something like:
+ # stat: /dev/[pt]tyx?: lstat: No such file or directory
+ # and we ignore it. XXX: We also ignore other error messages.
+ #
+ _ptyfs_tmp="$(mktemp /tmp/postinstall.ptyfs.XXXXXXXX)"
+ for d1 in p q r s t u v w x y z P Q R S T; do
+ ${STAT} -f "%Hr %N" "${DEST_DIR}/dev/"[pt]ty${d1}? 2>&1
+ done \
+ | while read -r major node ; do
+ case "$major" in
+ ${maj_ptym}|${maj_ptys}) echo "$node" ;;
+ esac
+ done >"${_ptyfs_tmp}"
+
+ _desc="legacy device node"
+ while read node; do
+ if [ "${_ptyfs_op}" = "check" ]; then
+ msg "Remove ${_desc} ${node}"
+ failed=1
+ else # "fix"
+ if rm "${node}"; then
+ msg "Removed ${_desc} ${node}"
+ else
+ warn "Failed to remove ${_desc} ${node}"
+ failed=1
+ fi
+ fi
+ done < "${_ptyfs_tmp}"
+ rm "${_ptyfs_tmp}"
+
+ 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". Pass multiple -s options to specify
+ multiple 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 explicitly):"
+ echo " Item Description"
+ echo " ---- -----------"
+ for i in ${otheritems}; do
+ eval desc=\"\${desc_${i}}\"
+ printf " %-12s %s\n" "${i}" "${desc}"
+ done
+
+}
+
+
+main()
+{
+ TGZLIST= # quoted list list of tgz files
+ SRC_ARGLIST= # quoted list of one or more "-s" args
+ SRC_DIR="${SRC_ARG}" # set default value for early usage()
+ N_SRC_ARGS=0 # number of "-s" args
+ TGZMODE=false # true if "-s" specifies a tgz file
+ DIRMODE=false # true if "-s" specified a directory
+ SOURCEMODE=false # true if "-s" specified a source directory
+
+ while getopts s:d:m:a: ch; do
+ case "${ch}" in
+ s)
+ qarg="$(shell_quote "${OPTARG}")"
+ N_SRC_ARGS=$(( $N_SRC_ARGS + 1 ))
+ SRC_ARGLIST="${SRC_ARGLIST}${SRC_ARGLIST:+ }-s ${qarg}"
+ if [ -f "${OPTARG}" ]; then
+ # arg refers to a *.tgz file.
+ # This may happen twice, for both
+ # etc.tgz and xetc.tgz, so we build up a
+ # quoted list in TGZLIST.
+ TGZMODE=true
+ TGZLIST="${TGZLIST}${TGZLIST:+ }${qarg}"
+ # Note that, when TGZMODE is true,
+ # SRC_ARG is used only for printing
+ # human-readable messages.
+ SRC_ARG="${TGZLIST}"
+ elif [ -d "${OPTARG}" ]; then
+ # arg refers to a directory.
+ # It might be a source directory, or a
+ # directory where the sets have already
+ # been extracted.
+ DIRMODE=true
+ SRC_ARG="${OPTARG}"
+ if [ -f "${OPTARG}/etc/Makefile" ]; then
+ SOURCEMODE=true
+ fi
+ 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 [ "$N_SRC_ARGS" -gt 1 ] && $DIRMODE; then
+ err 2 "Multiple -s args are allowed only with tgz files"
+ fi
+ if [ "$N_SRC_ARGS" -eq 0 ]; then
+ # The default SRC_ARG was set elsewhere
+ DIRMODE=true
+ SOURCEMODE=true
+ SRC_ARGLIST="-s $(shell_quote "${SRC_ARG}")"
+ fi
+
+ #
+ # If '-s' arg or args specified tgz files, extract them
+ # to a scratch directory.
+ #
+ if $TGZMODE; then
+ ETCTGZDIR="${SCRATCHDIR}/etc.tgz"
+ echo "Note: Creating temporary directory ${ETCTGZDIR}"
+ if ! mkdir "${ETCTGZDIR}"; then
+ err 2 "Can't create ${ETCTGZDIR}"
+ fi
+ ( # subshell to localise changes to "$@"
+ eval "set -- ${TGZLIST}"
+ for tgz in "$@"; do
+ echo "Note: Extracting files from ${tgz}"
+ cat "${tgz}" | (
+ cd "${ETCTGZDIR}" &&
+ tar -zxf -
+ ) || err 2 "Can't extract ${tgz}"
+ done
+ )
+ 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 ! $SOURCEMODE && ! [ -f "${SRC_DIR}/etc/mtree/set.etc" ]; then
+ err 2 "Files from the etc.tgz set are missing"
+ fi
+
+ # 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=""
+
+ detect_x11
+
+ 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 $TGZMODE; 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 $TGZMODE; 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} ${SRC_ARGLIST} -d ${DEST_DIR:-/}$m fix${items_failed}
+Note that this may overwrite local changes.
+_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