前言
HP 1020 Plus 属于 GDI 驱动(基于主机的驱动),此类打印机需要连接上主机后,由主机主动向打印机写入一段驱动才可以正常运行。
而威联通是不支持此类打印机的。不支持体现在打印机可以正常连接上 NAS,但是点击打印后,显示打印完成,但是没有产生任何实际打印行为。
在网上搜到一篇此类问题的求助:QNAP USB打印机问题
问题
上述链接中,有人回答使用虚拟机,但是用虚拟机又带来了几个问题:
- Windows 可以很好的支持 GDI 驱动打印机,但是 Linux 系列比较麻烦,需要手动安装驱动。我虚拟机中运行的是 Ubuntu Server 18;
- 每次 USB 打印机连接上 NAS 之后,必须手动的在 Virtualization Station 中将该 USB 设备分配给虚拟机,非常麻烦,毕竟打印机不会常开,我家人并不会操作威联通的管理页面;
解决问题
1. 给 Ubuntu Server 安装驱动
首先解决第一个问题,Ubuntu Server 如何安装 HP 1020 Plus 的驱动?请参考我的这篇博客:https://blog.csdn.net/hanziyuan08/article/details/108396537。
我在文中详细的描述了以下几件事情:
- 安装 cups 用于管理打印机;
- 利用 foo2zjs 安装打印机驱动,并将驱动设置到 cups 中;
2. 自动分配 USB 打印机给虚拟机
- 检测虚拟机是否有 USB 打印机;
- 如果虚拟机没有 USB 打印机则将 USB 打印机分配给虚拟机;
这一步可以通过脚本完成,先解释一下脚本涉及到的几个知识点:
2.1. virsh 相关知识
- virsh 是管理 KVM 虚拟机的工具,也是 VirtualizationStation 的虚拟机管理工具。利用 virsh 工具我们可以检测虚拟机分配了哪些 USB 设备,也可以将 USB 设备分配给虚拟机;
- virsh 命令没有被加到环境变量,所以需用绝对路径:
/QVS/usr/bin/virsh
;
2.2. 通过 virsh 获取虚拟机名称
虚拟机名称可以通过 virsh list
命令获得,如:
[/QVS/usr/bin] $ /QVS/usr/bin/virsh listId Name State
----------------------------------------------------1 39d664db-d642-4922-9ddd-ccca6b372b9d running
2.3. 创建 USB 设备的 XML 描述文件
先看下我的 XML 文件:
<hostdev mode='subsystem' type='usb'><source><vendor id='0x03f0'/><product id='0x2b17'/></source>
</hostdev>
这里有 2 个点需要注意,vendor id 和 product id,每个设备都具有唯一的两个 ID,如何获取呢?通过 lsusb
命令,如:
[/QVS/usr/bin] $ lsusb
Bus 001 Device 003: ID 1005:b155 Apacer Technology, Inc.
Bus 001 Device 008: ID 03f0:2b17 Hewlett-Packard LaserJet 1020 # 这一行是我的 HP 1020 Plus 打印机
Bus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub
Bus 002 Device 001: ID 1d6b:0003 Linux Foundation 3.0 root hub
注意到 03f0:2b17
了吗?03f0
就是 vendor id,2b17
就是 product id。
2.4. 创建 shell 脚本检测并分配设备给虚拟机
脚本文件如下:
#!/bin/bash
# set -x
set -euo pipefail# 宿主机是否连接设备
HOST_ATTACHED=0
# 虚拟机是否已连接设备
VM_ATTACHED=0
# 虚拟机名称
NAME="39d664db-d642-4922-9ddd-ccca6b372b9d"
# USB 打印机的 XML 描述文件
XML_PATH="/share/my_cron/printer_1020_plus.xml"
# 本脚本工作的日志路径
LOG_PATH="/share/my_cron/printer_1020_plus_attach.log"
# USB 设备名称
DEVICE_NAME_FRAGMENT="LaserJet\ 1020"if /QVS/usr/bin/virsh qemu-monitor-command --domain $NAME --hmp --cmd "info usb" | grep -q "$DEVICE_NAME_FRAGMENT"; thenVM_ATTACHED=1
fi
if lsusb | grep -q "$DEVICE_NAME_FRAGMENT"; thenHOST_ATTACHED=1
fi# 如果虚拟机没有连接设备,且宿主机连接了设备,则将设备分配给虚拟机
if [ $VM_ATTACHED -eq 0 ] && [ $HOST_ATTACHED -eq 1 ]; then/QVS/usr/bin/virsh attach-device $NAME $XML_PATH > /dev/nullMSG="`date` attached_printer"echo $MSG >> $LOG_PATH
fi# 虚拟机连接了设备,但是宿主机没有该设备,则意味着设备是通过断电离线的,需要排除
# 此场景只出现了一次,暂不能确定具体原因
if [ $VM_ATTACHED -eq 1 ] && [ $HOST_ATTACHED -eq 0 ]; then/QVS/usr/bin/virsh detach-device $NAME $XML_PATH > /dev/nullMSG="`date` detached_printer"echo $MSG >> $LOG_PATH
fi
注意将脚本中的变量修改为你自己的,变量我都放置在脚本前面了,有注释的那 4 个。
2.5. 创建定时任务
另有一种方案:利用 udev 监听 usb 设备变化,无需定时任务,参考:https://github.com/Bpazy/usb-libvirt-hotplug
首先修改 cron 配置:
# 每分钟运行一次脚本,检测到 USB 设备没有分配给虚拟机则会进行分配
echo "*/1 * * * * /bin/bash /share/my_cron/printer_1020_plus_attacher.sh" >> /etc/config/crontab
# 重启 crontab
crontab /etc/config/crontab && /etc/init.d/crond.sh restart
完结撒花
好了,这下可以放心的给打印机断电了,需要的时候打开打印机,会自动分配给虚拟机,而后就可以正常打印了。
还有个问题,就是通过 virsh 分配 USB 设备给虚拟机之后,在 VirtualizationStation 里面体现不出来,会显示 USB 仍未分配给虚拟机,不过这个显然是个小问题,忽略即可。
最后看个日志吧
Thu Sep 10 17:15:00 HKT 2020 attached_printer
Thu Sep 10 19:03:00 HKT 2020 detached_printer
Thu Sep 10 19:07:00 HKT 2020 attached_printer
Thu Sep 10 19:41:00 HKT 2020 detached_printer
Thu Sep 10 22:06:05 HKT 2020 attached_printer
Fri Sep 11 00:08:00 HKT 2020 detached_printer