implement warn on dnssd name collisions

This commit is contained in:
juergen committed 2026-10-20 11:11:45 +02:00
1 parent 3910ab974c
commit f15ea07f44
3 files changed
+159 -16

No files matched your search

+83 -2
View File
@@ -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.