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 69err() 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 80warn() 81{ 82 echo 1>&2 "${PROGNAME}: $*" 83} 84 85msg() 86{ 87 echo " $*" 88} 89 90mkdtemp() 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# 117shell_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}")" 161bre_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# 173unprefix() 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# 186additem() 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# 197adddisableditem() 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# 208check_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# 236check_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# 306populate_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# 365compare_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# 382move_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# 409rcconf_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# 442rcvar_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# 469find_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# 499file_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# 521obsolete_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# 564obsolete_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 573exclude() 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# 597exclude_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 622function digit(v, c, n) { return (n <= c) ? v[n] : 0 } 623 624function 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# 675obsolete_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# 701modify_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# 737contents_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 767get_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. 784detect_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# 803find_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 826handle_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 855additem atf "install missing atf configuration files and validate them" 856do_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 899additem autofsconfig "automounter configuration files" 900do_autofsconfig() 901{ 902 [ -n "$1" ] || err 3 "USAGE: do_autofsconfig fix|check" 903 local autofs_files=" 904include_ldap 905include_nis 906special_hosts 907special_media 908special_noauto 909special_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 935fixblock() 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 961additem blocklist "rename old files to blocklist" 962do_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 992additem bluetooth "Bluetooth configuration is up to date" 993do_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 1028obsolete_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 1066additem catpages "remove outdated cat pages" 1067do_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 1092additem ddbonpanic "verify ddb.onpanic is configured in sysctl.conf" 1093do_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 1123additem defaults "/etc/defaults/ being up to date" 1124do_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 1180additem dhcpcd "dhcpcd configuration is up to date" 1181do_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 1263additem dhcpcdrundir "accidentally created /@RUNDIR@ does not exist" 1264do_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 1289additem envsys "envsys configuration is up to date" 1290do_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 1318additem fontconfig "X11 font configuration is up to date" 1319do_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=" 133710-autohint.conf 133810-scale-bitmap-fonts.conf 133910-sub-pixel-bgr.conf 134010-sub-pixel-none.conf 134110-sub-pixel-rgb.conf 134210-sub-pixel-vbgr.conf 134310-sub-pixel-vrgb.conf 134410-unhinted.conf 134511-lcdfilter-default.conf 134611-lcdfilter-legacy.conf 134711-lcdfilter-light.conf 134820-unhint-small-vera.conf 134925-unhint-nonlatin.conf 135030-metric-aliases.conf 135140-nonlatin.conf 135245-generic.conf 135345-latin.conf 135449-sansserif.conf 135550-user.conf 135651-local.conf 135760-generic.conf 135860-latin.conf 135965-fonts-persian.conf 136065-khmer.conf 136165-nonlatin.conf 136269-unifont.conf 136370-no-bitmaps.conf 136470-yes-bitmaps.conf 136580-delicious.conf 136690-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=" 138810-autohint.conf 138910-no-sub-pixel.conf 139010-sub-pixel-bgr.conf 139110-sub-pixel-rgb.conf 139210-sub-pixel-vbgr.conf 139310-sub-pixel-vrgb.conf 139410-unhinted.conf 139525-unhint-nonlatin.conf 139665-khmer.conf 139770-no-bitmaps.conf 139870-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 1423additem gid "required groups in /etc/group" 1424do_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 1440additem gpio "gpio configuration is up to date" 1441do_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 1459additem hosts "/etc/hosts being up to date" 1460do_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 1479additem iscsi "/etc/iscsi is populated" 1480do_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 1496adddisableditem mailerconf "update /etc/mailer.conf after sendmail removal" 1497do_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 1525additem makedev "/dev/MAKEDEV being up to date" 1526do_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 1563additem manconf "check for a mandoc usage in /etc/man.conf" 1564do_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 1592additem motd "contents of motd" 1593do_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 1634additem mtree "/etc/mtree/ being up to date" 1635do_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# 1664handle_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 1695additem named "named configuration update" 1696do_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 1722additem opensslcertsconf "ensure TLS trust anchor configuration exists" 1723do_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 1803additem opensslcertsrehash "make /etc/openssl/certs cache of TLS trust anchors" 1804do_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 1878additem pam "/etc/pam.d is populated" 1879do_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 1901additem periodic "/etc/{daily,weekly,monthly,security} being up to date" 1902do_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 1915additem pf "pf configuration being up to date" 1916do_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 1942additem ptyfsoldnodes "remove legacy device nodes when using ptyfs" 1943do_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 2037additem pwd_mkdb "passwd database version" 2038do_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. 2080rc_644_files=" 2081rc 2082rc.subr 2083rc.shutdown 2084" 2085 2086rc_obsolete_vars=" 2087amd amd_master 2088btcontrol btcontrol_devices 2089critical_filesystems critical_filesystems_beforenet 2090mountcritlocal mountcritremote 2091network ip6forwarding 2092network nfsiod_flags 2093sdpd sdpd_control 2094sdpd sdpd_groupname 2095sdpd sdpd_username 2096sysctl defcorename 2097" 2098 2099update_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 2123select_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 2134select_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 2156getetcsets() 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 2165additem rc "/etc/rc* and /etc/rc.d/ being up to date" 2166do_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 2260adddisableditem sendmail "remove obsolete sendmail configuration files and scripts" 2261do_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 2295additem ssh "ssh configuration update" 2296do_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 2392additem tcpdumpchroot "remove /var/chroot/tcpdump/etc/protocols" 2393do_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 2417additem uid "required users in /etc/master.passwd" 2418do_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 2434additem varrwho "required ownership of files in /var/rwho" 2435do_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 2447additem varshm "check for a tmpfs mounted on /var/shm" 2448do_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 2481additem wscons "wscons configuration file update" 2482do_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 2510additem x11 "x11 configuration update" 2511do_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 2587additem xkb "clean up for xkbdata to xkeyboard-config upgrade" 2588do_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 2649obsolete_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 2672adddisableditem obsolete_stand "remove obsolete files from /stand" 2673do_obsolete_stand() 2674{ 2675 obsolete_stand_internal "" "$@" 2676 return $? 2677} 2678 2679adddisableditem obsolete_stand_debug "remove obsolete files from /usr/libdata/debug/stand" 2680do_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 2693listarchsubdirs() 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 2703getarchsubdirs() 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 2719getcompatlibdirs() 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 2730additem obsolete "remove obsolete file sets and minor libraries" 2731do_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 2763help() 2764{ 2765 cat << _USAGE_ 2766Usage: ${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 2805usage() 2806{ 2807 help 1>&2 2808 exit 2 2809} 2810 2811 2812list() 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 2832main() 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_ 3094To fix, run: 3095 ${HOST_SH} ${0} ${SRC_ARGLIST} ${XSRC_DIR_FIX}-d ${DEST_DIR:-/}$m fix${items_failed} 3096Note 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 3119if [ -n "$POSTINSTALL_FUNCTION" ]; then 3120 eval "$POSTINSTALL_FUNCTION" 3121 exit 0 3122fi 3123 3124# defaults 3125# 3126PROGNAME="${0##*/}" 3127SRC_ARG="/usr/src" 3128DEST_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 3132DIFF_STYLE= 3133DIFF_OPT= 3134NOT_FIXED=" (FIX MANUALLY)" 3135SCRATCHDIR="$( mkdtemp )" || err 2 "Can't create scratch directory" 3136trap "${RM} -rf \"\${SCRATCHDIR}\" ; exit 0" 1 2 3 15 # HUP INT QUIT TERM 3137 3138umask 022 3139exec 3>/dev/null 3140exec 4>/dev/null 3141exitstatus=0 3142 3143main "$@" 3144${RM} -rf "${SCRATCHDIR}" 3145exit $exitstatus 3146