1#!/bin/sh
2#
3# Copyright (C) Internet Systems Consortium, Inc. ("ISC")
4#
5# SPDX-License-Identifier: MPL-2.0
6#
7# This Source Code Form is subject to the terms of the Mozilla Public
8# License, v. 2.0. If a copy of the MPL was not distributed with this
9# file, you can obtain one at https://mozilla.org/MPL/2.0/.
10#
11# See the COPYRIGHT file distributed with this work for additional
12# information regarding copyright ownership.
13
14testsock6() {
15	if test -n "$PERL" && $PERL -e "use IO::Socket::INET6;" 2> /dev/null
16	then
17		$PERL "$TOP/bin/tests/system/testsock6.pl" "$@"
18	else
19		false
20	fi
21}
22
23export LANG=C
24
25. ${TOP}/version
26
27#
28# Common lists of system tests to run.
29#
30# The "stress" test is not run by default since it creates enough
31# load on the machine to make it unusable to other users.
32# The "dialup", "delzone", and "dupsigs" tests are also not run by
33# default because they take a very long time to complete.
34#
35# The following tests are hard-coded to use ports 5300 and 9953. For
36# this reason, these must be run sequentially.
37#
38# Sequential tests that only run on unix/linux should be added to
39# SEQUENTIAL_UNIX in conf.sh.in; those that only run on windows should
40# be added to SEQUENTIAL_WINDOWS in conf.sh.win32.
41#
42SEQUENTIAL_COMMON="ecdsa eddsa tkey"
43
44#
45# These tests can use ports assigned by the caller (other than 5300
46# and 9953). Because separate blocks of ports can be used for teach
47# test, these tests can be run in parallel.
48#
49# Parallel tests that only run on unix/linux should be added to
50# PARALLEL_UNIX in conf.sh.in; those that only run on windows should
51# be added to PARALLEL_WINDOWS in conf.sh.win32.
52#
53# Note: some of the longer-running tests such as serve-stale and
54# rpzrecurse are scheduled first, in order to get more benefit from
55# parallelism.
56#
57PARALLEL_COMMON="dnssec rpzrecurse serve-stale \
58acl \
59additional \
60addzone \
61allow-query \
62auth \
63autosign \
64builtin \
65cacheclean \
66case \
67catz \
68cds \
69chain \
70checkconf \
71checkds \
72checknames \
73checkzone \
74database \
75digdelv \
76dlz \
77dlzexternal \
78dns64 \
79dscp \
80dsdigest \
81dyndb \
82ednscompliance \
83emptyzones \
84fetchlimit \
85filter-aaaa \
86formerr \
87forward \
88geoip2 \
89glue \
90idna \
91inline \
92integrity \
93ixfr \
94journal \
95kasp \
96keepalive \
97keymgr2kasp \
98legacy \
99limits \
100masterfile \
101masterformat \
102metadata \
103mirror \
104mkeys \
105names \
106notify \
107nsec3 \
108nslookup \
109nsupdate \
110nzd2nzf \
111padding \
112pending \
113pipelined \
114qmin \
115reclimit \
116redirect \
117resolver \
118rndc \
119rootkeysentinel \
120rpz \
121rrchecker \
122rrl \
123rrsetorder \
124rsabigexponent \
125runtime \
126sfcache \
127shutdown \
128smartsign \
129sortlist \
130spf \
131staticstub \
132statistics \
133statschannel \
134stub \
135synthfromdnssec \
136timeouts \
137tcp \
138tools \
139tsig \
140tsiggss \
141ttl \
142unknown \
143upforwd \
144verify \
145views \
146wildcard \
147xfer \
148xferquota \
149zero \
150zonechecks"
151
152#
153# Set up color-coded test output
154#
155if [ ${SYSTEMTEST_FORCE_COLOR:-0} -eq 1 ] || test -t 1 && type tput > /dev/null 2>&1 && tput setaf 7 > /dev/null 2>&1 ; then
156    COLOR_END=`tput setaf 4`    # blue
157    COLOR_FAIL=`tput setaf 1`   # red
158    COLOR_INFO=`tput bold`      # bold
159    COLOR_NONE=`tput sgr0`
160    COLOR_PASS=`tput setaf 2`   # green
161    COLOR_START=`tput setaf 4`  # blue
162    COLOR_WARN=`tput setaf 3`   # yellow
163else
164    # set to empty strings so printf succeeds
165    COLOR_END=''
166    COLOR_FAIL=''
167    COLOR_INFO=''
168    COLOR_NONE=''
169    COLOR_PASS=''
170    COLOR_START=''
171    COLOR_WARN=''
172fi
173
174SYSTESTDIR="`basename $PWD`"
175
176if type printf > /dev/null 2>&1
177then
178	echofail () {
179		printf "${COLOR_FAIL}%s${COLOR_NONE}\n" "$*"
180	}
181	echowarn () {
182		printf "${COLOR_WARN}%s${COLOR_NONE}\n" "$*"
183	}
184	echopass () {
185		printf "${COLOR_PASS}%s${COLOR_NONE}\n" "$*"
186	}
187	echoinfo () {
188		printf "${COLOR_INFO}%s${COLOR_NONE}\n" "$*"
189	}
190	echostart () {
191		printf "${COLOR_START}%s${COLOR_NONE}\n" "$*"
192	}
193	echoend () {
194		printf "${COLOR_END}%s${COLOR_NONE}\n" "$*"
195	}
196	echo_i() {
197	    printf '%s\n' "$*" | while IFS= read -r __LINE ; do
198	       echoinfo "I:$SYSTESTDIR:$__LINE"
199	    done
200	}
201
202	echo_ic() {
203	    printf '%s\n' "$*" | while IFS= read -r __LINE ; do
204	       echoinfo "I:$SYSTESTDIR:  $__LINE"
205	    done
206	}
207
208	echo_d() {
209	    printf '%s\n' "$*" | while IFS= read -r __LINE ; do
210	       echoinfo "D:$SYSTESTDIR:$__LINE"
211	    done
212	}
213else
214	echofail () {
215		echo "$*"
216	}
217	echowarn () {
218		echo "$*"
219	}
220	echopass () {
221		echo "$*"
222	}
223	echoinfo () {
224		echo "$*"
225	}
226	echostart () {
227		echo "$*"
228	}
229	echoend () {
230		echo "$*"
231	}
232
233	echo_i() {
234	    echo "$@" | while IFS= read -r __LINE ; do
235	       echoinfo "I:$SYSTESTDIR:$__LINE"
236	    done
237	}
238
239	echo_ic() {
240	    echo "$@" | while IFS= read -r __LINE ; do
241	       echoinfo "I:$SYSTESTDIR:  $__LINE"
242	    done
243	}
244
245	echo_d() {
246	    echo "$@" | while IFS= read -r __LINE ; do
247	       echoinfo "D:$SYSTESTDIR:$__LINE"
248	    done
249	}
250fi
251
252cat_i() {
253    while IFS= read -r __LINE ; do
254       echoinfo "I:$SYSTESTDIR:$__LINE"
255    done
256}
257
258cat_d() {
259    while IFS= read -r __LINE ; do
260       echoinfo "D:$SYSTESTDIR:$__LINE"
261    done
262}
263
264digcomp() {
265    output=`$PERL $SYSTEMTESTTOP/digcomp.pl "$@"`
266    result=$?
267    [ -n "$output" ] &&  { echo "digcomp failed:"; echo "$output"; } | cat_i
268    return $result
269}
270
271start_server() {
272    $PERL "$TOP_SRCDIR/bin/tests/system/start.pl" "$@"
273}
274
275stop_server() {
276    $PERL "$TOP_SRCDIR/bin/tests/system/stop.pl" "$@"
277}
278
279send() {
280    $PERL "$TOP_SRCDIR/bin/tests/system/send.pl" "$@"
281}
282
283#
284# Useful variables in test scripts
285#
286
287# Default algorithm for testing.
288DEFAULT_ALGORITHM=ECDSAP256SHA256
289DEFAULT_ALGORITHM_NUMBER=13
290DEFAULT_BITS=256
291
292# This is an alternative algorithm for test cases that require more than
293# one algorithm (for example algorithm rollover).  Must be different from
294# DEFAULT_ALGORITHM.
295ALTERNATIVE_ALGORITHM=RSASHA256
296ALTERNATIVE_ALGORITHM_NUMBER=8
297ALTERNATIVE_BITS=1280
298
299# This is an algorithm that is used for tests against the
300# "disable-algorithms" configuration option.  Must be different from above
301# algorithms.
302DISABLED_ALGORITHM=ECDSAP384SHA384
303DISABLED_ALGORITHM_NUMBER=14
304DISABLED_BITS=384
305
306#
307# Useful functions in test scripts
308#
309
310# assert_int_equal: compare two integer variables, $1 and $2
311#
312# If $1 and $2 are equal, return 0; if $1 and $2 are not equal, report
313# the error using the description of the tested variable provided in $3
314# and return 1.
315assert_int_equal() {
316	found="$1"
317	expected="$2"
318	description="$3"
319
320	if [ "${expected}" -ne "${found}" ]; then
321		echo_i "incorrect ${description}: got ${found}, expected ${expected}"
322		return 1
323	fi
324
325	return 0
326}
327
328# keyfile_to_keys_section: helper function for keyfile_to_*_keys() which
329# converts keyfile data into a key-style trust anchor configuration
330# section using the supplied parameters
331keyfile_to_keys() {
332    section_name=$1
333    key_prefix=$2
334    shift
335    shift
336    echo "$section_name {"
337    for keyname in $*; do
338	awk '!/^; /{
339	    printf "\t\""$1"\" "
340	    printf "'"$key_prefix "'"
341	    printf $4 " " $5 " " $6 " \""
342	    for (i=7; i<=NF; i++) printf $i
343	    printf "\";\n"
344	}' $keyname.key
345    done
346    echo "};"
347}
348
349# keyfile_to_dskeys_section: helper function for keyfile_to_*_dskeys()
350# converts keyfile data into a DS-style trust anchor configuration
351# section using the supplied parameters
352keyfile_to_dskeys() {
353    section_name=$1
354    key_prefix=$2
355    shift
356    shift
357    echo "$section_name {"
358    for keyname in $*; do
359        $DSFROMKEY $keyname.key | \
360	awk '!/^; /{
361	    printf "\t\""$1"\" "
362	    printf "'"$key_prefix "'"
363	    printf $4 " " $5 " " $6 " \""
364	    for (i=7; i<=NF; i++) printf $i
365	    printf "\";\n"
366	}'
367    done
368    echo "};"
369}
370
371# keyfile_to_trusted_keys: convert key data contained in the keyfile(s)
372# provided to a "trust-keys" section suitable for including in a
373# resolver's configuration file
374keyfile_to_trusted_keys() {
375    keyfile_to_keys "trusted-keys" "" $*
376}
377
378# keyfile_to_static_keys: convert key data contained in the keyfile(s)
379# provided to a *static-key* "trust-anchors" section suitable for including in
380# a resolver's configuration file
381keyfile_to_static_keys() {
382    keyfile_to_keys "trust-anchors" "static-key" $*
383}
384
385# keyfile_to_initial_keys: convert key data contained in the keyfile(s)
386# provided to an *initial-key* "trust-anchors" section suitable for including
387# in a resolver's configuration file
388keyfile_to_initial_keys() {
389    keyfile_to_keys "trust-anchors" "initial-key" $*
390}
391
392# keyfile_to_static_ds_keys: convert key data contained in the keyfile(s)
393# provided to a *static-ds* "trust-anchors" section suitable for including in a
394# resolver's configuration file
395keyfile_to_static_ds() {
396    keyfile_to_dskeys "trust-anchors" "static-ds" $*
397}
398
399# keyfile_to_initial_ds_keys: convert key data contained in the keyfile(s)
400# provided to an *initial-ds* "trust-anchors" section suitable for including
401# in a resolver's configuration file
402keyfile_to_initial_ds() {
403    keyfile_to_dskeys "trust-anchors" "initial-ds" $*
404}
405
406# keyfile_to_key_id: convert a key file name to a key ID
407#
408# For a given key file name (e.g. "Kexample.+013+06160") provided as $1,
409# print the key ID with leading zeros stripped ("6160" for the
410# aforementioned example).
411keyfile_to_key_id() {
412	echo "$1" | sed "s/.*+0\{0,4\}//"
413}
414
415# private_type_record: write a private type record recording the state of the
416# signing process
417#
418# For a given zone ($1), algorithm number ($2) and key file ($3), print the
419# private type record with default type value of 65534, indicating that the
420# signing process for this key is completed.
421private_type_record() {
422        _zone=$1
423        _algorithm=$2
424        _keyfile=$3
425
426        _id=$(keyfile_to_key_id "$_keyfile")
427
428        printf "%s. 0 IN TYPE65534 %s 5 %02x%04x0000\n" "$_zone" "\\#" "$_algorithm" "$_id"
429}
430
431# nextpart*() - functions for reading files incrementally
432#
433# These functions aim to facilitate looking for (or waiting for)
434# messages which may be logged more than once throughout the lifetime of
435# a given named instance by outputting just the part of the file which
436# has been appended since the last time we read it.
437#
438# Calling some of these functions causes temporary *.prev files to be
439# created that need to be cleaned up manually (usually by a given system
440# test's clean.sh script).
441#
442# Note that unlike other nextpart*() functions, nextpartread() is not
443# meant to be directly used in system tests; its sole purpose is to
444# reduce code duplication below.
445#
446# A quick usage example:
447#
448#     $ echo line1 > named.log
449#     $ echo line2 >> named.log
450#     $ nextpart named.log
451#     line1
452#     line2
453#     $ echo line3 >> named.log
454#     $ nextpart named.log
455#     line3
456#     $ nextpart named.log
457#     $ echo line4 >> named.log
458#     $ nextpartpeek named.log
459#     line4
460#     $ nextpartpeek named.log
461#     line4
462#     $ nextpartreset named.log
463#     $ nextpartpeek named.log
464#     line1
465#     line2
466#     line3
467#     line4
468#     $ nextpart named.log
469#     line1
470#     line2
471#     line3
472#     line4
473#     $ nextpart named.log
474#     $
475
476# nextpartreset: reset the marker used by nextpart() and nextpartpeek()
477# so that it points to the start of the given file
478nextpartreset() {
479    echo "0" > $1.prev
480}
481
482# nextpartread: read everything that's been appended to a file since the
483# last time nextpart() was called and print it to stdout, print the
484# total number of lines read from that file so far to stderr
485nextpartread() {
486    [ -f $1.prev ] || nextpartreset $1
487    prev=`cat $1.prev`
488    awk "NR > $prev "'{ print }
489	 END          { print NR > "/dev/stderr" }' $1
490}
491
492# nextpart: read everything that's been appended to a file since the
493# last time nextpart() was called
494nextpart() {
495	nextpartread $1 2> $1.prev.tmp
496	mv $1.prev.tmp $1.prev
497}
498
499# nextpartpeek: read everything that's been appended to a file since the
500# last time nextpart() was called
501nextpartpeek() {
502	nextpartread $1 2> /dev/null
503}
504
505# _search_log: look for message $1 in file $2 with nextpart().
506_search_log() (
507	msg="$1"
508	file="$2"
509	nextpart "$file" | grep -F -e "$msg" > /dev/null
510)
511
512# _search_log_peek: look for message $1 in file $2 with nextpartpeek().
513_search_log_peek() (
514	msg="$1"
515	file="$2"
516	nextpartpeek "$file" | grep -F -e "$msg" > /dev/null
517)
518
519# wait_for_log: wait until message $2 in file $3 appears.  Bail out after
520# $1 seconds.  This needs to be used in conjunction with a prior call to
521# nextpart() or nextpartreset() on the same file to guarantee the offset is
522# set correctly.  Tests using wait_for_log() are responsible for cleaning up
523# the created <file>.prev files.
524wait_for_log() (
525	timeout="$1"
526	msg="$2"
527	file="$3"
528	retry_quiet "$timeout" _search_log "$msg" "$file" && return 0
529	echo_i "exceeded time limit waiting for '$msg' in $file"
530        return 1
531)
532
533# wait_for_log_peek: similar to wait_for_log() but peeking, so the file offset
534# does not change.
535wait_for_log_peek() (
536	timeout="$1"
537	msg="$2"
538	file="$3"
539	retry_quiet "$timeout" _search_log_peek "$msg" "$file" && return 0
540	echo_i "exceeded time limit waiting for '$msg' in $file"
541        return 1
542)
543
544# _retry: keep running a command until it succeeds, up to $1 times, with
545# one-second intervals, optionally printing a message upon every attempt
546_retry() {
547	__retries="${1}"
548	shift
549
550	while :; do
551		if "$@"; then
552			return 0
553		fi
554		__retries=$((__retries-1))
555		if [ "${__retries}" -gt 0 ]; then
556			if [ "${__retry_quiet}" -ne 1 ]; then
557				echo_i "retrying"
558			fi
559			sleep 1
560		else
561			return 1
562		fi
563	done
564}
565
566# retry: call _retry() in verbose mode
567retry() {
568	__retry_quiet=0
569	_retry "$@"
570}
571
572# retry_quiet: call _retry() in silent mode
573retry_quiet() {
574	__retry_quiet=1
575	_retry "$@"
576}
577
578# _repeat: keep running command up to $1 times, unless it fails
579_repeat() (
580    __retries="${1}"
581    shift
582    while :; do
583	if ! "$@"; then
584	    return 1
585	fi
586	__retries=$((__retries-1))
587	if [ "${__retries}" -le 0 ]; then
588	    break
589	fi
590    done
591    return 0
592)
593
594rndc_reload() {
595    $RNDC -c ../common/rndc.conf -s $2 -p ${CONTROLPORT} reload $3 2>&1 | sed 's/^/'"I:$SYSTESTDIR:$1"' /'
596    # reloading single zone is synchronous, if we're reloading whole server
597    # we need to wait for reload to finish
598    if [ -z "$3" ]; then
599	for __try in 0 1 2 3 4 5 6 7 8 9; do
600	    $RNDC -c ../common/rndc.conf -s $2 -p ${CONTROLPORT} status | grep "reload/reconfig in progress" > /dev/null || break
601	    sleep 1
602	done
603    fi
604}
605
606rndc_reconfig() {
607    $RNDC -c ../common/rndc.conf -s $2 -p ${CONTROLPORT} reconfig 2>&1 | sed 's/^/'"I:$SYSTESTDIR:$1"' /'
608    for __try in 0 1 2 3 4 5 6 7 8 9; do
609	$RNDC -c ../common/rndc.conf -s $2 -p ${CONTROLPORT} status | grep "reload/reconfig in progress" > /dev/null || break
610	sleep 1
611    done
612}
613
614# rndc_dumpdb: call "rndc dumpdb [...]" and wait until it completes
615#
616# The first argument is the name server instance to send the command to, in the
617# form of "nsX" (where "X" is the instance number), e.g. "ns5".  The remaining
618# arguments, if any, are appended to the rndc command line after "dumpdb".
619#
620# Control channel configuration for the name server instance to send the
621# command to must match the contents of bin/tests/system/common/rndc.conf.
622#
623# rndc output is stored in a file called rndc.out.test${n}; the "n" variable is
624# required to be set by the calling tests.sh script.
625#
626# Return 0 if the dump completes successfully; return 1 if rndc returns an exit
627# code other than 0 or if the "; Dump complete" string does not appear in the
628# dump within 10 seconds.
629rndc_dumpdb() {
630	__ret=0
631	__dump_complete=0
632	__server="${1}"
633	__ip="10.53.0.$(echo "${__server}" | tr -c -d "0-9")"
634
635	shift
636	${RNDC} -c ../common/rndc.conf -p "${CONTROLPORT}" -s "${__ip}" dumpdb "$@" > "rndc.out.test${n}" 2>&1 || __ret=1
637
638	for _ in 0 1 2 3 4 5 6 7 8 9
639	do
640		if grep '^; Dump complete$' "${__server}/named_dump.db" > /dev/null; then
641			mv "${__server}/named_dump.db" "${__server}/named_dump.db.test${n}"
642			__dump_complete=1
643			break
644		fi
645		sleep 1
646	done
647
648	if [ ${__dump_complete} -eq 0 ]; then
649		echo_i "timed out waiting for 'rndc dumpdb' to finish"
650		__ret=1
651	fi
652
653	return ${__ret}
654}
655
656# get_dig_xfer_stats: extract transfer statistics from dig output stored
657# in $1, converting them to a format used by some system tests.
658get_dig_xfer_stats() {
659	LOGFILE="$1"
660	sed -n "s/^;; XFR size: .*messages \([0-9][0-9]*\).*/messages=\1/p" "${LOGFILE}"
661	sed -n "s/^;; XFR size: \([0-9][0-9]*\) records.*/records=\1/p" "${LOGFILE}"
662	sed -n "s/^;; XFR size: .*bytes \([0-9][0-9]*\).*/bytes=\1/p" "${LOGFILE}"
663}
664
665# get_named_xfer_stats: from named log file $1, extract transfer
666# statistics for the last transfer for peer $2 and zone $3 (from a log
667# message which has to contain the string provided in $4), converting
668# them to a format used by some system tests.
669get_named_xfer_stats() {
670	LOGFILE="$1"
671	PEER="`echo $2 | sed 's/\./\\\\./g'`"
672	ZONE="`echo $3 | sed 's/\./\\\\./g'`"
673	MESSAGE="$4"
674	grep " ${PEER}#.*${MESSAGE}:" "${LOGFILE}" | \
675		sed -n "s/.* '${ZONE}\/.* \([0-9][0-9]*\) messages.*/messages=\1/p" | tail -1
676	grep " ${PEER}#.*${MESSAGE}:" "${LOGFILE}" | \
677		sed -n "s/.* '${ZONE}\/.* \([0-9][0-9]*\) records.*/records=\1/p" | tail -1
678	grep " ${PEER}#.*${MESSAGE}:" "${LOGFILE}" | \
679		sed -n "s/.* '${ZONE}\/.* \([0-9][0-9]*\) bytes.*/bytes=\1/p" | tail -1
680}
681
682# copy_setports - Copy Configuration File and Replace Ports
683#
684# Convenience function to copy a configuration file, replacing the tokens
685# QUERYPORT, CONTROLPORT and EXTRAPORT[1-8] with the values of the equivalent
686# environment variables. (These values are set by "run.sh", which calls the
687# scripts invoking this function.)
688#
689# Usage:
690#   copy_setports infile outfile
691#
692copy_setports() {
693    # The indirect method of handling the substitution of the PORT variables
694    # (defining "atsign" then substituting for it in the "sed" statement) is
695    # required to prevent the "Configure" script (in the win32utils/ directory)
696    # from replacing the <at>PORT<at> substitution tokens when it processes
697    # this file and produces conf.sh.
698    atsign="@"
699    sed -e "s/${atsign}PORT${atsign}/${PORT}/g" \
700        -e "s/${atsign}EXTRAPORT1${atsign}/${EXTRAPORT1}/g" \
701        -e "s/${atsign}EXTRAPORT2${atsign}/${EXTRAPORT2}/g" \
702        -e "s/${atsign}EXTRAPORT3${atsign}/${EXTRAPORT3}/g" \
703        -e "s/${atsign}EXTRAPORT4${atsign}/${EXTRAPORT4}/g" \
704        -e "s/${atsign}EXTRAPORT5${atsign}/${EXTRAPORT5}/g" \
705        -e "s/${atsign}EXTRAPORT6${atsign}/${EXTRAPORT6}/g" \
706        -e "s/${atsign}EXTRAPORT7${atsign}/${EXTRAPORT7}/g" \
707        -e "s/${atsign}EXTRAPORT8${atsign}/${EXTRAPORT8}/g" \
708        -e "s/${atsign}CONTROLPORT${atsign}/${CONTROLPORT}/g" \
709        -e "s/${atsign}DEFAULT_ALGORITHM${atsign}/${DEFAULT_ALGORITHM}/g" \
710        -e "s/${atsign}DEFAULT_ALGORITHM_NUMBER${atsign}/${DEFAULT_ALGORITHM_NUMBER}/g" \
711        -e "s/${atsign}DEFAULT_BITS${atsign}/${DEFAULT_BITS}/g" \
712        -e "s/${atsign}ALTERNATIVE_ALGORITHM${atsign}/${ALTERNATIVE_ALGORITHM}/g" \
713        -e "s/${atsign}ALTERNATIVE_ALGORITHM_NUMBER${atsign}/${ALTERNATIVE_ALGORITHM_NUMBER}/g" \
714        -e "s/${atsign}ALTERNATIVE_BITS${atsign}/${ALTERNATIVE_BITS}/g" \
715        -e "s/${atsign}DISABLED_ALGORITHM${atsign}/${DISABLED_ALGORITHM}/g" \
716        -e "s/${atsign}DISABLED_ALGORITHM_NUMBER${atsign}/${DISABLED_ALGORITHM_NUMBER}/g" \
717        -e "s/${atsign}DISABLED_BITS${atsign}/${DISABLED_BITS}/g" \
718        $1 > $2
719}
720
721#
722# Export command paths
723#
724export ARPANAME
725export BIGKEY
726export CDS
727export CHECKZONE
728export CYGWIN
729export DESCRIPTION
730export DIG
731export FEATURETEST
732export FSTRM_CAPTURE
733export GENCHECK
734export JOURNALPRINT
735export KEYCREATE
736export KEYDELETE
737export KEYFRLAB
738export KEYGEN
739export KEYSETTOOL
740export KEYSIGNER
741export KRB5_CONFIG
742export KRB5_KTNAME
743export MAKEJOURNAL
744export MDIG
745export NAMED
746export NSEC3HASH
747export NSLOOKUP
748export NSUPDATE
749export NZD2NZF
750export PERL
751export PIPEQUERIES
752export PK11DEL
753export PK11GEN
754export PK11LIST
755export PSSUSPEND
756export PYTHON
757export RESOLVE
758export RNDC
759export RRCHECKER
760export SIGNER
761export SUBDIRS
762export TMPDIR
763export TSIGKEYGEN
764export VERIFY
765export WIRETEST
766