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