Home | History | Annotate | Line # | Download | only in postinstall
postinstall.in revision 1.63
      1 #!/bin/sh
      2 #
      3 # $NetBSD: postinstall.in,v 1.63 2024/04/05 16:44:54 christos Exp $
      4 #
      5 # Copyright (c) 2002-2022 The NetBSD Foundation, Inc.
      6 # All rights reserved.
      7 #
      8 # This code is derived from software contributed to The NetBSD Foundation
      9 # by Luke Mewburn.
     10 #
     11 # Redistribution and use in source and binary forms, with or without
     12 # modification, are permitted provided that the following conditions
     13 # are met:
     14 # 1. Redistributions of source code must retain the above copyright
     15 #    notice, this list of conditions and the following disclaimer.
     16 # 2. Redistributions in binary form must reproduce the above copyright
     17 #    notice, this list of conditions and the following disclaimer in the
     18 #    documentation and/or other materials provided with the distribution.
     19 #
     20 # THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
     21 # ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     22 # TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     23 # PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
     24 # BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     25 # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     26 # SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     27 # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     28 # CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     29 # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     30 # POSSIBILITY OF SUCH DAMAGE.
     31 #
     32 # postinstall
     33 #	Check for or fix configuration changes that occur
     34 #	over time as NetBSD evolves.
     35 #
     36 
     37 #
     38 # NOTE: Be sure to use ${DEST_DIR} prefix before all real file operations.
     39 #
     40 
     41 #
     42 # checks to add:
     43 #	- sysctl(8) renames (net.inet6.ip6.bindv6only -> net.inet6.ip6.v6only)
     44 #	- de* -> tlp* migration (/etc/ifconfig.de*, $ifconfig_de*, ...) ?
     45 #	- support quiet/verbose mode ?
     46 #	- differentiate between failures caused by missing source
     47 #	  and real failures
     48 #	- install moduli into usr/share/examples/ssh and use from there?
     49 #	- differentiate between "needs fix" versus "can't fix" issues
     50 #
     51 
     52 # This script is executed as part of a cross build.  Allow the build
     53 # environment to override the locations of some tools.
     54 : ${AWK:=awk}
     55 : ${DB:=db}
     56 : ${GREP:=grep}
     57 : ${HOST_SH:=sh}
     58 : ${MAKE:=make}
     59 : ${PWD_MKDB:=/usr/sbin/pwd_mkdb}
     60 : ${SED:=sed}
     61 : ${SORT:=sort}
     62 : ${STAT:=stat}
     63 : ${RM:=rm}
     64 
     65 #
     66 #	helper functions
     67 #
     68 
     69 err()
     70 {
     71 	local exitval=$1
     72 	shift
     73 	echo 1>&2 "${PROGNAME}: $*"
     74 	if [ -n "${SCRATCHDIR}" ]; then
     75 	    ${RM} -rf "${SCRATCHDIR}"
     76 	fi
     77 	exit ${exitval}
     78 }
     79 
     80 warn()
     81 {
     82 	echo 1>&2 "${PROGNAME}: $*"
     83 }
     84 
     85 msg()
     86 {
     87 	echo "	$*"
     88 }
     89 
     90 mkdtemp()
     91 {
     92 	# Make sure we don't loop forever if mkdir will always fail.
     93 	[ -d /tmp ] || err 2 /tmp is not a directory
     94 	[ -w /tmp ] || err 2 /tmp is not writable
     95 
     96 	local base="/tmp/_postinstall.$$"
     97 	local serial=0
     98 	local dir
     99 
    100 	while true; do
    101 		dir="${base}.${serial}"
    102 		mkdir -m 0700 "${dir}" && break
    103 		serial=$((${serial} + 1))
    104 	done
    105 	echo "${dir}"
    106 }
    107 
    108 # Quote args to make them safe in the shell.
    109 # Usage: quotedlist="$(shell_quote args...)"
    110 #
    111 # After building up a quoted list, use it by evaling it inside
    112 # double quotes, like this:
    113 #    eval "set -- $quotedlist"
    114 # or like this:
    115 #    eval "\$command $quotedlist \$filename"
    116 #
    117 shell_quote()
    118 {(
    119 	local result=''
    120 	local arg qarg
    121 	LC_COLLATE=C ; export LC_COLLATE # so [a-zA-Z0-9] works in ASCII
    122 	for arg in "$@" ; do
    123 		case "${arg}" in
    124 		'')
    125 			qarg="''"
    126 			;;
    127 		*[!-./a-zA-Z0-9]*)
    128 			# Convert each embedded ' to '\'',
    129 			# then insert ' at the beginning of the first line,
    130 			# and append ' at the end of the last line.
    131 			# Finally, elide unnecessary '' pairs at the
    132 			# beginning and end of the result and as part of
    133 			# '\'''\'' sequences that result from multiple
    134 			# adjacent quotes in he input.
    135 			qarg="$(printf "%s\n" "$arg" | \
    136 			    ${SED} -e "s/'/'\\\\''/g" \
    137 				-e "1s/^/'/" -e "\$s/\$/'/" \
    138 				-e "1s/^''//" -e "\$s/''\$//" \
    139 				-e "s/'''/'/g"
    140 				)"
    141 			;;
    142 		*)
    143 			# Arg is not the empty string, and does not contain
    144 			# any unsafe characters.  Leave it unchanged for
    145 			# readability.
    146 			qarg="${arg}"
    147 			;;
    148 		esac
    149 		result="${result}${result:+ }${qarg}"
    150 	done
    151 	printf "%s\n" "$result"
    152 )}
    153 
    154 # Convert arg $1 to a basic regular expression (as in sed)
    155 # that will match the arg.  This works by inserting backslashes
    156 # before characters that are special in basic regular expressions.
    157 # It also inserts backslashes before the extra characters specified
    158 # in $2 (which defaults to "/,").
    159 # XXX: Does not handle embedded newlines.
    160 # Usage: regex="$(bre_quote "${string}")"
    161 bre_quote()
    162 {
    163 	local arg="$1"
    164 	local extra="${2-/,}"
    165 	printf "%s\n" "${arg}" | ${SED} -e 's/[][^$.*\\'"${extra}"']/\\&/g'
    166 }
    167 
    168 # unprefix dir
    169 #	Remove any dir prefix from a list of paths on stdin,
    170 #	and write the result to stdout.  Useful for converting
    171 #	from ${DEST_DIR}/path to /path.
    172 #
    173 unprefix()
    174 {
    175 	[ $# -eq 1 ] || err 3 "USAGE: unprefix dir"
    176 	local prefix="${1%/}"
    177 	prefix="$(bre_quote "${prefix}")"
    178 
    179 	${SED} -e "s,^${prefix}/,/,"
    180 }
    181 
    182 # additem item description
    183 #	Add item to list of supported items to check/fix,
    184 #	which are checked/fixed by default if no item is requested by user.
    185 #
    186 additem()
    187 {
    188 	[ $# -eq 2 ] || err 3 "USAGE: additem item description"
    189 	defaultitems="${defaultitems}${defaultitems:+ }$1"
    190 	eval desc_$1=\"\$2\"
    191 }
    192 
    193 # adddisableditem item description
    194 #	Add item to list of supported items to check/fix,
    195 #	but execute the item only if the user asks for it explicitly.
    196 #
    197 adddisableditem()
    198 {
    199 	[ $# -eq 2 ] || err 3 "USAGE: adddisableditem item description"
    200 	otheritems="${otheritems}${otheritems:+ }$1"
    201 	eval desc_$1=\"\$2\"
    202 }
    203 
    204 # checkdir op dir mode
    205 #	Ensure dir exists, and if not, create it with the appropriate mode.
    206 #	Returns 0 if ok, 1 otherwise.
    207 #
    208 check_dir()
    209 {
    210 	[ $# -eq 3 ] || err 3 "USAGE: check_dir op dir mode"
    211 	local op="$1"
    212 	local dir="$2"
    213 	local mode="$3"
    214 	[ -d "${dir}" ] && return 0
    215 	if [ "${op}" = "check" ]; then
    216 		msg "${dir} is not a directory"
    217 		return 1
    218 	elif ! mkdir -m "${mode}" "${dir}" ; then
    219 		msg "Can't create missing ${dir}"
    220 		return 1
    221 	else
    222 		msg "Missing ${dir} created"
    223 	fi
    224 	return 0
    225 }
    226 
    227 # check_ids op type file srcfile start id ...
    228 #	Check if file of type "users" or "groups" contains the relevant IDs.
    229 #	Use srcfile as a reference for the expected contents.
    230 #	The specified "id" names should be given in numerical order,
    231 #	with the first name corresponding to numerical value "start",
    232 #	and with the special name "SKIP" being used to mark gaps in the
    233 #	sequence.
    234 #	Returns 0 if ok, 1 otherwise.
    235 #
    236 check_ids()
    237 {
    238 	[ $# -ge 6 ] || err 3 "USAGE: checks_ids op type file srcfile start id ..."
    239 	local op="$1"
    240 	local type="$2"
    241 	local file="$3"
    242 	local srcfile="$4"
    243 	local start="$5"
    244 	shift 5
    245 	#local ids="$@"
    246 
    247 	if [ ! -f "${file}" ]; then
    248 		msg "${file} doesn't exist; can't check for missing ${type}"
    249 		return 1
    250 	fi
    251 	if [ ! -r "${file}" ]; then
    252 		msg "${file} is not readable; can't check for missing ${type}"
    253 		return 1
    254 	fi
    255 	local notfixed=""
    256 	if [ "${op}" = "fix" ]; then
    257 		notfixed="${NOT_FIXED}"
    258 	fi
    259 	local missing="$(${AWK} -v start=$start -F: '
    260 		BEGIN {
    261 			for (x = 1; x < ARGC; x++) {
    262 				if (ARGV[x] == "SKIP")
    263 					continue;
    264 				idlist[ARGV[x]]++;
    265 				value[ARGV[x]] = start + x - 1;
    266 			}
    267 			ARGC=1
    268 		}
    269 		{
    270 			found[$1]++
    271 			number[$1] = $3
    272 		}
    273 		END {
    274 			for (id in idlist) {
    275 				if (!(id in found))
    276 					printf("%s (missing)\n", id)
    277 				else if (number[id] != value[id])
    278 					printf("%s (%d != %d)\n", id,
    279 					    number[id], value[id])
    280 				start++;
    281 			}
    282 		}
    283 	' "$@" < "${file}")"	|| return 1
    284 	if [ -n "${missing}" ]; then
    285 		msg "Error ${type}${notfixed}:" $(echo ${missing})
    286 		msg "Use the following as a template:"
    287 		set -- ${missing}
    288 		while [ $# -gt 0 ]
    289 		do
    290 			${GREP} -E "^${1}:" ${srcfile}
    291 			shift 2
    292 		done | sort -t: -k3n
    293 		msg "and adjust if necessary."
    294 		return 1
    295 	fi
    296 	return 0
    297 }
    298 
    299 # populate_dir op onlynew src dst mode file ...
    300 #	Perform op ("check" or "fix") on files in src/ against dst/
    301 #	If op = "check" display missing or changed files, optionally with diffs.
    302 #	If op != "check" copies any missing or changed files.
    303 #	If onlynew evaluates to true, changed files are ignored.
    304 #	Returns 0 if ok, 1 otherwise.
    305 #
    306 populate_dir()
    307 {
    308 	[ $# -ge 5 ] || err 3 "USAGE: populate_dir op onlynew src dst mode file ..."
    309 	local op="$1"
    310 	local onlynew="$2"
    311 	local src="$3"
    312 	local dst="$4"
    313 	local mode="$5"
    314 	shift 5
    315 	#local files="$@"
    316 
    317 	if [ ! -d "${src}" ]; then
    318 		msg "${src} is not a directory; skipping check"
    319 		return 1
    320 	fi
    321 	check_dir "${op}" "${dst}" 755 || return 1
    322 
    323 	local cmpdir_rv=0
    324 	local f fs fd error
    325 	for f in "$@"; do
    326 		fs="${src}/${f}"
    327 		fd="${dst}/${f}"
    328 		error=""
    329 		if [ ! -f "${fd}" ]; then
    330 			error="${fd} does not exist"
    331 		elif ! cmp -s "${fs}" "${fd}" ; then
    332 			if $onlynew; then	# leave existing ${fd} alone
    333 				continue;
    334 			fi
    335 			error="${fs} != ${fd}"
    336 		else
    337 			continue
    338 		fi
    339 		if [ "${op}" = "check" ]; then
    340 			msg "${error}"
    341 			if [ -n "${DIFF_STYLE}" -a -f "${fd}" ]; then
    342 				diff -${DIFF_STYLE} ${DIFF_OPT} "${fd}" "${fs}"
    343 			fi
    344 			cmpdir_rv=1
    345 		elif ! ${RM} -f "${fd}" ||
    346 		     ! cp -f "${fs}" "${fd}"; then
    347 			msg "Can't copy ${fs} to ${fd}"
    348 			cmpdir_rv=1
    349 		elif ! chmod "${mode}" "${fd}"; then
    350 			msg "Can't change mode of ${fd} to ${mode}"
    351 			cmpdir_rv=1
    352 		else
    353 			msg "Copied ${fs} to ${fd}"
    354 		fi
    355 	done
    356 	return ${cmpdir_rv}
    357 }
    358 
    359 # compare_dir op src dst mode file ...
    360 #	Perform op ("check" or "fix") on files in src/ against dst/
    361 #	If op = "check" display missing or changed files, optionally with diffs.
    362 #	If op != "check" copies any missing or changed files.
    363 #	Returns 0 if ok, 1 otherwise.
    364 #
    365 compare_dir()
    366 {
    367 	[ $# -ge 4 ] || err 3 "USAGE: compare_dir op src dst mode file ..."
    368 	local op="$1"
    369 	local src="$2"
    370 	local dst="$3"
    371 	local mode="$4"
    372 	shift 4
    373 	#local files="$@"
    374 
    375 	populate_dir "$op" false "$src" "$dst" "$mode" "$@"
    376 }
    377 
    378 # move_file op src dst --
    379 #	Check (op == "check") or move (op != "check") from src to dst.
    380 #	Returns 0 if ok, 1 otherwise.
    381 #
    382 move_file()
    383 {
    384 	[ $# -eq 3 ] || err 3 "USAGE: move_file op src dst"
    385 	local op="$1"
    386 	local src="$2"
    387 	local dst="$3"
    388 
    389 	if [ -f "${src}" -a ! -f "${dst}" ]; then
    390 		if [ "${op}" = "check" ]; then
    391 			msg "Move ${src} to ${dst}"
    392 			return 1
    393 		fi
    394 		if ! mv "${src}" "${dst}"; then
    395 			msg "Can't move ${src} to ${dst}"
    396 			return 1
    397 		fi
    398 		msg "Moved ${src} to ${dst}"
    399 	fi
    400 	return 0
    401 }
    402 
    403 # rcconf_is_set op name var [verbose] --
    404 #	Load the rcconf for name, and check if obsolete rc.conf(5) variable
    405 #	var is defined or not.
    406 #	Returns 0 if defined (even to ""), otherwise 1.
    407 #	If verbose != "", print an obsolete warning if the var is defined.
    408 #
    409 rcconf_is_set()
    410 {
    411 	[ $# -ge 3 ] || err 3 "USAGE: rcconf_is_set op name var [verbose]"
    412 	local op="$1"
    413 	local name="$2"
    414 	local var="$3"
    415 	local verbose="$4"
    416 	local notfixed=""
    417 	if [ "${op}" = "fix" ]; then
    418 		notfixed="${NOT_FIXED}"
    419 	fi
    420 	(
    421 		for f in \
    422 		    "${DEST_DIR}/etc/rc.conf" \
    423 		    "${DEST_DIR}/etc/rc.conf.d/${name}"; do
    424 			[ -f "${f}" ] && . "${f}"
    425 		done
    426 		eval echo -n \"\${${var}}\" 1>&3
    427 		if eval "[ -n \"\${${var}+SET}\" ]"; then
    428 			if [ -n "${verbose}" ]; then
    429 				msg \
    430     "Obsolete rc.conf(5) variable '\$${var}' found.${notfixed}"
    431 			fi
    432 			exit 0
    433 		else
    434 			exit 1
    435 		fi
    436 	)
    437 }
    438 
    439 # rcvar_is_enabled var
    440 #	Check if rcvar is enabled
    441 #
    442 rcvar_is_enabled()
    443 {
    444 	[ $# -eq 1 ] || err 3 "USAGE: rcvar_is_enabled var"
    445 	local var="$1"
    446 	(
    447 		[ -f "${DEST_DIR}/etc/rc.conf" ] && . "${DEST_DIR}/etc/rc.conf"
    448 		eval val=\"\${${var}}\"
    449 		case $val in
    450 		#	"yes", "true", "on", or "1"
    451 		[Yy][Ee][Ss]|[Tt][Rr][Uu][Ee]|[Oo][Nn]|1)
    452 			exit 0
    453 			;;
    454 
    455 		*)
    456 			exit 1
    457 			;;
    458 		esac
    459 	)
    460 }
    461 
    462 # find_file_in_dirlist() file message dir1 ... --
    463 #	Find which directory file is in, and sets ${dir} to match.
    464 #	Returns 0 if matched, otherwise 1 (and sets ${dir} to "").
    465 #
    466 #	Generally, check the directory for the "checking from source" case,
    467 #	and then the directory for the "checking from extracted etc.tgz" case.
    468 #
    469 find_file_in_dirlist()
    470 {
    471 	[ $# -ge 3 ] || err 3 "USAGE: find_file_in_dirlist file msg dir1 ..."
    472 
    473 	local file="$1" ; shift
    474 	local msg="$1" ; shift
    475 	local dir1st=	# first dir in list
    476 	# returns dir
    477 	for dir in "$@"; do
    478 		: ${dir1st:="${dir}"}
    479 		if [ -f "${dir}/${file}" ]; then
    480 			if [ "${dir1st}" != "${dir}" ]; then
    481 				msg \
    482     "(Checking for ${msg} from ${dir} instead of ${dir1st})"
    483 			fi
    484 			return 0
    485 		fi
    486 	done
    487 	msg "Can't find source directory for ${msg}"
    488 	return 1
    489 }
    490 
    491 # file_exists_exact path
    492 #	Returns true if a file exists in the ${DEST_DIR} whose name
    493 #	is exactly ${path}, interpreted in a case-sensitive way
    494 #	even if the underlying file system is case-insensitive.
    495 #
    496 #	The path must begin with '/' or './', and is interpreted as
    497 #	being relative to ${DEST_DIR}.
    498 #
    499 file_exists_exact()
    500 {
    501 	[ -n "$1" ] || err 3 "USAGE: file_exists_exact path"
    502 	local path="${1#.}"
    503 	[ -h "${DEST_DIR}${path}" ] || \
    504 		[ -e "${DEST_DIR}${path}" ] || return 1
    505 	while [ "${path}" != "/" -a "${path}" != "." ] ; do
    506 		local dirname="$(dirname "${path}" 2>/dev/null)"
    507 		local basename="$(basename "${path}" 2>/dev/null)"
    508 		ls -fa "${DEST_DIR}${dirname}" 2> /dev/null \
    509 			| ${GREP} -q -F -x "${basename}" \
    510 			|| return 1
    511 		path="${dirname}"
    512 	done
    513 	return 0
    514 }
    515 
    516 # obsolete_paths op
    517 #	Obsolete the list of paths provided on stdin.
    518 #	Each path should start with '/' or './', and
    519 #	will be interpreted relative to ${DEST_DIR}.
    520 #
    521 obsolete_paths()
    522 {
    523 	[ -n "$1" ] || err 3 "USAGE: obsolete_paths fix|check"
    524 	local op="$1"
    525 	local failed=0
    526 	local ofile cmd ftype
    527 
    528 	while read ofile; do
    529 		if ! ${file_exists_exact} "${ofile}"; then
    530 			continue
    531 		fi
    532 		ofile="${DEST_DIR}${ofile#.}"
    533 		cmd="${RM}"
    534 		ftype="file"
    535 		if [ -h "${ofile}" ]; then
    536 			ftype="link"
    537 		elif [ -d "${ofile}" ]; then
    538 			ftype="directory"
    539 			cmd="rmdir"
    540 		elif [ ! -e "${ofile}" ]; then
    541 			continue
    542 		fi
    543 		if [ "${op}" = "check" ]; then
    544 			msg "Remove obsolete ${ftype} ${ofile}"
    545 			failed=1
    546 		elif ! eval "${cmd} \"\${ofile}\""; then
    547 			msg "Can't remove obsolete ${ftype} ${ofile}"
    548 			failed=1
    549 		else
    550 			msg "Removed obsolete ${ftype} ${ofile}"
    551 		fi
    552 	done
    553 	return ${failed}
    554 }
    555 
    556 # obsolete_libs dir
    557 #	Display the minor/teeny shared libraries in dir that are considered
    558 #	to be obsolete.
    559 #
    560 #	The implementation supports removing obsolete major libraries
    561 #	if the awk variable AllLibs is set, although there is no way to
    562 #	enable that in the enclosing shell function as this time.
    563 #
    564 obsolete_libs()
    565 {
    566 	[ $# -eq 1 ] || err 3 "USAGE: obsolete_libs dir"
    567 	local dir="$1"
    568 
    569 	_obsolete_libs "${dir}"
    570 	_obsolete_libs "/usr/libdata/debug/${dir}"
    571 }
    572 
    573 exclude()
    574 {
    575 	local dollar
    576 	case "$1" in
    577 	-t)
    578 		dollar='$'
    579 		shift
    580 		;;
    581 	*)
    582 		dollar=
    583 		;;
    584 	esac
    585 	if [ -z "$*" ]; then
    586 		cat
    587 	else
    588 		eval ${GREP} -v -E "'(^$(echo $* | \
    589 		    ${SED} -e s/\\./\\\\./g -e 's/ /'${dollar}'|^/'g)${dollar})'"
    590 	fi
    591 }
    592 
    593 #
    594 # find all the target symlinks of shared libraries and exclude them
    595 # from consideration for removal
    596 #
    597 exclude_libs()
    598 {
    599 	local target="$(ls -l -d lib*.so.* 2> /dev/null \
    600 	    | ${AWK} '{ print $11; }' \
    601 	    | ${SED} -e 's@.*/@@' | ${SORT} -u)"
    602 	exclude -t ${target}
    603 }
    604 
    605 _obsolete_libs()
    606 {
    607 	local dir="$1"
    608 
    609 	(
    610 
    611 	if [ ! -e "${DEST_DIR}/${dir}" ]
    612 	then
    613 		return 0
    614 	fi
    615 
    616 	cd "${DEST_DIR}/${dir}" || err 2 "can't cd to ${DEST_DIR}/${dir}"
    617 	echo lib*.so.* \
    618 	| tr ' ' '\n' \
    619 	| ${AWK} -v LibDir="${dir}/" '
    620 #{
    621 
    622 function digit(v, c, n) { return (n <= c) ? v[n] : 0 }
    623 
    624 function checklib(results, line, regex) {
    625 	if (! match(line, regex))
    626 		return
    627 	lib = substr(line, RSTART, RLENGTH)
    628 	rev = substr($0, RLENGTH+1)
    629 	if (! (lib in results)) {
    630 		results[lib] = rev
    631 		return
    632 	}
    633 	orevc = split(results[lib], orev, ".")
    634 	nrevc = split(rev, nrev, ".")
    635 	maxc = (orevc > nrevc) ? orevc : nrevc
    636 	for (i = 1; i <= maxc; i++) {
    637 		res = digit(orev, orevc, i) - digit(nrev, nrevc, i)
    638 		if (res < 0) {
    639 			print LibDir lib results[lib]
    640 			results[lib] = rev
    641 			return
    642 		} else if (res > 0) {
    643 			print LibDir lib rev
    644 			return
    645 		}
    646 	}
    647 }
    648 
    649 /^lib.*\.so\.[0-9]+\.[0-9]+(\.[0-9]+)?(\.debug)?$/ {
    650 	if (AllLibs)
    651 		checklib(minor, $0, "^lib.*\\.so\\.")
    652 	else
    653 		checklib(found, $0, "^lib.*\\.so\\.[0-9]+\\.")
    654 }
    655 
    656 /^lib.*\.so\.[0-9]+$/ {
    657 	if (AllLibs)
    658 		checklib(major, $0, "^lib.*\\.so\\.")
    659 }
    660 
    661 #}' | exclude_libs
    662 
    663 	)
    664 }
    665 
    666 # obsolete_stand dir
    667 #	Prints the names of all obsolete files and subdirs below the
    668 #	provided dir.  dir should be something like /stand/${MACHINE}.
    669 #	The input dir and all output paths are interpreted
    670 #	relative to ${DEST_DIR}.
    671 #
    672 #	Assumes that the numerically largest subdir is current, and all
    673 #	others are obsolete.
    674 #
    675 obsolete_stand()
    676 {
    677 	[ $# -eq 1 ] || err 3 "USAGE: obsolete_stand dir"
    678 	local dir="$1"
    679 	local subdir
    680 
    681 	if ! [ -d "${DEST_DIR}${dir}" ]; then
    682 		msg "${DEST_DIR}${dir} doesn't exist; can't check for obsolete files"
    683 		return 1
    684 	fi
    685 
    686 	( cd "${DEST_DIR}${dir}" && ls -1d [0-9]*[0-9]/. ) \
    687 	| ${GREP} -v '[^0-9./]' \
    688 	| sort -t. -r -n -k1,1 -k2,2 -k3,3 \
    689 	| tail -n +2 \
    690 	| while read subdir ; do
    691 		subdir="${subdir%/.}"
    692 		find "${DEST_DIR}${dir}/${subdir}" -depth -print
    693 	done \
    694 	| unprefix "${DEST_DIR}"
    695 }
    696 
    697 # modify_file op srcfile scratchfile awkprog
    698 #	Apply awkprog to srcfile sending output to scratchfile, and
    699 #	if appropriate replace srcfile with scratchfile.
    700 #
    701 modify_file()
    702 {
    703 	[ $# -eq 4 ] || err 3 "USAGE: modify_file op file scratch awkprog"
    704 
    705 	local op="$1"
    706 	local file="$2"
    707 	local scratch="$3"
    708 	local prog="$4"
    709 	local failed=0
    710 	local line
    711 
    712 	${AWK} "${prog}" < "${file}" > "${scratch}"
    713 	if ! cmp -s "${file}" "${scratch}"; then
    714 		diff "${file}" "${scratch}" > "${scratch}.diffs"
    715 		if [ "${op}" = "check" ]; then
    716 			msg "${file} needs the following changes:"
    717 			mffailed=1
    718 		elif ! ${RM} -f "${file}" ||
    719 		     ! cp -f "${scratch}" "${file}"; then
    720 			msg "${file} changes not applied:"
    721 			mffailed=1
    722 		else
    723 			msg "${file} changes applied:"
    724 		fi
    725 		while read line; do
    726 			msg "	${line}"
    727 		done < "${scratch}.diffs"
    728 	fi
    729 	return ${failed}
    730 }
    731 
    732 
    733 # contents_owner op directory user group
    734 #	Make sure directory and contents are owned (and group-owned)
    735 #	as specified.
    736 #
    737 contents_owner()
    738 {
    739 	[ $# -eq 4 ] || err 3 "USAGE: contents_owner op dir user group"
    740 
    741 	local op="$1"
    742 	local dir="$2"
    743 	local user="$3"
    744 	local grp="$4"
    745 	local files error
    746 
    747 	if [ "${op}" = "check" ]; then
    748 		files=$(find "${dir}" \( \( ! -user "${user}" \) -o \
    749 		                \( ! -group "${grp}" \) \) )
    750 		error=$?
    751 		if [ ! -z "$files" ] || [ $error != 0 ]; then
    752 			msg "${dir} and contents not all owned by" \
    753 			    "${user}:${grp}"
    754 			return 1
    755 		else
    756 			return 0
    757 		fi
    758 	elif [ "${op}" = "fix" ]; then
    759 		find "${dir}" \( \( ! -user "${user}" \) -o \
    760 		\( ! -group "${grp}" \) \) \
    761 		-exec chown "${user}:${grp}" -- {} \;
    762 	fi
    763 }
    764 
    765 # get_makevar var ...
    766 #	Retrieve the value of a user-settable system make variable
    767 get_makevar()
    768 {
    769 	local var value
    770 	$SOURCEMODE || err 3 "get_makevar must be used in source mode"
    771 	[ $# -eq 0 ] && err 3 "USAGE: get_makevar var ..."
    772 
    773 	for var in "$@"; do
    774 		value="$(echo '.include <bsd.own.mk>' | \
    775 		    ${MAKE} -f - -V "\${${var}}")"
    776 
    777 		eval ${var}=\"\${value}\"
    778 	done
    779 }
    780 
    781 # detect_x11
    782 #	Detect if X11 components should be analysed and set values of
    783 #	relevant variables.
    784 detect_x11()
    785 {
    786 	if $SOURCEMODE; then
    787 		get_makevar MKX11 X11ROOTDIR X11SRCDIR
    788 	else
    789 		if [ -f "${SRC_DIR}/etc/mtree/set.xetc" ]; then
    790 			MKX11=yes
    791 			X11ROOTDIR=/this/value/isnt/used/yet
    792 		else
    793 			MKX11=no
    794 			X11ROOTDIR=
    795 		fi
    796 		X11SRCDIR=/nonexistent/xsrc
    797 	fi
    798 }
    799 
    800 #
    801 #	find out where MAKEDEV lives, set MAKEDEV_DIR appropriately
    802 #
    803 find_makedev()
    804 {
    805 	if [ -e "${DEST_DIR}/dev/MAKEDEV" ]; then
    806 		MAKEDEV_DIR="${DEST_DIR}/dev"
    807 	elif [ -e "${DEST_DIR}/etc/MAKEDEV" ]; then
    808 		MAKEDEV_DIR="${DEST_DIR}/etc"
    809 	else
    810 		MAKEDEV_DIR="${DEST_DIR}/dev"
    811 	fi
    812 }
    813 
    814 
    815 #
    816 #	items
    817 #	-----
    818 #
    819 # NOTE: Keep these items sorted, except for obsolete* which are listed last.
    820 #
    821 
    822 #
    823 #	atf
    824 #
    825 
    826 handle_atf_user()
    827 {
    828 	local op="$1"
    829 	local conf="$2"
    830 	local option="unprivileged-user"
    831 	local old="_atf"
    832 	local new="_tests"
    833 	local failed=0
    834 
    835 	local c=$(readlink -f "${conf}")
    836 	if ${GREP} -q "[^#]*${option}[ \t]*=.*${old}" "${c}"
    837 	then
    838 		if [ "${op}" = "fix" ]; then
    839 			${SED} -e "/[^#]*${option}[\ t]*=/s/${old}/${new}/" \
    840 			    "${c}" >"${c}.new"
    841 			failed=$(( ${failed} + $? ))
    842 			mv "${c}.new" "${c}"
    843 			failed=$(( ${failed} + $? ))
    844 			msg "Set ${option}=${new} in ${c}"
    845 		else
    846 			msg "${option}=${old} in ${c} should be " \
    847 			    "${option}=${new}"
    848 			failed=1
    849 		fi
    850 	fi
    851 
    852 	return ${failed}
    853 }
    854 
    855 additem atf "install missing atf configuration files and validate them"
    856 do_atf()
    857 {
    858 	[ -n "$1" ] || err 3 "USAGE: do_atf fix|check"
    859 	local conf="${DEST_DIR}/etc/atf/common.conf"
    860 	local atfdir="${DEST_DIR}/etc/atf"
    861 	local op="$1"
    862 	local failed=0
    863 
    864 	# Ensure atf configuration files are in place.
    865 	if find_file_in_dirlist NetBSD.conf "NetBSD.conf" \
    866 	    "${SRC_DIR}/external/bsd/atf/etc/atf" \
    867 	    "${SRC_DIR}/etc/atf"; then
    868 		    # ${dir} is set by find_file_in_dirlist()
    869 		    populate_dir "${op}" true "${dir}" "${atfdir}" 644 \
    870 		    NetBSD.conf common.conf || failed=1
    871 	else
    872 		failed=1
    873 	fi
    874 	if find_file_in_dirlist atf-run.hooks "atf-run.hooks" \
    875 	    "${SRC_DIR}/external/bsd/atf/dist/tools/sample" \
    876 	    "${SRC_DIR}/etc/atf"; then
    877 		# ${dir} is set by find_file_in_dirlist()
    878 		populate_dir "${op}" true "${dir}" "${atfdir}" 644 \
    879 		    atf-run.hooks || failed=1
    880 	else
    881 		failed=1
    882 	fi
    883 
    884 	# Validate the _atf to _tests user/group renaming.
    885 	if [ -f "${conf}" ]; then
    886 		handle_atf_user "${op}" "${conf}" || failed=1
    887 	else
    888 		failed=1
    889 	fi
    890 
    891 	return ${failed}
    892 }
    893 
    894 
    895 #
    896 #	autofsconfig
    897 #
    898 
    899 additem autofsconfig "automounter configuration files"
    900 do_autofsconfig()
    901 {
    902 	[ -n "$1" ] || err 3 "USAGE: do_autofsconfig fix|check"
    903 	local autofs_files="
    904 include_ldap
    905 include_nis
    906 special_hosts
    907 special_media
    908 special_noauto
    909 special_null
    910 "
    911 	local op="$1"
    912 	local failed=0
    913 
    914 	if [ "$op" = "fix" ]; then
    915 		mkdir -p "${DEST_DIR}/etc/autofs"
    916 	fi
    917 	failed=$(( ${failed} + $? ))
    918 	populate_dir "$op" true "${SRC_DIR}/etc" \
    919 	    "${DEST_DIR}/etc" \
    920 	    644 \
    921 	    auto_master
    922 	failed=$(( ${failed} + $? ))
    923 	populate_dir "$op" true "${SRC_DIR}/etc/autofs" \
    924 	    "${DEST_DIR}/etc/autofs" \
    925 	    644 \
    926 	    ${autofs_files}
    927 	return ${failed}
    928 }
    929 
    930 
    931 #
    932 #	blocklist
    933 #
    934 
    935 fixblock()
    936 {
    937 	local op="$1"
    938 	local target="${DEST_DIR}$2"
    939 
    940 	if [ ! -f "${target}" ]; then
    941 		continue
    942 	fi
    943 
    944 	if ${GREP} '[bB]lack' "${target}" > /dev/null; then
    945 		if [ "$1" = "check" ]; then
    946 			msg "Fix old configuration file(s)."
    947 			return 1
    948 		else
    949 			local p=$(${STAT} -f %Lp "${target}")
    950 			chmod u+w "${target}" || return 1
    951 			if [ "$2" = "/etc/npf.conf" ]; then
    952 				${SED} -i -e 's/"blacklistd"/"blocklistd"/g' "${target}"
    953 			else
    954 				${SED} -i -e 's/\([bB]\)lacklist/\1locklist/g' "${target}"
    955 			fi
    956 			chmod "${p}" "${target}"
    957 		fi
    958 	fi
    959 }
    960 
    961 additem blocklist "rename old files to blocklist"
    962 do_blocklist()
    963 {
    964 	[ -n "$1" ] || err 3 "USAGE: do_blocklist fix|check"
    965 	local op="$1"
    966 	local i old
    967 
    968 	# if we are actually using blocklistd
    969 	for i in /var/db/blacklist.db /etc/blacklistd.conf; do
    970 		old="${DEST_DIR}${i}"
    971 		if [ ! -f "${old}" ]; then
    972 			continue
    973 		elif [ "$1" = "check" ]; then
    974 			msg "Rename old file(s)."
    975 			return 1
    976 		fi
    977 		local new=$(echo "${old}" | ${SED} s/black/block/)
    978 		mv "${old}" "${new}" || return 1
    979 	done
    980 
    981 	for i in /etc/rc.conf /etc/npf.conf /etc/blocklistd.conf \
    982 	    /etc/defaults/rc.conf; do
    983 		fixblock "${op}" "${i}" || return 1
    984 	done
    985 }
    986 
    987 
    988 #
    989 #	bluetooth
    990 #
    991 
    992 additem bluetooth "Bluetooth configuration is up to date"
    993 do_bluetooth()
    994 {
    995 	[ -n "$1" ] || err 3 "USAGE: do_bluetooth fix|check"
    996 	local op="$1"
    997 	local failed=0
    998 
    999 	populate_dir "${op}" true \
   1000 		"${SRC_DIR}/etc/bluetooth" "${DEST_DIR}/etc/bluetooth" 644 \
   1001 		hosts protocols btattach.conf btdevctl.conf
   1002 	failed=$(( ${failed} + $? ))
   1003 
   1004 	move_file "${op}" "${DEST_DIR}/var/db/btdev.xml" \
   1005 			"${DEST_DIR}/var/db/btdevctl.plist"
   1006 	failed=$(( ${failed} + $? ))
   1007 
   1008 	local notfixed=""
   1009 	if [ "${op}" = "fix" ]; then
   1010 		notfixed="${NOT_FIXED}"
   1011 	fi
   1012 	for _v in btattach btconfig btdevctl; do
   1013 		if rcvar_is_enabled "${_v}"; then
   1014 			msg \
   1015     "${_v} is obsolete in rc.conf(5)${notfixed}: use bluetooth=YES"
   1016 			failed=$(( ${failed} + 1 ))
   1017 		fi
   1018 	done
   1019 
   1020 	return ${failed}
   1021 }
   1022 
   1023 
   1024 #
   1025 #	catpages
   1026 #
   1027 
   1028 obsolete_catpages()
   1029 {
   1030 	local op="$1"
   1031 	local basedir="$2"
   1032 	local section="$3"
   1033 	local mandir="${basedir}/man${section}"
   1034 	local catdir="${basedir}/cat${section}"
   1035 	test -d "$mandir" || return 0
   1036 	test -d "$catdir" || return 0
   1037 	(cd "$mandir" && find . -type f) | {
   1038 	local failed=0
   1039 	while read manpage; do
   1040 		manpage="${manpage#./}"
   1041 		case "$manpage" in
   1042 		*.Z)
   1043 			catname="$catdir/${manpage%.*.Z}.0"
   1044 			;;
   1045 		*.gz)
   1046 			catname="$catdir/${manpage%.*.gz}.0"
   1047 			;;
   1048 		*)
   1049 			catname="$catdir/${manpage%.*}.0"
   1050 			;;
   1051 		esac
   1052 		test -e "$catname" -a "$catname" -ot "$mandir/$manpage" || continue
   1053 		if [ "${op}" = "fix" ]; then
   1054 			${RM} "$catname"
   1055 			failed=$(( ${failed} + $? ))
   1056 			msg "Removed obsolete cat page $catname"
   1057 		else
   1058 			msg "Obsolete cat page $catname"
   1059 			failed=1
   1060 		fi
   1061 	done
   1062 	exit $failed
   1063 	}
   1064 }
   1065 
   1066 additem catpages "remove outdated cat pages"
   1067 do_catpages()
   1068 {
   1069 	local op="$1"
   1070 	local failed=0
   1071 	local manbase sec
   1072 	for manbase in /usr/share/man /usr/X11R6/man /usr/X11R7/man; do
   1073 		for sec in 1 2 3 4 5 6 7 8 9; do
   1074 			obsolete_catpages "$1" "${DEST_DIR}${manbase}" "${sec}"
   1075 			failed=$(( ${failed} + $? ))
   1076 			if [ "${op}" = "fix" ]; then
   1077 				rmdir "${DEST_DIR}${manbase}/cat${sec}"/* \
   1078 					2>/dev/null
   1079 				rmdir "${DEST_DIR}${manbase}/cat${sec}" \
   1080 					2>/dev/null
   1081 			fi
   1082 		done
   1083 	done
   1084 	return $failed
   1085 }
   1086 
   1087 
   1088 #
   1089 #	ddbonpanic
   1090 #
   1091 
   1092 additem ddbonpanic "verify ddb.onpanic is configured in sysctl.conf"
   1093 do_ddbonpanic()
   1094 {
   1095 	[ -n "$1" ] || err 3 "USAGE: do_ddbonpanic fix|check"
   1096 
   1097 	if ${GREP} -E '^#*[[:space:]]*ddb\.onpanic[[:space:]]*\??=[[:space:]]*[[:digit:]]+' \
   1098 		"${DEST_DIR}/etc/sysctl.conf" >/dev/null 2>&1
   1099 	then
   1100 		result=0
   1101 	else
   1102 		if [ "$1" = check ]; then
   1103 			msg \
   1104     "The ddb.onpanic behaviour is not explicitly specified in /etc/sysctl.conf"
   1105 			result=1
   1106 		else
   1107 			echo >> "${DEST_DIR}/etc/sysctl.conf"
   1108 			${SED} < "${SRC_DIR}/etc/sysctl.conf" \
   1109 			   -e '/^ddb\.onpanic/q' | \
   1110 			       ${SED} -e '1,/^$/d' >> \
   1111 			    "${DEST_DIR}/etc/sysctl.conf"
   1112 			result=$?
   1113 		fi
   1114 	fi
   1115 	return ${result}
   1116 }
   1117 
   1118 
   1119 #
   1120 #	defaults
   1121 #
   1122 
   1123 additem defaults "/etc/defaults/ being up to date"
   1124 do_defaults()
   1125 {
   1126 	[ -n "$1" ] || err 3 "USAGE: do_defaults fix|check"
   1127 	local op="$1"
   1128 	local failed=0
   1129 	local etcsets=$(getetcsets)
   1130 
   1131 	local rc_exclude_scripts=""
   1132 	if $SOURCEMODE; then
   1133 		# For most architectures rc.conf(5) should be the same as the
   1134 		# one obtained from a source directory, except for the ones
   1135 		# that have an append file for it.
   1136 		local rc_conf_app="${SRC_DIR}/etc/etc.${MACHINE}/rc.conf.append"
   1137 		if [ -f "${rc_conf_app}" ]; then
   1138 			rc_exclude_scripts="rc.conf"
   1139 
   1140 			# Generate and compare the correct rc.conf(5) file
   1141 			mkdir "${SCRATCHDIR}/defaults"
   1142 
   1143 			cat "${SRC_DIR}/etc/defaults/rc.conf" "${rc_conf_app}" \
   1144 			    > "${SCRATCHDIR}/defaults/rc.conf"
   1145 
   1146 			compare_dir "${op}" "${SCRATCHDIR}/defaults" \
   1147 			    "${DEST_DIR}/etc/defaults" \
   1148 			    444 \
   1149 			    "rc.conf"
   1150 			failed=$(( ${failed} + $? ))
   1151 		fi
   1152 	fi
   1153 
   1154 	find_file_in_dirlist pf.boot.conf "pf.boot.conf" \
   1155 	    "${SRC_DIR}/usr.sbin/pf/etc/defaults" "${SRC_DIR}/etc/defaults" \
   1156 	    || return 1
   1157 	# ${dir} is set by find_file_in_dirlist()
   1158 	compare_dir "$op" "${dir}" "${DEST_DIR}/etc/defaults" 444 pf.boot.conf
   1159 	failed=$(( ${failed} + $? ))
   1160 
   1161 	rc_exclude_scripts="${rc_exclude_scripts} pf.boot.conf"
   1162 
   1163 	local rc_default_conf_files="$(select_set_files /etc/defaults/ \
   1164 	    "/etc/defaults/\([^[:space:]]*\.conf\)" ${etcsets} | \
   1165 	    exclude ${rc_exclude_scripts})"
   1166 	compare_dir "$op" "${SRC_DIR}/etc/defaults" "${DEST_DIR}/etc/defaults" \
   1167 		444 \
   1168 		${rc_default_conf_files}
   1169 	failed=$(( ${failed} + $? ))
   1170 
   1171 
   1172 	return ${failed}
   1173 }
   1174 
   1175 
   1176 #
   1177 #	dhcpcd
   1178 #
   1179 
   1180 additem dhcpcd "dhcpcd configuration is up to date"
   1181 do_dhcpcd()
   1182 {
   1183 	[ -n "$1" ] || err 3 "USAGE: do_dhcpcd fix|check"
   1184 	local op="$1"
   1185 	local failed=0
   1186 
   1187 	find_file_in_dirlist dhcpcd.conf "dhcpcd.conf" \
   1188 	    "${SRC_DIR}/external/bsd/dhcpcd/dist/src" \
   1189 	    "${SRC_DIR}/etc" || return 1
   1190 			# ${dir} is set by find_file_in_dirlist()
   1191 	populate_dir "$op" true "${dir}" "${DEST_DIR}/etc" 644 dhcpcd.conf
   1192 	failed=$(( ${failed} + $? ))
   1193 
   1194 	check_dir "${op}" "${DEST_DIR}/var/db/dhcpcd" 755
   1195 	failed=$(( ${failed} + $? ))
   1196 
   1197 	move_file "${op}" \
   1198 		"${DEST_DIR}/etc/dhcpcd.duid" \
   1199 		"${DEST_DIR}/var/db/dhcpcd/duid"
   1200 	failed=$(( ${failed} + $? ))
   1201 
   1202 	move_file "${op}" \
   1203 		"${DEST_DIR}/etc/dhcpcd.secret" \
   1204 		"${DEST_DIR}/var/db/dhcpcd/secret"
   1205 	failed=$(( ${failed} + $? ))
   1206 
   1207 	move_file "${op}" \
   1208 		"${DEST_DIR}/var/db/dhcpcd-rdm.monotonic" \
   1209 		"${DEST_DIR}/var/db/dhcpcd/rdm_monotonic"
   1210 	failed=$(( ${failed} + $? ))
   1211 
   1212 	for lease in "${DEST_DIR}/var/db/dhcpcd-"*.lease*; do
   1213 		[ -f "${lease}" ] || continue
   1214 		new_lease=$(basename "${lease}" | ${SED} -e 's/dhcpcd-//')
   1215 		new_lease="${DEST_DIR}/var/db/dhcpcd/${new_lease}"
   1216 		move_file "${op}" "${lease}" "${new_lease}"
   1217 		failed=$(( ${failed} + $? ))
   1218 	done
   1219 
   1220 	chroot_dir="${DEST_DIR}/var/chroot/dhcpcd"
   1221 	move_file "${op}" \
   1222 		"${chroot_dir}/var/db/dhcpcd/duid" \
   1223 		"${DEST_DIR}/var/db/dhcpcd/duid"
   1224 	failed=$(( ${failed} + $? ))
   1225 
   1226 	move_file "${op}" \
   1227 		"${chroot_dir}/var/db/dhcpcd/secret" \
   1228 		"${DEST_DIR}/var/db/dhcpcd/secret"
   1229 	failed=$(( ${failed} + $? ))
   1230 
   1231 	move_file "${op}" \
   1232 		"${chroot_dir}/var/db/dhcpcd/rdm_monotonic" \
   1233 		"${DEST_DIR}/var/db/dhcpcd/rdm_monotonic"
   1234 	failed=$(( ${failed} + $? ))
   1235 
   1236 	for lease in "${chroot_dir}/var/db/dhcpcd/"*.lease*; do
   1237 		[ -f "${lease}" ] || continue
   1238 		new_lease="${DEST_DIR}/var/db/dhcpcd/$(basename ${lease})"
   1239 		move_file "${op}" "${lease}" "${new_lease}"
   1240 		failed=$(( ${failed} + $? ))
   1241 	done
   1242 
   1243 	# Ensure chroot is now empty
   1244 	for dir in \
   1245 		$(find ${chroot_dir} ! -type d) \
   1246 		$(find ${chroot_dir} -type d -mindepth 1 | sort -r)
   1247 	do
   1248 		echo "/var/chroot/dhcpcd${dir##${chroot_dir}}"
   1249 	done | obsolete_paths "${op}"
   1250 	failed=$(( ${failed} + $? ))
   1251 
   1252 	contents_owner "${op}" "${DEST_DIR}/var/db/dhcpcd" root wheel
   1253 	failed=$(( ${failed} + $? ))
   1254 
   1255 	return ${failed}
   1256 }
   1257 
   1258 
   1259 #
   1260 #	dhcpcdrundir
   1261 #
   1262 
   1263 additem dhcpcdrundir "accidentally created /@RUNDIR@ does not exist"
   1264 do_dhcpcdrundir()
   1265 {
   1266 	[ -n "$1" ] || err 3 "USAGE: do_dhcpcdrundir fix|check"
   1267 	local op="$1"
   1268 	local failed=0
   1269 
   1270 	if [ -d "${DEST_DIR}/@RUNDIR@" ]; then
   1271 		if [ "${op}" = "check" ]; then
   1272 			msg "Remove erroneously created /@RUNDIR@"
   1273 			failed=1
   1274 		elif ! ${RM} -r "${DEST_DIR}/@RUNDIR@"; then
   1275 			msg "Failed to remove ${DEST_DIR}/@RUNDIR@"
   1276 			failed=1
   1277 		else
   1278 			msg "Removed erroneously created ${DEST_DIR}/@RUNDIR@"
   1279 		fi
   1280 	fi
   1281 	return ${failed}
   1282 }
   1283 
   1284 
   1285 #
   1286 #	envsys
   1287 #
   1288 
   1289 additem envsys "envsys configuration is up to date"
   1290 do_envsys()
   1291 {
   1292 	[ -n "$1" ] || err 3 "USAGE: do_envsys fix|check"
   1293 	local op="$1"
   1294 	local failed=0
   1295 	local etcsets=$(getetcsets)
   1296 
   1297 	populate_dir "$op" true "${SRC_DIR}/etc" "${DEST_DIR}/etc" 644 \
   1298 		envsys.conf
   1299 	failed=$(( ${failed} + $? ))
   1300 
   1301 	local powerd_scripts="$(select_set_files /etc/powerd/scripts/ \
   1302 	    "/etc/powerd/scripts/\([^[:space:]/]*\)" ${etcsets})"
   1303 
   1304 	populate_dir "$op" true "${SRC_DIR}/etc/powerd/scripts" \
   1305 		"${DEST_DIR}/etc/powerd/scripts" \
   1306 		555 \
   1307 		${powerd_scripts}
   1308 	failed=$(( ${failed} + $? ))
   1309 
   1310 	return ${failed}
   1311 }
   1312 
   1313 
   1314 #
   1315 #	fontconfig
   1316 #
   1317 
   1318 additem fontconfig "X11 font configuration is up to date"
   1319 do_fontconfig()
   1320 {
   1321 	[ -n "$1" ] || err 3 "USAGE: do_fontconfig fix|check"
   1322 	local op="$1"
   1323 	local failed=0
   1324 
   1325 	# First, check for updates we can handle.
   1326 	if ! $SOURCEMODE; then
   1327 		FONTCONFIG_DIR="${SRC_DIR}/etc/fonts/conf.avail"
   1328 	else
   1329 		FONTCONFIG_DIR="${XSRC_DIR}/external/mit/fontconfig/dist/conf.d"
   1330 	fi
   1331 
   1332 	if [ ! -d "${FONTCONFIG_DIR}" ]; then
   1333 		msg "${FONTCONFIG_DIR} is not a directory; skipping check"
   1334 		return 0
   1335 	fi
   1336 	local regular_fonts="
   1337 10-autohint.conf
   1338 10-scale-bitmap-fonts.conf
   1339 10-sub-pixel-bgr.conf
   1340 10-sub-pixel-none.conf
   1341 10-sub-pixel-rgb.conf
   1342 10-sub-pixel-vbgr.conf
   1343 10-sub-pixel-vrgb.conf
   1344 10-unhinted.conf
   1345 11-lcdfilter-default.conf
   1346 11-lcdfilter-legacy.conf
   1347 11-lcdfilter-light.conf
   1348 20-unhint-small-vera.conf
   1349 25-unhint-nonlatin.conf
   1350 30-metric-aliases.conf
   1351 40-nonlatin.conf
   1352 45-generic.conf
   1353 45-latin.conf
   1354 49-sansserif.conf
   1355 50-user.conf
   1356 51-local.conf
   1357 60-generic.conf
   1358 60-latin.conf
   1359 65-fonts-persian.conf
   1360 65-khmer.conf
   1361 65-nonlatin.conf
   1362 69-unifont.conf
   1363 70-no-bitmaps.conf
   1364 70-yes-bitmaps.conf
   1365 80-delicious.conf
   1366 90-synthetic.conf
   1367 "
   1368 	populate_dir "$op" false "${FONTCONFIG_DIR}" \
   1369 	    "${DEST_DIR}/etc/fonts/conf.avail" \
   1370 	    444 \
   1371 	    ${regular_fonts}
   1372 	failed=$(( ${failed} + $? ))
   1373 
   1374 	if ! $SOURCEMODE; then
   1375 		FONTS_DIR="${SRC_DIR}/etc/fonts"
   1376 	else
   1377 		FONTS_DIR="${SRC_DIR}/external/mit/xorg/lib/fontconfig/etc"
   1378 	fi
   1379 
   1380 	populate_dir "$op" false "${FONTS_DIR}" "${DEST_DIR}/etc/fonts" 444 \
   1381 		fonts.conf
   1382 	failed=$(( ${failed} + $? ))
   1383 
   1384 	# We can't modify conf.d easily; someone might have removed a file.
   1385 
   1386 	# Look for old files that need to be deleted.
   1387 	local obsolete_fonts="
   1388 10-autohint.conf
   1389 10-no-sub-pixel.conf
   1390 10-sub-pixel-bgr.conf
   1391 10-sub-pixel-rgb.conf
   1392 10-sub-pixel-vbgr.conf
   1393 10-sub-pixel-vrgb.conf
   1394 10-unhinted.conf
   1395 25-unhint-nonlatin.conf
   1396 65-khmer.conf
   1397 70-no-bitmaps.conf
   1398 70-yes-bitmaps.conf
   1399 "
   1400 	local failed_fonts=""
   1401 	for i in ${obsolete_fonts}; do
   1402 	    if [ -f "${DEST_DIR}/etc/fonts/conf.d/$i" ]; then
   1403 		    conf_d_failed=1
   1404 		    failed_fonts="$failed_fonts $i"
   1405 	    fi
   1406 	done
   1407 
   1408 	if [ -n "$failed_fonts" ]; then
   1409 		msg \
   1410     "Broken fontconfig configuration found; please delete these files:"
   1411 		msg "[$failed_fonts]"
   1412 		failed=$(( ${failed} + 1 ))
   1413 	fi
   1414 
   1415 	return ${failed}
   1416 }
   1417 
   1418 
   1419 #
   1420 #	gid
   1421 #
   1422 
   1423 additem gid "required groups in /etc/group"
   1424 do_gid()
   1425 {
   1426 	[ -n "$1" ] || err 3 "USAGE: do_gid fix|check"
   1427 
   1428 	check_ids "$1" groups "${DEST_DIR}/etc/group" \
   1429 	    "${SRC_DIR}/etc/group" 14 \
   1430 	    named ntpd sshd SKIP _pflogd _rwhod staff _proxy _timedc \
   1431 	    _sdpd _httpd _mdnsd _tests _tcpdump _tss _gpio _rtadvd SKIP \
   1432 	    _unbound _nsd nvmm _dhcpcd
   1433 }
   1434 
   1435 
   1436 #
   1437 #	gpio
   1438 #
   1439 
   1440 additem gpio "gpio configuration is up to date"
   1441 do_gpio()
   1442 {
   1443 	[ -n "$1" ] || err 3 "USAGE: do_gpio fix|check"
   1444 	local op="$1"
   1445 	local failed=0
   1446 
   1447 	populate_dir "$op" true "${SRC_DIR}/etc" "${DEST_DIR}/etc" 644 \
   1448 		gpio.conf
   1449 	failed=$(( ${failed} + $? ))
   1450 
   1451 	return ${failed}
   1452 }
   1453 
   1454 
   1455 #
   1456 #	hosts
   1457 #
   1458 
   1459 additem hosts "/etc/hosts being up to date"
   1460 do_hosts()
   1461 {
   1462 	[ -n "$1" ] || err 3 "USAGE: do_hosts fix|check"
   1463 
   1464 	modify_file "$1" "${DEST_DIR}/etc/hosts" "${SCRATCHDIR}/hosts" '
   1465 		/^(127\.0\.0\.1|::1)[ 	]+[^\.]*$/ {
   1466 			print $0, "localhost."
   1467 			next
   1468 		}
   1469 		{ print }
   1470 	'
   1471 	return $?
   1472 }
   1473 
   1474 
   1475 #
   1476 #	iscsi
   1477 #
   1478 
   1479 additem iscsi "/etc/iscsi is populated"
   1480 do_iscsi()
   1481 {
   1482 	[ -n "$1" ] || err 3 "USAGE: do_iscsi fix|check"
   1483 
   1484 	populate_dir "${op}" true \
   1485 	    "${SRC_DIR}/etc/iscsi" "${DEST_DIR}/etc/iscsi" 600 auths
   1486 	populate_dir "${op}" true \
   1487 	    "${SRC_DIR}/etc/iscsi" "${DEST_DIR}/etc/iscsi" 644 targets
   1488 	return $?
   1489 }
   1490 
   1491 
   1492 #
   1493 #	mailerconf
   1494 #
   1495 
   1496 adddisableditem mailerconf "update /etc/mailer.conf after sendmail removal"
   1497 do_mailerconf()
   1498 {
   1499 	[ -n "$1" ] || err 3 "USAGE: do_mailterconf fix|check"
   1500 	local op="$1"
   1501 
   1502 	local failed=0
   1503 	mta_path="$(${AWK} '/^sendmail[ \t]/{print$2}' \
   1504 		"${DEST_DIR}/etc/mailer.conf")"
   1505 	old_sendmail_path="/usr/libexec/sendmail/sendmail"
   1506 	if [ "${mta_path}" = "${old_sendmail_path}" ]; then
   1507 	    if [ "$op" = check ]; then
   1508 		msg "mailer.conf points to obsolete ${old_sendmail_path}"
   1509 		failed=1;
   1510 	    else
   1511 		populate_dir "${op}" false \
   1512 		"${SRC_DIR}/etc" "${DEST_DIR}/etc" 644 mailer.conf
   1513 		failed=$?
   1514 	    fi
   1515 	fi
   1516 
   1517 	return ${failed}
   1518 }
   1519 
   1520 
   1521 #
   1522 #	makedev
   1523 #
   1524 
   1525 additem makedev "/dev/MAKEDEV being up to date"
   1526 do_makedev()
   1527 {
   1528 	[ -n "$1" ] || err 3 "USAGE: do_makedev fix|check"
   1529 	local failed=0
   1530 
   1531 	if [ -f "${SRC_DIR}/etc/MAKEDEV.tmpl" ]; then
   1532 			# generate MAKEDEV from source if source is available
   1533 		env MACHINE="${MACHINE}" \
   1534 		    MACHINE_ARCH="${MACHINE_ARCH}" \
   1535 		    NETBSDSRCDIR="${SRC_DIR}" \
   1536 		    ${AWK} -f "${SRC_DIR}/etc/MAKEDEV.awk" \
   1537 		    "${SRC_DIR}/etc/MAKEDEV.tmpl" > "${SCRATCHDIR}/MAKEDEV"
   1538 	fi
   1539 
   1540 	find_file_in_dirlist MAKEDEV "MAKEDEV" \
   1541 	    "${SCRATCHDIR}" "${SRC_DIR}/dev" \
   1542 	    || return 1
   1543 			# ${dir} is set by find_file_in_dirlist()
   1544 	find_makedev
   1545 	compare_dir "$1" "${dir}" "${MAKEDEV_DIR}" 555 MAKEDEV
   1546 	failed=$(( ${failed} + $? ))
   1547 
   1548 	find_file_in_dirlist MAKEDEV.local "MAKEDEV.local" \
   1549 	    "${SRC_DIR}/etc" "${SRC_DIR}/dev" \
   1550 	    || return 1
   1551 			# ${dir} is set by find_file_in_dirlist()
   1552 	compare_dir "$1" "${dir}" "${DEST_DIR}/dev" 555 MAKEDEV.local
   1553 	failed=$(( ${failed} + $? ))
   1554 
   1555 	return ${failed}
   1556 }
   1557 
   1558 
   1559 #
   1560 #	man.conf
   1561 #
   1562 
   1563 additem manconf "check for a mandoc usage in /etc/man.conf"
   1564 do_manconf()
   1565 {
   1566 	[ -n "$1" ] || err 3 "USAGE: do_manconf fix|check"
   1567 	local op="$1"
   1568 	local failed=0
   1569 
   1570 	[ -f "${DEST_DIR}/etc/man.conf" ] || return 0
   1571 	if ${GREP} -w "mandoc" "${DEST_DIR}/etc/man.conf" >/dev/null 2>&1;
   1572 	then
   1573 		failed=0;
   1574 	else
   1575 		failed=1
   1576 		notfixed=""
   1577 		if [ "${op}" = "fix" ]; then
   1578 			notfixed="${NOT_FIXED}"
   1579 		fi
   1580 		msg "The file /etc/man.conf has not been adapted to mandoc usage; you"
   1581 		msg "probably want to copy a new version over. ${notfixed}"
   1582 	fi
   1583 
   1584 	return ${failed}
   1585 }
   1586 
   1587 
   1588 #
   1589 #	motd
   1590 #
   1591 
   1592 additem motd "contents of motd"
   1593 do_motd()
   1594 {
   1595 	[ -n "$1" ] || err 3 "USAGE: do_motd fix|check"
   1596 
   1597 	if ${GREP} -i 'http://www.NetBSD.org/Misc/send-pr.html' \
   1598 		"${DEST_DIR}/etc/motd" >/dev/null 2>&1 \
   1599 	    || ${GREP} -i 'https*://www.NetBSD.org/support/send-pr.html' \
   1600 		"${DEST_DIR}/etc/motd" >/dev/null 2>&1
   1601 	then
   1602 		tmp1="$(mktemp /tmp/postinstall.motd.XXXXXXXX)"
   1603 		tmp2="$(mktemp /tmp/postinstall.motd.XXXXXXXX)"
   1604 		${SED} '1,2d' <"${SRC_DIR}/etc/motd" >"${tmp1}"
   1605 		${SED} '1,2d' <"${DEST_DIR}/etc/motd" >"${tmp2}"
   1606 
   1607 		if [ "$1" = check ]; then
   1608 			cmp -s "${tmp1}" "${tmp2}"
   1609 			result=$?
   1610 			if [ "${result}" -ne 0 ]; then
   1611 				msg \
   1612     "Bug reporting messages do not seem to match the installed release"
   1613 			fi
   1614 		else
   1615 			head -n 2 "${DEST_DIR}/etc/motd" >"${tmp1}"
   1616 			${SED} '1,2d' <"${SRC_DIR}/etc/motd" >>"${tmp1}"
   1617 			cp "${tmp1}" "${DEST_DIR}/etc/motd"
   1618 			result=0
   1619 		fi
   1620 
   1621 		${RM} -f "${tmp1}" "${tmp2}"
   1622 	else
   1623 		result=0
   1624 	fi
   1625 
   1626 	return ${result}
   1627 }
   1628 
   1629 
   1630 #
   1631 #	mtree
   1632 #
   1633 
   1634 additem mtree "/etc/mtree/ being up to date"
   1635 do_mtree()
   1636 {
   1637 	[ -n "$1" ] || err 3 "USAGE: do_mtree fix|check"
   1638 	local failed=0
   1639 
   1640 	compare_dir "$1" "${SRC_DIR}/etc/mtree" "${DEST_DIR}/etc/mtree" 444 special
   1641 	failed=$(( ${failed} + $? ))
   1642 
   1643 	if ! $SOURCEMODE; then
   1644 		MTREE_DIR="${SRC_DIR}/etc/mtree"
   1645 	else
   1646 		${RM} -rf "${SCRATCHDIR}/obj"
   1647 		mkdir "${SCRATCHDIR}/obj"
   1648 		${MAKE} -s -C "${SRC_DIR}/etc/mtree" TOOL_AWK="${AWK}" \
   1649 		    MAKEOBJDIR="${SCRATCHDIR}/obj" emit_dist_file > \
   1650 		    "${SCRATCHDIR}/NetBSD.dist"
   1651 		MTREE_DIR="${SCRATCHDIR}"
   1652 		${RM} -rf "${SCRATCHDIR}/obj"
   1653 	fi
   1654 	compare_dir "$1" "${MTREE_DIR}" "${DEST_DIR}/etc/mtree" 444 NetBSD.dist
   1655 	failed=$(( ${failed} + $? ))
   1656 
   1657 	return ${failed}
   1658 }
   1659 
   1660 
   1661 #
   1662 #	named
   1663 #
   1664 handle_named_conf()
   1665 {
   1666 	local op="$1"
   1667 	local option="dnssec-enable"
   1668 	local failed=0
   1669 	local conf
   1670 
   1671 	shift
   1672 
   1673 	for conf; do
   1674 		local c=$(readlink -f "${conf}")
   1675 		if ! ${GREP} -qs "${option}" "${c}"
   1676 		then
   1677 			continue
   1678 		fi
   1679 
   1680 		if [ "${op}" = "fix" ]; then
   1681 			${SED} -e "/${option}/d" "${c}" > "${c}.new"
   1682 			failed=$(( ${failed} + $? ))
   1683 			mv "${c}.new" "${c}"
   1684 			failed=$(( ${failed} + $? ))
   1685 			msg "Removed obsolete '${option}' in ${c}"
   1686 		else
   1687 			msg "'${option}' option in ${c} should be removed"
   1688 			failed=$(( ${failed} + 1 ))
   1689 		fi
   1690 	done
   1691 
   1692 	return ${failed}
   1693 }
   1694 
   1695 additem named "named configuration update"
   1696 do_named()
   1697 {
   1698 	local oldconf="${DEST_DIR}/etc/namedb/named.conf"
   1699 	local conf="${DEST_DIR}/etc/named.conf"
   1700 	[ -n "$1" ] || err 3 "USAGE: do_named fix|check"
   1701 	local op="$1"
   1702 
   1703 	move_file "${op}" "${oldconf}" "${conf}"
   1704 	handle_named_conf "${op}" "${oldconf}" "${conf}"
   1705 
   1706 	compare_dir "${op}" "${SRC_DIR}/etc/namedb" "${DEST_DIR}/etc/namedb" \
   1707 		644 \
   1708 		root.cache
   1709 
   1710 	local od="${DEST_DIR}/usr/libexec/named"
   1711 	if [ -d "$od" ]; then
   1712 		rm -fr "$od"
   1713 		msg "Removed obsolete '${od}'"
   1714 	fi
   1715 }
   1716 
   1717 
   1718 #
   1719 #	opensslcertsconf
   1720 #
   1721 
   1722 additem opensslcertsconf "ensure TLS trust anchor configuration exists"
   1723 do_opensslcertsconf()
   1724 {
   1725 	local certsdir certsconf defaultconf manualmsg
   1726 
   1727 	[ -n "$1" ] || err 3 "USAGE: do_opensslcertsconf fix|check"
   1728 
   1729 	certsdir="${DEST_DIR}/etc/openssl/certs"
   1730 	certsconf="${DEST_DIR}/etc/openssl/certs.conf"
   1731 	defaultconf="${DEST_DIR}/usr/share/examples/certctl/certs.conf"
   1732 
   1733 	case $1 in
   1734 	check)	if [ ! -r "$certsconf" ]; then
   1735 			msg "/etc/openssl/certs.conf missing; see certctl(8)"
   1736 			return 1
   1737 		fi
   1738 		;;
   1739 	fix)	# If /etc/openssl/certs.conf is already there, nothing
   1740 		# to do.
   1741 		if [ -r "$certsconf" ]; then
   1742 			return 0
   1743 		fi
   1744 
   1745 		# If /etc/openssl/certs is a symlink, or exists but is
   1746 		# not a directory, or is a directory but is nonempty,
   1747 		# then either it's managed by someone else or something
   1748 		# fishy is afoot.  So set it manual in that case.
   1749 		# Otherwise, install the default config file.
   1750 		if [ -h "$certsdir" ] ||
   1751 		    [ -e "$certsdir" -a ! -d "$certsdir" ] ||
   1752 		    ([ -d "$certsdir" ] &&
   1753 			find -f "$certsdir" -- \
   1754 			    -maxdepth 0 -type d -empty -exit 1)
   1755 		then
   1756 			msg "/etc/openssl/certs appears manually configured"
   1757 			manualmsg="[existing /etc/openssl/certs configuration"
   1758 			manualmsg="$manualmsg detected by postinstall(8)]"
   1759                         # Change the commented-out `#manual' line to
   1760                         # uncommented `manual', or print an error
   1761                         # message if there is no `#manual' line and put
   1762                         # `manual' at the end.
   1763                         awk -v defaultconf="$defaultconf" \
   1764 			    -v manualmsg="$manualmsg" '
   1765 				BEGIN {
   1766 					manual = 0
   1767 				}
   1768 				/^#manual/ && !manual {
   1769 					manual = 1
   1770 					sub(/^#/, "")
   1771 					print
   1772 					print "#", manualmsg
   1773 					next
   1774 				}
   1775 				{
   1776 					print
   1777 				}
   1778 				END {
   1779 					if (!manual) {
   1780 						printf "warning: %s %s?\n", \
   1781 						    "corrupt", defaultconf \
   1782 						    >"/dev/stderr"
   1783 						print "manual"
   1784 						print "#", manualmsg
   1785 					}
   1786 				}
   1787 			' <$defaultconf >${certsconf}.tmp
   1788 		else
   1789 			msg "installing default /etc/openssl/certs.conf"
   1790 			cat <$defaultconf >${certsconf}.tmp
   1791 		fi && mv -f -- "${certsconf}.tmp" "$certsconf"
   1792 		;;
   1793 	*)	err 3 "USAGE: do_opensslcerts fix|check"
   1794 		;;
   1795 	esac
   1796 }
   1797 
   1798 
   1799 #
   1800 #	opensslcertsrehash
   1801 #
   1802 
   1803 additem opensslcertsrehash "make /etc/openssl/certs cache of TLS trust anchors"
   1804 do_opensslcertsrehash()
   1805 {
   1806 	local mtreekeys scratchdir
   1807 
   1808 	[ -n "$1" ] || err 3 "USAGE: do_opensslcertsrehash fix|check"
   1809 
   1810 	if [ ! -r "${DEST_DIR}/etc/openssl/certs.conf" ]; then
   1811 		msg "/etc/openssl/certs.conf missing; see certctl(8)"
   1812 		return 1
   1813 	fi
   1814 
   1815 	case $1 in
   1816 	check)	# Create a scratch rehash for comparison.
   1817 		mtreekeys="type,link"
   1818 		scratchdir="${SCRATCHDIR}/opensslcerts"
   1819 		/usr/sbin/certctl -c "$scratchdir" rehash || return $?
   1820 
   1821 		# This will create ${scratchdir}/.certctl unless the
   1822 		# configuration is manual.  If the configuration is
   1823 		# manual, stop here; nothing to do.  certctl(8) will
   1824 		# have already printed a message about that.
   1825 		#
   1826 		# XXX Grody to rely on the internal structure used by
   1827 		# certctl(8), but less bad than having two versions of
   1828 		# the config parsing logic.
   1829 		if [ ! -f "${scratchdir}/.certctl" ]; then
   1830 			return 0
   1831 		fi
   1832 
   1833 		# Do a dry run of rehashing into the real
   1834 		# /etc/openssl/certs.  This curious extra step ensures
   1835 		# that we report a failure if /etc/openssl/certs
   1836 		# appears to be managed manually, but `manual' was not
   1837 		# specified in /etc/openssl/certs.conf.
   1838 		/usr/sbin/certctl -n rehash || return $?
   1839 
   1840 		# Compare the trees with mtree(8).  Inconveniently,
   1841 		# mtree returns status zero even if there are missing
   1842 		# or extra files.  So instead of examining the return
   1843 		# status, test for any output.  Empty output means
   1844 		# everything matches; otherwise the mismatch, missing,
   1845 		# or extra files are output.
   1846 		mtree -p "$scratchdir" -c -k "$mtreekeys" \
   1847 		| mtree -p "${DEST_DIR}/etc/openssl/certs" 2>&1 \
   1848 		| {
   1849 			while read -r line; do
   1850 				# mismatch, missing, or extra
   1851 				msg "/etc/openssl/certs needs rehash"
   1852 				exit 1
   1853 			done
   1854 			exit 0
   1855 		}
   1856 		;;
   1857 	fix)	# This runs openssl(1), which is not available as a
   1858 		# build-time tool.  So for now, restrict it to running
   1859 		# on the installed system.
   1860 		case $DEST_DIR in
   1861 		''|/)	;;
   1862 		*)	msg "opensslcertsrehash limited to DEST_DIR=/"
   1863 			return 1
   1864 			;;
   1865 		esac
   1866 		/usr/sbin/certctl rehash
   1867 		;;
   1868 	*)	err 3 "USAGE: do_opensslcerts fix|check"
   1869 		;;
   1870 	esac
   1871 }
   1872 
   1873 
   1874 #
   1875 #	pam
   1876 #
   1877 
   1878 additem pam "/etc/pam.d is populated"
   1879 do_pam()
   1880 {
   1881 	[ -n "$1" ] || err 3 "USAGE: do_pam fix|check"
   1882 	local op="$1"
   1883 	local failed=0
   1884 
   1885 	populate_dir "${op}" true "${SRC_DIR}/etc/pam.d" \
   1886 		"${DEST_DIR}/etc/pam.d" 644 \
   1887 		README cron display_manager ftpd gdm imap kde login other \
   1888 		passwd pop3 ppp racoon rexecd rsh sshd su system telnetd \
   1889 		xdm xserver
   1890 
   1891 	failed=$(( ${failed} + $? ))
   1892 
   1893 	return ${failed}
   1894 }
   1895 
   1896 
   1897 #
   1898 #	periodic
   1899 #
   1900 
   1901 additem periodic "/etc/{daily,weekly,monthly,security} being up to date"
   1902 do_periodic()
   1903 {
   1904 	[ -n "$1" ] || err 3 "USAGE: do_periodic fix|check"
   1905 
   1906 	compare_dir "$1" "${SRC_DIR}/etc" "${DEST_DIR}/etc" 644 \
   1907 		daily weekly monthly security
   1908 }
   1909 
   1910 
   1911 #
   1912 #	pf
   1913 #
   1914 
   1915 additem pf "pf configuration being up to date"
   1916 do_pf()
   1917 {
   1918 	[ -n "$1" ] || err 3 "USAGE: do_pf fix|check"
   1919 	local op="$1"
   1920 	local failed=0
   1921 
   1922 	find_file_in_dirlist pf.os "pf.os" \
   1923 	    "${SRC_DIR}/dist/pf/etc" "${SRC_DIR}/etc" \
   1924 	    || return 1
   1925 			# ${dir} is set by find_file_in_dirlist()
   1926 	populate_dir "${op}" true \
   1927 	    "${dir}" "${DEST_DIR}/etc" 644 \
   1928 	    pf.conf
   1929 	failed=$(( ${failed} + $? ))
   1930 
   1931 	compare_dir "${op}" "${dir}" "${DEST_DIR}/etc" 444 pf.os
   1932 	failed=$(( ${failed} + $? ))
   1933 
   1934 	return ${failed}
   1935 }
   1936 
   1937 
   1938 #
   1939 #	ptyfsoldnodes
   1940 #
   1941 
   1942 additem ptyfsoldnodes "remove legacy device nodes when using ptyfs"
   1943 do_ptyfsoldnodes()
   1944 {
   1945 	[ -n "$1" ] || err 3 "USAGE: do_ptyfsoldnodes fix|check"
   1946 	local op="$1"
   1947 
   1948 	# Check whether ptyfs is in use
   1949 	local failed=0;
   1950 	if ! ${GREP} -E "^ptyfs" "${DEST_DIR}/etc/fstab" > /dev/null; then
   1951 		msg "ptyfs is not in use"
   1952 		return 0
   1953 	fi
   1954 
   1955 	if [ ! -e "${DEST_DIR}/dev/pts" ]; then
   1956 		msg "ptyfs is not properly configured: missing /dev/pts"
   1957 		return 1
   1958 	fi
   1959 
   1960 	# Find the device major numbers for the pty master and slave
   1961 	# devices, by parsing the output from "MAKEDEV -s pty0".
   1962 	#
   1963 	# Output from MAKEDEV looks like this:
   1964 	# ./ttyp0 type=char device=netbsd,5,0 mode=666 gid=0 uid=0
   1965 	# ./ptyp0 type=char device=netbsd,6,0 mode=666 gid=0 uid=0
   1966 	#
   1967 	# Output from awk, used in the eval statement, looks like this:
   1968 	# maj_ptym=6; maj_ptys=5;
   1969 	#
   1970 	local maj_ptym maj_ptys
   1971 	find_makedev
   1972 	eval "$(
   1973 	    ${HOST_SH} "${MAKEDEV_DIR}/MAKEDEV" -s pty0 2>/dev/null \
   1974 	    | ${AWK} '\
   1975 	    BEGIN { before_re = ".*device=[a-zA-Z]*,"; after_re = ",.*"; }
   1976 	    /ptyp0/ { maj_ptym = gensub(before_re, "", 1, $0);
   1977 		      maj_ptym = gensub(after_re, "", 1, maj_ptym); }
   1978 	    /ttyp0/ { maj_ptys = gensub(before_re, "", 1, $0);
   1979 		      maj_ptys = gensub(after_re, "", 1, maj_ptys); }
   1980 	    END { print "maj_ptym=" maj_ptym "; maj_ptys=" maj_ptys ";"; }
   1981 	    '
   1982 	    )"
   1983 	#msg "Major numbers are maj_ptym=${maj_ptym} maj_ptys=${maj_ptys}"
   1984 	if [ -z "$maj_ptym" ] || [ -z "$maj_ptys" ]; then
   1985 		msg "Cannot find device major numbers for pty master and slave"
   1986 		return 1
   1987 	fi
   1988 
   1989 	# look for /dev/[pt]ty[p-zP-T][0-9a-zA-Z], and check that they
   1990 	# have the expected device major numbers.  ttyv* is typically not a
   1991 	# pty device, but we check it anyway.
   1992 	#
   1993 	# The "for d1" loop is intended to avoid overflowing ARG_MAX;
   1994 	# otherwise we could have used a single glob pattern.
   1995 	#
   1996 	# If there are no files that match a particular pattern,
   1997 	# then stat prints something like:
   1998 	#    stat: /dev/[pt]tyx?: lstat: No such file or directory
   1999 	# and we ignore it.  XXX: We also ignore other error messages.
   2000 	#
   2001 	local d1 major node
   2002 	local tmp="$(mktemp /tmp/postinstall.ptyfs.XXXXXXXX)"
   2003 
   2004 	for d1 in p q r s t u v w x y z P Q R S T; do
   2005 		${STAT} -f "%Hr %N" "${DEST_DIR}/dev/"[pt]ty${d1}? 2>&1
   2006 	done \
   2007 	| while read -r major node ; do
   2008 		case "$major" in
   2009 		${maj_ptym}|${maj_ptys}) echo "$node" ;;
   2010 		esac
   2011 	done > "${tmp}"
   2012 
   2013 	local desc="legacy device node"
   2014 	while read node; do
   2015 		if [ "${op}" = "check" ]; then
   2016 			msg "Remove ${desc} ${node}"
   2017 			failed=1
   2018 		else # "fix"
   2019 			if ${RM} "${node}"; then
   2020 				msg "Removed ${desc} ${node}"
   2021 			else
   2022 				warn "Failed to remove ${desc} ${node}"
   2023 				failed=1
   2024 			fi
   2025 		fi
   2026 	done < "${tmp}"
   2027 	${RM} "${tmp}"
   2028 
   2029 	return ${failed}
   2030 }
   2031 
   2032 
   2033 #
   2034 #	pwd_mkdb
   2035 #
   2036 
   2037 additem pwd_mkdb "passwd database version"
   2038 do_pwd_mkdb()
   2039 {
   2040 	[ -n "$1" ] || err 3 "USAGE: do_pwd_mkdb fix|check"
   2041 	local op="$1"
   2042 	local failed=0
   2043 
   2044 	# XXX Ideally, we should figure out the endianness of the
   2045 	# target machine, and add "-E B"/"-E L" to the db(1) flags,
   2046 	# and "-B"/"-L" to the pwd_mkdb(8) flags if the target is not
   2047 	# the same as the host machine.  It probably doesn't matter,
   2048 	# because we don't expect "postinstall fix pwd_mkdb" to be
   2049 	# invoked during a cross build.
   2050 
   2051 	set -- $(${DB} -q -Sb -Ub -To -N hash "${DEST_DIR}/etc/pwd.db" \
   2052 		'VERSION\0')
   2053 	case "$2" in
   2054 	'\001\000\000\000') return 0 ;; # version 1, little-endian
   2055 	'\000\000\000\001') return 0 ;; # version 1, big-endian
   2056 	esac
   2057 
   2058 	if [ "${op}" = "check" ]; then
   2059 		msg "Update format of passwd database"
   2060 		failed=1
   2061 	elif ! ${PWD_MKDB} -V 1 -d "${DEST_DIR:-/}" \
   2062 			"${DEST_DIR}/etc/master.passwd";
   2063 	then
   2064 		msg "Can't update format of passwd database"
   2065 		failed=1
   2066 	else
   2067 		msg "Updated format of passwd database"
   2068 	fi
   2069 
   2070 	return ${failed}
   2071 }
   2072 
   2073 
   2074 #
   2075 #	rc
   2076 #
   2077 
   2078 # There is no info in src/distrib or /etc/mtree which rc* files
   2079 # can be overwritten unconditionally on upgrade. See PR/54741.
   2080 rc_644_files="
   2081 rc
   2082 rc.subr
   2083 rc.shutdown
   2084 "
   2085 
   2086 rc_obsolete_vars="
   2087 amd amd_master
   2088 btcontrol btcontrol_devices
   2089 critical_filesystems critical_filesystems_beforenet
   2090 mountcritlocal mountcritremote
   2091 network ip6forwarding
   2092 network nfsiod_flags
   2093 sdpd sdpd_control
   2094 sdpd sdpd_groupname
   2095 sdpd sdpd_username
   2096 sysctl defcorename
   2097 "
   2098 
   2099 update_rc()
   2100 {
   2101 	local op=$1
   2102 	local dir=$2
   2103 	local name=$3
   2104 	local bindir=$4
   2105 	local rcdir=$5
   2106 
   2107 	if [ ! -x "${DEST_DIR}/${bindir}/${name}" ]; then
   2108 		return 0
   2109 	fi
   2110 
   2111 	if ! find_file_in_dirlist "${name}" "${name}" \
   2112 	    "${rcdir}" "${SRC_DIR}/etc/rc.d"; then
   2113 		return 1
   2114 	fi
   2115 	populate_dir "${op}" false "${dir}" "${DEST_DIR}/etc/rc.d" 555 "${name}"
   2116 	return $?
   2117 }
   2118 
   2119 # select non-obsolete files in a sets file
   2120 # $1: directory pattern
   2121 # $2: file pattern
   2122 # $3: filename
   2123 select_set_files()
   2124 {
   2125 	local qdir="$(echo $1 | ${SED} -e s@/@\\\\/@g -e s/\\./\\\\./g)"
   2126 	${SED} -n -e /obsolete/d \
   2127 	    -e "/^\.${qdir}/s@^.$2[[:space:]].*@\1@p" $3
   2128 }
   2129 
   2130 # select obsolete files in a sets file
   2131 # $1: directory pattern
   2132 # $2: file pattern
   2133 # $3: setname
   2134 select_obsolete_files()
   2135 {
   2136 	if $SOURCEMODE; then
   2137 		${SED} -n -e "/obsolete/s@\.$1$2[[:space:]].*@\1@p" \
   2138 		    "${SRC_DIR}/distrib/sets/lists/$3/mi"
   2139 		return
   2140 	fi
   2141 
   2142 	# On upgrade builds we don't extract the "etc" set so we
   2143 	# try to use the source set instead. See PR/54730 for
   2144 	# ways to better handle this.
   2145 
   2146 	local obsolete_dir
   2147 
   2148 	if [ $3 = "etc" ] ;then
   2149 		obsolete_dir="${SRC_DIR}/var/db/obsolete"
   2150 	else
   2151 		obsolete_dir="${DEST_DIR}/var/db/obsolete"
   2152 	fi
   2153 	${SED} -n -e "s@\.$1$2\$@\1@p" "${obsolete_dir}/$3"
   2154 }
   2155 
   2156 getetcsets()
   2157 {
   2158 	if $SOURCEMODE; then
   2159 		echo "${SRC_DIR}/distrib/sets/lists/etc/mi"
   2160 	else
   2161 		echo "${SRC_DIR}/etc/mtree/set.etc"
   2162 	fi
   2163 }
   2164 
   2165 additem rc "/etc/rc* and /etc/rc.d/ being up to date"
   2166 do_rc()
   2167 {
   2168 	[ -n "$1" ] || err 3 "USAGE: do_rc fix|check"
   2169 	local op="$1"
   2170 	local failed=0
   2171 	local generated_scripts=""
   2172 	local etcsets=$(getetcsets)
   2173 	if [ "${MKX11}" != "no" ]; then
   2174 		generated_scripts="${generated_scripts} xdm xfs"
   2175 	fi
   2176 
   2177 	# Directories of external programs that have rc files (in bsd)
   2178 	local rc_external_files="blocklist nsd unbound"
   2179 
   2180 	# rc* files in /etc/
   2181 	# XXX: at least rc.conf and rc.local shouldn't be updated. PR/54741
   2182 	#local rc_644_files="$(select_set_files /etc/rc \
   2183 	#    "/etc/\(rc[^[:space:]/]*\)" ${etcsets})"
   2184 
   2185 	# no-obsolete rc files in /etc/rc.d
   2186 	local rc_555_files="$(select_set_files /etc/rc.d/ \
   2187 	    "/etc/rc\.d/\([^[:space:]]*\)" ${etcsets} | \
   2188 	    exclude ${rc_external_files})"
   2189 
   2190 	# obsolete rc file in /etc/rc.d
   2191 	local rc_obsolete_files="$(select_obsolete_files /etc/rc.d/ \
   2192 	    "\([^[:space:]]*\)" etc)"
   2193 
   2194 	compare_dir "${op}" "${SRC_DIR}/etc" "${DEST_DIR}/etc" 644 \
   2195 		${rc_644_files}
   2196 	failed=$(( ${failed} + $? ))
   2197 
   2198 	local extra_scripts
   2199 	if ! $SOURCEMODE; then
   2200 		extra_scripts="${generated_scripts}"
   2201 	else
   2202 		extra_scripts=""
   2203 	fi
   2204 
   2205 	compare_dir "${op}" "${SRC_DIR}/etc/rc.d" "${DEST_DIR}/etc/rc.d" 555 \
   2206 		${rc_555_files} \
   2207 		${extra_scripts}
   2208 	failed=$(( ${failed} + $? ))
   2209 
   2210 	local i rc_file
   2211 	for i in ${rc_external_files}; do
   2212 	    case $i in
   2213 	    *d) rc_file=${i};;
   2214 	    *)	rc_file=${i}d;;
   2215 	    esac
   2216 
   2217 	    update_rc "${op}" "${dir}" ${rc_file} /sbin \
   2218 		"${SRC_DIR}/external/bsd/$i/etc/rc.d"
   2219 	    failed=$(( ${failed} + $? ))
   2220 	done
   2221 
   2222 	if $SOURCEMODE && [ -n "${generated_scripts}" ]; then
   2223 		# generate scripts
   2224 		mkdir "${SCRATCHDIR}/rc"
   2225 		for f in ${generated_scripts}; do
   2226 			${SED} -e "s,@X11ROOTDIR@,${X11ROOTDIR},g" \
   2227 			    < "${SRC_DIR}/etc/rc.d/${f}.in" \
   2228 			    > "${SCRATCHDIR}/rc/${f}"
   2229 		done
   2230 		compare_dir "${op}" "${SCRATCHDIR}/rc" \
   2231 		    "${DEST_DIR}/etc/rc.d" 555 \
   2232 		    ${generated_scripts}
   2233 		failed=$(( ${failed} + $? ))
   2234 	fi
   2235 
   2236 		# check for obsolete rc.d files
   2237 	for f in ${rc_obsolete_files}; do
   2238 		local fd="/etc/rc.d/${f}"
   2239 		[ -e "${DEST_DIR}${fd}" ] && echo "${fd}"
   2240 	done | obsolete_paths "${op}"
   2241 	failed=$(( ${failed} + $? ))
   2242 
   2243 		# check for obsolete rc.conf(5) variables
   2244 	set -- ${rc_obsolete_vars}
   2245 	while [ $# -gt 1 ]; do
   2246 		if rcconf_is_set "${op}" "$1" "$2" 1; then
   2247 			failed=1
   2248 		fi
   2249 		shift 2
   2250 	done
   2251 
   2252 	return ${failed}
   2253 }
   2254 
   2255 
   2256 #
   2257 #	sendmail
   2258 #
   2259 
   2260 adddisableditem sendmail "remove obsolete sendmail configuration files and scripts"
   2261 do_sendmail()
   2262 {
   2263 	[ -n "$1" ] || err 3 "USAGE: do_sendmail fix|check"
   2264 	op="$1"
   2265 	failed=0
   2266 
   2267 	# Don't complain if the "sendmail" package is installed because the
   2268 	# files might still be in use.
   2269 	if /usr/sbin/pkg_info -qe sendmail >/dev/null 2>&1; then
   2270 		return 0
   2271 	fi
   2272 
   2273 	for f in /etc/mail/helpfile /etc/mail/local-host-names \
   2274 	    /etc/mail/sendmail.cf /etc/mail/submit.cf /etc/rc.d/sendmail \
   2275 	    /etc/rc.d/smmsp /usr/share/misc/sendmail.hf \
   2276 	    $( ( find "${DEST_DIR}/usr/share/sendmail" -type f ; \
   2277 	         find "${DEST_DIR}/usr/share/sendmail" -type d \
   2278 	       ) | unprefix "${DEST_DIR}" ) \
   2279 	    /var/log/sendmail.st \
   2280 	    /var/spool/clientmqueue \
   2281 	    /var/spool/mqueue
   2282 	do
   2283 		[ -e "${DEST_DIR}${f}" ] && echo "${f}"
   2284 	done | obsolete_paths "${op}"
   2285 	failed=$(( ${failed} + $? ))
   2286 
   2287 	return ${failed}
   2288 }
   2289 
   2290 
   2291 #
   2292 #	ssh
   2293 #
   2294 
   2295 additem ssh "ssh configuration update"
   2296 do_ssh()
   2297 {
   2298 	[ -n "$1" ] || err 3 "USAGE: do_ssh fix|check"
   2299 	local op="$1"
   2300 
   2301 	local failed=0
   2302 	local etcssh="${DEST_DIR}/etc/ssh"
   2303 	if ! check_dir "${op}" "${etcssh}" 755; then
   2304 		failed=1
   2305 	fi
   2306 
   2307 	if [ ${failed} -eq 0 ]; then
   2308 		for f in \
   2309 			    ssh_known_hosts ssh_known_hosts2 \
   2310 			    ssh_host_dsa_key ssh_host_dsa_key.pub \
   2311 			    ssh_host_rsa_key ssh_host_rsa_key.pub \
   2312 			    ssh_host_key ssh_host_key.pub \
   2313 		    ; do
   2314 			if ! move_file "${op}" \
   2315 			    "${DEST_DIR}/etc/${f}" "${etcssh}/${f}" ; then
   2316 				failed=1
   2317 			fi
   2318 		done
   2319 		for f in sshd.conf ssh.conf ; do
   2320 				# /etc/ssh/ssh{,d}.conf -> ssh{,d}_config
   2321 				#
   2322 			if ! move_file "${op}" \
   2323 			    "${etcssh}/${f}" "${etcssh}/${f%.conf}_config" ;
   2324 			then
   2325 				failed=1
   2326 			fi
   2327 				# /etc/ssh{,d}.conf -> /etc/ssh/ssh{,d}_config
   2328 				#
   2329 			if ! move_file "${op}" \
   2330 			    "${DEST_DIR}/etc/${f}" \
   2331 			    "${etcssh}/${f%.conf}_config" ;
   2332 			then
   2333 				failed=1
   2334 			fi
   2335 		done
   2336 	fi
   2337 
   2338 	local sshdconf=""
   2339 	local f
   2340 	for f in \
   2341 	    "${etcssh}/sshd_config" \
   2342 	    "${etcssh}/sshd.conf" \
   2343 	    "${DEST_DIR}/etc/sshd.conf" ; do
   2344 		if [ -f "${f}" ]; then
   2345 			sshdconf="${f}"
   2346 			break
   2347 		fi
   2348 	done
   2349 	if [ -n "${sshdconf}" ]; then
   2350 		modify_file "${op}" "${sshdconf}" "${SCRATCHDIR}/sshdconf" '
   2351 			/^[^#$]/ {
   2352 				kw = tolower($1)
   2353 				if (kw == "hostkey" &&
   2354 				    $2 ~ /^\/etc\/+ssh_host(_[dr]sa)?_key$/ ) {
   2355 					sub(/\/etc\/+/, "/etc/ssh/")
   2356 				}
   2357 				if (kw == "rhostsauthentication" ||
   2358 				    kw == "verifyreversemapping" ||
   2359 				    kw == "reversemappingcheck") {
   2360 					sub(/^/, "# DEPRECATED:\t")
   2361 				}
   2362 			}
   2363 			{ print }
   2364 		'
   2365 		failed=$(( ${failed} + $? ))
   2366 	fi
   2367 
   2368 	if ! find_file_in_dirlist moduli "moduli" \
   2369 	    "${SRC_DIR}/crypto/external/bsd/openssh/dist" "${SRC_DIR}/etc" ; then
   2370 		failed=1
   2371 			# ${dir} is set by find_file_in_dirlist()
   2372 	elif ! compare_dir "${op}" "${dir}" "${DEST_DIR}/etc" 444 moduli; then
   2373 		failed=1
   2374 	fi
   2375 
   2376 	if ! check_dir "${op}" "${DEST_DIR}/var/chroot/sshd" 755 ; then
   2377 		failed=1
   2378 	fi
   2379 
   2380 	if rcconf_is_set "${op}" sshd sshd_conf_dir 1; then
   2381 		failed=1
   2382 	fi
   2383 
   2384 	return ${failed}
   2385 }
   2386 
   2387 
   2388 #
   2389 #	tcpdumpchroot
   2390 #
   2391 
   2392 additem tcpdumpchroot "remove /var/chroot/tcpdump/etc/protocols"
   2393 do_tcpdumpchroot()
   2394 {
   2395 	[ -n "$1" ] || err 3 "USAGE: do_tcpdumpchroot fix|check"
   2396 	local op="$1"
   2397 
   2398 	local failed=0;
   2399 	if [ -r "${DEST_DIR}/var/chroot/tcpdump/etc/protocols" ]; then
   2400 		if [ "${op}" = "fix" ]; then
   2401 			${RM} "${DEST_DIR}/var/chroot/tcpdump/etc/protocols"
   2402 			failed=$(( ${failed} + $? ))
   2403 			rmdir "${DEST_DIR}/var/chroot/tcpdump/etc"
   2404 			failed=$(( ${failed} + $? ))
   2405 		else
   2406 			failed=1
   2407 		fi
   2408 	fi
   2409 	return ${failed}
   2410 }
   2411 
   2412 
   2413 #
   2414 #	uid
   2415 #
   2416 
   2417 additem uid "required users in /etc/master.passwd"
   2418 do_uid()
   2419 {
   2420 	[ -n "$1" ] || err 3 "USAGE: do_uid fix|check"
   2421 
   2422 	check_ids "$1" users "${DEST_DIR}/etc/master.passwd" \
   2423 	    "${SRC_DIR}/etc/master.passwd" 12 \
   2424 	    postfix SKIP named ntpd sshd SKIP _pflogd _rwhod SKIP _proxy \
   2425 	    _timedc _sdpd _httpd _mdnsd _tests _tcpdump _tss SKIP _rtadvd \
   2426 	    SKIP _unbound _nsd SKIP _dhcpcd
   2427 }
   2428 
   2429 
   2430 #
   2431 #	varrwho
   2432 #
   2433 
   2434 additem varrwho "required ownership of files in /var/rwho"
   2435 do_varrwho()
   2436 {
   2437 	[ -n "$1" ] || err 3 "USAGE: do_varrwho fix|check"
   2438 
   2439 	contents_owner "$1" "${DEST_DIR}/var/rwho" _rwhod _rwhod
   2440 }
   2441 
   2442 
   2443 #
   2444 #	varshm
   2445 #
   2446 
   2447 additem varshm "check for a tmpfs mounted on /var/shm"
   2448 do_varshm()
   2449 {
   2450 	[ -n "$1" ] || err 3 "USAGE: do_varshm fix|check"
   2451 	op="$1"
   2452 	failed=0
   2453 
   2454 	[ -f "${DEST_DIR}/etc/fstab" ] || return 0
   2455 	if ${GREP} -E "^var_shm_symlink" "${DEST_DIR}/etc/rc.conf" >/dev/null 2>&1;
   2456 	then
   2457 		failed=0;
   2458 	elif ${GREP} -w "/var/shm" "${DEST_DIR}/etc/fstab" >/dev/null 2>&1;
   2459 	then
   2460 		failed=0;
   2461 	else
   2462 		if [ "${op}" = "check" ]; then
   2463 			failed=1
   2464 			msg "No /var/shm mount found in ${DEST_DIR}/etc/fstab"
   2465 		elif [ "${op}" = "fix" ]; then
   2466 			printf '\ntmpfs\t/var/shm\ttmpfs\trw,-m1777,-sram%%25\n' \
   2467 				>> "${DEST_DIR}/etc/fstab"
   2468 			msg "Added tmpfs with 25% ram limit as /var/shm"
   2469 
   2470 		fi
   2471 	fi
   2472 
   2473 	return ${failed}
   2474 }
   2475 
   2476 
   2477 #
   2478 #	wscons
   2479 #
   2480 
   2481 additem wscons "wscons configuration file update"
   2482 do_wscons()
   2483 {
   2484 	[ -n "$1" ] || err 3 "USAGE: do_wscons fix|check"
   2485 	op="$1"
   2486 
   2487 	[ -f "${DEST_DIR}/etc/wscons.conf" ] || return 0
   2488 
   2489 	failed=0
   2490 	notfixed=""
   2491 	if [ "${op}" = "fix" ]; then
   2492 		notfixed="${NOT_FIXED}"
   2493 	fi
   2494 	while read _type _arg1 _rest; do
   2495 		if [ "${_type}" = "mux" -a "${_arg1}" = "1" ]; then
   2496 			msg \
   2497     "Obsolete wscons.conf(5) entry \""${_type} ${_arg1}"\" found.${notfixed}"
   2498 			failed=1
   2499 		fi
   2500 	done < "${DEST_DIR}/etc/wscons.conf"
   2501 
   2502 	return ${failed}
   2503 }
   2504 
   2505 
   2506 #
   2507 #	x11
   2508 #
   2509 
   2510 additem x11 "x11 configuration update"
   2511 do_x11()
   2512 {
   2513 	[ -n "$1" ] || err 3 "USAGE: do_x11 fix|check"
   2514 	local p="$1"
   2515 
   2516 	local failed=0
   2517 	local etcx11="${DEST_DIR}/etc/X11"
   2518 	local libx11=""
   2519 	if [ ! -d "${etcx11}" ]; then
   2520 		msg "${etcx11} is not a directory; skipping check"
   2521 		return 0
   2522 	fi
   2523 	if [ -d "${DEST_DIR}/usr/X11R6/." ]
   2524 	then
   2525 		libx11="${DEST_DIR}/usr/X11R6/lib/X11"
   2526 		if [ ! -d "${libx11}" ]; then
   2527 			msg "${libx11} is not a directory; skipping check"
   2528 			return 0
   2529 		fi
   2530 	fi
   2531 
   2532 	local notfixed=""
   2533 	if [ "${op}" = "fix" ]; then
   2534 		notfixed="${NOT_FIXED}"
   2535 	fi
   2536 
   2537 	local d
   2538 	# check if /usr/X11R6/lib/X11 needs to migrate to /etc/X11
   2539 	if [ -n "${libx11}" ]; then
   2540 		for d in \
   2541 		    fs lbxproxy proxymngr rstart twm xdm xinit xserver xsm \
   2542 		    ; do
   2543 			sd="${libx11}/${d}"
   2544 			ld="/etc/X11/${d}"
   2545 			td="${DEST_DIR}${ld}"
   2546 			if [ -h "${sd}" ]; then
   2547 				continue
   2548 			elif [ -d "${sd}" ]; then
   2549 				tdfiles="$(find "${td}" \! -type d)"
   2550 				if [ -n "${tdfiles}" ]; then
   2551 					msg "${sd} exists yet ${td} already" \
   2552 					    "contains files${notfixed}"
   2553 				else
   2554 					msg "Migrate ${sd} to ${td}${notfixed}"
   2555 				fi
   2556 				failed=1
   2557 			elif [ -e "${sd}" ]; then
   2558 				msg "Unexpected file ${sd}${notfixed}"
   2559 				continue
   2560 			else
   2561 				continue
   2562 			fi
   2563 		done
   2564 	fi
   2565 
   2566 	# check if xdm resources have been updated
   2567 	if [ -r ${etcx11}/xdm/Xresources ] && \
   2568 	    ! ${GREP} -q 'inpColor:' ${etcx11}/xdm/Xresources; then
   2569 		msg "Update ${etcx11}/xdm/Xresources${notfixed}"
   2570 		failed=1
   2571 	fi
   2572 
   2573 	return ${failed}
   2574 }
   2575 
   2576 
   2577 #
   2578 #	xkb
   2579 #
   2580 # /usr/X11R7/lib/X11/xkb/symbols/pc used to be a directory, but changed
   2581 # to a file on 2009-06-12.  Fixing this requires removing the directory
   2582 # (which we can do) and re-extracting the xbase set (which we can't do),
   2583 # or at least adding that one file (which we may be able to do if X11SRCDIR
   2584 # is available).
   2585 #
   2586 
   2587 additem xkb "clean up for xkbdata to xkeyboard-config upgrade"
   2588 do_xkb()
   2589 {
   2590 	[ -n "$1" ] || err 3 "USAGE: do_xkb fix|check"
   2591 	local op="$1"
   2592 	local failed=0
   2593 
   2594 	local pcpath="/usr/X11R7/lib/X11/xkb/symbols/pc"
   2595 	local pcsrcdir="${X11SRCDIR}/external/mit/xkeyboard-config/dist/symbols"
   2596 
   2597 	local filemsg="\
   2598 ${pcpath} was a directory, should be a file.
   2599     To fix, extract the xbase set again."
   2600 
   2601 	local notfixed=""
   2602 	if [ "${op}" = "fix" ]; then
   2603 		notfixed="${NOT_FIXED}"
   2604 	fi
   2605 
   2606 	if [ ! -d "${DEST_DIR}${pcpath}" ]; then
   2607 		return 0
   2608 	fi
   2609 
   2610 	# Delete obsolete files in the directory, and the directory
   2611 	# itself.  If the directory contains unexpected extra files
   2612 	# then it will not be deleted.
   2613 	( [ -f "${DEST_DIR}"/var/db/obsolete/xbase ] \
   2614 	    &&  ${SORT} -ru "${DEST_DIR}"/var/db/obsolete/xbase \
   2615 	    | ${GREP} -E "^\\.?${pcpath}/" ;
   2616 	    echo "${pcpath}" ) \
   2617 	| obsolete_paths "${op}"
   2618 	failed=$(( ${failed} + $? ))
   2619 
   2620 	# If the directory was removed above, then try to replace it with
   2621 	# a file.
   2622 	if [ -d "${DEST_DIR}${pcpath}" ]; then
   2623 		msg "${filemsg}${notfixed}"
   2624 		failed=$(( ${failed} + 1 ))
   2625 	else
   2626 		if ! find_file_in_dirlist pc "${pcpath}" \
   2627 			"${pcsrcdir}" "${SRC_DIR}${pcpath%/*}"
   2628 		then
   2629 			msg "${filemsg}${notfixed}"
   2630 			failed=$(( ${failed} + 1 ))
   2631 		else
   2632 			# ${dir} is set by find_file_in_dirlist()
   2633 			populate_dir "${op}" true \
   2634 				"${dir}" "${DEST_DIR}${pcpath%/*}" 444 \
   2635 				pc
   2636 			failed=$(( ${failed} + $? ))
   2637 		fi
   2638 	fi
   2639 
   2640 	return $failed
   2641 }
   2642 
   2643 
   2644 #
   2645 #	obsolete_stand
   2646 #	obsolete_stand_debug
   2647 #
   2648 
   2649 obsolete_stand_internal()
   2650 {
   2651 	local prefix="$1"
   2652 	shift
   2653 	[ -n "$1" ] || err 3 "USAGE: do_obsolete_stand fix|check"
   2654 	local op="$1"
   2655 	local failed=0
   2656 	local dir
   2657 
   2658 	for dir in \
   2659 	    ${prefix}/stand/${MACHINE} \
   2660 	    ${prefix}/stand/${MACHINE}-4xx \
   2661 	    ${prefix}/stand/${MACHINE}-booke \
   2662 	    ${prefix}/stand/${MACHINE}-xen \
   2663 	    ${prefix}/stand/${MACHINE}pae-xen
   2664 	do
   2665 		[ -d "${DEST_DIR}${dir}" ] && obsolete_stand "${dir}"
   2666 	done | obsolete_paths "${op}"
   2667 	failed=$(( ${failed} + $? ))
   2668 
   2669 	return ${failed}
   2670 }
   2671 
   2672 adddisableditem obsolete_stand "remove obsolete files from /stand"
   2673 do_obsolete_stand()
   2674 {
   2675 	obsolete_stand_internal "" "$@"
   2676 	return $?
   2677 }
   2678 
   2679 adddisableditem obsolete_stand_debug "remove obsolete files from /usr/libdata/debug/stand"
   2680 do_obsolete_stand_debug()
   2681 {
   2682 	obsolete_stand_internal "/usr/libdata/debug" "$@"
   2683 	return $?
   2684 }
   2685 
   2686 
   2687 #
   2688 #	obsolete
   2689 #
   2690 # NOTE: This item is last to allow other items to move obsolete files.
   2691 #
   2692 
   2693 listarchsubdirs()
   2694 {
   2695 	if ! $SOURCEMODE; then
   2696 		echo "@ARCHSUBDIRS@"
   2697 	else
   2698 		${SED} -n -e '/ARCHDIR_SUBDIR/s/[[:space:]]//gp' \
   2699 		    "${SRC_DIR}/compat/archdirs.mk"
   2700 	fi
   2701 }
   2702 
   2703 getarchsubdirs()
   2704 {
   2705 	local m
   2706 	local i
   2707 
   2708 	case ${MACHINE_ARCH} in
   2709 	*arm*|*aarch64*)	m=arm;;
   2710 	x86_64)			m=amd64;;
   2711 	*)			m=${MACHINE_ARCH};;
   2712 	esac
   2713 
   2714 	for i in $(listarchsubdirs); do
   2715 		echo $i
   2716 	done | ${SORT} -u | ${SED} -n -e "/=${m}/s@.*=${m}/\(.*\)@\1@p"
   2717 }
   2718 
   2719 getcompatlibdirs()
   2720 {
   2721 	local i
   2722 
   2723 	for i in $(getarchsubdirs); do
   2724 		if [ -d "${DEST_DIR}/usr/lib/$i" ]; then
   2725 			echo /usr/lib/$i
   2726 		fi
   2727 	done
   2728 }
   2729 
   2730 additem obsolete "remove obsolete file sets and minor libraries"
   2731 do_obsolete()
   2732 {
   2733 	[ -n "$1" ] || err 3 "USAGE: do_obsolete fix|check"
   2734 	local op="$1"
   2735 	local failed=0
   2736 	local i
   2737 
   2738 	${SORT} -ru "${DEST_DIR}"/var/db/obsolete/* | obsolete_paths "${op}"
   2739 	failed=$(( ${failed} + $? ))
   2740 
   2741 	(
   2742 		obsolete_libs /lib
   2743 		obsolete_libs /usr/lib
   2744 		obsolete_libs /usr/lib/i18n
   2745 		obsolete_libs /usr/X11R6/lib
   2746 		obsolete_libs /usr/X11R7/lib
   2747 		for i in $(getcompatlibdirs); do
   2748 			obsolete_libs $i
   2749 		done
   2750 	) | obsolete_paths "${op}"
   2751 	failed=$(( ${failed} + $? ))
   2752 
   2753 	return ${failed}
   2754 }
   2755 
   2756 
   2757 #
   2758 #	end of items
   2759 #	------------
   2760 #
   2761 
   2762 
   2763 help()
   2764 {
   2765 	cat << _USAGE_
   2766 Usage: ${PROGNAME} [-a ARCH] [-d DEST_DIR] [-m MACHINE] [-s SRC_ARG] [-x XSRC_DIR] OPERATION ...
   2767        ${PROGNAME} -?
   2768 
   2769 	Perform post-installation checks and/or fixes on a system's
   2770 	configuration files.
   2771 	If no items are provided, a default set of checks or fixes is applied.
   2772 
   2773 	Options:
   2774 	-?		Display this help, and exit.
   2775 	-a ARCH		Set \$MACHINE_ARCH to ARCH.	[${MACHINE_ARCH}]
   2776 	-d DEST_DIR	Destination directory to check. [${DEST_DIR:-/}]
   2777 	-m MACHINE	Set \$MACHINE to MACHINE.	[${MACHINE}]
   2778 	-s SRC_ARG	Location of the source files.  This may be any of
   2779 			the following:
   2780 			-s SRC_DIR	A directory that contains a NetBSD
   2781 					source tree.
   2782 			-s TGZ_DIR	A directory in which one or both of
   2783 					"etc.tgz" and "xetc.tgz" have been
   2784 					extracted.
   2785 			-s TGZ_FILE	A distribution set file such as
   2786 					"etc.tgz" or "xetc.tgz".
   2787 					May be specified multipled times.
   2788 							[${SRC_DIR:-/usr/src}]
   2789 	-x XSRC_DIR	Location of the X11 source files.  This must be
   2790 			a directory that contains a NetBSD xsrc tree.
   2791 							[${XSRC_DIR:-/usr/src/../xsrc}]
   2792 
   2793 	Supported values for OPERATION:
   2794 	help		Display this help, and exit.
   2795 	list		List available items.
   2796 	check ITEM ...	Perform post-installation checks on ITEMs.
   2797 	diff [-bcenpuw] ITEM ...
   2798 			Similar to 'check' but also output difference of files,
   2799 			using diff with the provided options.
   2800 	fix ITEM ...	Apply fixes that 'check' determines need to be applied.
   2801 	usage		Display this help, and exit.
   2802 _USAGE_
   2803 }
   2804 
   2805 usage()
   2806 {
   2807 	help 1>&2
   2808 	exit 2
   2809 }
   2810 
   2811 
   2812 list()
   2813 {
   2814 	local i
   2815 	echo "Default set of items (to apply if no items are provided by user):"
   2816 	echo " Item                 Description"
   2817 	echo " ----                 -----------"
   2818 	for i in ${defaultitems}; do
   2819 		eval desc=\"\${desc_${i}}\"
   2820 		printf " %-20s %s\n" "${i}" "${desc}"
   2821 	done
   2822 	echo "Items disabled by default (must be requested explicitly):"
   2823 	echo " Item                 Description"
   2824 	echo " ----                 -----------"
   2825 	for i in ${otheritems}; do
   2826 		eval desc=\"\${desc_${i}}\"
   2827 		printf " %-20s %s\n" "${i}" "${desc}"
   2828 	done
   2829 }
   2830 
   2831 
   2832 main()
   2833 {
   2834 	DIRMODE=false		# true if "-s" specified a directory
   2835 	ITEMS=			# items to check|diff|fix. [${defaultitems}]
   2836 	N_SRC_ARGS=0		# number of "-s" args in SRC_ARGLIST
   2837 	SOURCEMODE=false	# true if "-s" specified a source directory
   2838 	SRC_ARGLIST=		# quoted list of one or more "-s" args
   2839 	SRC_DIR="${SRC_ARG}"	# set default value for early usage()
   2840 	TGZLIST=		# quoted list list of tgz files
   2841 	TGZMODE=false		# true if "-s" specifies a tgz file
   2842 	XSRC_DIR="${SRC_ARG}/../xsrc"
   2843 	XSRC_DIR_FIX=
   2844 
   2845 	case "$(uname -s)" in
   2846 	Darwin)
   2847 		# case sensitive match for case insensitive fs
   2848 		file_exists_exact=file_exists_exact
   2849 		;;
   2850 	*)
   2851 		file_exists_exact=:
   2852 		;;
   2853 	esac
   2854 
   2855 		# Validate options.
   2856 		#
   2857 	while getopts :a:d:m:s:x: ch; do
   2858 		case "${ch}" in
   2859 		a)
   2860 			MACHINE_ARCH="${OPTARG}"
   2861 			;;
   2862 		d)
   2863 			DEST_DIR="${OPTARG}"
   2864 			;;
   2865 		m)
   2866 			MACHINE="${OPTARG}"
   2867 			;;
   2868 		s)
   2869 			qarg="$(shell_quote "${OPTARG}")"
   2870 			N_SRC_ARGS=$(( $N_SRC_ARGS + 1 ))
   2871 			SRC_ARGLIST="${SRC_ARGLIST}${SRC_ARGLIST:+ }-s ${qarg}"
   2872 			if [ -f "${OPTARG}" ]; then
   2873 				# arg refers to a *.tgz file.
   2874 				# This may happen twice, for both
   2875 				# etc.tgz and xetc.tgz, so we build up a
   2876 				# quoted list in TGZLIST.
   2877 				TGZMODE=true
   2878 				TGZLIST="${TGZLIST}${TGZLIST:+ }${qarg}"
   2879 				# Note that, when TGZMODE is true,
   2880 				# SRC_ARG is used only for printing
   2881 				# human-readable messages.
   2882 				SRC_ARG="${TGZLIST}"
   2883 			elif [ -d "${OPTARG}" ]; then
   2884 				# arg refers to a directory.
   2885 				# It might be a source directory, or a
   2886 				# directory where the sets have already
   2887 				# been extracted.
   2888 				DIRMODE=true
   2889 				SRC_ARG="${OPTARG}"
   2890 				if [ -f "${OPTARG}/etc/Makefile" ]; then
   2891 					SOURCEMODE=true
   2892 				fi
   2893 			else
   2894 				err 2 "Invalid argument for -s option"
   2895 			fi
   2896 			;;
   2897 		x)
   2898 			if [ -d "${OPTARG}" ]; then
   2899 				# arg refers to a directory.
   2900 				XSRC_DIR="${OPTARG}"
   2901 				XSRC_DIR_FIX="-x ${OPTARG} "
   2902 			else
   2903 				err 2 "Not a directory for -x option"
   2904 			fi
   2905 			;;
   2906 		"?")
   2907 			if [ "${OPTARG}" = "?" ]; then
   2908 				help
   2909 				return	# no further processing or validation
   2910 			fi
   2911 			warn "Unknown option -${OPTARG}"
   2912 			usage
   2913 			;;
   2914 
   2915 		:)
   2916 			warn "Missing argument for option -${OPTARG}"
   2917 			usage
   2918 			;;
   2919 
   2920 		*)
   2921 			err 3 "Unimplemented option -${ch}"
   2922 			;;
   2923 		esac
   2924 	done
   2925 	shift $((${OPTIND} - 1))
   2926 	if [ $# -eq 0 ] ; then
   2927 		warn "Missing operation"
   2928 		usage
   2929 	fi
   2930 	op="$1"
   2931 	shift
   2932 
   2933 	if [ "$N_SRC_ARGS" -gt 1 ] && $DIRMODE; then
   2934 		err 2 "Multiple -s args are allowed only with tgz files"
   2935 	fi
   2936 	if [ "$N_SRC_ARGS" -eq 0 ]; then
   2937 		# The default SRC_ARG was set elsewhere
   2938 		DIRMODE=true
   2939 		SOURCEMODE=true
   2940 		SRC_ARGLIST="-s $(shell_quote "${SRC_ARG}")"
   2941 	fi
   2942 
   2943 		# Validate 'diff' first, as it becomes 'check'
   2944 		#
   2945 	case "${op}" in
   2946 
   2947 	diff)
   2948 		op=check
   2949 		DIFF_STYLE=n			# default style is RCS
   2950 		OPTIND=1
   2951 		while getopts :bcenpuw ch; do
   2952 			case "${ch}" in
   2953 			c|e|n|u)
   2954 				if [ "${DIFF_STYLE}" != "n" -a \
   2955 				    "${DIFF_STYLE}" != "${ch}" ]; then
   2956 					warn "diff: conflicting output style: -${ch}"
   2957 					usage
   2958 				fi
   2959 				DIFF_STYLE="${ch}"
   2960 				;;
   2961 			b|p|w)
   2962 				DIFF_OPT="${DIFF_OPT} -${ch}"
   2963 				;;
   2964 			"?")
   2965 				# NOTE: not supporting diff -?
   2966 				warn "diff: Unknown option -${OPTARG}"
   2967 				usage
   2968 				;;
   2969 			:)
   2970 				warn "diff: Missing argument for option -${OPTARG}"
   2971 				usage
   2972 				;;
   2973 			*)
   2974 				err 3 "diff: Unimplemented option -${ch}"
   2975 				;;
   2976 			esac
   2977 		done
   2978 		shift $((${OPTIND} - 1))
   2979 		;;
   2980 
   2981 	esac
   2982 
   2983 		# Validate operation and items.
   2984 		#
   2985 	case "${op}" in
   2986 
   2987 	check|fix)
   2988 		ITEMS="$*"
   2989 		: ${ITEMS:="${defaultitems}"}
   2990 
   2991 		# ensure that all supplied items are valid
   2992 		#
   2993 		for i in ${ITEMS}; do
   2994 			eval desc=\"\${desc_${i}}\"
   2995 			[ -n "${desc}" ] || err 2 "Unsupported ${op} '"${i}"'"
   2996 		done
   2997 		;;
   2998 
   2999 	help|usage)
   3000 		help
   3001 		return	# no further processing or validation
   3002 		;;
   3003 
   3004 	list)
   3005 		# processed below
   3006 		;;
   3007 
   3008 	*)
   3009 		warn "Unknown operation '"${op}"'"
   3010 		usage
   3011 		;;
   3012 
   3013 	esac
   3014 
   3015 	#
   3016 	# If '-s' arg or args specified tgz files, extract them
   3017 	# to a scratch directory.
   3018 	#
   3019 	if $TGZMODE; then
   3020 		ETCTGZDIR="${SCRATCHDIR}/etc.tgz"
   3021 		echo "Note: Creating temporary directory ${ETCTGZDIR}"
   3022 		if ! mkdir "${ETCTGZDIR}"; then
   3023 			err 2 "Can't create ${ETCTGZDIR}"
   3024 		fi
   3025 		( # subshell to localise changes to "$@"
   3026 			eval "set -- ${TGZLIST}"
   3027 			for tgz in "$@"; do
   3028 				echo "Note: Extracting files from ${tgz}"
   3029 				cat "${tgz}" | (
   3030 					cd "${ETCTGZDIR}" &&
   3031 					tar -zxf -
   3032 				) || err 2 "Can't extract ${tgz}"
   3033 			done
   3034 		)
   3035 		SRC_DIR="${ETCTGZDIR}"
   3036 	else
   3037 		SRC_DIR="${SRC_ARG}"
   3038 	fi
   3039 
   3040 	[ -d "${SRC_DIR}" ]	|| err 2 "${SRC_DIR} is not a directory"
   3041 	[ -d "${DEST_DIR}" ]	|| err 2 "${DEST_DIR} is not a directory"
   3042 	[ -n "${MACHINE}" ]	|| err 2 "\${MACHINE} is not defined"
   3043 	[ -n "${MACHINE_ARCH}" ] || err 2 "\${MACHINE_ARCH} is not defined"
   3044 	if ! $SOURCEMODE && ! [ -f "${SRC_DIR}/etc/mtree/set.etc" ]; then
   3045 		err 2 "Files from the etc.tgz set are missing"
   3046 	fi
   3047 
   3048 		# If directories are /, clear them, so various messages
   3049 		# don't have leading "//".   However, this requires
   3050 		# the use of ${foo:-/} to display the variables.
   3051 		#
   3052 	[ "${SRC_DIR}" = "/" ]	&& SRC_DIR=""
   3053 	[ "${DEST_DIR}" = "/" ]	&& DEST_DIR=""
   3054 
   3055 	detect_x11
   3056 
   3057 		# Perform operation.
   3058 		#
   3059 	case "${op}" in
   3060 
   3061 	check|fix)
   3062 		[ -n "${ITEMS}" ] || err 2 "${op}: missing items"
   3063 
   3064 		echo "Source directory: ${SRC_DIR:-/}"
   3065 		if $TGZMODE; then
   3066 			echo " (extracted from: ${SRC_ARG})"
   3067 		fi
   3068 		echo "Target directory: ${DEST_DIR:-/}"
   3069 		items_passed=
   3070 		items_failed=
   3071 		for i in ${ITEMS}; do
   3072 			echo "${i} ${op}:"
   3073 			( eval do_${i} ${op} )
   3074 			if [ $? -eq 0 ]; then
   3075 				items_passed="${items_passed} ${i}"
   3076 			else
   3077 				items_failed="${items_failed} ${i}"
   3078 			fi
   3079 		done
   3080 
   3081 		if [ "${op}" = "check" ]; then
   3082 			plural="checks"
   3083 		else
   3084 			plural="fixes"
   3085 		fi
   3086 
   3087 		echo "${PROGNAME} ${plural} passed:${items_passed}"
   3088 		echo "${PROGNAME} ${plural} failed:${items_failed}"
   3089 		if [ -n "${items_failed}" ]; then
   3090 		    exitstatus=1;
   3091 		    if [ "${op}" = "check" ]; then
   3092 			[ "$MACHINE" = "$(uname -m)" ] && m= || m=" -m $MACHINE"
   3093 			cat <<_Fix_me_
   3094 To fix, run:
   3095     ${HOST_SH} ${0} ${SRC_ARGLIST} ${XSRC_DIR_FIX}-d ${DEST_DIR:-/}$m fix${items_failed}
   3096 Note that this may overwrite local changes.
   3097 _Fix_me_
   3098 		    fi
   3099 		fi
   3100 		;;
   3101 
   3102 	list)
   3103 		echo "Source directory: ${SRC_DIR:-/}"
   3104 		echo "Target directory: ${DEST_DIR:-/}"
   3105 		if $TGZMODE; then
   3106 			echo " (extracted from: ${SRC_ARG})"
   3107 		fi
   3108 		list
   3109 		;;
   3110 
   3111 	*)
   3112 			# diff, help, usage handled during operation validation
   3113 		err 3 "Unimplemented operation '"${op}"'"
   3114 		;;
   3115 
   3116 	esac
   3117 }
   3118 
   3119 if [ -n "$POSTINSTALL_FUNCTION" ]; then
   3120 	eval "$POSTINSTALL_FUNCTION"
   3121 	exit 0
   3122 fi
   3123 
   3124 # defaults
   3125 #
   3126 PROGNAME="${0##*/}"
   3127 SRC_ARG="/usr/src"
   3128 DEST_DIR="/"
   3129 : ${MACHINE:="$( uname -m )"}	# assume native build if $MACHINE is not set
   3130 : ${MACHINE_ARCH:="$( uname -p )"}# assume native build if not set
   3131 
   3132 DIFF_STYLE=
   3133 DIFF_OPT=
   3134 NOT_FIXED=" (FIX MANUALLY)"
   3135 SCRATCHDIR="$( mkdtemp )" || err 2 "Can't create scratch directory"
   3136 trap "${RM} -rf \"\${SCRATCHDIR}\" ; exit 0" 1 2 3 15	# HUP INT QUIT TERM
   3137 
   3138 umask 022
   3139 exec 3>/dev/null
   3140 exec 4>/dev/null
   3141 exitstatus=0
   3142 
   3143 main "$@"
   3144 ${RM} -rf "${SCRATCHDIR}"
   3145 exit $exitstatus
   3146