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