Linux作服务器系统时,客户端常常要定位到服务器某个目录进行访问里面的网页或其它文件资源,那么如何做到客户端访问到服务器的USB设备(如U盘)呢?
显然需要在U盘等USB设备插到主板后,自动将其挂载到被访问目录,那如何实现?
有两种方式可以实现,一种是用udev服务来管理USB设备(以U盘为例),一种是自写脚本,通过不断刷描/dev/sda*里面U盘端口是否存在,以确定U盘已经插入,然后执行挂载。通常采用udev服务来实现自动挂载,因为udev服务在很多系统都是预安装的。
udev服务来实现自动挂载
1.原理:当驱动程序检测到USB设备插入、拔出、读写时,内核会发送uevent事件,udev服务监听这个事件。当udev监听到event,会在规则目录(系统规则目录:/lib/udev/rules.d/,用户规则目录:/etc/udev/rules.d/)下匹配所有规则文件(按开头数据编号优先级),匹配到含有uevent相应设备时,就执行规则后面的RUN,通常是启动了一个服务或脚本,达到检测到USB设备执行相应功能的目的。
2.根据原理,要实现自动挂载,需要三步:一是写一个执行脚本(实现挂载功能),二是写一个服务配置文件,服务执行的就是这个脚本,三是编写规则文件,使之能匹配到我们想要的USB设备(U盘)的拔插读写。
3. 与U盘挂载相关命令
udevadm monitor #监控USB插入或拔出,并将信息打印到终端
lsblk #查看当前所有挂载设备情况
mount [-t auto] [-o uid=pi] [-o pid=pi] [-o iocharset=utf8] [dev] [mountdir] #将dev挂载到mountdir下
umount [dev] #取消挂载设备
4.写一个执行脚本,就是检测到USB设备插入或拔出,挂载这个设备到指定目录,将脚本改权限可执行:sudo chmod a+x xy_mount(本脚本不带后缀.sh是为方便调用时,可以像命令那样直接写名字即可),并将其保存在/usr/bin目录下,以方便调用
#!/usr/bin/bash
logfile=/home/biqu/printer_data/logs/usb_log
user=biqu
group=biqu
mountdir=/home/biqu/printer_data/gcodes/usb
[[ ! -e $logfile ]] && {
touch $logfile
}
logi() {
echo $1 >> $logfile
}
#权限检查
[[ `id -u` != 0 ]] && {
logi "Error:current tool need root permission"
exit 1
}
#参数检查
[[ ! $1 ]] && {
logi "Error: need one parameter to signate the usb-device"
exit 1
}
dev=/dev/${1##*/}
[[ ! -b $dev ]] && {
if grep /etc/mtab -qe "^$dev"; then
logi "$dev device already removed, so umount and clear media"
if umount $dev;then
exitcode=0
else
exitcode=$?
logi "Error: umount $dev errorcode:$exitcode"
fi
else
exitcode=0
logi "Device doesn't exist anymore or not a block device:$dev"
fi
#删除挂载点
rm -rf $mountdir
exit $exitcode
}
#使用blkid读取更多设备信息,eval将信息加进脚本
eval $(blkid -po export $dev)
[[ -z $TYPE ]] && {
logi "$dev has no known filesystem type, ignring mount request"
exit 0
}
#创建挂载点,并挂载设备到挂载点上
logi "Mount-dir:$mountdir,dev:$dev"
mkdir -p $mountdir
#必须加iocharset,不然有些系统可能挂上去文件名显示不正常
if mount -t auto -o uid=$user -o gid=$group -o iocharset=utf8 $dev $mountdir;then
username="$(ps au | awk '$11 ~/^xinit/ {print $1;exit}')"
[ $username ] && DISPLAY=:0 runuser -u $username xdg-open $mountdir
logi "Device successfully mounted:$mountdir"
exit 0
fi
logi "Error: mount-result:$?"
rm -rf $mountdir
exit 1
5.编写服务配置文件,以使udev可以以服务形式启动挂载脚本
[Unit]
Description=An usb device auto mount
[Service]
Type=forking
GuessMainPID=no
ExecStart=/usr/bin/xy_mount %I
6.编写规则
6.1 udev规则目录有两个:/lib/udev/rules.d/和/etc/udev/rules.d/,前者是linux默认规则目录,一般不要去改动,后者是为用户提供的规则目录,因此,主要是在后面这个目录中加入规则
6.2 进入规则目录后,新增规则目录文件,如:touch 60-my.rules,文件名以数字开头,数字越小,优先级越高;以.rules结尾;中间的名字可以任意取
6.3编辑规则文件,文件中以#号开头表示注释,不会被匹配
KERNEL用于匹配内核设备名称,通常设备插入会出现在/dev/下面,如/dev/sda1
SUBSYSTEM,ACTION等都是匹配udevadm monitor中对应的属性名称的,其中最重要的ACTION,指示当前是add,remove等动作
RUN则是匹配到了,该执行什么操作,这里是启动上面的服务
#mount the device when added
KERNEL=="sd[a-z]*", SUBSYSTEM=="block", ACTION=="add", RUN+="/bin/systemctl --no-block restart yusb@%k.service"
#clean up after removal
KERNEL=="sd[a-z]*", SUBSYSTEM=="block", ACTION=="remove", RUN+="/bin/systemctl --no-block restart yusb@%k.service"
注意:systemctl使用绝对路径,需要查看systemctl在哪个目录(which systemctl),有些系统是在/usr/bin下面,有些是在/bin下面,相应的,规则文件中的systemctl路径也要作改变