implement warn on dnssd name collisions
This commit is contained in:
1 parent
3910ab974c
commit
f15ea07f44
3 files changed
+159
-16
No files matched your search
+83
-2
@@ -15,8 +15,11 @@
|
||||
# PRINTER_IP IP address / host name of the network printer.
|
||||
# PRINTER_URI Full device URI; overrides PRINTER_IP when set.
|
||||
# PRINTER_PROTOCOL socket (default), lpd or ipp - used with PRINTER_IP.
|
||||
# PRINTER_NAME CUPS queue name and advertised (DNS-SD) name.
|
||||
# PRINTER_DESCRIPTION CUPS Description (lpadmin -D) shown in the web UI.
|
||||
# PRINTER_NAME CUPS queue name; base of the advertised (DNS-SD)
|
||||
# name "<name> @ <host>" while no Description is set.
|
||||
# PRINTER_DESCRIPTION CUPS Description (lpadmin -D), shown in the web UI;
|
||||
# takes precedence over PRINTER_NAME as the advertised
|
||||
# (DNS-SD) name.
|
||||
# PPD_FILE PPD used for the queue.
|
||||
# PRINTER_OPTIONS Space-separated PPD option assignments (key=value)
|
||||
# applied as queue defaults on every start, e.g.
|
||||
@@ -400,6 +403,84 @@ if ! curl -fsS --noproxy '*' --max-time 2 -o /dev/null http://127.0.0.1:631/ 2>/
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# --- DNS-SD name collision check --------------------------------------------
|
||||
# CUPS advertises every shared queue as the DNS-SD instance
|
||||
# "<Description> @ <host>" - the queue name when no Description is set.
|
||||
# Avahi can register only one instance per name, and CUPS 2.4 does not rename
|
||||
# on collision (scheduler/dnssd.c: "TODO: Handle collisions with
|
||||
# avahi_alternate_service_name"), so with duplicate derived names one queue is
|
||||
# silently never advertised. Clients that pinned the missing name - macOS
|
||||
# stores the exact instance name in the queue's dnssd:// device URI - then
|
||||
# report the printer offline. Detection only; a collision is never fatal
|
||||
# (see README, "macOS shows the printer offline after some time").
|
||||
check_dnssd_name_collisions() {
|
||||
# Queue names and Descriptions straight from cupsd, forced to the C locale
|
||||
# so the "Description:" detail line parses regardless of the container
|
||||
# locale. An empty or failed result skips the check silently.
|
||||
lpstat_out="$(LC_ALL=C lpstat -l -p 2>/dev/null || true)"
|
||||
[ -n "${lpstat_out}" ] || return 0
|
||||
|
||||
# One "base<TAB>queue1, queue2" line per colliding name. The Shared flags
|
||||
# come from printers.conf (both <Printer> and <DefaultPrinter> blocks,
|
||||
# "Shared Yes/No"); a queue that cannot be read there (file not flushed
|
||||
# after this run's lpadmin, no Shared line yet) counts as shared: a false
|
||||
# warning is actionable, a missed one reproduces the incident. Every parse
|
||||
# failure degrades to "no collision found" so that set -eu never trips
|
||||
# inside this diagnostic.
|
||||
collisions="$(printf '%s\n' "${lpstat_out}" | awk -v conf=/etc/cups/printers.conf '
|
||||
BEGIN {
|
||||
while ((getline line < conf) > 0) {
|
||||
if (line ~ /^<(Default)?Printer /) {
|
||||
cur = line
|
||||
sub(/^<(Default)?Printer /, "", cur)
|
||||
sub(/>$/, "", cur)
|
||||
} else if (line ~ /^<\/(Default)?Printer>$/) {
|
||||
cur = ""
|
||||
} else if (cur != "" && line ~ /^Shared /) {
|
||||
flag[cur] = tolower(substr(line, 8))
|
||||
}
|
||||
}
|
||||
close(conf)
|
||||
}
|
||||
/^[ \t]*printer / {
|
||||
curq = $2
|
||||
order[++n] = curq
|
||||
next
|
||||
}
|
||||
/^[ \t]*Description: / {
|
||||
sub(/^[ \t]*Description: /, "")
|
||||
if (curq != "") desc[curq] = $0
|
||||
}
|
||||
END {
|
||||
for (i = 1; i <= n; i++) {
|
||||
q = order[i]
|
||||
if ((q in flag) && flag[q] == "no") continue
|
||||
base = ((q in desc) && desc[q] != "") ? desc[q] : q
|
||||
count[base]++
|
||||
list[base] = list[base] (list[base] == "" ? "" : ", ") q
|
||||
}
|
||||
for (b in count)
|
||||
if (count[b] > 1) print b "\t" list[b]
|
||||
}' || true)"
|
||||
[ -n "${collisions}" ] || return 0
|
||||
|
||||
dnssd_host=" @ $(hostname -s 2>/dev/null || hostname 2>/dev/null || printf host)"
|
||||
printf "%s\n" "${collisions}" \
|
||||
| while IFS="$(printf '\t')" read -r base queues; do
|
||||
log "warning: queues ${queues} would all be advertised as the DNS-SD name"
|
||||
log " '${base}${dnssd_host}' - Avahi keeps only one of them, so every"
|
||||
log " other queue is silently NOT advertised, and clients pinned to the"
|
||||
log " missing name (macOS dnssd:// device URI) show the printer offline."
|
||||
log " fix: give each queue a unique Description (lpadmin -p <queue> -D \"...\")"
|
||||
log " or remove the redundant queue (lpadmin -x <queue>); then remove"
|
||||
log " and re-add the printer on the client - see README, \"macOS shows"
|
||||
log " the printer offline after some time\"."
|
||||
done
|
||||
return 0
|
||||
}
|
||||
|
||||
check_dnssd_name_collisions
|
||||
|
||||
log "ready: CUPS on 631/tcp, mDNS on 5353/udp"
|
||||
|
||||
# Keep the container running by waiting on cupsd.
|
||||
|
||||
Reference in new issue
Block a user