#!/usr/bin/env pmake -f ### ntpqlist.make -*- Makefile -*- ## Maintain a list of public NTP servers that answer to ntpq queries. ### Ivan Shmakov, 2019 ## To the extent possible under law, the author(s) have dedicated ## all copyright and related and neighboring rights to this software ## to the public domain worldwide. This software is distributed ## without any warranty. ## You should have received a copy of the CC0 Public Domain Dedication ## along with this software. If not, see ## . ### History: ## 0.4 2019-12-10 18:39Z ## Fixed: use proper key (was: $1 after removing the initial few ## fields) when updating the tail array in UPDATE. Also simplify ## UPDATE by removing special treatment of the third field (as we ## do it in the dig target code anyway.) Invoke NTPQ at most MAXQ ## (defaults to 13) times in the dig target. ## 0.3 2019-12-10 17:30:11Z ## (sfn.dNIforNhqDwqoHX74F7huHkgEArdtu1KhPo-_kto7Ec.make) ## Record both the last query timestamp and last successful query ## one (was: only the latter); change UPDATE and the dig target ## code accordingly. Fixed: test last query (was: last DNS) ## timestamp against NOTNEWER. ## 0.2 2019-12-10 16:55:35Z ## (sfn.e9ht8BQJ--uHRVGnDTK1jMQDQF6hVovJnqpM3XDMg1E.make) ## Implemented the ntpq target. Set NTPQ_OPTS to -pn (was: -n.) ## Use shell arithmetic in NOTNEWER, NOTOLDER (was: awk.) ## Generalize UPDATE (was: UPDATEDNS) to handle ntpq test results ## as well (was: DNS-only); change the dig target code accordingly. ## 0.1 2019-12-10 16:17:23Z ## (sfn.W4oxzt2Kj9i7W5RdCFbSkUwQhcmc1WJuexJkRnO5jNI.make) ## Initial revision. ### Code: AWK = awk CMP = cmp DATE = date DIG = dig DIG_OPTS = +short MKTEMP = mktemp MV = mv NTPQ = ntpq NTPQ_OPTS = -pn POOLS = 0.debian.pool.ntp.org 1.debian.pool.ntp.org \ 2.debian.pool.ntp.org 3.debian.pool.ntp.org RECORDS = AAAA A MAXQ = 13 NOW != $(DATE) +%s ## FIXME: check that the equality tests are applied consistently below NOTNEWER != printf %s\\n $$(($(NOW) - 511)) NOTOLDER != printf %s\\n $$(($(NOW) - 524287)) LISTFILE = ntpq.list ## NB: tail[k] gets overwritten if at all present in the new record, ## even though it may have less fields than a previous one. UPDATE = $(AWK) -vnow='$(NOW)' -vnotnewer='$(NOTNEWER)' ' \ ! ((k = $$1) in lastdns) { \ ord[++rn] = $$1; \ } \ lastdns[$$1] < notnewer { \ lastdns[k] = (NF >= 2 ? $$2 : now); \ } \ 1 { \ sub(/^[[:blank:]]*[^[:blank:]]+([[:blank:]]+[^[:blank:]]+)?[[:blank:]]*/, ""); \ if (NF > 0) { tail[k] = $$0; } \ next; \ } \ END { \ for (i = 1; i <= rn; ++i) { \ k = ord[i]; \ print k, lastdns[k], tail[k]; \ } \ }' .PHONY: default .PHONY: dig ntpq default: dig ntpq dig:: set -e ; set -x -u ; \ x=$$($(MKTEMP) -- "$(LISTFILE)".XXXXX) ; \ (for r in $(RECORDS) ; do dig +short "$$r" $(POOLS) ; done) \ | $(UPDATE) "$(LISTFILE)" - \ > "$$x" ; \ $(CMP) -- "$$x" "$(LISTFILE)" \ || $(MV) -- "$$x" "$(LISTFILE)" ## NB: calling ntpq once and parsing the output would perhaps be more ## efficient, but arguably not as robust as the following. ntpq:: set -e ; set -x -u ; \ x=$$($(MKTEMP) -- "$(LISTFILE)".XXXXX) ; \ n=0 ; \ while read -r -- s d q v tail ; do \ test "$$d" -gt $(NOTOLDER) \ && test "$${q:-0}" -lt $(NOTNEWER) \ || continue ; \ if x=$$($(NTPQ) $(NTPQ_OPTS) -- "$$s") \ && test -n "$$x" ; then v= ; else : "$${v:=0}" ; fi ; \ ts=$$($(DATE) +%s) ; \ printf %s\\n "$${s} $${d} $${ts} $${v:-$${ts}} $${tail:+ }$${tail}" ; \ n=$$((1 + n)) ; \ test -z '$(MAXQ)' || test "$$n" -lt '$(MAXQ)' || break ; \ done \ < "$(LISTFILE)" \ | $(UPDATE) "$(LISTFILE)" - \ > "$$x" ; \ $(CMP) -- "$$x" "$(LISTFILE)" \ || $(MV) -- "$$x" "$(LISTFILE)" ### ntpqlist.make ends here