在Ubuntu20.04(控制台)下自动挂载NTFS文件系统的U盘

首先,请确认rootfs的版本是Ubuntu20.04。高版本或低版本不好用概不负责。
其次,这份方案是为了解决 1)挂载NTFS U盘 和 2)控制台模式这两个问题。如果是Ubuntu桌面系统,那么解决的办法一大把。
第三,我是在自己编译操作系统的时候遇到的问题,所以首先要确保内核里编译了FUSE(File Systems —>FUSE) 和 NTFS文件系统(File Systems —>DOS/FAT/EXFAT/NT Filesystems —>NTFS file system support + NTFS write support + NTFS Read-Write file system support)

1.安装必要的工具


apt-get install -y fuse
apt-get install -y ntfs-3g

2.创建udev在systemd中的配置


vi /etc/systemd/system/systemd-udevd.service

然后写入如下内容

#保留默认配置
.include /usr/lib/systemd/system/systemd-udevd.service
[Service]
#以用户态身份Mount
PrivateMounts=no

这样做是为了修改方便。直接去修改/usr/lib/systemd/system/systemd-udevd.service也是一样的。
有价值的只有最后一行。据说在Ubuntu20.04以前的版本里,写成MountFlags=shared。这是我遇到的第一个坑。

3.创建新的udev规则


vi /etc/udev/rules.d/99-usb-mount.rules

文件名开头是规则的执行顺序,尽量用99-开头,意味着最后执行。后缀要是rules。中间随意。

然后写入下面内容

KERNEL=="sd?[1-9]", SUBSYSTEM=="block", ACTION=="add", RUN+="/bin/bash /etc/udev/rules.d/usb-disk-monitor.sh %k"
KERNEL=="sd?[1-9]", SUBSYSTEM=="block", ACTION=="remove", RUN+="/bin/bash /etc/udev/rules.d/usb-disk-monitor.sh %k"

两条规则的意思是,检知到sdnX设备(通常是U盘)有add/remove动作时,执行同目录下的usb-disk-monitor.sh脚本。%k是udev规则中自动生成的变量,kernel name,也就是sda1、sdb1这种名字。脚本里要用到,所以作为参数传进去。
为了避免意外,所有路径都写全路径。

4.创建mount执行的脚本


vi /etc/udev/rules.d/usb-disk-monitor.sh

有人说这个脚本不放这个位置也可以。我没试。

#!/bin/bash
DEV_NAME=$1
#输出到串口
FLOG=/dev/ttyPS0
echo "" >> $FLOG
echo $(date) >> $FLOG
MNT_PATH=/run/media/
if [ ! -d "$MNT_PATH" ]; then
   mkdir -p "$MNT_PATH"
fi
DEST_NAME=$MNT_PATH$DEV_NAME
if [ "$ACTION" = "add" ]; then
   /bin/mkdir -p $DEST_NAME &>> $FLOG
   /usr/bin/systemd-mount --no-block --collect $DEVNAME $DEST_NAME &>> $FLOG

elif [ "$ACTION" = remove ]; then
   /usr/bin/systemd-mount --umount $DEST_NAME &>> $FLOG
   /bin/rmdir $DEST_NAME &>> $FLOG
fi

这个文件遇到了第二个坑和第三个坑。
第二个坑是shell的判断语句,Ubuntu里不能写“==”,只能写“=”。
第三个坑就是mount命令本身。如果用ID_FS_TYPE进行判断,执行mount -t vfat挂载FAT32格式的U盘,没任何问题。但是如果用mount -t ntfs-3g命令挂载NTFS格式的U盘,挂载看着是成功了,但访问U盘时会出现“Transport endpoint not connected”错误。这其实在udev的官方文档里有专门的说明,udev的规则里不能用mount命令对FUSE文件系统进行挂载。如果进行操作,挂载进程会在几秒后被杀掉。解决办法就是换成systemd-mount。我没去查这个命令在哪个包里,反正我做的系统里就有。
另外挂载的位置是在/run/media/。有需要变的自己去改脚本里的MNT_PATH变量即可。
还有,这个脚本里如果不作重定向,是看不到任何输出的。我的基板上串口0是/dev/ttyPS0。如果有需要请自行调整。

都配置好之后,重启,然后就可以看到现象了。
理论上重启udev服务也可以做到生效,但强烈不推荐。

已有7条评论

  1. 谁格式化的NTFS文件系统U盘啊,砍了他!

    1. 客户就是提了一嘴要能识别正常的U盘,然后二鬼子就给当成了需求,就得满足。给鬼子干活就这样。

      1. 有二鬼子那味了。
        就当作假如有人往上面插多分区的移动硬盘吧。

  2. `if [ “$ACTION” = “add” ]; then` 不能用 `==` 有点奇怪吧,Ubuntu下的Bash跟其他系统是一样的啊,而且我项目里面也都是用的双等号,没出线问题啊。

    1. 找到的资料语焉不详,有一种说法是udev初始化阶段跑的不是bash。

      1. 我也查了一下,有人说可能也不是Bash,然后给了我这么一个玩意:
        “`
        RUN+=”/bin/bash –posix /etc/udev/rules.d/usb-disk-monitor.sh %k”
        “`
        也有人说if条件两端改成[[]]。
        基本上没人知道怎么回事。就跟你说的第三个坑一样,systemd-mount也是谁都不知道。udev和systemd这些玩意,做之前人人都反对,但是硬需求就摆在那,又没人做,这俩玩意做出来之后也没多少人懂是怎么回事,UNIX/BSD/Linux这几个社区还在那掐架。

  3. 看到这篇技术文,突然想起我装的debian11桌面环境有些自带应用没法用图形界面的应用管理器卸载,一会儿找个教程研究一下

    1. 这恐怕帮补上你什么忙,我们很少用图形界面。

  4. 上回我的EOS(基于ubuntu)本子装了个windows电脑拆下的固态硬盘,因为有数据就没格式化,ntfs格式的,系统能识别默认不挂载(好像linux都这样?),但是点击后挂载就出错,必须得设置开机自动挂载才行,也不知道啥毛病,其他ntfs的就没遇到过这个问题。

    1. 也许挂载命令或者挂载工具需要更新一下?Ubuntu很讨厌的一点是大版本升级后很多对应的工具完全换掉了,找资料的时候必须带版本号。

你好,新朋友。留言前请先填写昵称邮箱