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