最近在做一个Python爬虫程序,会自动爬取一个社区上的图片保存到本地,然后挑一些喜欢的保存下来,嘿嘿。我打算用香橙派来跑这个爬虫,同时把下载的图片保存到一个外接的U盘里,因为sd卡的空间不是很大。

Linux既然要挂磁盘,那必然得是我们的老朋友/etc/fstab,但是fstab好像不太聪明的样子,它只在开机时挂载一次,如果开机后U盘掉线再插回来时,它的挂载状态就丢失了,又要手动挂载一次。

虽然写个Python脚本定时检测并主动调用命令行挂回来不是什么难事,但这个做法我怎么都觉得不够优雅,肯定有更好的解决办法。

经过一段时间的搜寻,我找到了一个叫autofs的软件,它不仅可以自动把掉线的u盘挂载回来,还可以在长时间不用的时候自动卸载U盘,感觉这个特性对机械硬盘来说非常有用,卸载掉之后机械硬盘可以停转休眠,能减少电量消耗和节省硬盘寿命。

autofs是个通用软件,除了挂载本地block设备,还可以挂载NFS,samba等协议设备。“通用”的东西一般都比“专用”的东西用起来要麻烦。经过一段时间的查阅文档,我大概了解autofs应该怎么用了。

首先autofs是有配置文件的,和fstab是差不多的作用,用来定义一些挂载规则。

autofs的配置文件分三种:

  • autofs自身的配置文件/etc/autofs.conf:用来修改autofs核心的一些功能的,一般不用修改这个文件
  • 主映射文件/etc/auto.master:用来存储所有子映射文件的一个文件。这个文件只能存在一个,一般不用修改这个文件
  • 子映射文件/etc/auto.xxx:用来存储所有具体映射规则的文件,可以存在多个(xxx为自定义名字)

autofs的挂载规则并不是一股脑全部写在主映射文件里的,而是分散写到各个子映射文件里,然后再在主映射文件里写上子映射文件的路径,这样就能定义好映射规则了。这个机制类似于nginx配置文件的include指令,但又稍微有些不同。

配置文件具体的关系用yaml格式描述如下:

- autofs.conf(自身配置文件)
- auto.master(主映射文件)
  - auto.foo(子映射文件foo)
    - 挂载规则1
    _ 挂载规则2
  - auto.bar(子映射文件bar)
    - 挂载规则1
    - 挂载规则2

autofs.confauto.master是并列的关系,而auto.xxx则隶属于auto.master下。而具体的一个个挂载规则是写到子映射文件里,虽然层次有点多,但也还算比较好理解。

我们要挂载u盘的话,首先得创建一个自己的子映射文件,这个文件可以自己取一个名字,我们就叫custom-usb好了。取好了名字,就可以创建这个子映射文件了/etc/auto.custom-usb。根据autofs的约定,这个文件一般放在etc目录下,以auto.前缀开始,自定义结尾。当然约定只是约定,放到别的位置也是没有问题的。

接着我们需要编辑主配置文件引用一下刚创建的/etc/auto.custom-usb。这里又有一个小约定:要往主映射文件下面添加内容时,我们一般不直接修改auto.master,而是在/etc/auto.master.d目录下新建一个以.autofs结尾的文件,然后auto.master它会自动扫描这个目录里面的.autofs文件并include到它自己的内容里面。这一点和nginx的include指令是一样的。这里我们创建/etc/auto.master.d/custom-usb.autofs,之所以也叫custom-usb.autofs只是为了方便联系到我们的/etc/auto.custom-usb文件而已,并没有强制一定要和子映射文件的文件名一样。

创建好了/etc/auto.master.d/custom-usb.autofs文件之后,就可以打开编辑了。这个文件的语法和主配置文件是一样的,文件内容为/- /etc/auto.custom-usb,好了以后保存关闭。(前面的/-是以“直接映射”的方式读取这个子映射文件,至于直接映射和间接映射后面会讲解)

接着回来编辑先前创建的子映射文件/etc/auto.custom-usb,我们填写/mnt/my-usb-1 -fstype=auto,async,noatime,nofail,rw :/dev/disk/by-partuuid/48375893-01然后保存关闭。

这个文件的内容根据空格可以分成三部分:

第一部分/mnt/my-usb-1是挂载点,这很好理解。

第二部分是以-开头的一大堆参数,这些参数以逗号作为分隔,会被传递给mount命令。

第三部分是以:开头的设备路径,也就是要被挂载的分区的设备。这里推荐使用uuid的形式进行访问,当然你喜欢用/dev/sda[0123456]这种编号访问也是没问题的,只是重启后可能会乱。

一切完毕之后我们保存关闭子映射文件/etc/auto.custom-usb,执行sudo systemctl reload autofs来重新加载我们刚刚写的配置文件。

接着我们打开/mnt目录,会发现没有/mnt/my-usb-1这个目录啊?其实是这样的,只有当你访问这个目录的时候,U盘才会被挂载,所以ls命令看不到是很正常的。我们可以直接cd进/mnt/my-usb-1这个目录,或者在sftp窗口里直接输入这个路径,就会发现:诶!这个目录突然出现了。过一段时间没有访问之后,这个设备又会被重新卸载掉。

最后提一下前面提到的直接映射和间接映射是什么,这两个都是autofs的映射模式。首先说一下间接映射吧。间接映射一般用在要挂载的设备很多的情况下,比如插入了100块硬盘,都要挂载到/mnt/harddisks/xxx这个目录下,你就可以把主映射文件里的/-换成/mnt/harddisks,然后在子映射文件里,每一行的第一部分,就不用写绝对路径了,可以就写一个yingpan1yingpan2,然后挂载的时候autofs会自动挂载到/mnt/harddisks/yingpan1/mnt/harddisks/yingpan2这样的路径上。除了手写yingpan1yingpan2,autofs还支持自动按编号挂载设备。如果想移动挂载点,只需要在主映射文件里修改/mnt/harddisks这个路径就好了,就不用在子映射文件一个个改了,会省事一点。

反过来,直接挂载就是不搞这么的复杂,直接在子映射文件里写绝对路径就好了,就像上面的例子一样,然后主映射文件里的路径就必须要写成/-(一个字不能差)这个死路径。一般设备少的话用直接挂载会省事一丢丢(真的就是一丢丢)。当然你喜欢的话用间接挂载也是完全没有问题的。

最后,如果你能读英文,可以看看autofs的手册:

  • 主映射文件的文件格式:man 5 auto.master
  • 子映射文件的文件格式:man 5 autofs