1#! /bin/sh --
2#
3#	$NetBSD: checkflist,v 1.46 2022/08/21 07:10:03 lukem Exp $
4#
5# Verify output of makeflist against contents of ${DESTDIR} and ${metalog}.
6
7if [ -z "${DESTDIR}" ]; then
8	echo "DESTDIR must be set"
9	exit 1
10fi
11
12prog="${0##*/}"
13rundir="$(dirname "$0")" # ${0%/*} isn't good enough when there's no "/"
14. "${rundir}/sets.subr"
15
16#
17# * ${SETS_DLIST}: files present in DESTDIR.
18# * ${SETS_FLIST}: files mentioned in flist;
19# * ${SETS_MLIST}: files mentioned in metalog;
20#
21SETS_DLIST="${DESTDIR}/SETS.dlist"
22SETS_FLIST="${DESTDIR}/SETS.flist"
23SETS_MLIST="${DESTDIR}/SETS.mlist"
24
25#
26# * ${SETS_METALOG_EXTRA}: Files in METALOG but missing from DESTDIR."
27# * ${SETS_METALOG_MISSING}: Files in DESTDIR but missing from METALOG."
28# * ${SETS_DESTDIR_EXTRA}: Files in DESTDIR but missing from setlist."
29# * ${SETS_DESTDIR_MISSING}: Files in setlist but missing from DESTDIR."
30#
31SETS_METALOG_EXTRA="${DESTDIR}/SETS.metalog.extra"
32SETS_METALOG_MISSING="${DESTDIR}/SETS.metalog.missing"
33SETS_DESTDIR_EXTRA="${DESTDIR}/SETS.destdir.extra"
34SETS_DESTDIR_MISSING="${DESTDIR}/SETS.destdir.missing"
35
36es=0
37cleanup()
38{
39	if [ ${es} -gt 255 ]; then
40		es=255
41	fi
42	exit ${es}
43}
44trap cleanup 0 2 3 13		# EXIT INT QUIT PIPE
45
46origin=.
47xargs=""
48dargs=""
49metalog=
50allowextra=false
51allowmissing=false
52
53# handle args
54while getopts xbL:M:em ch; do
55	case ${ch} in
56	x)
57		xargs="-x"
58		origin="./etc/X11 ./etc/fonts ./usr/X11R7"
59		;;
60	# backward compat
61	b)
62		xargs="-b"
63		;;
64	L)
65		xargs="-L ${OPTARG}"
66		;;
67	M)
68		metalog="${OPTARG}"
69		;;
70	e)
71		allowextra=true
72		;;
73	m)
74		allowmissing=true
75		;;
76	*)
77		cat 1>&2 <<USAGE
78Usage: ${prog} [-x|-b|-L lists] [-M metalog] [-e] [-m]
79	-x		check only x11 lists
80	-b		check netbsd + x11 lists
81	-L base,x,ext	check specified lists
82	-M metalog	metalog file
83	-e		extra files are not considered an error
84	-m		missing files are not considered an error
85USAGE
86		exit 1
87		;;
88	esac
89done
90shift $((${OPTIND} - 1))
91
92#
93# Exceptions to flist checking (all begin with "./"):
94#
95# * ignore var/db/syspkg and its contents
96# * ignore METALOG and METALOG.*
97# * ignore etc/mtree/set.*
98#
99ignore_exceptions()
100{
101IGNORE_REGEXP_SYSPKG="^\./var/db/syspkg(\$|/)"
102IGNORE_REGEXP_METALOG="^\./METALOG(\..*)?\$"
103IGNORE_REGEXP_SETS="^\./SETS\..*\$"
104IGNORE_REGEXP_MTREE="^\./etc/mtree/set\.[a-z]*\$"
105
106	${EGREP} -v \
107		-e "${IGNORE_REGEXP_SYSPKG}" \
108		-e "${IGNORE_REGEXP_METALOG}" \
109		-e "${IGNORE_REGEXP_SETS}" \
110		-e "${IGNORE_REGEXP_MTREE}"
111}
112
113#
114# Here would be a good place to add custom exceptions to flist checking.
115#
116
117#
118# Make three lists:
119#
120# All three lists are filtered against ${IGNORE_REGEXP}.
121#
122
123generate_dlist()
124{
125( cd "${DESTDIR}" && ${FIND} ${origin} \
126	\( -type d -o -type f -o -type l \) -print ) \
127	| ${SORT} -u | ignore_exceptions >"${SETS_DLIST}"
128}
129
130generate_flist()
131{
132${HOST_SH} "${rundir}/makeflist" ${xargs} ${dargs} \
133	| ${SORT} -u | ignore_exceptions >"${SETS_FLIST}"
134}
135
136generate_mlist()
137{
138if [ -n "${metalog}" ]; then
139	${AWK} '{print $1}' <"${metalog}" \
140	| ${SORT} -u | ignore_exceptions >"${SETS_MLIST}"
141else
142	SETS_MLIST=/dev/null
143fi
144}
145
146generate_mlist_missing()
147{
148	${COMM} -23 "${SETS_DLIST}" "${SETS_MLIST}" > "${SETS_METALOG_MISSING}"
149}
150
151generate_mlist_extra()
152{
153	${COMM} -13 "${SETS_DLIST}" "${SETS_MLIST}" > "${SETS_METALOG_EXTRA}"
154}
155
156generate_dlist_missing()
157{
158	${COMM} -23 "${SETS_FLIST}" "${SETS_DLIST}" > "${SETS_DESTDIR_MISSING}"
159}
160
161generate_dlist_extra()
162{
163	${COMM} -13 "${SETS_FLIST}" "${SETS_DLIST}" > "${SETS_DESTDIR_EXTRA}"
164}
165
166exist_case_insensitive()
167{
168	while read f; do
169		[ -f "${DESTDIR}/${f}" ] || \
170		[ -d "${DESTDIR}/${f}" ] || \
171		[ -L "${DESTDIR}/${f}" ] || \
172		echo "$f"
173	done
174}
175
176#
177# compare DESTDIR with METALOG, and report on differences.
178#
179compare_metalog()
180{
181    # Handle case insensitive filesystems
182    mv -f "${SETS_METALOG_EXTRA}" "${SETS_METALOG_EXTRA}.all"
183    exist_case_insensitive < "${SETS_METALOG_EXTRA}.all" > "${SETS_METALOG_EXTRA}"
184    rm -f "${SETS_METALOG_EXTRA}.all"
185
186    check_metalog_extra
187    check_metalog_missing
188}
189
190check_metalog_extra()
191{
192    if [ -s "${SETS_METALOG_EXTRA}" ]; then
193	count="$(${AWK} 'END {print NR}' "${SETS_METALOG_EXTRA}")"
194	echo ""
195	echo "=======  ${count} extra files in METALOG  ========="
196	echo "Files in METALOG but missing from DESTDIR."
197	echo "File was deleted after installation ?"
198	echo "------------------------------------------"
199	cat "${SETS_METALOG_EXTRA}"
200	echo "=========  end of ${count} extra files  ==========="
201	echo ""
202	es=1 # this is fatal even if ${allowextra} is true
203    fi
204}
205
206check_metalog_missing()
207{
208    if [ -s "${SETS_METALOG_MISSING}" ]; then
209	count="$(${AWK} 'END {print NR}' "${SETS_METALOG_MISSING}")"
210	echo ""
211	echo "======  ${count} missing files in METALOG  ========"
212	echo "Files in DESTDIR but missing from METALOG."
213	echo "File installed but not registered in METALOG ?"
214	echo "------------------------------------------"
215	cat "${SETS_METALOG_MISSING}"
216	echo "========  end of ${count} missing files  =========="
217	echo ""
218	es=1 # this is fatal even if ${allowmissing} is true
219    fi
220}
221
222#
223# compare flist with DESTDIR, and report on differences.
224#
225compare_destdir()
226{
227# Handle case insensitive filesystems
228mv -f "${SETS_DESTDIR_MISSING}" "${SETS_DESTDIR_MISSING}.all"
229exist_case_insensitive < "${SETS_DESTDIR_MISSING}.all" > "${SETS_DESTDIR_MISSING}"
230rm -f "${SETS_DESTDIR_MISSING}.all"
231
232check_destdir_extra
233check_destdir_missing
234}
235
236check_destdir_extra()
237{
238if [ -s "${SETS_DESTDIR_EXTRA}" ]; then
239	count="$(${AWK} 'END {print NR}' "${SETS_DESTDIR_EXTRA}")"
240	echo ""
241	echo "=======  ${count} extra files in DESTDIR  ========="
242	echo "Files in DESTDIR but missing from flist."
243	echo "File is obsolete or flist is out of date ?"
244	if ${allowextra}; then
245		echo "This is non-fatal, due to '-e' option."
246	else
247		es=1
248	fi
249	echo "------------------------------------------"
250	cat "${SETS_DESTDIR_EXTRA}"
251	echo "=========  end of ${count} extra files  ==========="
252	echo ""
253fi
254}
255
256check_destdir_missing()
257{
258if [ -s "${SETS_DESTDIR_MISSING}" ]; then
259	count="$(${AWK} 'END {print NR}' "${SETS_DESTDIR_MISSING}")"
260	echo ""
261	echo "======  ${count} missing files in DESTDIR  ========"
262	echo "Files in flist but missing from DESTDIR."
263	echo "File wasn't installed ?"
264	if ${allowmissing}; then
265		echo "This is non-fatal, due to '-m' option."
266	else
267		es=1
268	fi
269	echo "------------------------------------------"
270	cat "${SETS_DESTDIR_MISSING}"
271	echo "========  end of ${count} missing files  =========="
272	echo ""
273fi
274}
275
276generate_dlist
277generate_flist
278generate_mlist
279
280generate_mlist_missing
281generate_mlist_extra
282
283generate_dlist_missing
284generate_dlist_extra
285
286if false && [ -n "${metalog}" ]; then
287	# XXX: Temporarily disabled due to problems with obsolete files in metalog
288	compare_metalog
289else
290	compare_destdir
291fi
292
293exit 0		# cleanup will exit with ${es}
294