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