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