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