资讯详情

资讯详情

CUPS 2.3.3源码编译与lpadmin队列排错

简介CUPS 2.3.3 源码包面向类 Unix 系统的开发者、系统管理员与打印服务学习者适合在本地部署、定制或研究开源打印系统涵盖打印作业管理、过滤器驱动、网页管理界面、加密传输与跨平台兼容等核心能力。压缩包共 1294 个文件、约 7.76MB以 C 与 C 源码、头文件、网页文档、测试脚本、模板和构建文件为主并含配置脚本、手册、打印描述示例、国际化文件及多种后端与过滤器资源目录覆盖服务端、库、工具链、策略和文档等模块。已有 928 人学习下载。完整源码结构便于读者在本地编译定制也可据此理解网络打印协议支持研究自定义过滤器与后端扩展方式或排查打印队列、驱动适配与配置管理问题对中高级运维与开发人员查漏补缺、二次开发均有参考价值。1. 从发行版包换成 cups-2.3.3-source.tar.gz一次「全都对就是打不出来」在一台要接三台网络打印机的机器上我遇到过很别扭的情况发行版仓库里装的打印服务能把队列建起来管理页面也能打开可一提交任务就卡在Filter failed日志翻半天只有一行看不出所以然的话。后来我把 cups-2.3.3-source.tar.gz 解开自己编问题没有立刻消失但至少每一步都在自己手里依赖装没装、运行目录权限对不对、过滤器在哪个目录、服务单元是谁写的全都能翻到。源码装 CUPS 最难的地方在于「编译成功」和「打印成功」是两件事——configure和make install一路绿灯只证明调度器能起来不证明你的纸能出来。2. 编译前清点工具链、依赖库与 lp 用户组的分配动手之前先花十分钟确认环境比编译完再回头补依赖省事得多。CUPS 2.3.3 属于 2.3 分支的收尾版本代码不算新对编译器要求不高但它对「系统里有没有 lp 用户」「/run 下有没有对应目录」这类事情的假设很强缺一样就在运行时报怪错。2.1 编译器与构建工具的最低要求CUPS 2.3.3 的代码大量使用 C99 特性gcc 4.8 以上、clang 3.4 以上都能编。make 需要 3.8 以上主要是为了让并行构建和install目标行为正常。另外记得装pkg-configconfigure 探测依赖库时靠它拿编译参数缺了不会直接报错但会静默判定「某个库不存在」最后你编出来的东西少一块功能。# 三行确认构建工具是否能满足 2.3.3 的最低要求 gcc --version | head -n1 # 期望 4.8 以上 make --version | head -n1 # 期望 3.8 以上 pkg-config --version # 期望 0.20 以上如果机器上同时装了多个 gcc别让 configure 抓到老的那个。我一般显式指定CC/usr/bin/gcc并在后面看config.log里实际用的是不是同一个。另外源码包里是带了configure的发布包不需要再跑autoreconf或autoconf。很多人习惯性先autoreconf -fi结果因为本机 autoconf 版本太新生成的脚本跟源码里的 m4 宏对不上直接在第一关失败。提示编译时不要往CFLAGS里加-Werror。CUPS 2.3.3 的代码在新版编译器下会产生不少新告警-Werror会把告警变成错误编到一半中断。2.2 依赖库清单必装、可选、能砍掉CUPS 的依赖分三层调度器自己需要的、过滤器需要的、外部功能需要的。先把这张表过一遍再决定装什么能少装一半东西。依赖对应功能不装的后果能否关掉zlib压缩、PPD 与 IPP 数据处理configure 直接报错退出不能libpng / libjpeg图像相关的内建转换configure 输出里这两项显示 no图像类任务受影响能但建议装openssl 开发头文件连接加密、摘要计算探测不到就退回明文基本打印不受影响能avahi / libavahi-client网段内自动发现打印机广播发现功能不可用手动加队列不受影响能加--with-dnssdnolibusbUSB 直连打印机USB 后端不可用网络打印机不受影响能cups-filtersPDF/PS 转设备格式的过滤器队列能建一打就Filter failed不能但它是独立包表格里最后一行是最容易忽略的从很早的版本开始CUPS 就把大部分过滤器拆到了独立项目里源码包装完之后/usr/lib/cups/filter下只有寥寥几个文件。你如果只用高端网络打印机自带的 IPP 处理能力问题不大一旦要驱动一台只懂 PCL 的老设备就必须另装过滤器包否则调度器会把任务接下来然后在中途找不到转换程序报一句非常笼统的错误。图像库里libpng和libjpeg这两个不用纠结装就完了。有些最小化系统只有运行时库没有开发头文件pkg-config --exists libpng返回 falseconfigure 就把这一项判成 no。装的时候记得带-devel或-dev后缀的包名。至于 avahi如果你的机器在机房里、打印机 IP 固定、队列全部手工建那就直接关掉。它带来的是一整条依赖链编译时间翻倍还容易在启动时因为守护进程没起而卡一下。我一般的写法是--with-dnssdno。2.3 用户组与安装前缀的提前规划CUPS 运行时要有两个身份一个非特权用户跑过滤器默认lp一个管理组决定谁能通过本地套接字做管理操作默认lpadmin。这两个东西不搞好后面lpadmin建队列会莫名其妙地提示认证失败。# 确认 lp 用户和 lpadmin 组是否存在缺了就补 getent passwd lp || useradd -r -s /sbin/nologin -d /var/spool/lpd lp getent group lpadmin || groupadd -r lpadmin # 把日常运维账号加进 lpadmin避免每次都用 root 做管理操作 usermod -aG lpadmin opsusermod之后要重新登录才生效别在这个 shell 里接着测会以为加组失败。管理组的作用是配置文件里写SYSTEM的地方实际展开就是这个组。Web 管理页要求输入账号密码时走的也是这套逻辑。安装前缀也要提前定。我固定用--prefix/usr、--sysconfdir/etc、--localstatedir/var。为什么不装/usr/local因为 CUPS 的部分组件有自己写死的默认路径查找逻辑装到/usr/local后 man 页、服务单元、以及某些按/usr/lib/cups硬编码的第三方脚本会对不上出问题时排查成本远大于省下的那点隔离收益。如果你的系统是 64 位且库目录分了 lib 和 lib64还要额外加--libdir/usr/lib64否则后端和过滤器会落到/usr/lib/cups而某些按 lib64 找东西的组件找不到它们表现就是「队列正常打印无声失败」。3. configure 到 make installCUPS 2.3.3 的参数逐条拆这一章是整个安装过程里最需要看清楚的一段。参数写错几个编译照样成功问题留到运行时才暴露那时候你就得靠日志猜了。3.1 解包与源码树自检# 先看包内结构确认是一级目录还是裸文件 tar -tzf cups-2.3.3-source.tar.gz | head -n 5 # 解开并进入源码目录 tar -xzf cups-2.3.3-source.tar.gz cd cups-2.3.3 # 发布包一定带这两个文件缺一个就说明拿到的不是发布包 ls -l configure INSTALLconfigure文件存在且可执行说明这是打包好的发布版本直接跑就行。如果只有configure.ac和configure.in那是开发树得先autoconf编译门槛和踩坑概率都会上一个台阶能换发布包就换。解包之后顺手看一眼CHANGES.txt里 2.3.3 这一节的修复条目能提前知道这个版本改过哪些路径相关的行为。长期维护的机器这一步值得做。3.2 configure 参数取舍这是我在这类环境里用得最多的一套组合./configure \ --prefix/usr \ --sysconfdir/etc \ --localstatedir/var \ --libdir/usr/lib64 \ --with-rundir/run/cups \ --with-system-groupslpadmin \ --with-printcap/etc/printcap \ --with-dnssdno \ --enable-shared \ --disable-static \ CFLAGS-O2 -g CXXFLAGS-O2 -g每个参数的理由--prefix/usr二进制落在/usr/sbin和系统里已有的工具路径一致PATH 不用改。--sysconfdir/etc配置文件最终进/etc/cups这是 CUPS 自己也在找的位置。--localstatedir/varspool 在/var/spool/cups日志在/var/log/cups缓存进/var/cache/cups。--libdir/usr/lib64决定后端、过滤器、通知器的安装位置。64 位系统上不写这个容易和按 lib64 找文件的组件错位。--with-rundir/run/cupsPID 文件、本地域套接字都在这里。用/run而不是/var/run是因为现在多数系统/var/run只是软链写死旧路径在某些场景下会失效。--with-system-groupslpadmin决定SYSTEM展开成哪个组直接影响谁能管理队列。--with-printcap/etc/printcap有些老脚本和老工具还在读这个文件留着能省事。--with-dnssdno关掉网段广播发现砍掉 avahi 依赖链。--enable-shared --disable-static只编动态库省体积也省编译时间。静态库在这类场景里没有使用价值。CFLAGS-O2 -g保留调试符号是为了将来真出问题时能用调试器看栈。生产机器上多几十兆磁盘换一个可排查的现场我觉得划算。跑完 configure别急着 make把输出末尾那段构建配置摘要存下来# 把 configure 的关键探测结果留下来将来对比版本差异时非常有用 ./configure ... 21 | tee /tmp/cups-configure.log grep -iE png|jpeg|openssl|avahi|dnssd|pam|usb /tmp/cups-configure.log摘要里如果某项显示 no 而你以为装了回去翻config.log搜索checking for对应的那一行能看到具体的编译或链接失败原因。这一步是后面所有排查的基础我习惯把这个日志留在机器上命名里带日期。3.3 make 并发与安装后的目录核验# 并行编译日志留一份编译告警不要忽略 make -j$(nproc) 21 | tee /tmp/cups-build.log # 安装注意这一步会往 /etc、/usr、/var 下写文件 make installmake -j的并发数按 CPU 核数给就行CUPS 的构建脚本没有并行依赖问题但把日志 tee 出来很重要。CUPS 编译过程中的告警里有一类是「某个可选组件未找到跳过」这类信息不会让编译失败但直接决定你装完以后功能是否完整。安装完成后按下面的清单核验一遍# 主程序是否就位、版本是否是 2.3.3 ls -l /usr/sbin/cupsd /usr/sbin/cupsd -v # 三个关键目录是否都有内容 ls /usr/lib64/cups/backend ls /usr/lib64/cups/filter ls /usr/lib64/cups/notifier # 配置目录下应该是 cupsd.conf、cups-files.conf 和对应的 .default ls -l /etc/cups # 检查 cupsd 链接了哪些外部库确认没有意外的缺库 ldd /usr/sbin/cupsd | grep -i not found关于/etc/cups有一点要提前知道make install遇到已存在的配置文件时不会直接覆盖新的那份会以.default结尾留下来。如果你是从旧版本升级或之前装过发行版包cupsd.conf很可能还是旧内容。第一次装可以不管但只要机器上原本就有配置就得手动对比一次否则你会以为参数生效了实际跑的还是一年前的配置。/usr/lib64/cups/filter目录里如果只有三四个文件不要慌这是正常的剩下的大量过滤器在独立的过滤器包里。这一点在第五章的排错里会详细说。4. 配置与接管cupsd.conf、自写 systemd 单元与第一个打印队列编译安装和「服务能自动拉起」之间还差好几步。源码包不会替你装服务单元也不会替你建运行目录更不会替你写好配置文件里那些必须显式声明的授权段落。这一章做完才算把这套东西接管过来。4.1 运行目录与权限cupsd 启动前必须存在的三处cupsd 启动时会检查几个目录缺了会自己建但权限不对时它会拒绝服务报出来的话通常很含糊只说某个目录不安全。手工先建好能少走一段弯路。# 运行目录放 PID 和本地套接字属主 root属组 lp0755 install -d -m 0755 -o root -g lp /run/cups # spool 目录放待打印任务权限必须收紧到 0710 install -d -m 0710 -o root -g lp /var/spool/cups # 日志与缓存目录 install -d -m 0755 -o root -g lp /var/log/cups install -d -m 0755 -o root -g lp /var/cache/cups/var/spool/cups的0710不是随手写的。打印任务里可能包含敏感文档这个目录如果对其他用户可读cupsd 启动时会打印一条警告某些编译选项下直接拒绝启动。0755是常见误填一定要改。/run目录还有个额外问题它基于内存文件系统重启就清空。所以要么用 systemd 的RuntimeDirectory要么写一条tmpfiles.d规则。我倾向后者因为调试时手动起停更可控# /etc/tmpfiles.d/cups.conf d /run/cups 0755 root lp -这条规则的意思是目录不存在就创建权限 0755属主 root属组 lp。tmpfiles在开机早期运行比服务启动早顺序上刚好。4.2 cupsd.conf 最小可用配置配置文件分两个cupsd.conf放服务行为cups-files.conf放路径和身份。这两者分开是有原因的从 1.6 之后User、Group、SystemGroup、ServerBin这类涉及文件系统访问的指令全部搬到了cups-files.conf写回cupsd.conf不会生效某些版本还会直接报「未知指令」。这是很典型的一个坑。先看cups-files.conf里要确认的几行# /etc/cups/cups-files.conf # 过滤器运行身份必须是一个真实存在的非特权用户 User lp Group lp # 管理组对应 SYSTEM 的展开结果 SystemGroup lpadmin # 本地域套接字位置lpadmin 通过它做认证 DomainSocket /run/cups/cups.sock再看cupsd.conf的最小可用版本# /etc/cups/cupsd.conf # 日志级别排查期用 debug2稳定后改回 warn LogLevel warn MaxLogSize 0 # 只监听本机和内网本地套接字必开 Listen localhost:631 Listen /run/cups/cups.sock # 允许 Web 管理页 WebInterface Yes # 默认认证方式 DefaultAuthType Basic Location / Order allow,deny Allow localhost Allow 192.168.10.0/24 /Location Location /admin Order allow,deny Allow localhost Allow 192.168.10.0/24 /Location Location /admin/conf AuthType Default Require user SYSTEM Order allow,deny Allow localhost /Location几个要点Listen localhost:631和Listen /run/cups/cups.sock这两行是并列关系前者给 Web 页面和远程 IPP 用后者给本机的lpadmin、lpstat等命令用。少写第二行命令行工具会去连默认套接字然后失败报的错是「无法连接到服务器」很容易被误判成服务没起。192.168.10.0/24换成你自己网段。这个网段只是示例实际要比你这台机器能访问的打印机的网段匹配。Location /admin/conf里加了Require user SYSTEM意思是只有管理组的人能改配置其他授权网段的人只能看队列和提交任务。这个分层的意义在于Web 界面谁都能打开但改配置需要身份。配置写完先做语法检查别急着启动# 只检查配置语法不真正启动服务 /usr/sbin/cupsd -t # 想看更细的解析过程加 -c 指定配置文件再配合 -t /usr/sbin/cupsd -t -c /etc/cups/cupsd.conf-t的返回值是 0 才继续非 0 就去/var/log/cups/error_log看最后几行通常会明确指出行号。4.3 自写 systemd 单元让服务开机自起源码安装不会给你装服务单元。自己写一份放在/etc/systemd/system下比改源码树里的模板更清楚来龙去脉。# /etc/systemd/system/cups.service [Unit] DescriptionCUPS Scheduler Afternetwork.target Wantsnetwork.target [Service] Typesimple # -f 表示前台运行交给 systemd 托管进程 ExecStart/usr/sbin/cupsd -f # 让 systemd 管理 /run/cups重启后自动重建 RuntimeDirectorycups RuntimeDirectoryMode0755 Restarton-failure RestartSec5s LimitNOFILE65536 [Install] WantedBymulti-user.targetTypesimple配-f是最省心的组合cupsd 在前台跑标准输出和错误都进 journalsystemctl status能直接看到。不要用Typeforking那样进程一退出父进程日志归属就乱了排查时体验很差。RuntimeDirectorycups会让 systemd 在启动前建好/run/cups并在停止后清理和前面写的 tmpfiles 规则功能重叠但不冲突。两处都留着是为了在手动cupsd -f调试时目录也在。启用并启动systemctl daemon-reload systemctl enable --now cups # 三件事一起看服务状态、端口监听、启动日志 systemctl status cups --no-pager ss -ltnp | grep 631 journalctl -u cups -n 30 --no-pager如果 631 端口没起来而服务显示 active多半是配置文件里的Listen段落写错或者端口被上一次没退干净的进程占着。ss -ltnp的输出里能看到占用者的 PID直接处理。4.4 用 lpadmin 建第一个队列服务起来之后先看看这台机器能识别到哪些设备# 列出所有可用的后端和设备 URI lpinfo -v输出里通常会有network ipp、network socket、direct usb这几类。网络打印机优先用 IPP直接写设备的 IPP 地址# 建一个走 IPP Everywhere 的队列由服务端自动协商能力 lpadmin -p office-a \ -E \ -v ipp://192.168.10.20/ipp/print \ -m everywhere \ -D Office A \ -L 3F \ -o printer-is-sharedfalse # 设为默认队列 lpadmin -d office-a参数拆开说-p是队列名只能用字母数字和连字符-E表示建完立刻启用并接受任务漏了它队列是禁用状态lpstat -t里会显示disabled-v是设备 URI-m everywhere让调度器跟设备协商生成 PPD不需要你预先准备驱动文件-D和-L是描述和位置人多的时候很有用-o printer-is-sharedfalse表示不通过广播共享出去。如果设备比较老、只认 9100 端口的原始数据流可以用 raw 队列跳过格式转换# 老设备兜底方案不打任何过滤直接把字节流送过去 lpadmin -p legacy-1 -E -v socket://192.168.10.31:9100 -m rawraw 队列的好处是不依赖过滤器坏处是格式转换全交给客户端。两种方式按设备情况选不要为了统一全用 raw那样 PDF 直接被推给打印机出来一堆乱码。5. 排查清单cupsd 起不来和打不出纸的五个现场这一章是我自己攒的问题记录。CUPS 的日志写得不算差但很多错误信息是「结果」不是「原因」得顺着往下摸。下面五条按现象、原因、解决的顺序写遇到对应症状可以直接对照。5.1 服务起不来的三个现场现象一systemctl start cups失败日志只有一行Unable to open Listen socket - Address already in use。原因上一次的 cupsd 没退干净或者系统里还有另一个打印服务单元在抢 631 端口。RPM 或 deb 包安装的版本和自己编的版本共存时特别容易出现两个单元名字不同但都监听同一端口。解决ss -ltnp | grep 631找到占用的 PID先确认是不是打印相关进程是就kill掉再systemctl disable掉不用的那个单元。别直接pkill cupsd完事端口释放有延迟隔一两秒再启动。现象二服务启动后立刻退出journalctl里只有cupsd: Child exited with status 1没有任何具体原因。原因cupsd 在守护化之前把真正的错误写到了标准错误但被 systemd 吞掉了或者配置里的LogLevel设得太高关键信息被过滤。另一个常见原因是cups-files.conf里User指定的用户不存在cupsd 在降权那一步失败后静默退出。解决手动前台跑一遍直接看输出# 前台运行标准错误直接打到终端最能暴露真实原因 /usr/sbin/cupsd -f -c /etc/cups/cupsd.conf顺手确认一下getent passwd lp有输出。这个「守护进程起不来就前台跑一遍」的习惯帮我省过太多次瞎猜。现象三服务起来了631 端口也在听但lpstat -t报Unable to connect to server。原因本地域套接字没建出来或者建在别的位置。cups-files.conf里的DomainSocket和cupsd.conf里的Listen没对齐时就会这样客户端按编译时的默认路径找套接字服务端在另一个路径上监听。解决ls -l /run/cups/cups.sock看文件在不在。不在的话检查两处路径是否一致改完重启。顺手看一眼semanage或强制访问控制的审计日志某些默认开启强制访问控制的系统上套接字会被策略挡住表现同样是「本文还有配套的精品资源点击获取
觉得有用,分享给同行:

为您的企业打造数字门面

稳重轻奢商务风格,端正雅致视觉,长效耐看不易过时。

立即咨询 →