你现在还用U盘吗?闪存卡、SD卡或MicroSD卡?移动硬盘呢?
即使在云计算无处不在的今天,人们仍然会出于各种原因随身携带大量数据。IT人员需要便携式存储介质,以应对网络瘫痪等紧急情况,例如需要对服务器或交换机进行紧急抢修时。其他人则使用移动硬盘来运行备用启动系统(例如,在Mac上使用Bootcamp)。从事数字媒体工作的人员通常会有一个“工作集”,其中包含他们正在处理的文件;或者,根据工作内容,他们可能会将整个作品集存储在一个硬盘上。虽然其中一些文件可以归档到云端,但当前的项目有时需要的存储空间远超笔记本电脑的容量。而且,并非所有人都能随时随地使用云端服务。
此外,在如今单卡系统时代,Micro-SD 卡随处可见。你上次备份树莓派是什么时候?如果你正在进行一些难以重做的复杂工作,你是否确信可以轻松地从备份中恢复?
在本教程中,我们将向您展示如何尽可能轻松地备份外部存储介质。我们的目标很简单:只需将设备插入 USB 接口,备份即可自动完成。作为用户,您无需进行任何操作,只需插入设备即可——无需运行脚本或点击按钮。插入设备后,备份会自动进行,备份文件会上传到您的云端存储库,备份完成后,您会收到通知,此时您可以安全地拔下设备。
怎么做?继续阅读!
udev 的魔力
udev 是 Linux 的一个设备管理器。它的一个实用功能是可以被编程为在特定事件发生时自动执行操作,我们将利用这一点来触发备份脚本。
在本教程中,我们不会具体说明您使用的是哪种云备份解决方案,因为可供选择的方案非常多。相反,我们将调用一个虚拟脚本(cloud_backup.sh),您可以对其进行修改,插入您正在执行的任何操作——例如 B2 API 调用、rclone 调用、使用 min.io 存储桶等等。
工作原理
首先,我们要找到一种方法来唯一(或半唯一)地识别您的 USB 设备。然后,当它被挂载时,系统会自动创建一个指向该设备的符号链接,并将该符号链接传递给我们的备份脚本。
请注意,我们将备份您的U盘原始镜像,之后您可以挂载该镜像或将其放回设备。这样做是为了确保即使U盘已加密,无需任何手动操作也能成功备份。如果U盘已加密,备份镜像也会被加密。
唯一标识您的 USB
我使用的是一台运行 Debian 11 的桌面系统,它配备了大量的 USB 3.0 和 USB 2.0 接口。在这个例子中,我将使用一个 32GB 的 Gorilla U 盘,但无论是 U 盘、移动硬盘还是闪存卡,原理都是一样的。任何带有 USB 接口的 Linux 系统都应该适用。其他 Linux 发行版的操作步骤可能略有不同。
插入您的 USB 设备(无需挂载)并运行
lsusb -tvv
你会看到类似这样的内容:
/: 总线 06.端口 1: 设备 1,类=root_hub,驱动程序=xhci_hcd/2p,10000M ID 1d6b:0003 Linux Foundation 3.0 根中心 /sys/bus/usb/devices/ /dev/bus/usb/006/001 /: 总线 05.端口 1: 设备 1,类=root_hub,驱动程序=xhci_hcd/2p,480M ID 1d6b:0002 Linux Foundation 2.0 根中心 /sys/bus/usb/devices/usb5 /dev/bus/usb/005/001 /: 总线 04.端口 1: 设备 1,类别=root_hub,驱动程序=ehci-pci/2p,480M ID 1d6b:0002 Linux Foundation 2.0 根中心 /sys/bus/usb/devices/usb4 /dev/bus/usb/004/001 |__ 端口 1:设备 2,接口 0,类别=集线器,驱动程序=hub/8p,480M ID 8087:8001 英特尔公司集成集线器 /sys/bus/usb/devices/4-1 /dev/bus/usb/004/002 /: 总线 03.端口 1: 设备 1,类=root_hub,驱动程序=xhci_hcd/6p,5000M ID 1d6b:0003 Linux Foundation 3.0 根中心 /sys/bus/usb/devices/usb3 /dev/bus/usb/003/001 /: 总线 02.端口 1: 设备 1,类=root_hub,驱动程序=xhci_hcd/14p,480M ID 1d6b:0002 Linux Foundation 2.0 根中心 /sys/bus/usb/devices/usb2 /dev/bus/usb/002/001 |__ 端口 12:设备 6,接口 0,类别=大容量存储,驱动程序=usb-storage,480M ID abcd:1234 LogiLink UDisk 闪存盘 /sys/bus/usb/devices/2-12 /dev/bus/usb/002/006 /: 总线 01.端口 1: 设备 1,类别=root_hub,驱动程序=ehci-pci/2p,480M ID 1d6b:0002 Linux Foundation 2.0 根中心 /sys/bus/usb/devices/usb1 /dev/bus/usb/001/001 |__ 端口 1:设备 2,接口 0,类别=集线器,驱动程序=hub/6p,480M ID 8087:8009 英特尔公司 /sys/bus/usb/devices/1-1 /dev/bus/usb/001/002
这说明有多个 USB 集线器和端口。我们感兴趣的是“大容量存储设备,驱动程序”端口。系统甚至很贴心地提供了路径:/sys/bus/usb/devices/2-12
我知道这会让你震惊,但显然有些厂商在执行电子产品标准时偷工减料。或许标准对“序列号”和“唯一标识符”的定义有所不同。最佳且正确的做法是使用 udevadm 查询设备并获取 ID_SERIAL 字段,然后围绕该字段建立规则。
然而,在检查了许多设备后,我发现它们通常采用以下几种方法之一:
- 不要实现 ID_SERIAL 字段
- 可以用类似“1234”这样的数字来实现。
- 使用一个简短的值(例如,“861F-CC42”),该值并非全球唯一,而是型号唯一。
有些厂商确实会将序列号刻录到可移动存储介质上,但这显然会增加生产成本,而且市场似乎并不在意。我会教你如何根据序列号建立规则,但你可能无法使用,所以我们会采用另一种方法。
与 udevadm 认同
执行类似于下面的 udevadm 命令,将路径的最后一部分替换为适合您系统的信息。如您所见,我们位于总线 2/端口 12,因此可以使用 bash 的 Tab 键自动补全功能在 /sys/bus/usb/devices 目录中轻松找到它。
我正在使用一个32GB的Gorilla USB闪存盘。让我们全力以赴,看看能否找到可用的WWID:
# udevadm info -q all /sys/bus/usb/devices/2-12|grep -i seri E: ID_SERIAL=USB闪存盘
看来不行。所以我们将使用另一个 udevadm 命令来显示所有属性。
# udevadm info -ap /sys/bus/usb/devices/2-12
Udevadm info 命令首先显示 devpath 指定的设备,然后显示其他信息。
逐级向上遍历父设备。它会为每个设备打印信息。
已找到 udev 规则键格式中的所有可能属性。
匹配规则可以由设备的属性组成。
以及来自单个父设备的属性。
正在查看设备“/devices/pci0000:00/0000:00:14.0/usb2/2-12”:
内核=="2-12"
子系统=="usb"
驱动程序=="usb"
ATTR{authorized}=="1"
ATTR{avoid_reset_quirk}=="0"
ATTR{bConfigurationValue}=="1"
ATTR{bDeviceClass}=="00"
ATTR{bDeviceProtocol}=="00"
ATTR{bDeviceSubClass}=="00"
ATTR{bMaxPacketSize0}=="64"
ATTR{bMaxPower}=="300mA"
ATTR{bNumConfigurations}=="1"
ATTR{bNumInterfaces}==" 1"
ATTR{bcdDevice}=="1100"
ATTR{bmAttributes}=="80"
ATTR{busnum}=="2"
ATTR{配置}==""
ATTR{devnum}=="16"
ATTR{devpath}=="12"
ATTR{idProduct}=="1000"
ATTR{idVendor}=="090c"
ATTR{ltm_capable}=="no"
ATTR{制造商}=="USB"
ATTR{maxchild}=="0"
ATTR{power/active_duration}=="147776"
ATTR{power/async}=="已启用"
ATTR{电源/自动挂起}=="2"
ATTR{power/autosuspend_delay_ms}=="2000"
ATTR{power/connected_duration}=="147776"
ATTR{电源/控制}=="开启"
ATTR{功率/级别}=="开启"
ATTR{power/persist}=="1"
ATTR{power/runtime_active_kids}=="1"
ATTR{power/runtime_active_time}=="147500"
ATTR{power/runtime_enabled}=="禁止"
ATTR{power/runtime_status}=="active"
ATTR{power/runtime_suspended_time}=="0"
ATTR{power/runtime_usage}=="1"
ATTR{product}=="闪存盘"
ATTR{quirks}=="0x0"
ATTR{可移除}=="可移除"
ATTR{rx_lanes}=="1"
ATTR{speed}=="480"
ATTR{tx_lanes}=="1"
ATTR{urbnum}=="573"
ATTR{version}==" 2.10"我已经对其进行了精简,因为之后它会遍历 USB 树并报告控制器等信息。您只需要第一个以空行分隔的部分。
我们会尝试获取其中一些字段,以使标识尽可能唯一。当然,如果您只有一个U盘插入特定电脑,这一点就不像您有多个U盘那样重要。
这是最终规则,我们将把它放在 /etc/udev/rules.d/95-local.rules 文件中(为了格式方便,这里分成了多行,但实际上应该在一行里)。
子系统=="usb", 操作=="绑定", 属性{制造商}=="USB", 属性{产品}=="闪存盘",
ATTR{idProduct}=="1000", ATTR{idVendor}=="090c", SYMLINK+="gorilla_drive",
RUN+="/usr/local/bin/backup-removable.sh gorilla_drive"好的,信息量很大:
- /etc/udev/rules.d 目录下的规则是按字母顺序处理的,所以请在规则名称前加上一个较大的数字,以确保它们最后被处理,而不会被其他规则覆盖。顺便一提,/lib/udev/rules.d 目录下有超过 100 条系统使用的规则。
- 注意使用 == 而不是 =。== 用于判断相等,而 = 用于赋值。上面我们使用 != 来判断“不相等”。语法要求严格,所以要小心引号、+= 等符号的使用。
- 子系统只是让udev知道我们在说什么。
- ACTION 设置为“bind”。这是“add”之后的步骤。如果您使用“add”,您的设备将被自动移除,并且在没有任何操作的情况下它才会出现。如果您在 /etc/udev/udev.conf 中设置 udev_log=debug,并在插入设备后查看 daemon.log,您就会看到这种情况。
- ATTR 链接是用于唯一标识产品的方法。如果我们有序列号,可以直接使用 ATTR{idSerial}=”whatever_serial”。但现在,我们将改为“如果制造商、产品、idProduct 和 idVendor 匹配,则视为匹配”。
- SYMLINK 子句指定将创建 /dev/gorilla_drive。
- RUN 子句指示“运行 /usr/local/bin/backup-removable.sh”,并将 gorilla_drive 参数传递给它。(请注意,传递的是一个字面字符串,因此 backup-removable.sh 将使用“gorilla_drive”而不是“/dev/gorilla_drive”来调用。)
备份脚本
这就需要你出面了。你想如何处理备份?
以下是一个简单的例子:
#!/bin/bash
DEVICE=${1} # 例如,“gorilla_drive”
如果 [ ! -f /dev/${DEVICE} ] ; 则
echo "错误!没有这样的设备:/dev/${DEVICE}"
或许可以在这里发送通知
出口 1
菲
dd if=/dev/${DEVICE} of=/backups/{DEVICE}.$(date '+%Y%m%d') bs=1MB
现在调用类似这样的工具,或者minio、scp、rsync,等等。
rclone sync /backups b2:some_backet
echo "设备 $DEVICE 备份完成" | mailx -s "设备 $DEVICE 备份完成" [email protected]
或者类似这样:
# aplay /usr/share/sounds/gnome/default/alerts/sonar.ogg
或者向您手机的短信应用发送电子邮件
或调用 API
# ETC。试一试
在这个例子中,我的 backup-removable.sh 脚本非常简单:
#!/bin/bash 设备=$1 echo "`date` 已备份 $DEVICE" >> /tmp/backup_log.txt
创建 95-local.rules 文件后,我运行了:
systemctl restart udev
这或许并非必要,但也不会有害。然后我用装置插入了它。
我立刻看到了:
# ls -l /dev/gorilla_drive lrwxrwxrwx 1 root root 15 Jan 17 12:35 /dev/gorilla_drive -> bus/usb/002/025 # cat /tmp/backup_log.txt 2022年1月17日星期一 12:35:45 PST 备份 gorilla_drive
恢复
如果您使用此方法进行备份,并且需要恢复,操作非常简单:
dd if=/backups/some_image of=/dev/gorilla_drive
或者,如果您只想从备份中提取某些文件:
创建目录 /mnt/thumb mount -o loop gorilla_drive.backup.20220117 /mnt/thumb
如果您使用加密解决方案(例如 TrueCrypt)进行挂载,请查阅相关文档。文档内容大致如下:
truecrypt gorilla_drive.backup.20220117 /mnt/thumb
这大概是我们能想到的最轻松的U盘备份方法了。如果你懒得把U盘插上自动备份……那就千万别去自助洗衣店!