3140 lines
70 KiB
Bash
Executable File
3140 lines
70 KiB
Bash
Executable File
#!/bin/sh
|
|
#
|
|
# $NetBSD: postinstall.in,v 1.62 2024/03/10 18:23:18 rillig Exp $
|
|
#
|
|
# Copyright (c) 2002-2022 The NetBSD Foundation, Inc.
|
|
# All rights reserved.
|
|
#
|
|
# This code is derived from software contributed to The NetBSD Foundation
|
|
# by Luke Mewburn.
|
|
#
|
|
# Redistribution and use in source and binary forms, with or without
|
|
# modification, are permitted provided that the following conditions
|
|
# are met:
|
|
# 1. Redistributions of source code must retain the above copyright
|
|
# notice, this list of conditions and the following disclaimer.
|
|
# 2. Redistributions in binary form must reproduce the above copyright
|
|
# notice, this list of conditions and the following disclaimer in the
|
|
# documentation and/or other materials provided with the distribution.
|
|
#
|
|
# THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
|
|
# ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
|
# TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
|
# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
|
|
# BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
|
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
|
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
|
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
|
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
|
# POSSIBILITY OF SUCH DAMAGE.
|
|
#
|
|
# postinstall
|
|
# Check for or fix configuration changes that occur
|
|
# over time as NetBSD evolves.
|
|
#
|
|
|
|
#
|
|
# NOTE: Be sure to use ${DEST_DIR} prefix before all real file operations.
|
|
#
|
|
|
|
#
|
|
# checks to add:
|
|
# - sysctl(8) renames (net.inet6.ip6.bindv6only -> net.inet6.ip6.v6only)
|
|
# - de* -> tlp* migration (/etc/ifconfig.de*, $ifconfig_de*, ...) ?
|
|
# - support quiet/verbose mode ?
|
|
# - differentiate between failures caused by missing source
|
|
# and real failures
|
|
# - install moduli into usr/share/examples/ssh and use from there?
|
|
# - differentiate between "needs fix" versus "can't fix" issues
|
|
#
|
|
|
|
# This script is executed as part of a cross build. Allow the build
|
|
# environment to override the locations of some tools.
|
|
: ${AWK:=awk}
|
|
: ${DB:=db}
|
|
: ${GREP:=grep}
|
|
: ${HOST_SH:=sh}
|
|
: ${MAKE:=make}
|
|
: ${PWD_MKDB:=/usr/sbin/pwd_mkdb}
|
|
: ${SED:=sed}
|
|
: ${SORT:=sort}
|
|
: ${STAT:=stat}
|
|
: ${RM:=rm}
|
|
|
|
#
|
|
# helper functions
|
|
#
|
|
|
|
err()
|
|
{
|
|
local exitval=$1
|
|
shift
|
|
echo 1>&2 "${PROGNAME}: $*"
|
|
if [ -n "${SCRATCHDIR}" ]; then
|
|
${RM} -rf "${SCRATCHDIR}"
|
|
fi
|
|
exit ${exitval}
|
|
}
|
|
|
|
warn()
|
|
{
|
|
echo 1>&2 "${PROGNAME}: $*"
|
|
}
|
|
|
|
msg()
|
|
{
|
|
echo " $*"
|
|
}
|
|
|
|
mkdtemp()
|
|
{
|
|
# Make sure we don't loop forever if mkdir will always fail.
|
|
[ -d /tmp ] || err 2 /tmp is not a directory
|
|
[ -w /tmp ] || err 2 /tmp is not writable
|
|
|
|
local base="/tmp/_postinstall.$$"
|
|
local serial=0
|
|
local dir
|
|
|
|
while true; do
|
|
dir="${base}.${serial}"
|
|
mkdir -m 0700 "${dir}" && break
|
|
serial=$((${serial} + 1))
|
|
done
|
|
echo "${dir}"
|
|
}
|
|
|
|
# Quote args to make them safe in the shell.
|
|
# Usage: quotedlist="$(shell_quote args...)"
|
|
#
|
|
# After building up a quoted list, use it by evaling it inside
|
|
# double quotes, like this:
|
|
# eval "set -- $quotedlist"
|
|
# or like this:
|
|
# eval "\$command $quotedlist \$filename"
|
|
#
|
|
shell_quote()
|
|
{(
|
|
local result=''
|
|
local arg qarg
|
|
LC_COLLATE=C ; export LC_COLLATE # so [a-zA-Z0-9] works in ASCII
|
|
for arg in "$@" ; do
|
|
case "${arg}" in
|
|
'')
|
|
qarg="''"
|
|
;;
|
|
*[!-./a-zA-Z0-9]*)
|
|
# Convert each embedded ' to '\'',
|
|
# then insert ' at the beginning of the first line,
|
|
# and append ' at the end of the last line.
|
|
# Finally, elide unnecessary '' pairs at the
|
|
# beginning and end of the result and as part of
|
|
# '\'''\'' sequences that result from multiple
|
|
# adjacent quotes in he input.
|
|
qarg="$(printf "%s\n" "$arg" | \
|
|
${SED} -e "s/'/'\\\\''/g" \
|
|
-e "1s/^/'/" -e "\$s/\$/'/" \
|
|
-e "1s/^''//" -e "\$s/''\$//" \
|
|
-e "s/'''/'/g"
|
|
)"
|
|
;;
|
|
*)
|
|
# Arg is not the empty string, and does not contain
|
|
# any unsafe characters. Leave it unchanged for
|
|
# readability.
|
|
qarg="${arg}"
|
|
;;
|
|
esac
|
|
result="${result}${result:+ }${qarg}"
|
|
done
|
|
printf "%s\n" "$result"
|
|
)}
|
|
|
|
# Convert arg $1 to a basic regular expression (as in sed)
|
|
# that will match the arg. This works by inserting backslashes
|
|
# before characters that are special in basic regular expressions.
|
|
# It also inserts backslashes before the extra characters specified
|
|
# in $2 (which defaults to "/,").
|
|
# XXX: Does not handle embedded newlines.
|
|
# Usage: regex="$(bre_quote "${string}")"
|
|
bre_quote()
|
|
{
|
|
local arg="$1"
|
|
local extra="${2-/,}"
|
|
printf "%s\n" "${arg}" | ${SED} -e 's/[][^$.*\\'"${extra}"']/\\&/g'
|
|
}
|
|
|
|
# unprefix dir
|
|
# Remove any dir prefix from a list of paths on stdin,
|
|
# and write the result to stdout. Useful for converting
|
|
# from ${DEST_DIR}/path to /path.
|
|
#
|
|
unprefix()
|
|
{
|
|
[ $# -eq 1 ] || err 3 "USAGE: unprefix dir"
|
|
local prefix="${1%/}"
|
|
prefix="$(bre_quote "${prefix}")"
|
|
|
|
${SED} -e "s,^${prefix}/,/,"
|
|
}
|
|
|
|
# additem item description
|
|
# Add item to list of supported items to check/fix,
|
|
# which are checked/fixed by default if no item is requested by user.
|
|
#
|
|
additem()
|
|
{
|
|
[ $# -eq 2 ] || err 3 "USAGE: additem item description"
|
|
defaultitems="${defaultitems}${defaultitems:+ }$1"
|
|
eval desc_$1=\"\$2\"
|
|
}
|
|
|
|
# adddisableditem item description
|
|
# Add item to list of supported items to check/fix,
|
|
# but execute the item only if the user asks for it explicitly.
|
|
#
|
|
adddisableditem()
|
|
{
|
|
[ $# -eq 2 ] || err 3 "USAGE: adddisableditem item description"
|
|
otheritems="${otheritems}${otheritems:+ }$1"
|
|
eval desc_$1=\"\$2\"
|
|
}
|
|
|
|
# checkdir op dir mode
|
|
# Ensure dir exists, and if not, create it with the appropriate mode.
|
|
# Returns 0 if ok, 1 otherwise.
|
|
#
|
|
check_dir()
|
|
{
|
|
[ $# -eq 3 ] || err 3 "USAGE: check_dir op dir mode"
|
|
local op="$1"
|
|
local dir="$2"
|
|
local mode="$3"
|
|
[ -d "${dir}" ] && return 0
|
|
if [ "${op}" = "check" ]; then
|
|
msg "${dir} is not a directory"
|
|
return 1
|
|
elif ! mkdir -m "${mode}" "${dir}" ; then
|
|
msg "Can't create missing ${dir}"
|
|
return 1
|
|
else
|
|
msg "Missing ${dir} created"
|
|
fi
|
|
return 0
|
|
}
|
|
|
|
# check_ids op type file srcfile start id ...
|
|
# Check if file of type "users" or "groups" contains the relevant IDs.
|
|
# Use srcfile as a reference for the expected contents.
|
|
# The specified "id" names should be given in numerical order,
|
|
# with the first name corresponding to numerical value "start",
|
|
# and with the special name "SKIP" being used to mark gaps in the
|
|
# sequence.
|
|
# Returns 0 if ok, 1 otherwise.
|
|
#
|
|
check_ids()
|
|
{
|
|
[ $# -ge 6 ] || err 3 "USAGE: checks_ids op type file srcfile start id ..."
|
|
local op="$1"
|
|
local type="$2"
|
|
local file="$3"
|
|
local srcfile="$4"
|
|
local start="$5"
|
|
shift 5
|
|
#local ids="$@"
|
|
|
|
if [ ! -f "${file}" ]; then
|
|
msg "${file} doesn't exist; can't check for missing ${type}"
|
|
return 1
|
|
fi
|
|
if [ ! -r "${file}" ]; then
|
|
msg "${file} is not readable; can't check for missing ${type}"
|
|
return 1
|
|
fi
|
|
local notfixed=""
|
|
if [ "${op}" = "fix" ]; then
|
|
notfixed="${NOT_FIXED}"
|
|
fi
|
|
local missing="$(${AWK} -v start=$start -F: '
|
|
BEGIN {
|
|
for (x = 1; x < ARGC; x++) {
|
|
if (ARGV[x] == "SKIP")
|
|
continue;
|
|
idlist[ARGV[x]]++;
|
|
value[ARGV[x]] = start + x - 1;
|
|
}
|
|
ARGC=1
|
|
}
|
|
{
|
|
found[$1]++
|
|
number[$1] = $3
|
|
}
|
|
END {
|
|
for (id in idlist) {
|
|
if (!(id in found))
|
|
printf("%s (missing)\n", id)
|
|
else if (number[id] != value[id])
|
|
printf("%s (%d != %d)\n", id,
|
|
number[id], value[id])
|
|
start++;
|
|
}
|
|
}
|
|
' "$@" < "${file}")" || return 1
|
|
if [ -n "${missing}" ]; then
|
|
msg "Error ${type}${notfixed}:" $(echo ${missing})
|
|
msg "Use the following as a template:"
|
|
set -- ${missing}
|
|
while [ $# -gt 0 ]
|
|
do
|
|
${GREP} -E "^${1}:" ${srcfile}
|
|
shift 2
|
|
done | sort -t: -k3n
|
|
msg "and adjust if necessary."
|
|
return 1
|
|
fi
|
|
return 0
|
|
}
|
|
|
|
# populate_dir op onlynew src dst mode file ...
|
|
# Perform op ("check" or "fix") on files in src/ against dst/
|
|
# If op = "check" display missing or changed files, optionally with diffs.
|
|
# If op != "check" copies any missing or changed files.
|
|
# If onlynew evaluates to true, changed files are ignored.
|
|
# Returns 0 if ok, 1 otherwise.
|
|
#
|
|
populate_dir()
|
|
{
|
|
[ $# -ge 5 ] || err 3 "USAGE: populate_dir op onlynew src dst mode file ..."
|
|
local op="$1"
|
|
local onlynew="$2"
|
|
local src="$3"
|
|
local dst="$4"
|
|
local mode="$5"
|
|
shift 5
|
|
#local files="$@"
|
|
|
|
if [ ! -d "${src}" ]; then
|
|
msg "${src} is not a directory; skipping check"
|
|
return 1
|
|
fi
|
|
check_dir "${op}" "${dst}" 755 || return 1
|
|
|
|
local cmpdir_rv=0
|
|
local f fs fd error
|
|
for f in "$@"; do
|
|
fs="${src}/${f}"
|
|
fd="${dst}/${f}"
|
|
error=""
|
|
if [ ! -f "${fd}" ]; then
|
|
error="${fd} does not exist"
|
|
elif ! cmp -s "${fs}" "${fd}" ; then
|
|
if $onlynew; then # leave existing ${fd} alone
|
|
continue;
|
|
fi
|
|
error="${fs} != ${fd}"
|
|
else
|
|
continue
|
|
fi
|
|
if [ "${op}" = "check" ]; then
|
|
msg "${error}"
|
|
if [ -n "${DIFF_STYLE}" -a -f "${fd}" ]; then
|
|
diff -${DIFF_STYLE} ${DIFF_OPT} "${fd}" "${fs}"
|
|
fi
|
|
cmpdir_rv=1
|
|
elif ! ${RM} -f "${fd}" ||
|
|
! cp -f "${fs}" "${fd}"; then
|
|
msg "Can't copy ${fs} to ${fd}"
|
|
cmpdir_rv=1
|
|
elif ! chmod "${mode}" "${fd}"; then
|
|
msg "Can't change mode of ${fd} to ${mode}"
|
|
cmpdir_rv=1
|
|
else
|
|
msg "Copied ${fs} to ${fd}"
|
|
fi
|
|
done
|
|
return ${cmpdir_rv}
|
|
}
|
|
|
|
# compare_dir op src dst mode file ...
|
|
# Perform op ("check" or "fix") on files in src/ against dst/
|
|
# If op = "check" display missing or changed files, optionally with diffs.
|
|
# If op != "check" copies any missing or changed files.
|
|
# Returns 0 if ok, 1 otherwise.
|
|
#
|
|
compare_dir()
|
|
{
|
|
[ $# -ge 4 ] || err 3 "USAGE: compare_dir op src dst mode file ..."
|
|
local op="$1"
|
|
local src="$2"
|
|
local dst="$3"
|
|
local mode="$4"
|
|
shift 4
|
|
#local files="$@"
|
|
|
|
populate_dir "$op" false "$src" "$dst" "$mode" "$@"
|
|
}
|
|
|
|
# move_file op src dst --
|
|
# Check (op == "check") or move (op != "check") from src to dst.
|
|
# Returns 0 if ok, 1 otherwise.
|
|
#
|
|
move_file()
|
|
{
|
|
[ $# -eq 3 ] || err 3 "USAGE: move_file op src dst"
|
|
local op="$1"
|
|
local src="$2"
|
|
local dst="$3"
|
|
|
|
if [ -f "${src}" -a ! -f "${dst}" ]; then
|
|
if [ "${op}" = "check" ]; then
|
|
msg "Move ${src} to ${dst}"
|
|
return 1
|
|
fi
|
|
if ! mv "${src}" "${dst}"; then
|
|
msg "Can't move ${src} to ${dst}"
|
|
return 1
|
|
fi
|
|
msg "Moved ${src} to ${dst}"
|
|
fi
|
|
return 0
|
|
}
|
|
|
|
# rcconf_is_set op name var [verbose] --
|
|
# Load the rcconf for name, and check if obsolete rc.conf(5) variable
|
|
# var is defined or not.
|
|
# Returns 0 if defined (even to ""), otherwise 1.
|
|
# If verbose != "", print an obsolete warning if the var is defined.
|
|
#
|
|
rcconf_is_set()
|
|
{
|
|
[ $# -ge 3 ] || err 3 "USAGE: rcconf_is_set op name var [verbose]"
|
|
local op="$1"
|
|
local name="$2"
|
|
local var="$3"
|
|
local verbose="$4"
|
|
local notfixed=""
|
|
if [ "${op}" = "fix" ]; then
|
|
notfixed="${NOT_FIXED}"
|
|
fi
|
|
(
|
|
for f in \
|
|
"${DEST_DIR}/etc/rc.conf" \
|
|
"${DEST_DIR}/etc/rc.conf.d/${name}"; do
|
|
[ -f "${f}" ] && . "${f}"
|
|
done
|
|
eval echo -n \"\${${var}}\" 1>&3
|
|
if eval "[ -n \"\${${var}+SET}\" ]"; then
|
|
if [ -n "${verbose}" ]; then
|
|
msg \
|
|
"Obsolete rc.conf(5) variable '\$${var}' found.${notfixed}"
|
|
fi
|
|
exit 0
|
|
else
|
|
exit 1
|
|
fi
|
|
)
|
|
}
|
|
|
|
# rcvar_is_enabled var
|
|
# Check if rcvar is enabled
|
|
#
|
|
rcvar_is_enabled()
|
|
{
|
|
[ $# -eq 1 ] || err 3 "USAGE: rcvar_is_enabled var"
|
|
local var="$1"
|
|
(
|
|
[ -f "${DEST_DIR}/etc/rc.conf" ] && . "${DEST_DIR}/etc/rc.conf"
|
|
eval val=\"\${${var}}\"
|
|
case $val in
|
|
# "yes", "true", "on", or "1"
|
|
[Yy][Ee][Ss]|[Tt][Rr][Uu][Ee]|[Oo][Nn]|1)
|
|
exit 0
|
|
;;
|
|
|
|
*)
|
|
exit 1
|
|
;;
|
|
esac
|
|
)
|
|
}
|
|
|
|
# find_file_in_dirlist() file message dir1 ... --
|
|
# Find which directory file is in, and sets ${dir} to match.
|
|
# Returns 0 if matched, otherwise 1 (and sets ${dir} to "").
|
|
#
|
|
# Generally, check the directory for the "checking from source" case,
|
|
# and then the directory for the "checking from extracted etc.tgz" case.
|
|
#
|
|
find_file_in_dirlist()
|
|
{
|
|
[ $# -ge 3 ] || err 3 "USAGE: find_file_in_dirlist file msg dir1 ..."
|
|
|
|
local file="$1" ; shift
|
|
local msg="$1" ; shift
|
|
local dir1st= # first dir in list
|
|
# returns dir
|
|
for dir in "$@"; do
|
|
: ${dir1st:="${dir}"}
|
|
if [ -f "${dir}/${file}" ]; then
|
|
if [ "${dir1st}" != "${dir}" ]; then
|
|
msg \
|
|
"(Checking for ${msg} from ${dir} instead of ${dir1st})"
|
|
fi
|
|
return 0
|
|
fi
|
|
done
|
|
msg "Can't find source directory for ${msg}"
|
|
return 1
|
|
}
|
|
|
|
# file_exists_exact path
|
|
# Returns true if a file exists in the ${DEST_DIR} whose name
|
|
# is exactly ${path}, interpreted in a case-sensitive way
|
|
# even if the underlying file system is case-insensitive.
|
|
#
|
|
# The path must begin with '/' or './', and is interpreted as
|
|
# being relative to ${DEST_DIR}.
|
|
#
|
|
file_exists_exact()
|
|
{
|
|
[ -n "$1" ] || err 3 "USAGE: file_exists_exact path"
|
|
local path="${1#.}"
|
|
[ -h "${DEST_DIR}${path}" ] || \
|
|
[ -e "${DEST_DIR}${path}" ] || return 1
|
|
while [ "${path}" != "/" -a "${path}" != "." ] ; do
|
|
local dirname="$(dirname "${path}" 2>/dev/null)"
|
|
local basename="$(basename "${path}" 2>/dev/null)"
|
|
ls -fa "${DEST_DIR}${dirname}" 2> /dev/null \
|
|
| ${GREP} -q -F -x "${basename}" \
|
|
|| return 1
|
|
path="${dirname}"
|
|
done
|
|
return 0
|
|
}
|
|
|
|
# obsolete_paths op
|
|
# Obsolete the list of paths provided on stdin.
|
|
# Each path should start with '/' or './', and
|
|
# will be interpreted relative to ${DEST_DIR}.
|
|
#
|
|
obsolete_paths()
|
|
{
|
|
[ -n "$1" ] || err 3 "USAGE: obsolete_paths fix|check"
|
|
local op="$1"
|
|
local failed=0
|
|
local ofile cmd ftype
|
|
|
|
while read ofile; do
|
|
if ! ${file_exists_exact} "${ofile}"; then
|
|
continue
|
|
fi
|
|
ofile="${DEST_DIR}${ofile#.}"
|
|
cmd="${RM}"
|
|
ftype="file"
|
|
if [ -h "${ofile}" ]; then
|
|
ftype="link"
|
|
elif [ -d "${ofile}" ]; then
|
|
ftype="directory"
|
|
cmd="rmdir"
|
|
elif [ ! -e "${ofile}" ]; then
|
|
continue
|
|
fi
|
|
if [ "${op}" = "check" ]; then
|
|
msg "Remove obsolete ${ftype} ${ofile}"
|
|
failed=1
|
|
elif ! eval "${cmd} \"\${ofile}\""; then
|
|
msg "Can't remove obsolete ${ftype} ${ofile}"
|
|
failed=1
|
|
else
|
|
msg "Removed obsolete ${ftype} ${ofile}"
|
|
fi
|
|
done
|
|
return ${failed}
|
|
}
|
|
|
|
# obsolete_libs dir
|
|
# Display the minor/teeny shared libraries in dir that are considered
|
|
# to be obsolete.
|
|
#
|
|
# The implementation supports removing obsolete major libraries
|
|
# if the awk variable AllLibs is set, although there is no way to
|
|
# enable that in the enclosing shell function as this time.
|
|
#
|
|
obsolete_libs()
|
|
{
|
|
[ $# -eq 1 ] || err 3 "USAGE: obsolete_libs dir"
|
|
local dir="$1"
|
|
|
|
_obsolete_libs "${dir}"
|
|
_obsolete_libs "/usr/libdata/debug/${dir}"
|
|
}
|
|
|
|
exclude()
|
|
{
|
|
local dollar
|
|
case "$1" in
|
|
-t)
|
|
dollar='$'
|
|
shift
|
|
;;
|
|
*)
|
|
dollar=
|
|
;;
|
|
esac
|
|
if [ -z "$*" ]; then
|
|
cat
|
|
else
|
|
eval ${GREP} -v -E "'(^$(echo $* | \
|
|
${SED} -e s/\\./\\\\./g -e 's/ /'${dollar}'|^/'g)${dollar})'"
|
|
fi
|
|
}
|
|
|
|
#
|
|
# find all the target symlinks of shared libraries and exclude them
|
|
# from consideration for removal
|
|
#
|
|
exclude_libs()
|
|
{
|
|
local target="$(ls -l -d lib*.so.* 2> /dev/null \
|
|
| ${AWK} '{ print $11; }' \
|
|
| ${SED} -e 's@.*/@@' | ${SORT} -u)"
|
|
exclude -t ${target}
|
|
}
|
|
|
|
_obsolete_libs()
|
|
{
|
|
local dir="$1"
|
|
|
|
(
|
|
|
|
if [ ! -e "${DEST_DIR}/${dir}" ]
|
|
then
|
|
return 0
|
|
fi
|
|
|
|
cd "${DEST_DIR}/${dir}" || err 2 "can't cd to ${DEST_DIR}/${dir}"
|
|
echo lib*.so.* \
|
|
| tr ' ' '\n' \
|
|
| ${AWK} -v LibDir="${dir}/" '
|
|
#{
|
|
|
|
function digit(v, c, n) { return (n <= c) ? v[n] : 0 }
|
|
|
|
function checklib(results, line, regex) {
|
|
if (! match(line, regex))
|
|
return
|
|
lib = substr(line, RSTART, RLENGTH)
|
|
rev = substr($0, RLENGTH+1)
|
|
if (! (lib in results)) {
|
|
results[lib] = rev
|
|
return
|
|
}
|
|
orevc = split(results[lib], orev, ".")
|
|
nrevc = split(rev, nrev, ".")
|
|
maxc = (orevc > nrevc) ? orevc : nrevc
|
|
for (i = 1; i <= maxc; i++) {
|
|
res = digit(orev, orevc, i) - digit(nrev, nrevc, i)
|
|
if (res < 0) {
|
|
print LibDir lib results[lib]
|
|
results[lib] = rev
|
|
return
|
|
} else if (res > 0) {
|
|
print LibDir lib rev
|
|
return
|
|
}
|
|
}
|
|
}
|
|
|
|
/^lib.*\.so\.[0-9]+\.[0-9]+(\.[0-9]+)?(\.debug)?$/ {
|
|
if (AllLibs)
|
|
checklib(minor, $0, "^lib.*\\.so\\.")
|
|
else
|
|
checklib(found, $0, "^lib.*\\.so\\.[0-9]+\\.")
|
|
}
|
|
|
|
/^lib.*\.so\.[0-9]+$/ {
|
|
if (AllLibs)
|
|
checklib(major, $0, "^lib.*\\.so\\.")
|
|
}
|
|
|
|
#}' | exclude_libs
|
|
|
|
)
|
|
}
|
|
|
|
# obsolete_stand dir
|
|
# Prints the names of all obsolete files and subdirs below the
|
|
# provided dir. dir should be something like /stand/${MACHINE}.
|
|
# The input dir and all output paths are interpreted
|
|
# relative to ${DEST_DIR}.
|
|
#
|
|
# Assumes that the numerically largest subdir is current, and all
|
|
# others are obsolete.
|
|
#
|
|
obsolete_stand()
|
|
{
|
|
[ $# -eq 1 ] || err 3 "USAGE: obsolete_stand dir"
|
|
local dir="$1"
|
|
local subdir
|
|
|
|
if ! [ -d "${DEST_DIR}${dir}" ]; then
|
|
msg "${DEST_DIR}${dir} doesn't exist; can't check for obsolete files"
|
|
return 1
|
|
fi
|
|
|
|
( cd "${DEST_DIR}${dir}" && ls -1d [0-9]*[0-9]/. ) \
|
|
| ${GREP} -v '[^0-9./]' \
|
|
| sort -t. -r -n -k1,1 -k2,2 -k3,3 \
|
|
| tail -n +2 \
|
|
| while read subdir ; do
|
|
subdir="${subdir%/.}"
|
|
find "${DEST_DIR}${dir}/${subdir}" -depth -print
|
|
done \
|
|
| unprefix "${DEST_DIR}"
|
|
}
|
|
|
|
# modify_file op srcfile scratchfile awkprog
|
|
# Apply awkprog to srcfile sending output to scratchfile, and
|
|
# if appropriate replace srcfile with scratchfile.
|
|
#
|
|
modify_file()
|
|
{
|
|
[ $# -eq 4 ] || err 3 "USAGE: modify_file op file scratch awkprog"
|
|
|
|
local op="$1"
|
|
local file="$2"
|
|
local scratch="$3"
|
|
local prog="$4"
|
|
local failed=0
|
|
local line
|
|
|
|
${AWK} "${prog}" < "${file}" > "${scratch}"
|
|
if ! cmp -s "${file}" "${scratch}"; then
|
|
diff "${file}" "${scratch}" > "${scratch}.diffs"
|
|
if [ "${op}" = "check" ]; then
|
|
msg "${file} needs the following changes:"
|
|
mffailed=1
|
|
elif ! ${RM} -f "${file}" ||
|
|
! cp -f "${scratch}" "${file}"; then
|
|
msg "${file} changes not applied:"
|
|
mffailed=1
|
|
else
|
|
msg "${file} changes applied:"
|
|
fi
|
|
while read line; do
|
|
msg " ${line}"
|
|
done < "${scratch}.diffs"
|
|
fi
|
|
return ${failed}
|
|
}
|
|
|
|
|
|
# contents_owner op directory user group
|
|
# Make sure directory and contents are owned (and group-owned)
|
|
# as specified.
|
|
#
|
|
contents_owner()
|
|
{
|
|
[ $# -eq 4 ] || err 3 "USAGE: contents_owner op dir user group"
|
|
|
|
local op="$1"
|
|
local dir="$2"
|
|
local user="$3"
|
|
local grp="$4"
|
|
local files error
|
|
|
|
if [ "${op}" = "check" ]; then
|
|
files=$(find "${dir}" \( \( ! -user "${user}" \) -o \
|
|
\( ! -group "${grp}" \) \) )
|
|
error=$?
|
|
if [ ! -z "$files" ] || [ $error != 0 ]; then
|
|
msg "${dir} and contents not all owned by" \
|
|
"${user}:${grp}"
|
|
return 1
|
|
else
|
|
return 0
|
|
fi
|
|
elif [ "${op}" = "fix" ]; then
|
|
find "${dir}" \( \( ! -user "${user}" \) -o \
|
|
\( ! -group "${grp}" \) \) \
|
|
-exec chown "${user}:${grp}" -- {} \;
|
|
fi
|
|
}
|
|
|
|
# get_makevar var ...
|
|
# Retrieve the value of a user-settable system make variable
|
|
get_makevar()
|
|
{
|
|
local var value
|
|
$SOURCEMODE || err 3 "get_makevar must be used in source mode"
|
|
[ $# -eq 0 ] && err 3 "USAGE: get_makevar var ..."
|
|
|
|
for var in "$@"; do
|
|
value="$(echo '.include <bsd.own.mk>' | \
|
|
${MAKE} -f - -V "\${${var}}")"
|
|
|
|
eval ${var}=\"\${value}\"
|
|
done
|
|
}
|
|
|
|
# detect_x11
|
|
# Detect if X11 components should be analysed and set values of
|
|
# relevant variables.
|
|
detect_x11()
|
|
{
|
|
if $SOURCEMODE; then
|
|
get_makevar MKX11 X11ROOTDIR X11SRCDIR
|
|
else
|
|
if [ -f "${SRC_DIR}/etc/mtree/set.xetc" ]; then
|
|
MKX11=yes
|
|
X11ROOTDIR=/this/value/isnt/used/yet
|
|
else
|
|
MKX11=no
|
|
X11ROOTDIR=
|
|
fi
|
|
X11SRCDIR=/nonexistent/xsrc
|
|
fi
|
|
}
|
|
|
|
#
|
|
# find out where MAKEDEV lives, set MAKEDEV_DIR appropriately
|
|
#
|
|
find_makedev()
|
|
{
|
|
if [ -e "${DEST_DIR}/dev/MAKEDEV" ]; then
|
|
MAKEDEV_DIR="${DEST_DIR}/dev"
|
|
elif [ -e "${DEST_DIR}/etc/MAKEDEV" ]; then
|
|
MAKEDEV_DIR="${DEST_DIR}/etc"
|
|
else
|
|
MAKEDEV_DIR="${DEST_DIR}/dev"
|
|
fi
|
|
}
|
|
|
|
|
|
#
|
|
# items
|
|
# -----
|
|
#
|
|
# NOTE: Keep these items sorted, except for obsolete* which are listed last.
|
|
#
|
|
|
|
#
|
|
# atf
|
|
#
|
|
|
|
handle_atf_user()
|
|
{
|
|
local op="$1"
|
|
local conf="$2"
|
|
local option="unprivileged-user"
|
|
local old="_atf"
|
|
local new="_tests"
|
|
local failed=0
|
|
|
|
local c=$(readlink -f "${conf}")
|
|
if ${GREP} -q "[^#]*${option}[ \t]*=.*${old}" "${c}"
|
|
then
|
|
if [ "${op}" = "fix" ]; then
|
|
${SED} -e "/[^#]*${option}[\ t]*=/s/${old}/${new}/" \
|
|
"${c}" >"${c}.new"
|
|
failed=$(( ${failed} + $? ))
|
|
mv "${c}.new" "${c}"
|
|
failed=$(( ${failed} + $? ))
|
|
msg "Set ${option}=${new} in ${c}"
|
|
else
|
|
msg "${option}=${old} in ${c} should be " \
|
|
"${option}=${new}"
|
|
failed=1
|
|
fi
|
|
fi
|
|
|
|
return ${failed}
|
|
}
|
|
|
|
additem atf "install missing atf configuration files and validate them"
|
|
do_atf()
|
|
{
|
|
[ -n "$1" ] || err 3 "USAGE: do_atf fix|check"
|
|
local conf="${DEST_DIR}/etc/atf/common.conf"
|
|
local atfdir="${DEST_DIR}/etc/atf"
|
|
local op="$1"
|
|
local failed=0
|
|
|
|
# Ensure atf configuration files are in place.
|
|
if find_file_in_dirlist NetBSD.conf "NetBSD.conf" \
|
|
"${SRC_DIR}/external/bsd/atf/etc/atf" \
|
|
"${SRC_DIR}/etc/atf"; then
|
|
# ${dir} is set by find_file_in_dirlist()
|
|
populate_dir "${op}" true "${dir}" "${atfdir}" 644 \
|
|
NetBSD.conf common.conf || failed=1
|
|
else
|
|
failed=1
|
|
fi
|
|
if find_file_in_dirlist atf-run.hooks "atf-run.hooks" \
|
|
"${SRC_DIR}/external/bsd/atf/dist/tools/sample" \
|
|
"${SRC_DIR}/etc/atf"; then
|
|
# ${dir} is set by find_file_in_dirlist()
|
|
populate_dir "${op}" true "${dir}" "${atfdir}" 644 \
|
|
atf-run.hooks || failed=1
|
|
else
|
|
failed=1
|
|
fi
|
|
|
|
# Validate the _atf to _tests user/group renaming.
|
|
if [ -f "${conf}" ]; then
|
|
handle_atf_user "${op}" "${conf}" || failed=1
|
|
else
|
|
failed=1
|
|
fi
|
|
|
|
return ${failed}
|
|
}
|
|
|
|
|
|
#
|
|
# autofsconfig
|
|
#
|
|
|
|
additem autofsconfig "automounter configuration files"
|
|
do_autofsconfig()
|
|
{
|
|
[ -n "$1" ] || err 3 "USAGE: do_autofsconfig fix|check"
|
|
local autofs_files="
|
|
include_ldap
|
|
include_nis
|
|
special_hosts
|
|
special_media
|
|
special_noauto
|
|
special_null
|
|
"
|
|
local op="$1"
|
|
local failed=0
|
|
|
|
if [ "$op" = "fix" ]; then
|
|
mkdir -p "${DEST_DIR}/etc/autofs"
|
|
fi
|
|
failed=$(( ${failed} + $? ))
|
|
populate_dir "$op" true "${SRC_DIR}/etc" \
|
|
"${DEST_DIR}/etc" \
|
|
644 \
|
|
auto_master
|
|
failed=$(( ${failed} + $? ))
|
|
populate_dir "$op" true "${SRC_DIR}/etc/autofs" \
|
|
"${DEST_DIR}/etc/autofs" \
|
|
644 \
|
|
${autofs_files}
|
|
return ${failed}
|
|
}
|
|
|
|
|
|
#
|
|
# blocklist
|
|
#
|
|
|
|
fixblock()
|
|
{
|
|
local op="$1"
|
|
local target="${DEST_DIR}$2"
|
|
|
|
if [ ! -f "${target}" ]; then
|
|
continue
|
|
fi
|
|
|
|
if ${GREP} '[bB]lack' "${target}" > /dev/null; then
|
|
if [ "$1" = "check" ]; then
|
|
msg "Fix old configuration file(s)."
|
|
return 1
|
|
else
|
|
local p=$(${STAT} -f %Lp "${target}")
|
|
chmod u+w "${target}" || return 1
|
|
if [ "$2" = "/etc/npf.conf" ]; then
|
|
${SED} -i -e 's/"blacklistd"/"blocklistd"/g' "${target}"
|
|
else
|
|
${SED} -i -e 's/\([bB]\)lacklist/\1locklist/g' "${target}"
|
|
fi
|
|
chmod "${p}" "${target}"
|
|
fi
|
|
fi
|
|
}
|
|
|
|
additem blocklist "rename old files to blocklist"
|
|
do_blocklist()
|
|
{
|
|
[ -n "$1" ] || err 3 "USAGE: do_blocklist fix|check"
|
|
local op="$1"
|
|
local i old
|
|
|
|
# if we are actually using blocklistd
|
|
for i in /var/db/blacklist.db /etc/blacklistd.conf; do
|
|
old="${DEST_DIR}${i}"
|
|
if [ ! -f "${old}" ]; then
|
|
continue
|
|
elif [ "$1" = "check" ]; then
|
|
msg "Rename old file(s)."
|
|
return 1
|
|
fi
|
|
local new=$(echo "${old}" | ${SED} s/black/block/)
|
|
mv "${old}" "${new}" || return 1
|
|
done
|
|
|
|
for i in /etc/rc.conf /etc/npf.conf /etc/blocklistd.conf \
|
|
/etc/defaults/rc.conf; do
|
|
fixblock "${op}" "${i}" || return 1
|
|
done
|
|
}
|
|
|
|
|
|
#
|
|
# bluetooth
|
|
#
|
|
|
|
additem bluetooth "Bluetooth configuration is up to date"
|
|
do_bluetooth()
|
|
{
|
|
[ -n "$1" ] || err 3 "USAGE: do_bluetooth fix|check"
|
|
local op="$1"
|
|
local failed=0
|
|
|
|
populate_dir "${op}" true \
|
|
"${SRC_DIR}/etc/bluetooth" "${DEST_DIR}/etc/bluetooth" 644 \
|
|
hosts protocols btattach.conf btdevctl.conf
|
|
failed=$(( ${failed} + $? ))
|
|
|
|
move_file "${op}" "${DEST_DIR}/var/db/btdev.xml" \
|
|
"${DEST_DIR}/var/db/btdevctl.plist"
|
|
failed=$(( ${failed} + $? ))
|
|
|
|
local notfixed=""
|
|
if [ "${op}" = "fix" ]; then
|
|
notfixed="${NOT_FIXED}"
|
|
fi
|
|
for _v in btattach btconfig btdevctl; do
|
|
if rcvar_is_enabled "${_v}"; then
|
|
msg \
|
|
"${_v} is obsolete in rc.conf(5)${notfixed}: use bluetooth=YES"
|
|
failed=$(( ${failed} + 1 ))
|
|
fi
|
|
done
|
|
|
|
return ${failed}
|
|
}
|
|
|
|
|
|
#
|
|
# catpages
|
|
#
|
|
|
|
obsolete_catpages()
|
|
{
|
|
local op="$1"
|
|
local basedir="$2"
|
|
local section="$3"
|
|
local mandir="${basedir}/man${section}"
|
|
local catdir="${basedir}/cat${section}"
|
|
test -d "$mandir" || return 0
|
|
test -d "$catdir" || return 0
|
|
(cd "$mandir" && find . -type f) | {
|
|
local failed=0
|
|
while read manpage; do
|
|
manpage="${manpage#./}"
|
|
case "$manpage" in
|
|
*.Z)
|
|
catname="$catdir/${manpage%.*.Z}.0"
|
|
;;
|
|
*.gz)
|
|
catname="$catdir/${manpage%.*.gz}.0"
|
|
;;
|
|
*)
|
|
catname="$catdir/${manpage%.*}.0"
|
|
;;
|
|
esac
|
|
test -e "$catname" -a "$catname" -ot "$mandir/$manpage" || continue
|
|
if [ "${op}" = "fix" ]; then
|
|
${RM} "$catname"
|
|
failed=$(( ${failed} + $? ))
|
|
msg "Removed obsolete cat page $catname"
|
|
else
|
|
msg "Obsolete cat page $catname"
|
|
failed=1
|
|
fi
|
|
done
|
|
exit $failed
|
|
}
|
|
}
|
|
|
|
additem catpages "remove outdated cat pages"
|
|
do_catpages()
|
|
{
|
|
local op="$1"
|
|
local failed=0
|
|
local manbase sec
|
|
for manbase in /usr/share/man /usr/X11R6/man /usr/X11R7/man; do
|
|
for sec in 1 2 3 4 5 6 7 8 9; do
|
|
obsolete_catpages "$1" "${DEST_DIR}${manbase}" "${sec}"
|
|
failed=$(( ${failed} + $? ))
|
|
if [ "${op}" = "fix" ]; then
|
|
rmdir "${DEST_DIR}${manbase}/cat${sec}"/* \
|
|
2>/dev/null
|
|
rmdir "${DEST_DIR}${manbase}/cat${sec}" \
|
|
2>/dev/null
|
|
fi
|
|
done
|
|
done
|
|
return $failed
|
|
}
|
|
|
|
|
|
#
|
|
# ddbonpanic
|
|
#
|
|
|
|
additem ddbonpanic "verify ddb.onpanic is configured in sysctl.conf"
|
|
do_ddbonpanic()
|
|
{
|
|
[ -n "$1" ] || err 3 "USAGE: do_ddbonpanic fix|check"
|
|
|
|
if ${GREP} -E '^#*[[:space:]]*ddb\.onpanic[[:space:]]*\??=[[:space:]]*[[:digit:]]+' \
|
|
"${DEST_DIR}/etc/sysctl.conf" >/dev/null 2>&1
|
|
then
|
|
result=0
|
|
else
|
|
if [ "$1" = check ]; then
|
|
msg \
|
|
"The ddb.onpanic behaviour is not explicitly specified in /etc/sysctl.conf"
|
|
result=1
|
|
else
|
|
echo >> "${DEST_DIR}/etc/sysctl.conf"
|
|
${SED} < "${SRC_DIR}/etc/sysctl.conf" \
|
|
-e '/^ddb\.onpanic/q' | \
|
|
${SED} -e '1,/^$/d' >> \
|
|
"${DEST_DIR}/etc/sysctl.conf"
|
|
result=$?
|
|
fi
|
|
fi
|
|
return ${result}
|
|
}
|
|
|
|
|
|
#
|
|
# defaults
|
|
#
|
|
|
|
additem defaults "/etc/defaults/ being up to date"
|
|
do_defaults()
|
|
{
|
|
[ -n "$1" ] || err 3 "USAGE: do_defaults fix|check"
|
|
local op="$1"
|
|
local failed=0
|
|
local etcsets=$(getetcsets)
|
|
|
|
local rc_exclude_scripts=""
|
|
if $SOURCEMODE; then
|
|
# For most architectures rc.conf(5) should be the same as the
|
|
# one obtained from a source directory, except for the ones
|
|
# that have an append file for it.
|
|
local rc_conf_app="${SRC_DIR}/etc/etc.${MACHINE}/rc.conf.append"
|
|
if [ -f "${rc_conf_app}" ]; then
|
|
rc_exclude_scripts="rc.conf"
|
|
|
|
# Generate and compare the correct rc.conf(5) file
|
|
mkdir "${SCRATCHDIR}/defaults"
|
|
|
|
cat "${SRC_DIR}/etc/defaults/rc.conf" "${rc_conf_app}" \
|
|
> "${SCRATCHDIR}/defaults/rc.conf"
|
|
|
|
compare_dir "${op}" "${SCRATCHDIR}/defaults" \
|
|
"${DEST_DIR}/etc/defaults" \
|
|
444 \
|
|
"rc.conf"
|
|
failed=$(( ${failed} + $? ))
|
|
fi
|
|
fi
|
|
|
|
find_file_in_dirlist pf.boot.conf "pf.boot.conf" \
|
|
"${SRC_DIR}/usr.sbin/pf/etc/defaults" "${SRC_DIR}/etc/defaults" \
|
|
|| return 1
|
|
# ${dir} is set by find_file_in_dirlist()
|
|
compare_dir "$op" "${dir}" "${DEST_DIR}/etc/defaults" 444 pf.boot.conf
|
|
failed=$(( ${failed} + $? ))
|
|
|
|
rc_exclude_scripts="${rc_exclude_scripts} pf.boot.conf"
|
|
|
|
local rc_default_conf_files="$(select_set_files /etc/defaults/ \
|
|
"/etc/defaults/\([^[:space:]]*\.conf\)" ${etcsets} | \
|
|
exclude ${rc_exclude_scripts})"
|
|
compare_dir "$op" "${SRC_DIR}/etc/defaults" "${DEST_DIR}/etc/defaults" \
|
|
444 \
|
|
${rc_default_conf_files}
|
|
failed=$(( ${failed} + $? ))
|
|
|
|
|
|
return ${failed}
|
|
}
|
|
|
|
|
|
#
|
|
# dhcpcd
|
|
#
|
|
|
|
additem dhcpcd "dhcpcd configuration is up to date"
|
|
do_dhcpcd()
|
|
{
|
|
[ -n "$1" ] || err 3 "USAGE: do_dhcpcd fix|check"
|
|
local op="$1"
|
|
local failed=0
|
|
|
|
find_file_in_dirlist dhcpcd.conf "dhcpcd.conf" \
|
|
"${SRC_DIR}/external/bsd/dhcpcd/dist/src" \
|
|
"${SRC_DIR}/etc" || return 1
|
|
# ${dir} is set by find_file_in_dirlist()
|
|
populate_dir "$op" true "${dir}" "${DEST_DIR}/etc" 644 dhcpcd.conf
|
|
failed=$(( ${failed} + $? ))
|
|
|
|
check_dir "${op}" "${DEST_DIR}/var/db/dhcpcd" 755
|
|
failed=$(( ${failed} + $? ))
|
|
|
|
move_file "${op}" \
|
|
"${DEST_DIR}/etc/dhcpcd.duid" \
|
|
"${DEST_DIR}/var/db/dhcpcd/duid"
|
|
failed=$(( ${failed} + $? ))
|
|
|
|
move_file "${op}" \
|
|
"${DEST_DIR}/etc/dhcpcd.secret" \
|
|
"${DEST_DIR}/var/db/dhcpcd/secret"
|
|
failed=$(( ${failed} + $? ))
|
|
|
|
move_file "${op}" \
|
|
"${DEST_DIR}/var/db/dhcpcd-rdm.monotonic" \
|
|
"${DEST_DIR}/var/db/dhcpcd/rdm_monotonic"
|
|
failed=$(( ${failed} + $? ))
|
|
|
|
for lease in "${DEST_DIR}/var/db/dhcpcd-"*.lease*; do
|
|
[ -f "${lease}" ] || continue
|
|
new_lease=$(basename "${lease}" | ${SED} -e 's/dhcpcd-//')
|
|
new_lease="${DEST_DIR}/var/db/dhcpcd/${new_lease}"
|
|
move_file "${op}" "${lease}" "${new_lease}"
|
|
failed=$(( ${failed} + $? ))
|
|
done
|
|
|
|
chroot_dir="${DEST_DIR}/var/chroot/dhcpcd"
|
|
move_file "${op}" \
|
|
"${chroot_dir}/var/db/dhcpcd/duid" \
|
|
"${DEST_DIR}/var/db/dhcpcd/duid"
|
|
failed=$(( ${failed} + $? ))
|
|
|
|
move_file "${op}" \
|
|
"${chroot_dir}/var/db/dhcpcd/secret" \
|
|
"${DEST_DIR}/var/db/dhcpcd/secret"
|
|
failed=$(( ${failed} + $? ))
|
|
|
|
move_file "${op}" \
|
|
"${chroot_dir}/var/db/dhcpcd/rdm_monotonic" \
|
|
"${DEST_DIR}/var/db/dhcpcd/rdm_monotonic"
|
|
failed=$(( ${failed} + $? ))
|
|
|
|
for lease in "${chroot_dir}/var/db/dhcpcd/"*.lease*; do
|
|
[ -f "${lease}" ] || continue
|
|
new_lease="${DEST_DIR}/var/db/dhcpcd/$(basename ${lease})"
|
|
move_file "${op}" "${lease}" "${new_lease}"
|
|
failed=$(( ${failed} + $? ))
|
|
done
|
|
|
|
# Ensure chroot is now empty
|
|
for dir in \
|
|
$(find ${chroot_dir} ! -type d) \
|
|
$(find ${chroot_dir} -type d -mindepth 1 | sort -r)
|
|
do
|
|
echo "/var/chroot/dhcpcd${dir##${chroot_dir}}"
|
|
done | obsolete_paths "${op}"
|
|
failed=$(( ${failed} + $? ))
|
|
|
|
contents_owner "${op}" "${DEST_DIR}/var/db/dhcpcd" root wheel
|
|
failed=$(( ${failed} + $? ))
|
|
|
|
return ${failed}
|
|
}
|
|
|
|
|
|
#
|
|
# dhcpcdrundir
|
|
#
|
|
|
|
additem dhcpcdrundir "accidentally created /@RUNDIR@ does not exist"
|
|
do_dhcpcdrundir()
|
|
{
|
|
[ -n "$1" ] || err 3 "USAGE: do_dhcpcdrundir fix|check"
|
|
local op="$1"
|
|
local failed=0
|
|
|
|
if [ -d "${DEST_DIR}/@RUNDIR@" ]; then
|
|
if [ "${op}" = "check" ]; then
|
|
msg "Remove erroneously created /@RUNDIR@"
|
|
failed=1
|
|
elif ! ${RM} -r "${DEST_DIR}/@RUNDIR@"; then
|
|
msg "Failed to remove ${DEST_DIR}/@RUNDIR@"
|
|
failed=1
|
|
else
|
|
msg "Removed erroneously created ${DEST_DIR}/@RUNDIR@"
|
|
fi
|
|
fi
|
|
return ${failed}
|
|
}
|
|
|
|
|
|
#
|
|
# envsys
|
|
#
|
|
|
|
additem envsys "envsys configuration is up to date"
|
|
do_envsys()
|
|
{
|
|
[ -n "$1" ] || err 3 "USAGE: do_envsys fix|check"
|
|
local op="$1"
|
|
local failed=0
|
|
local etcsets=$(getetcsets)
|
|
|
|
populate_dir "$op" true "${SRC_DIR}/etc" "${DEST_DIR}/etc" 644 \
|
|
envsys.conf
|
|
failed=$(( ${failed} + $? ))
|
|
|
|
local powerd_scripts="$(select_set_files /etc/powerd/scripts/ \
|
|
"/etc/powerd/scripts/\([^[:space:]/]*\)" ${etcsets})"
|
|
|
|
populate_dir "$op" true "${SRC_DIR}/etc/powerd/scripts" \
|
|
"${DEST_DIR}/etc/powerd/scripts" \
|
|
555 \
|
|
${powerd_scripts}
|
|
failed=$(( ${failed} + $? ))
|
|
|
|
return ${failed}
|
|
}
|
|
|
|
|
|
#
|
|
# fontconfig
|
|
#
|
|
|
|
additem fontconfig "X11 font configuration is up to date"
|
|
do_fontconfig()
|
|
{
|
|
[ -n "$1" ] || err 3 "USAGE: do_fontconfig fix|check"
|
|
local op="$1"
|
|
local failed=0
|
|
|
|
# First, check for updates we can handle.
|
|
if ! $SOURCEMODE; then
|
|
FONTCONFIG_DIR="${SRC_DIR}/etc/fonts/conf.avail"
|
|
else
|
|
FONTCONFIG_DIR="${XSRC_DIR}/external/mit/fontconfig/dist/conf.d"
|
|
fi
|
|
|
|
if [ ! -d "${FONTCONFIG_DIR}" ]; then
|
|
msg "${FONTCONFIG_DIR} is not a directory; skipping check"
|
|
return 0
|
|
fi
|
|
local regular_fonts="
|
|
10-autohint.conf
|
|
10-scale-bitmap-fonts.conf
|
|
10-sub-pixel-bgr.conf
|
|
10-sub-pixel-none.conf
|
|
10-sub-pixel-rgb.conf
|
|
10-sub-pixel-vbgr.conf
|
|
10-sub-pixel-vrgb.conf
|
|
10-unhinted.conf
|
|
11-lcdfilter-default.conf
|
|
11-lcdfilter-legacy.conf
|
|
11-lcdfilter-light.conf
|
|
20-unhint-small-vera.conf
|
|
25-unhint-nonlatin.conf
|
|
30-metric-aliases.conf
|
|
40-nonlatin.conf
|
|
45-generic.conf
|
|
45-latin.conf
|
|
49-sansserif.conf
|
|
50-user.conf
|
|
51-local.conf
|
|
60-generic.conf
|
|
60-latin.conf
|
|
65-fonts-persian.conf
|
|
65-khmer.conf
|
|
65-nonlatin.conf
|
|
69-unifont.conf
|
|
70-no-bitmaps.conf
|
|
70-yes-bitmaps.conf
|
|
80-delicious.conf
|
|
90-synthetic.conf
|
|
"
|
|
populate_dir "$op" false "${FONTCONFIG_DIR}" \
|
|
"${DEST_DIR}/etc/fonts/conf.avail" \
|
|
444 \
|
|
${regular_fonts}
|
|
failed=$(( ${failed} + $? ))
|
|
|
|
if ! $SOURCEMODE; then
|
|
FONTS_DIR="${SRC_DIR}/etc/fonts"
|
|
else
|
|
FONTS_DIR="${SRC_DIR}/external/mit/xorg/lib/fontconfig/etc"
|
|
fi
|
|
|
|
populate_dir "$op" false "${FONTS_DIR}" "${DEST_DIR}/etc/fonts" 444 \
|
|
fonts.conf
|
|
failed=$(( ${failed} + $? ))
|
|
|
|
# We can't modify conf.d easily; someone might have removed a file.
|
|
|
|
# Look for old files that need to be deleted.
|
|
local obsolete_fonts="
|
|
10-autohint.conf
|
|
10-no-sub-pixel.conf
|
|
10-sub-pixel-bgr.conf
|
|
10-sub-pixel-rgb.conf
|
|
10-sub-pixel-vbgr.conf
|
|
10-sub-pixel-vrgb.conf
|
|
10-unhinted.conf
|
|
25-unhint-nonlatin.conf
|
|
65-khmer.conf
|
|
70-no-bitmaps.conf
|
|
70-yes-bitmaps.conf
|
|
"
|
|
local failed_fonts=""
|
|
for i in ${obsolete_fonts}; do
|
|
if [ -f "${DEST_DIR}/etc/fonts/conf.d/$i" ]; then
|
|
conf_d_failed=1
|
|
failed_fonts="$failed_fonts $i"
|
|
fi
|
|
done
|
|
|
|
if [ -n "$failed_fonts" ]; then
|
|
msg \
|
|
"Broken fontconfig configuration found; please delete these files:"
|
|
msg "[$failed_fonts]"
|
|
failed=$(( ${failed} + 1 ))
|
|
fi
|
|
|
|
return ${failed}
|
|
}
|
|
|
|
|
|
#
|
|
# gid
|
|
#
|
|
|
|
additem gid "required groups in /etc/group"
|
|
do_gid()
|
|
{
|
|
[ -n "$1" ] || err 3 "USAGE: do_gid fix|check"
|
|
|
|
check_ids "$1" groups "${DEST_DIR}/etc/group" \
|
|
"${SRC_DIR}/etc/group" 14 \
|
|
named ntpd sshd SKIP _pflogd _rwhod staff _proxy _timedc \
|
|
_sdpd _httpd _mdnsd _tests _tcpdump _tss _gpio _rtadvd SKIP \
|
|
_unbound _nsd nvmm _dhcpcd
|
|
}
|
|
|
|
|
|
#
|
|
# gpio
|
|
#
|
|
|
|
additem gpio "gpio configuration is up to date"
|
|
do_gpio()
|
|
{
|
|
[ -n "$1" ] || err 3 "USAGE: do_gpio fix|check"
|
|
local op="$1"
|
|
local failed=0
|
|
|
|
populate_dir "$op" true "${SRC_DIR}/etc" "${DEST_DIR}/etc" 644 \
|
|
gpio.conf
|
|
failed=$(( ${failed} + $? ))
|
|
|
|
return ${failed}
|
|
}
|
|
|
|
|
|
#
|
|
# hosts
|
|
#
|
|
|
|
additem hosts "/etc/hosts being up to date"
|
|
do_hosts()
|
|
{
|
|
[ -n "$1" ] || err 3 "USAGE: do_hosts fix|check"
|
|
|
|
modify_file "$1" "${DEST_DIR}/etc/hosts" "${SCRATCHDIR}/hosts" '
|
|
/^(127\.0\.0\.1|::1)[ ]+[^\.]*$/ {
|
|
print $0, "localhost."
|
|
next
|
|
}
|
|
{ print }
|
|
'
|
|
return $?
|
|
}
|
|
|
|
|
|
#
|
|
# iscsi
|
|
#
|
|
|
|
additem iscsi "/etc/iscsi is populated"
|
|
do_iscsi()
|
|
{
|
|
[ -n "$1" ] || err 3 "USAGE: do_iscsi fix|check"
|
|
|
|
populate_dir "${op}" true \
|
|
"${SRC_DIR}/etc/iscsi" "${DEST_DIR}/etc/iscsi" 600 auths
|
|
populate_dir "${op}" true \
|
|
"${SRC_DIR}/etc/iscsi" "${DEST_DIR}/etc/iscsi" 644 targets
|
|
return $?
|
|
}
|
|
|
|
|
|
#
|
|
# mailerconf
|
|
#
|
|
|
|
adddisableditem mailerconf "update /etc/mailer.conf after sendmail removal"
|
|
do_mailerconf()
|
|
{
|
|
[ -n "$1" ] || err 3 "USAGE: do_mailterconf fix|check"
|
|
local op="$1"
|
|
|
|
local failed=0
|
|
mta_path="$(${AWK} '/^sendmail[ \t]/{print$2}' \
|
|
"${DEST_DIR}/etc/mailer.conf")"
|
|
old_sendmail_path="/usr/libexec/sendmail/sendmail"
|
|
if [ "${mta_path}" = "${old_sendmail_path}" ]; then
|
|
if [ "$op" = check ]; then
|
|
msg "mailer.conf points to obsolete ${old_sendmail_path}"
|
|
failed=1;
|
|
else
|
|
populate_dir "${op}" false \
|
|
"${SRC_DIR}/etc" "${DEST_DIR}/etc" 644 mailer.conf
|
|
failed=$?
|
|
fi
|
|
fi
|
|
|
|
return ${failed}
|
|
}
|
|
|
|
|
|
#
|
|
# makedev
|
|
#
|
|
|
|
additem makedev "/dev/MAKEDEV being up to date"
|
|
do_makedev()
|
|
{
|
|
[ -n "$1" ] || err 3 "USAGE: do_makedev fix|check"
|
|
local failed=0
|
|
|
|
if [ -f "${SRC_DIR}/etc/MAKEDEV.tmpl" ]; then
|
|
# generate MAKEDEV from source if source is available
|
|
env MACHINE="${MACHINE}" \
|
|
MACHINE_ARCH="${MACHINE_ARCH}" \
|
|
NETBSDSRCDIR="${SRC_DIR}" \
|
|
${AWK} -f "${SRC_DIR}/etc/MAKEDEV.awk" \
|
|
"${SRC_DIR}/etc/MAKEDEV.tmpl" > "${SCRATCHDIR}/MAKEDEV"
|
|
fi
|
|
|
|
find_file_in_dirlist MAKEDEV "MAKEDEV" \
|
|
"${SCRATCHDIR}" "${SRC_DIR}/dev" \
|
|
|| return 1
|
|
# ${dir} is set by find_file_in_dirlist()
|
|
find_makedev
|
|
compare_dir "$1" "${dir}" "${MAKEDEV_DIR}" 555 MAKEDEV
|
|
failed=$(( ${failed} + $? ))
|
|
|
|
find_file_in_dirlist MAKEDEV.local "MAKEDEV.local" \
|
|
"${SRC_DIR}/etc" "${SRC_DIR}/dev" \
|
|
|| return 1
|
|
# ${dir} is set by find_file_in_dirlist()
|
|
compare_dir "$1" "${dir}" "${DEST_DIR}/dev" 555 MAKEDEV.local
|
|
failed=$(( ${failed} + $? ))
|
|
|
|
return ${failed}
|
|
}
|
|
|
|
|
|
#
|
|
# man.conf
|
|
#
|
|
|
|
additem manconf "check for a mandoc usage in /etc/man.conf"
|
|
do_manconf()
|
|
{
|
|
[ -n "$1" ] || err 3 "USAGE: do_manconf fix|check"
|
|
local op="$1"
|
|
local failed=0
|
|
|
|
[ -f "${DEST_DIR}/etc/man.conf" ] || return 0
|
|
if ${GREP} -w "mandoc" "${DEST_DIR}/etc/man.conf" >/dev/null 2>&1;
|
|
then
|
|
failed=0;
|
|
else
|
|
failed=1
|
|
notfixed=""
|
|
if [ "${op}" = "fix" ]; then
|
|
notfixed="${NOT_FIXED}"
|
|
fi
|
|
msg "The file /etc/man.conf has not been adapted to mandoc usage; you"
|
|
msg "probably want to copy a new version over. ${notfixed}"
|
|
fi
|
|
|
|
return ${failed}
|
|
}
|
|
|
|
|
|
#
|
|
# motd
|
|
#
|
|
|
|
additem motd "contents of motd"
|
|
do_motd()
|
|
{
|
|
[ -n "$1" ] || err 3 "USAGE: do_motd fix|check"
|
|
|
|
if ${GREP} -i 'http://www.NetBSD.org/Misc/send-pr.html' \
|
|
"${DEST_DIR}/etc/motd" >/dev/null 2>&1 \
|
|
|| ${GREP} -i 'https*://www.NetBSD.org/support/send-pr.html' \
|
|
"${DEST_DIR}/etc/motd" >/dev/null 2>&1
|
|
then
|
|
tmp1="$(mktemp /tmp/postinstall.motd.XXXXXXXX)"
|
|
tmp2="$(mktemp /tmp/postinstall.motd.XXXXXXXX)"
|
|
${SED} '1,2d' <"${SRC_DIR}/etc/motd" >"${tmp1}"
|
|
${SED} '1,2d' <"${DEST_DIR}/etc/motd" >"${tmp2}"
|
|
|
|
if [ "$1" = check ]; then
|
|
cmp -s "${tmp1}" "${tmp2}"
|
|
result=$?
|
|
if [ "${result}" -ne 0 ]; then
|
|
msg \
|
|
"Bug reporting messages do not seem to match the installed release"
|
|
fi
|
|
else
|
|
head -n 2 "${DEST_DIR}/etc/motd" >"${tmp1}"
|
|
${SED} '1,2d' <"${SRC_DIR}/etc/motd" >>"${tmp1}"
|
|
cp "${tmp1}" "${DEST_DIR}/etc/motd"
|
|
result=0
|
|
fi
|
|
|
|
${RM} -f "${tmp1}" "${tmp2}"
|
|
else
|
|
result=0
|
|
fi
|
|
|
|
return ${result}
|
|
}
|
|
|
|
|
|
#
|
|
# mtree
|
|
#
|
|
|
|
additem mtree "/etc/mtree/ being up to date"
|
|
do_mtree()
|
|
{
|
|
[ -n "$1" ] || err 3 "USAGE: do_mtree fix|check"
|
|
local failed=0
|
|
|
|
compare_dir "$1" "${SRC_DIR}/etc/mtree" "${DEST_DIR}/etc/mtree" 444 special
|
|
failed=$(( ${failed} + $? ))
|
|
|
|
if ! $SOURCEMODE; then
|
|
MTREE_DIR="${SRC_DIR}/etc/mtree"
|
|
else
|
|
${RM} -rf "${SCRATCHDIR}/obj"
|
|
mkdir "${SCRATCHDIR}/obj"
|
|
${MAKE} -s -C "${SRC_DIR}/etc/mtree" TOOL_AWK="${AWK}" \
|
|
MAKEOBJDIR="${SCRATCHDIR}/obj" emit_dist_file > \
|
|
"${SCRATCHDIR}/NetBSD.dist"
|
|
MTREE_DIR="${SCRATCHDIR}"
|
|
${RM} -rf "${SCRATCHDIR}/obj"
|
|
fi
|
|
compare_dir "$1" "${MTREE_DIR}" "${DEST_DIR}/etc/mtree" 444 NetBSD.dist
|
|
failed=$(( ${failed} + $? ))
|
|
|
|
return ${failed}
|
|
}
|
|
|
|
|
|
#
|
|
# named
|
|
#
|
|
handle_named_conf()
|
|
{
|
|
local op="$1"
|
|
local option="dnssec-enable"
|
|
local failed=0
|
|
local conf
|
|
|
|
shift
|
|
|
|
for conf; do
|
|
local c=$(readlink -f "${conf}")
|
|
if ! ${GREP} -qs "${option}" "${c}"
|
|
then
|
|
continue
|
|
fi
|
|
|
|
if [ "${op}" = "fix" ]; then
|
|
${SED} -e "/${option}/d" "${c}" > "${c}.new"
|
|
failed=$(( ${failed} + $? ))
|
|
mv "${c}.new" "${c}"
|
|
failed=$(( ${failed} + $? ))
|
|
msg "Removed obsolete '${option}' in ${c}"
|
|
else
|
|
msg "'${option}' option in ${c} should be removed"
|
|
failed=$(( ${failed} + 1 ))
|
|
fi
|
|
done
|
|
|
|
return ${failed}
|
|
}
|
|
|
|
additem named "named configuration update"
|
|
do_named()
|
|
{
|
|
local oldconf="${DEST_DIR}/etc/namedb/named.conf"
|
|
local conf="${DEST_DIR}/etc/named.conf"
|
|
[ -n "$1" ] || err 3 "USAGE: do_named fix|check"
|
|
local op="$1"
|
|
|
|
move_file "${op}" "${oldconf}" "${conf}"
|
|
handle_named_conf "${op}" "${oldconf}" "${conf}"
|
|
|
|
compare_dir "${op}" "${SRC_DIR}/etc/namedb" "${DEST_DIR}/etc/namedb" \
|
|
644 \
|
|
root.cache
|
|
}
|
|
|
|
|
|
#
|
|
# opensslcertsconf
|
|
#
|
|
|
|
additem opensslcertsconf "ensure TLS trust anchor configuration exists"
|
|
do_opensslcertsconf()
|
|
{
|
|
local certsdir certsconf defaultconf manualmsg
|
|
|
|
[ -n "$1" ] || err 3 "USAGE: do_opensslcertsconf fix|check"
|
|
|
|
certsdir="${DEST_DIR}/etc/openssl/certs"
|
|
certsconf="${DEST_DIR}/etc/openssl/certs.conf"
|
|
defaultconf="${DEST_DIR}/usr/share/examples/certctl/certs.conf"
|
|
|
|
case $1 in
|
|
check) if [ ! -r "$certsconf" ]; then
|
|
msg "/etc/openssl/certs.conf missing; see certctl(8)"
|
|
return 1
|
|
fi
|
|
;;
|
|
fix) # If /etc/openssl/certs.conf is already there, nothing
|
|
# to do.
|
|
if [ -r "$certsconf" ]; then
|
|
return 0
|
|
fi
|
|
|
|
# If /etc/openssl/certs is a symlink, or exists but is
|
|
# not a directory, or is a directory but is nonempty,
|
|
# then either it's managed by someone else or something
|
|
# fishy is afoot. So set it manual in that case.
|
|
# Otherwise, install the default config file.
|
|
if [ -h "$certsdir" ] ||
|
|
[ -e "$certsdir" -a ! -d "$certsdir" ] ||
|
|
([ -d "$certsdir" ] &&
|
|
find -f "$certsdir" -- \
|
|
-maxdepth 0 -type d -empty -exit 1)
|
|
then
|
|
msg "/etc/openssl/certs appears manually configured"
|
|
manualmsg="[existing /etc/openssl/certs configuration"
|
|
manualmsg="$manualmsg detected by postinstall(8)]"
|
|
# Change the commented-out `#manual' line to
|
|
# uncommented `manual', or print an error
|
|
# message if there is no `#manual' line and put
|
|
# `manual' at the end.
|
|
awk -v defaultconf="$defaultconf" \
|
|
-v manualmsg="$manualmsg" '
|
|
BEGIN {
|
|
manual = 0
|
|
}
|
|
/^#manual/ && !manual {
|
|
manual = 1
|
|
sub(/^#/, "")
|
|
print
|
|
print "#", manualmsg
|
|
next
|
|
}
|
|
{
|
|
print
|
|
}
|
|
END {
|
|
if (!manual) {
|
|
printf "warning: %s %s?\n", \
|
|
"corrupt", defaultconf \
|
|
>"/dev/stderr"
|
|
print "manual"
|
|
print "#", manualmsg
|
|
}
|
|
}
|
|
' <$defaultconf >${certsconf}.tmp
|
|
else
|
|
msg "installing default /etc/openssl/certs.conf"
|
|
cat <$defaultconf >${certsconf}.tmp
|
|
fi && mv -f -- "${certsconf}.tmp" "$certsconf"
|
|
;;
|
|
*) err 3 "USAGE: do_opensslcerts fix|check"
|
|
;;
|
|
esac
|
|
}
|
|
|
|
|
|
#
|
|
# opensslcertsrehash
|
|
#
|
|
|
|
additem opensslcertsrehash "make /etc/openssl/certs cache of TLS trust anchors"
|
|
do_opensslcertsrehash()
|
|
{
|
|
local mtreekeys scratchdir
|
|
|
|
[ -n "$1" ] || err 3 "USAGE: do_opensslcertsrehash fix|check"
|
|
|
|
if [ ! -r "${DEST_DIR}/etc/openssl/certs.conf" ]; then
|
|
msg "/etc/openssl/certs.conf missing; see certctl(8)"
|
|
return 1
|
|
fi
|
|
|
|
case $1 in
|
|
check) # Create a scratch rehash for comparison.
|
|
mtreekeys="type,link"
|
|
scratchdir="${SCRATCHDIR}/opensslcerts"
|
|
/usr/sbin/certctl -c "$scratchdir" rehash || return $?
|
|
|
|
# This will create ${scratchdir}/.certctl unless the
|
|
# configuration is manual. If the configuration is
|
|
# manual, stop here; nothing to do. certctl(8) will
|
|
# have already printed a message about that.
|
|
#
|
|
# XXX Grody to rely on the internal structure used by
|
|
# certctl(8), but less bad than having two versions of
|
|
# the config parsing logic.
|
|
if [ ! -f "${scratchdir}/.certctl" ]; then
|
|
return 0
|
|
fi
|
|
|
|
# Do a dry run of rehashing into the real
|
|
# /etc/openssl/certs. This curious extra step ensures
|
|
# that we report a failure if /etc/openssl/certs
|
|
# appears to be managed manually, but `manual' was not
|
|
# specified in /etc/openssl/certs.conf.
|
|
/usr/sbin/certctl -n rehash || return $?
|
|
|
|
# Compare the trees with mtree(8). Inconveniently,
|
|
# mtree returns status zero even if there are missing
|
|
# or extra files. So instead of examining the return
|
|
# status, test for any output. Empty output means
|
|
# everything matches; otherwise the mismatch, missing,
|
|
# or extra files are output.
|
|
mtree -p "$scratchdir" -c -k "$mtreekeys" \
|
|
| mtree -p "${DEST_DIR}/etc/openssl/certs" 2>&1 \
|
|
| {
|
|
while read -r line; do
|
|
# mismatch, missing, or extra
|
|
msg "/etc/openssl/certs needs rehash"
|
|
exit 1
|
|
done
|
|
exit 0
|
|
}
|
|
;;
|
|
fix) # This runs openssl(1), which is not available as a
|
|
# build-time tool. So for now, restrict it to running
|
|
# on the installed system.
|
|
case $DEST_DIR in
|
|
''|/) ;;
|
|
*) msg "opensslcertsrehash limited to DEST_DIR=/"
|
|
return 1
|
|
;;
|
|
esac
|
|
/usr/sbin/certctl rehash
|
|
;;
|
|
*) err 3 "USAGE: do_opensslcerts fix|check"
|
|
;;
|
|
esac
|
|
}
|
|
|
|
|
|
#
|
|
# pam
|
|
#
|
|
|
|
additem pam "/etc/pam.d is populated"
|
|
do_pam()
|
|
{
|
|
[ -n "$1" ] || err 3 "USAGE: do_pam fix|check"
|
|
local op="$1"
|
|
local failed=0
|
|
|
|
populate_dir "${op}" true "${SRC_DIR}/etc/pam.d" \
|
|
"${DEST_DIR}/etc/pam.d" 644 \
|
|
README cron display_manager ftpd gdm imap kde login other \
|
|
passwd pop3 ppp racoon rexecd rsh sshd su system telnetd \
|
|
xdm xserver
|
|
|
|
failed=$(( ${failed} + $? ))
|
|
|
|
return ${failed}
|
|
}
|
|
|
|
|
|
#
|
|
# periodic
|
|
#
|
|
|
|
additem periodic "/etc/{daily,weekly,monthly,security} being up to date"
|
|
do_periodic()
|
|
{
|
|
[ -n "$1" ] || err 3 "USAGE: do_periodic fix|check"
|
|
|
|
compare_dir "$1" "${SRC_DIR}/etc" "${DEST_DIR}/etc" 644 \
|
|
daily weekly monthly security
|
|
}
|
|
|
|
|
|
#
|
|
# pf
|
|
#
|
|
|
|
additem pf "pf configuration being up to date"
|
|
do_pf()
|
|
{
|
|
[ -n "$1" ] || err 3 "USAGE: do_pf fix|check"
|
|
local op="$1"
|
|
local failed=0
|
|
|
|
find_file_in_dirlist pf.os "pf.os" \
|
|
"${SRC_DIR}/dist/pf/etc" "${SRC_DIR}/etc" \
|
|
|| return 1
|
|
# ${dir} is set by find_file_in_dirlist()
|
|
populate_dir "${op}" true \
|
|
"${dir}" "${DEST_DIR}/etc" 644 \
|
|
pf.conf
|
|
failed=$(( ${failed} + $? ))
|
|
|
|
compare_dir "${op}" "${dir}" "${DEST_DIR}/etc" 444 pf.os
|
|
failed=$(( ${failed} + $? ))
|
|
|
|
return ${failed}
|
|
}
|
|
|
|
|
|
#
|
|
# ptyfsoldnodes
|
|
#
|
|
|
|
additem ptyfsoldnodes "remove legacy device nodes when using ptyfs"
|
|
do_ptyfsoldnodes()
|
|
{
|
|
[ -n "$1" ] || err 3 "USAGE: do_ptyfsoldnodes fix|check"
|
|
local op="$1"
|
|
|
|
# Check whether ptyfs is in use
|
|
local failed=0;
|
|
if ! ${GREP} -E "^ptyfs" "${DEST_DIR}/etc/fstab" > /dev/null; then
|
|
msg "ptyfs is not in use"
|
|
return 0
|
|
fi
|
|
|
|
if [ ! -e "${DEST_DIR}/dev/pts" ]; then
|
|
msg "ptyfs is not properly configured: missing /dev/pts"
|
|
return 1
|
|
fi
|
|
|
|
# Find the device major numbers for the pty master and slave
|
|
# devices, by parsing the output from "MAKEDEV -s pty0".
|
|
#
|
|
# Output from MAKEDEV looks like this:
|
|
# ./ttyp0 type=char device=netbsd,5,0 mode=666 gid=0 uid=0
|
|
# ./ptyp0 type=char device=netbsd,6,0 mode=666 gid=0 uid=0
|
|
#
|
|
# Output from awk, used in the eval statement, looks like this:
|
|
# maj_ptym=6; maj_ptys=5;
|
|
#
|
|
local maj_ptym maj_ptys
|
|
find_makedev
|
|
eval "$(
|
|
${HOST_SH} "${MAKEDEV_DIR}/MAKEDEV" -s pty0 2>/dev/null \
|
|
| ${AWK} '\
|
|
BEGIN { before_re = ".*device=[a-zA-Z]*,"; after_re = ",.*"; }
|
|
/ptyp0/ { maj_ptym = gensub(before_re, "", 1, $0);
|
|
maj_ptym = gensub(after_re, "", 1, maj_ptym); }
|
|
/ttyp0/ { maj_ptys = gensub(before_re, "", 1, $0);
|
|
maj_ptys = gensub(after_re, "", 1, maj_ptys); }
|
|
END { print "maj_ptym=" maj_ptym "; maj_ptys=" maj_ptys ";"; }
|
|
'
|
|
)"
|
|
#msg "Major numbers are maj_ptym=${maj_ptym} maj_ptys=${maj_ptys}"
|
|
if [ -z "$maj_ptym" ] || [ -z "$maj_ptys" ]; then
|
|
msg "Cannot find device major numbers for pty master and slave"
|
|
return 1
|
|
fi
|
|
|
|
# look for /dev/[pt]ty[p-zP-T][0-9a-zA-Z], and check that they
|
|
# have the expected device major numbers. ttyv* is typically not a
|
|
# pty device, but we check it anyway.
|
|
#
|
|
# The "for d1" loop is intended to avoid overflowing ARG_MAX;
|
|
# otherwise we could have used a single glob pattern.
|
|
#
|
|
# If there are no files that match a particular pattern,
|
|
# then stat prints something like:
|
|
# stat: /dev/[pt]tyx?: lstat: No such file or directory
|
|
# and we ignore it. XXX: We also ignore other error messages.
|
|
#
|
|
local d1 major node
|
|
local tmp="$(mktemp /tmp/postinstall.ptyfs.XXXXXXXX)"
|
|
|
|
for d1 in p q r s t u v w x y z P Q R S T; do
|
|
${STAT} -f "%Hr %N" "${DEST_DIR}/dev/"[pt]ty${d1}? 2>&1
|
|
done \
|
|
| while read -r major node ; do
|
|
case "$major" in
|
|
${maj_ptym}|${maj_ptys}) echo "$node" ;;
|
|
esac
|
|
done > "${tmp}"
|
|
|
|
local desc="legacy device node"
|
|
while read node; do
|
|
if [ "${op}" = "check" ]; then
|
|
msg "Remove ${desc} ${node}"
|
|
failed=1
|
|
else # "fix"
|
|
if ${RM} "${node}"; then
|
|
msg "Removed ${desc} ${node}"
|
|
else
|
|
warn "Failed to remove ${desc} ${node}"
|
|
failed=1
|
|
fi
|
|
fi
|
|
done < "${tmp}"
|
|
${RM} "${tmp}"
|
|
|
|
return ${failed}
|
|
}
|
|
|
|
|
|
#
|
|
# pwd_mkdb
|
|
#
|
|
|
|
additem pwd_mkdb "passwd database version"
|
|
do_pwd_mkdb()
|
|
{
|
|
[ -n "$1" ] || err 3 "USAGE: do_pwd_mkdb fix|check"
|
|
local op="$1"
|
|
local failed=0
|
|
|
|
# XXX Ideally, we should figure out the endianness of the
|
|
# target machine, and add "-E B"/"-E L" to the db(1) flags,
|
|
# and "-B"/"-L" to the pwd_mkdb(8) flags if the target is not
|
|
# the same as the host machine. It probably doesn't matter,
|
|
# because we don't expect "postinstall fix pwd_mkdb" to be
|
|
# invoked during a cross build.
|
|
|
|
set -- $(${DB} -q -Sb -Ub -To -N hash "${DEST_DIR}/etc/pwd.db" \
|
|
'VERSION\0')
|
|
case "$2" in
|
|
'\001\000\000\000') return 0 ;; # version 1, little-endian
|
|
'\000\000\000\001') return 0 ;; # version 1, big-endian
|
|
esac
|
|
|
|
if [ "${op}" = "check" ]; then
|
|
msg "Update format of passwd database"
|
|
failed=1
|
|
elif ! ${PWD_MKDB} -V 1 -d "${DEST_DIR:-/}" \
|
|
"${DEST_DIR}/etc/master.passwd";
|
|
then
|
|
msg "Can't update format of passwd database"
|
|
failed=1
|
|
else
|
|
msg "Updated format of passwd database"
|
|
fi
|
|
|
|
return ${failed}
|
|
}
|
|
|
|
|
|
#
|
|
# rc
|
|
#
|
|
|
|
# There is no info in src/distrib or /etc/mtree which rc* files
|
|
# can be overwritten unconditionally on upgrade. See PR/54741.
|
|
rc_644_files="
|
|
rc
|
|
rc.subr
|
|
rc.shutdown
|
|
"
|
|
|
|
rc_obsolete_vars="
|
|
amd amd_master
|
|
btcontrol btcontrol_devices
|
|
critical_filesystems critical_filesystems_beforenet
|
|
mountcritlocal mountcritremote
|
|
network ip6forwarding
|
|
network nfsiod_flags
|
|
sdpd sdpd_control
|
|
sdpd sdpd_groupname
|
|
sdpd sdpd_username
|
|
sysctl defcorename
|
|
"
|
|
|
|
update_rc()
|
|
{
|
|
local op=$1
|
|
local dir=$2
|
|
local name=$3
|
|
local bindir=$4
|
|
local rcdir=$5
|
|
|
|
if [ ! -x "${DEST_DIR}/${bindir}/${name}" ]; then
|
|
return 0
|
|
fi
|
|
|
|
if ! find_file_in_dirlist "${name}" "${name}" \
|
|
"${rcdir}" "${SRC_DIR}/etc/rc.d"; then
|
|
return 1
|
|
fi
|
|
populate_dir "${op}" false "${dir}" "${DEST_DIR}/etc/rc.d" 555 "${name}"
|
|
return $?
|
|
}
|
|
|
|
# select non-obsolete files in a sets file
|
|
# $1: directory pattern
|
|
# $2: file pattern
|
|
# $3: filename
|
|
select_set_files()
|
|
{
|
|
local qdir="$(echo $1 | ${SED} -e s@/@\\\\/@g -e s/\\./\\\\./g)"
|
|
${SED} -n -e /obsolete/d \
|
|
-e "/^\.${qdir}/s@^.$2[[:space:]].*@\1@p" $3
|
|
}
|
|
|
|
# select obsolete files in a sets file
|
|
# $1: directory pattern
|
|
# $2: file pattern
|
|
# $3: setname
|
|
select_obsolete_files()
|
|
{
|
|
if $SOURCEMODE; then
|
|
${SED} -n -e "/obsolete/s@\.$1$2[[:space:]].*@\1@p" \
|
|
"${SRC_DIR}/distrib/sets/lists/$3/mi"
|
|
return
|
|
fi
|
|
|
|
# On upgrade builds we don't extract the "etc" set so we
|
|
# try to use the source set instead. See PR/54730 for
|
|
# ways to better handle this.
|
|
|
|
local obsolete_dir
|
|
|
|
if [ $3 = "etc" ] ;then
|
|
obsolete_dir="${SRC_DIR}/var/db/obsolete"
|
|
else
|
|
obsolete_dir="${DEST_DIR}/var/db/obsolete"
|
|
fi
|
|
${SED} -n -e "s@\.$1$2\$@\1@p" "${obsolete_dir}/$3"
|
|
}
|
|
|
|
getetcsets()
|
|
{
|
|
if $SOURCEMODE; then
|
|
echo "${SRC_DIR}/distrib/sets/lists/etc/mi"
|
|
else
|
|
echo "${SRC_DIR}/etc/mtree/set.etc"
|
|
fi
|
|
}
|
|
|
|
additem rc "/etc/rc* and /etc/rc.d/ being up to date"
|
|
do_rc()
|
|
{
|
|
[ -n "$1" ] || err 3 "USAGE: do_rc fix|check"
|
|
local op="$1"
|
|
local failed=0
|
|
local generated_scripts=""
|
|
local etcsets=$(getetcsets)
|
|
if [ "${MKX11}" != "no" ]; then
|
|
generated_scripts="${generated_scripts} xdm xfs"
|
|
fi
|
|
|
|
# Directories of external programs that have rc files (in bsd)
|
|
local rc_external_files="blocklist nsd unbound"
|
|
|
|
# rc* files in /etc/
|
|
# XXX: at least rc.conf and rc.local shouldn't be updated. PR/54741
|
|
#local rc_644_files="$(select_set_files /etc/rc \
|
|
# "/etc/\(rc[^[:space:]/]*\)" ${etcsets})"
|
|
|
|
# no-obsolete rc files in /etc/rc.d
|
|
local rc_555_files="$(select_set_files /etc/rc.d/ \
|
|
"/etc/rc\.d/\([^[:space:]]*\)" ${etcsets} | \
|
|
exclude ${rc_external_files})"
|
|
|
|
# obsolete rc file in /etc/rc.d
|
|
local rc_obsolete_files="$(select_obsolete_files /etc/rc.d/ \
|
|
"\([^[:space:]]*\)" etc)"
|
|
|
|
compare_dir "${op}" "${SRC_DIR}/etc" "${DEST_DIR}/etc" 644 \
|
|
${rc_644_files}
|
|
failed=$(( ${failed} + $? ))
|
|
|
|
local extra_scripts
|
|
if ! $SOURCEMODE; then
|
|
extra_scripts="${generated_scripts}"
|
|
else
|
|
extra_scripts=""
|
|
fi
|
|
|
|
compare_dir "${op}" "${SRC_DIR}/etc/rc.d" "${DEST_DIR}/etc/rc.d" 555 \
|
|
${rc_555_files} \
|
|
${extra_scripts}
|
|
failed=$(( ${failed} + $? ))
|
|
|
|
local i rc_file
|
|
for i in ${rc_external_files}; do
|
|
case $i in
|
|
*d) rc_file=${i};;
|
|
*) rc_file=${i}d;;
|
|
esac
|
|
|
|
update_rc "${op}" "${dir}" ${rc_file} /sbin \
|
|
"${SRC_DIR}/external/bsd/$i/etc/rc.d"
|
|
failed=$(( ${failed} + $? ))
|
|
done
|
|
|
|
if $SOURCEMODE && [ -n "${generated_scripts}" ]; then
|
|
# generate scripts
|
|
mkdir "${SCRATCHDIR}/rc"
|
|
for f in ${generated_scripts}; do
|
|
${SED} -e "s,@X11ROOTDIR@,${X11ROOTDIR},g" \
|
|
< "${SRC_DIR}/etc/rc.d/${f}.in" \
|
|
> "${SCRATCHDIR}/rc/${f}"
|
|
done
|
|
compare_dir "${op}" "${SCRATCHDIR}/rc" \
|
|
"${DEST_DIR}/etc/rc.d" 555 \
|
|
${generated_scripts}
|
|
failed=$(( ${failed} + $? ))
|
|
fi
|
|
|
|
# check for obsolete rc.d files
|
|
for f in ${rc_obsolete_files}; do
|
|
local fd="/etc/rc.d/${f}"
|
|
[ -e "${DEST_DIR}${fd}" ] && echo "${fd}"
|
|
done | obsolete_paths "${op}"
|
|
failed=$(( ${failed} + $? ))
|
|
|
|
# check for obsolete rc.conf(5) variables
|
|
set -- ${rc_obsolete_vars}
|
|
while [ $# -gt 1 ]; do
|
|
if rcconf_is_set "${op}" "$1" "$2" 1; then
|
|
failed=1
|
|
fi
|
|
shift 2
|
|
done
|
|
|
|
return ${failed}
|
|
}
|
|
|
|
|
|
#
|
|
# sendmail
|
|
#
|
|
|
|
adddisableditem sendmail "remove obsolete sendmail configuration files and scripts"
|
|
do_sendmail()
|
|
{
|
|
[ -n "$1" ] || err 3 "USAGE: do_sendmail fix|check"
|
|
op="$1"
|
|
failed=0
|
|
|
|
# Don't complain if the "sendmail" package is installed because the
|
|
# files might still be in use.
|
|
if /usr/sbin/pkg_info -qe sendmail >/dev/null 2>&1; then
|
|
return 0
|
|
fi
|
|
|
|
for f in /etc/mail/helpfile /etc/mail/local-host-names \
|
|
/etc/mail/sendmail.cf /etc/mail/submit.cf /etc/rc.d/sendmail \
|
|
/etc/rc.d/smmsp /usr/share/misc/sendmail.hf \
|
|
$( ( find "${DEST_DIR}/usr/share/sendmail" -type f ; \
|
|
find "${DEST_DIR}/usr/share/sendmail" -type d \
|
|
) | unprefix "${DEST_DIR}" ) \
|
|
/var/log/sendmail.st \
|
|
/var/spool/clientmqueue \
|
|
/var/spool/mqueue
|
|
do
|
|
[ -e "${DEST_DIR}${f}" ] && echo "${f}"
|
|
done | obsolete_paths "${op}"
|
|
failed=$(( ${failed} + $? ))
|
|
|
|
return ${failed}
|
|
}
|
|
|
|
|
|
#
|
|
# ssh
|
|
#
|
|
|
|
additem ssh "ssh configuration update"
|
|
do_ssh()
|
|
{
|
|
[ -n "$1" ] || err 3 "USAGE: do_ssh fix|check"
|
|
local op="$1"
|
|
|
|
local failed=0
|
|
local etcssh="${DEST_DIR}/etc/ssh"
|
|
if ! check_dir "${op}" "${etcssh}" 755; then
|
|
failed=1
|
|
fi
|
|
|
|
if [ ${failed} -eq 0 ]; then
|
|
for f in \
|
|
ssh_known_hosts ssh_known_hosts2 \
|
|
ssh_host_dsa_key ssh_host_dsa_key.pub \
|
|
ssh_host_rsa_key ssh_host_rsa_key.pub \
|
|
ssh_host_key ssh_host_key.pub \
|
|
; do
|
|
if ! move_file "${op}" \
|
|
"${DEST_DIR}/etc/${f}" "${etcssh}/${f}" ; then
|
|
failed=1
|
|
fi
|
|
done
|
|
for f in sshd.conf ssh.conf ; do
|
|
# /etc/ssh/ssh{,d}.conf -> ssh{,d}_config
|
|
#
|
|
if ! move_file "${op}" \
|
|
"${etcssh}/${f}" "${etcssh}/${f%.conf}_config" ;
|
|
then
|
|
failed=1
|
|
fi
|
|
# /etc/ssh{,d}.conf -> /etc/ssh/ssh{,d}_config
|
|
#
|
|
if ! move_file "${op}" \
|
|
"${DEST_DIR}/etc/${f}" \
|
|
"${etcssh}/${f%.conf}_config" ;
|
|
then
|
|
failed=1
|
|
fi
|
|
done
|
|
fi
|
|
|
|
local sshdconf=""
|
|
local f
|
|
for f in \
|
|
"${etcssh}/sshd_config" \
|
|
"${etcssh}/sshd.conf" \
|
|
"${DEST_DIR}/etc/sshd.conf" ; do
|
|
if [ -f "${f}" ]; then
|
|
sshdconf="${f}"
|
|
break
|
|
fi
|
|
done
|
|
if [ -n "${sshdconf}" ]; then
|
|
modify_file "${op}" "${sshdconf}" "${SCRATCHDIR}/sshdconf" '
|
|
/^[^#$]/ {
|
|
kw = tolower($1)
|
|
if (kw == "hostkey" &&
|
|
$2 ~ /^\/etc\/+ssh_host(_[dr]sa)?_key$/ ) {
|
|
sub(/\/etc\/+/, "/etc/ssh/")
|
|
}
|
|
if (kw == "rhostsauthentication" ||
|
|
kw == "verifyreversemapping" ||
|
|
kw == "reversemappingcheck") {
|
|
sub(/^/, "# DEPRECATED:\t")
|
|
}
|
|
}
|
|
{ print }
|
|
'
|
|
failed=$(( ${failed} + $? ))
|
|
fi
|
|
|
|
if ! find_file_in_dirlist moduli "moduli" \
|
|
"${SRC_DIR}/crypto/external/bsd/openssh/dist" "${SRC_DIR}/etc" ; then
|
|
failed=1
|
|
# ${dir} is set by find_file_in_dirlist()
|
|
elif ! compare_dir "${op}" "${dir}" "${DEST_DIR}/etc" 444 moduli; then
|
|
failed=1
|
|
fi
|
|
|
|
if ! check_dir "${op}" "${DEST_DIR}/var/chroot/sshd" 755 ; then
|
|
failed=1
|
|
fi
|
|
|
|
if rcconf_is_set "${op}" sshd sshd_conf_dir 1; then
|
|
failed=1
|
|
fi
|
|
|
|
return ${failed}
|
|
}
|
|
|
|
|
|
#
|
|
# tcpdumpchroot
|
|
#
|
|
|
|
additem tcpdumpchroot "remove /var/chroot/tcpdump/etc/protocols"
|
|
do_tcpdumpchroot()
|
|
{
|
|
[ -n "$1" ] || err 3 "USAGE: do_tcpdumpchroot fix|check"
|
|
local op="$1"
|
|
|
|
local failed=0;
|
|
if [ -r "${DEST_DIR}/var/chroot/tcpdump/etc/protocols" ]; then
|
|
if [ "${op}" = "fix" ]; then
|
|
${RM} "${DEST_DIR}/var/chroot/tcpdump/etc/protocols"
|
|
failed=$(( ${failed} + $? ))
|
|
rmdir "${DEST_DIR}/var/chroot/tcpdump/etc"
|
|
failed=$(( ${failed} + $? ))
|
|
else
|
|
failed=1
|
|
fi
|
|
fi
|
|
return ${failed}
|
|
}
|
|
|
|
|
|
#
|
|
# uid
|
|
#
|
|
|
|
additem uid "required users in /etc/master.passwd"
|
|
do_uid()
|
|
{
|
|
[ -n "$1" ] || err 3 "USAGE: do_uid fix|check"
|
|
|
|
check_ids "$1" users "${DEST_DIR}/etc/master.passwd" \
|
|
"${SRC_DIR}/etc/master.passwd" 12 \
|
|
postfix SKIP named ntpd sshd SKIP _pflogd _rwhod SKIP _proxy \
|
|
_timedc _sdpd _httpd _mdnsd _tests _tcpdump _tss SKIP _rtadvd \
|
|
SKIP _unbound _nsd SKIP _dhcpcd
|
|
}
|
|
|
|
|
|
#
|
|
# varrwho
|
|
#
|
|
|
|
additem varrwho "required ownership of files in /var/rwho"
|
|
do_varrwho()
|
|
{
|
|
[ -n "$1" ] || err 3 "USAGE: do_varrwho fix|check"
|
|
|
|
contents_owner "$1" "${DEST_DIR}/var/rwho" _rwhod _rwhod
|
|
}
|
|
|
|
|
|
#
|
|
# varshm
|
|
#
|
|
|
|
additem varshm "check for a tmpfs mounted on /var/shm"
|
|
do_varshm()
|
|
{
|
|
[ -n "$1" ] || err 3 "USAGE: do_varshm fix|check"
|
|
op="$1"
|
|
failed=0
|
|
|
|
[ -f "${DEST_DIR}/etc/fstab" ] || return 0
|
|
if ${GREP} -E "^var_shm_symlink" "${DEST_DIR}/etc/rc.conf" >/dev/null 2>&1;
|
|
then
|
|
failed=0;
|
|
elif ${GREP} -w "/var/shm" "${DEST_DIR}/etc/fstab" >/dev/null 2>&1;
|
|
then
|
|
failed=0;
|
|
else
|
|
if [ "${op}" = "check" ]; then
|
|
failed=1
|
|
msg "No /var/shm mount found in ${DEST_DIR}/etc/fstab"
|
|
elif [ "${op}" = "fix" ]; then
|
|
printf '\ntmpfs\t/var/shm\ttmpfs\trw,-m1777,-sram%%25\n' \
|
|
>> "${DEST_DIR}/etc/fstab"
|
|
msg "Added tmpfs with 25% ram limit as /var/shm"
|
|
|
|
fi
|
|
fi
|
|
|
|
return ${failed}
|
|
}
|
|
|
|
|
|
#
|
|
# wscons
|
|
#
|
|
|
|
additem wscons "wscons configuration file update"
|
|
do_wscons()
|
|
{
|
|
[ -n "$1" ] || err 3 "USAGE: do_wscons fix|check"
|
|
op="$1"
|
|
|
|
[ -f "${DEST_DIR}/etc/wscons.conf" ] || return 0
|
|
|
|
failed=0
|
|
notfixed=""
|
|
if [ "${op}" = "fix" ]; then
|
|
notfixed="${NOT_FIXED}"
|
|
fi
|
|
while read _type _arg1 _rest; do
|
|
if [ "${_type}" = "mux" -a "${_arg1}" = "1" ]; then
|
|
msg \
|
|
"Obsolete wscons.conf(5) entry \""${_type} ${_arg1}"\" found.${notfixed}"
|
|
failed=1
|
|
fi
|
|
done < "${DEST_DIR}/etc/wscons.conf"
|
|
|
|
return ${failed}
|
|
}
|
|
|
|
|
|
#
|
|
# x11
|
|
#
|
|
|
|
additem x11 "x11 configuration update"
|
|
do_x11()
|
|
{
|
|
[ -n "$1" ] || err 3 "USAGE: do_x11 fix|check"
|
|
local p="$1"
|
|
|
|
local failed=0
|
|
local etcx11="${DEST_DIR}/etc/X11"
|
|
local libx11=""
|
|
if [ ! -d "${etcx11}" ]; then
|
|
msg "${etcx11} is not a directory; skipping check"
|
|
return 0
|
|
fi
|
|
if [ -d "${DEST_DIR}/usr/X11R6/." ]
|
|
then
|
|
libx11="${DEST_DIR}/usr/X11R6/lib/X11"
|
|
if [ ! -d "${libx11}" ]; then
|
|
msg "${libx11} is not a directory; skipping check"
|
|
return 0
|
|
fi
|
|
fi
|
|
|
|
local notfixed=""
|
|
if [ "${op}" = "fix" ]; then
|
|
notfixed="${NOT_FIXED}"
|
|
fi
|
|
|
|
local d
|
|
# check if /usr/X11R6/lib/X11 needs to migrate to /etc/X11
|
|
if [ -n "${libx11}" ]; then
|
|
for d in \
|
|
fs lbxproxy proxymngr rstart twm xdm xinit xserver xsm \
|
|
; do
|
|
sd="${libx11}/${d}"
|
|
ld="/etc/X11/${d}"
|
|
td="${DEST_DIR}${ld}"
|
|
if [ -h "${sd}" ]; then
|
|
continue
|
|
elif [ -d "${sd}" ]; then
|
|
tdfiles="$(find "${td}" \! -type d)"
|
|
if [ -n "${tdfiles}" ]; then
|
|
msg "${sd} exists yet ${td} already" \
|
|
"contains files${notfixed}"
|
|
else
|
|
msg "Migrate ${sd} to ${td}${notfixed}"
|
|
fi
|
|
failed=1
|
|
elif [ -e "${sd}" ]; then
|
|
msg "Unexpected file ${sd}${notfixed}"
|
|
continue
|
|
else
|
|
continue
|
|
fi
|
|
done
|
|
fi
|
|
|
|
# check if xdm resources have been updated
|
|
if [ -r ${etcx11}/xdm/Xresources ] && \
|
|
! ${GREP} -q 'inpColor:' ${etcx11}/xdm/Xresources; then
|
|
msg "Update ${etcx11}/xdm/Xresources${notfixed}"
|
|
failed=1
|
|
fi
|
|
|
|
return ${failed}
|
|
}
|
|
|
|
|
|
#
|
|
# xkb
|
|
#
|
|
# /usr/X11R7/lib/X11/xkb/symbols/pc used to be a directory, but changed
|
|
# to a file on 2009-06-12. Fixing this requires removing the directory
|
|
# (which we can do) and re-extracting the xbase set (which we can't do),
|
|
# or at least adding that one file (which we may be able to do if X11SRCDIR
|
|
# is available).
|
|
#
|
|
|
|
additem xkb "clean up for xkbdata to xkeyboard-config upgrade"
|
|
do_xkb()
|
|
{
|
|
[ -n "$1" ] || err 3 "USAGE: do_xkb fix|check"
|
|
local op="$1"
|
|
local failed=0
|
|
|
|
local pcpath="/usr/X11R7/lib/X11/xkb/symbols/pc"
|
|
local pcsrcdir="${X11SRCDIR}/external/mit/xkeyboard-config/dist/symbols"
|
|
|
|
local filemsg="\
|
|
${pcpath} was a directory, should be a file.
|
|
To fix, extract the xbase set again."
|
|
|
|
local notfixed=""
|
|
if [ "${op}" = "fix" ]; then
|
|
notfixed="${NOT_FIXED}"
|
|
fi
|
|
|
|
if [ ! -d "${DEST_DIR}${pcpath}" ]; then
|
|
return 0
|
|
fi
|
|
|
|
# Delete obsolete files in the directory, and the directory
|
|
# itself. If the directory contains unexpected extra files
|
|
# then it will not be deleted.
|
|
( [ -f "${DEST_DIR}"/var/db/obsolete/xbase ] \
|
|
&& ${SORT} -ru "${DEST_DIR}"/var/db/obsolete/xbase \
|
|
| ${GREP} -E "^\\.?${pcpath}/" ;
|
|
echo "${pcpath}" ) \
|
|
| obsolete_paths "${op}"
|
|
failed=$(( ${failed} + $? ))
|
|
|
|
# If the directory was removed above, then try to replace it with
|
|
# a file.
|
|
if [ -d "${DEST_DIR}${pcpath}" ]; then
|
|
msg "${filemsg}${notfixed}"
|
|
failed=$(( ${failed} + 1 ))
|
|
else
|
|
if ! find_file_in_dirlist pc "${pcpath}" \
|
|
"${pcsrcdir}" "${SRC_DIR}${pcpath%/*}"
|
|
then
|
|
msg "${filemsg}${notfixed}"
|
|
failed=$(( ${failed} + 1 ))
|
|
else
|
|
# ${dir} is set by find_file_in_dirlist()
|
|
populate_dir "${op}" true \
|
|
"${dir}" "${DEST_DIR}${pcpath%/*}" 444 \
|
|
pc
|
|
failed=$(( ${failed} + $? ))
|
|
fi
|
|
fi
|
|
|
|
return $failed
|
|
}
|
|
|
|
|
|
#
|
|
# obsolete_stand
|
|
# obsolete_stand_debug
|
|
#
|
|
|
|
obsolete_stand_internal()
|
|
{
|
|
local prefix="$1"
|
|
shift
|
|
[ -n "$1" ] || err 3 "USAGE: do_obsolete_stand fix|check"
|
|
local op="$1"
|
|
local failed=0
|
|
local dir
|
|
|
|
for dir in \
|
|
${prefix}/stand/${MACHINE} \
|
|
${prefix}/stand/${MACHINE}-4xx \
|
|
${prefix}/stand/${MACHINE}-booke \
|
|
${prefix}/stand/${MACHINE}-xen \
|
|
${prefix}/stand/${MACHINE}pae-xen
|
|
do
|
|
[ -d "${DEST_DIR}${dir}" ] && obsolete_stand "${dir}"
|
|
done | obsolete_paths "${op}"
|
|
failed=$(( ${failed} + $? ))
|
|
|
|
return ${failed}
|
|
}
|
|
|
|
adddisableditem obsolete_stand "remove obsolete files from /stand"
|
|
do_obsolete_stand()
|
|
{
|
|
obsolete_stand_internal "" "$@"
|
|
return $?
|
|
}
|
|
|
|
adddisableditem obsolete_stand_debug "remove obsolete files from /usr/libdata/debug/stand"
|
|
do_obsolete_stand_debug()
|
|
{
|
|
obsolete_stand_internal "/usr/libdata/debug" "$@"
|
|
return $?
|
|
}
|
|
|
|
|
|
#
|
|
# obsolete
|
|
#
|
|
# NOTE: This item is last to allow other items to move obsolete files.
|
|
#
|
|
|
|
listarchsubdirs()
|
|
{
|
|
if ! $SOURCEMODE; then
|
|
echo "@ARCHSUBDIRS@"
|
|
else
|
|
${SED} -n -e '/ARCHDIR_SUBDIR/s/[[:space:]]//gp' \
|
|
"${SRC_DIR}/compat/archdirs.mk"
|
|
fi
|
|
}
|
|
|
|
getarchsubdirs()
|
|
{
|
|
local m
|
|
local i
|
|
|
|
case ${MACHINE_ARCH} in
|
|
*arm*|*aarch64*) m=arm;;
|
|
x86_64) m=amd64;;
|
|
*) m=${MACHINE_ARCH};;
|
|
esac
|
|
|
|
for i in $(listarchsubdirs); do
|
|
echo $i
|
|
done | ${SORT} -u | ${SED} -n -e "/=${m}/s@.*=${m}/\(.*\)@\1@p"
|
|
}
|
|
|
|
getcompatlibdirs()
|
|
{
|
|
local i
|
|
|
|
for i in $(getarchsubdirs); do
|
|
if [ -d "${DEST_DIR}/usr/lib/$i" ]; then
|
|
echo /usr/lib/$i
|
|
fi
|
|
done
|
|
}
|
|
|
|
additem obsolete "remove obsolete file sets and minor libraries"
|
|
do_obsolete()
|
|
{
|
|
[ -n "$1" ] || err 3 "USAGE: do_obsolete fix|check"
|
|
local op="$1"
|
|
local failed=0
|
|
local i
|
|
|
|
${SORT} -ru "${DEST_DIR}"/var/db/obsolete/* | obsolete_paths "${op}"
|
|
failed=$(( ${failed} + $? ))
|
|
|
|
(
|
|
obsolete_libs /lib
|
|
obsolete_libs /usr/lib
|
|
obsolete_libs /usr/lib/i18n
|
|
obsolete_libs /usr/X11R6/lib
|
|
obsolete_libs /usr/X11R7/lib
|
|
for i in $(getcompatlibdirs); do
|
|
obsolete_libs $i
|
|
done
|
|
) | obsolete_paths "${op}"
|
|
failed=$(( ${failed} + $? ))
|
|
|
|
return ${failed}
|
|
}
|
|
|
|
|
|
#
|
|
# end of items
|
|
# ------------
|
|
#
|
|
|
|
|
|
help()
|
|
{
|
|
cat << _USAGE_
|
|
Usage: ${PROGNAME} [-a ARCH] [-d DEST_DIR] [-m MACHINE] [-s SRC_ARG] [-x XSRC_DIR] OPERATION ...
|
|
${PROGNAME} -?
|
|
|
|
Perform post-installation checks and/or fixes on a system's
|
|
configuration files.
|
|
If no items are provided, a default set of checks or fixes is applied.
|
|
|
|
Options:
|
|
-? Display this help, and exit.
|
|
-a ARCH Set \$MACHINE_ARCH to ARCH. [${MACHINE_ARCH}]
|
|
-d DEST_DIR Destination directory to check. [${DEST_DIR:-/}]
|
|
-m MACHINE Set \$MACHINE to MACHINE. [${MACHINE}]
|
|
-s SRC_ARG Location of the source files. This may be any of
|
|
the following:
|
|
-s SRC_DIR A directory that contains a NetBSD
|
|
source tree.
|
|
-s TGZ_DIR A directory in which one or both of
|
|
"etc.tgz" and "xetc.tgz" have been
|
|
extracted.
|
|
-s TGZ_FILE A distribution set file such as
|
|
"etc.tgz" or "xetc.tgz".
|
|
May be specified multipled times.
|
|
[${SRC_DIR:-/usr/src}]
|
|
-x XSRC_DIR Location of the X11 source files. This must be
|
|
a directory that contains a NetBSD xsrc tree.
|
|
[${XSRC_DIR:-/usr/src/../xsrc}]
|
|
|
|
Supported values for OPERATION:
|
|
help Display this help, and exit.
|
|
list List available items.
|
|
check ITEM ... Perform post-installation checks on ITEMs.
|
|
diff [-bcenpuw] ITEM ...
|
|
Similar to 'check' but also output difference of files,
|
|
using diff with the provided options.
|
|
fix ITEM ... Apply fixes that 'check' determines need to be applied.
|
|
usage Display this help, and exit.
|
|
_USAGE_
|
|
}
|
|
|
|
usage()
|
|
{
|
|
help 1>&2
|
|
exit 2
|
|
}
|
|
|
|
|
|
list()
|
|
{
|
|
local i
|
|
echo "Default set of items (to apply if no items are provided by user):"
|
|
echo " Item Description"
|
|
echo " ---- -----------"
|
|
for i in ${defaultitems}; do
|
|
eval desc=\"\${desc_${i}}\"
|
|
printf " %-20s %s\n" "${i}" "${desc}"
|
|
done
|
|
echo "Items disabled by default (must be requested explicitly):"
|
|
echo " Item Description"
|
|
echo " ---- -----------"
|
|
for i in ${otheritems}; do
|
|
eval desc=\"\${desc_${i}}\"
|
|
printf " %-20s %s\n" "${i}" "${desc}"
|
|
done
|
|
}
|
|
|
|
|
|
main()
|
|
{
|
|
DIRMODE=false # true if "-s" specified a directory
|
|
ITEMS= # items to check|diff|fix. [${defaultitems}]
|
|
N_SRC_ARGS=0 # number of "-s" args in SRC_ARGLIST
|
|
SOURCEMODE=false # true if "-s" specified a source directory
|
|
SRC_ARGLIST= # quoted list of one or more "-s" args
|
|
SRC_DIR="${SRC_ARG}" # set default value for early usage()
|
|
TGZLIST= # quoted list list of tgz files
|
|
TGZMODE=false # true if "-s" specifies a tgz file
|
|
XSRC_DIR="${SRC_ARG}/../xsrc"
|
|
XSRC_DIR_FIX=
|
|
|
|
case "$(uname -s)" in
|
|
Darwin)
|
|
# case sensitive match for case insensitive fs
|
|
file_exists_exact=file_exists_exact
|
|
;;
|
|
*)
|
|
file_exists_exact=:
|
|
;;
|
|
esac
|
|
|
|
# Validate options.
|
|
#
|
|
while getopts :a:d:m:s:x: ch; do
|
|
case "${ch}" in
|
|
a)
|
|
MACHINE_ARCH="${OPTARG}"
|
|
;;
|
|
d)
|
|
DEST_DIR="${OPTARG}"
|
|
;;
|
|
m)
|
|
MACHINE="${OPTARG}"
|
|
;;
|
|
s)
|
|
qarg="$(shell_quote "${OPTARG}")"
|
|
N_SRC_ARGS=$(( $N_SRC_ARGS + 1 ))
|
|
SRC_ARGLIST="${SRC_ARGLIST}${SRC_ARGLIST:+ }-s ${qarg}"
|
|
if [ -f "${OPTARG}" ]; then
|
|
# arg refers to a *.tgz file.
|
|
# This may happen twice, for both
|
|
# etc.tgz and xetc.tgz, so we build up a
|
|
# quoted list in TGZLIST.
|
|
TGZMODE=true
|
|
TGZLIST="${TGZLIST}${TGZLIST:+ }${qarg}"
|
|
# Note that, when TGZMODE is true,
|
|
# SRC_ARG is used only for printing
|
|
# human-readable messages.
|
|
SRC_ARG="${TGZLIST}"
|
|
elif [ -d "${OPTARG}" ]; then
|
|
# arg refers to a directory.
|
|
# It might be a source directory, or a
|
|
# directory where the sets have already
|
|
# been extracted.
|
|
DIRMODE=true
|
|
SRC_ARG="${OPTARG}"
|
|
if [ -f "${OPTARG}/etc/Makefile" ]; then
|
|
SOURCEMODE=true
|
|
fi
|
|
else
|
|
err 2 "Invalid argument for -s option"
|
|
fi
|
|
;;
|
|
x)
|
|
if [ -d "${OPTARG}" ]; then
|
|
# arg refers to a directory.
|
|
XSRC_DIR="${OPTARG}"
|
|
XSRC_DIR_FIX="-x ${OPTARG} "
|
|
else
|
|
err 2 "Not a directory for -x option"
|
|
fi
|
|
;;
|
|
"?")
|
|
if [ "${OPTARG}" = "?" ]; then
|
|
help
|
|
return # no further processing or validation
|
|
fi
|
|
warn "Unknown option -${OPTARG}"
|
|
usage
|
|
;;
|
|
|
|
:)
|
|
warn "Missing argument for option -${OPTARG}"
|
|
usage
|
|
;;
|
|
|
|
*)
|
|
err 3 "Unimplemented option -${ch}"
|
|
;;
|
|
esac
|
|
done
|
|
shift $((${OPTIND} - 1))
|
|
if [ $# -eq 0 ] ; then
|
|
warn "Missing operation"
|
|
usage
|
|
fi
|
|
op="$1"
|
|
shift
|
|
|
|
if [ "$N_SRC_ARGS" -gt 1 ] && $DIRMODE; then
|
|
err 2 "Multiple -s args are allowed only with tgz files"
|
|
fi
|
|
if [ "$N_SRC_ARGS" -eq 0 ]; then
|
|
# The default SRC_ARG was set elsewhere
|
|
DIRMODE=true
|
|
SOURCEMODE=true
|
|
SRC_ARGLIST="-s $(shell_quote "${SRC_ARG}")"
|
|
fi
|
|
|
|
# Validate 'diff' first, as it becomes 'check'
|
|
#
|
|
case "${op}" in
|
|
|
|
diff)
|
|
op=check
|
|
DIFF_STYLE=n # default style is RCS
|
|
OPTIND=1
|
|
while getopts :bcenpuw ch; do
|
|
case "${ch}" in
|
|
c|e|n|u)
|
|
if [ "${DIFF_STYLE}" != "n" -a \
|
|
"${DIFF_STYLE}" != "${ch}" ]; then
|
|
warn "diff: conflicting output style: -${ch}"
|
|
usage
|
|
fi
|
|
DIFF_STYLE="${ch}"
|
|
;;
|
|
b|p|w)
|
|
DIFF_OPT="${DIFF_OPT} -${ch}"
|
|
;;
|
|
"?")
|
|
# NOTE: not supporting diff -?
|
|
warn "diff: Unknown option -${OPTARG}"
|
|
usage
|
|
;;
|
|
:)
|
|
warn "diff: Missing argument for option -${OPTARG}"
|
|
usage
|
|
;;
|
|
*)
|
|
err 3 "diff: Unimplemented option -${ch}"
|
|
;;
|
|
esac
|
|
done
|
|
shift $((${OPTIND} - 1))
|
|
;;
|
|
|
|
esac
|
|
|
|
# Validate operation and items.
|
|
#
|
|
case "${op}" in
|
|
|
|
check|fix)
|
|
ITEMS="$*"
|
|
: ${ITEMS:="${defaultitems}"}
|
|
|
|
# ensure that all supplied items are valid
|
|
#
|
|
for i in ${ITEMS}; do
|
|
eval desc=\"\${desc_${i}}\"
|
|
[ -n "${desc}" ] || err 2 "Unsupported ${op} '"${i}"'"
|
|
done
|
|
;;
|
|
|
|
help|usage)
|
|
help
|
|
return # no further processing or validation
|
|
;;
|
|
|
|
list)
|
|
# processed below
|
|
;;
|
|
|
|
*)
|
|
warn "Unknown operation '"${op}"'"
|
|
usage
|
|
;;
|
|
|
|
esac
|
|
|
|
#
|
|
# If '-s' arg or args specified tgz files, extract them
|
|
# to a scratch directory.
|
|
#
|
|
if $TGZMODE; then
|
|
ETCTGZDIR="${SCRATCHDIR}/etc.tgz"
|
|
echo "Note: Creating temporary directory ${ETCTGZDIR}"
|
|
if ! mkdir "${ETCTGZDIR}"; then
|
|
err 2 "Can't create ${ETCTGZDIR}"
|
|
fi
|
|
( # subshell to localise changes to "$@"
|
|
eval "set -- ${TGZLIST}"
|
|
for tgz in "$@"; do
|
|
echo "Note: Extracting files from ${tgz}"
|
|
cat "${tgz}" | (
|
|
cd "${ETCTGZDIR}" &&
|
|
tar -zxf -
|
|
) || err 2 "Can't extract ${tgz}"
|
|
done
|
|
)
|
|
SRC_DIR="${ETCTGZDIR}"
|
|
else
|
|
SRC_DIR="${SRC_ARG}"
|
|
fi
|
|
|
|
[ -d "${SRC_DIR}" ] || err 2 "${SRC_DIR} is not a directory"
|
|
[ -d "${DEST_DIR}" ] || err 2 "${DEST_DIR} is not a directory"
|
|
[ -n "${MACHINE}" ] || err 2 "\${MACHINE} is not defined"
|
|
[ -n "${MACHINE_ARCH}" ] || err 2 "\${MACHINE_ARCH} is not defined"
|
|
if ! $SOURCEMODE && ! [ -f "${SRC_DIR}/etc/mtree/set.etc" ]; then
|
|
err 2 "Files from the etc.tgz set are missing"
|
|
fi
|
|
|
|
# If directories are /, clear them, so various messages
|
|
# don't have leading "//". However, this requires
|
|
# the use of ${foo:-/} to display the variables.
|
|
#
|
|
[ "${SRC_DIR}" = "/" ] && SRC_DIR=""
|
|
[ "${DEST_DIR}" = "/" ] && DEST_DIR=""
|
|
|
|
detect_x11
|
|
|
|
# Perform operation.
|
|
#
|
|
case "${op}" in
|
|
|
|
check|fix)
|
|
[ -n "${ITEMS}" ] || err 2 "${op}: missing items"
|
|
|
|
echo "Source directory: ${SRC_DIR:-/}"
|
|
if $TGZMODE; then
|
|
echo " (extracted from: ${SRC_ARG})"
|
|
fi
|
|
echo "Target directory: ${DEST_DIR:-/}"
|
|
items_passed=
|
|
items_failed=
|
|
for i in ${ITEMS}; do
|
|
echo "${i} ${op}:"
|
|
( eval do_${i} ${op} )
|
|
if [ $? -eq 0 ]; then
|
|
items_passed="${items_passed} ${i}"
|
|
else
|
|
items_failed="${items_failed} ${i}"
|
|
fi
|
|
done
|
|
|
|
if [ "${op}" = "check" ]; then
|
|
plural="checks"
|
|
else
|
|
plural="fixes"
|
|
fi
|
|
|
|
echo "${PROGNAME} ${plural} passed:${items_passed}"
|
|
echo "${PROGNAME} ${plural} failed:${items_failed}"
|
|
if [ -n "${items_failed}" ]; then
|
|
exitstatus=1;
|
|
if [ "${op}" = "check" ]; then
|
|
[ "$MACHINE" = "$(uname -m)" ] && m= || m=" -m $MACHINE"
|
|
cat <<_Fix_me_
|
|
To fix, run:
|
|
${HOST_SH} ${0} ${SRC_ARGLIST} ${XSRC_DIR_FIX}-d ${DEST_DIR:-/}$m fix${items_failed}
|
|
Note that this may overwrite local changes.
|
|
_Fix_me_
|
|
fi
|
|
fi
|
|
;;
|
|
|
|
list)
|
|
echo "Source directory: ${SRC_DIR:-/}"
|
|
echo "Target directory: ${DEST_DIR:-/}"
|
|
if $TGZMODE; then
|
|
echo " (extracted from: ${SRC_ARG})"
|
|
fi
|
|
list
|
|
;;
|
|
|
|
*)
|
|
# diff, help, usage handled during operation validation
|
|
err 3 "Unimplemented operation '"${op}"'"
|
|
;;
|
|
|
|
esac
|
|
}
|
|
|
|
if [ -n "$POSTINSTALL_FUNCTION" ]; then
|
|
eval "$POSTINSTALL_FUNCTION"
|
|
exit 0
|
|
fi
|
|
|
|
# defaults
|
|
#
|
|
PROGNAME="${0##*/}"
|
|
SRC_ARG="/usr/src"
|
|
DEST_DIR="/"
|
|
: ${MACHINE:="$( uname -m )"} # assume native build if $MACHINE is not set
|
|
: ${MACHINE_ARCH:="$( uname -p )"}# assume native build if not set
|
|
|
|
DIFF_STYLE=
|
|
DIFF_OPT=
|
|
NOT_FIXED=" (FIX MANUALLY)"
|
|
SCRATCHDIR="$( mkdtemp )" || err 2 "Can't create scratch directory"
|
|
trap "${RM} -rf \"\${SCRATCHDIR}\" ; exit 0" 1 2 3 15 # HUP INT QUIT TERM
|
|
|
|
umask 022
|
|
exec 3>/dev/null
|
|
exec 4>/dev/null
|
|
exitstatus=0
|
|
|
|
main "$@"
|
|
${RM} -rf "${SCRATCHDIR}"
|
|
exit $exitstatus
|