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