Linux下基于udev+udisks+autofs实现智能设备自动挂载与状态监控方案


阅读 8 次

问题场景分析

在Gentoo系统中使用autofs-5.0.4-r5时遇到两个典型问题:

  • 预定义挂载点名称在设备顺序变化时(如MMC卡与U盘设备号交换)会导致混乱
  • 无法实现基于文件系统LABEL的动态挂载点创建

核心需求

需要实现以下功能组合:

1. 设备插入时仅创建LABEL命名的挂载点(ghost mount)
2. 首次访问时才实际挂载文件系统(autofs特性)
3. 实时监控所有自动挂载点的状态
4. 支持本地和网络文件系统(NFS/CIFS)的统一管理

技术方案实现

1. udev规则配置

创建/etc/udev/rules.d/99-automount.rules:

# USB设备规则
ACTION=="add", KERNEL=="sd*[!0-9]", SUBSYSTEM=="block", ENV{ID_FS_LABEL_ENC}=="?*", \
    RUN+="/usr/local/bin/automount-notify.sh add %k $env{ID_FS_LABEL_ENC}"

# MMC设备规则  
ACTION=="add", KERNEL=="mmcblk*", SUBSYSTEM=="block", ENV{ID_FS_LABEL_ENC}=="?*", \
    RUN+="/usr/local/bin/automount-notify.sh add %k $env{ID_FS_LABEL_ENC}"

2. autofs主配置

/etc/autofs/auto.master配置:

/media/autofs /etc/autofs/auto.media --timeout=30 --ghost

/etc/autofs/auto.media配置模板:

# 动态生成挂载点
* -fstype=auto,noatime,nosuid,nodev :/dev/disk/by-label/&

3. udisks2集成脚本

/usr/local/bin/automount-notify.sh示例:

#!/bin/bash
ACTION=$1
DEVICE=$2
LABEL=$3

case $ACTION in
    add)
        # 确保挂载点目录存在
        mkdir -p "/media/autofs/${LABEL}"
        # 发送桌面通知
        notify-send -i drive-removable-media "设备就绪" "${LABEL} 已准备就绪"
        ;;
    remove)
        # 清理空目录
        rmdir "/media/autofs/${LABEL}" 2>/dev/null
        notify-send -i drive-removable-media "设备移除" "${LABEL} 已安全移除"
        ;;
esac

状态监控方案

1. 系统托盘指示器

使用Python+GTK实现状态监控:

#!/usr/bin/env python3
import gi
gi.require_version('Gtk', '3.0')
from gi.repository import Gtk, GLib
import os
import subprocess

class MountNotifier(Gtk.StatusIcon):
    def __init__(self):
        super().__init__()
        self.set_from_icon_name("drive-removable")
        self.set_tooltip_text("自动挂载监控")
        self.connect("activate", self.on_click)
        GLib.timeout_add_seconds(5, self.update_status)
        
    def update_status(self):
        mounts = subprocess.getoutput("mount | grep '/media/autofs/'")
        if mounts:
            self.set_from_icon_name("drive-removable-media")
            self.set_tooltip_text(f"已挂载设备:\n{mounts}")
        else:
            self.set_from_icon_name("drive-removable")
            self.set_tooltip_text("无挂载设备")
        return True
        
    def on_click(self, widget):
        menu = Gtk.Menu()
        item = Gtk.MenuItem(label="退出")
        item.connect("activate", Gtk.main_quit)
        menu.append(item)
        menu.show_all()
        menu.popup(None, None, None, None, 0, Gtk.get_current_event_time())

if __name__ == "__main__":
    app = MountNotifier()
    Gtk.main()

2. 网络文件系统支持

在auto.media中添加NFS/CIFS支持:

# NFS示例
nfs-share -fstype=nfs4,rw,noatime,nodiratime server:/path/to/share

# SMB示例
smb-share -fstype=cifs,rw,credentials=/etc/samba/creds ://server/share

注意事项

  • 确保所有脚本具有可执行权限:chmod +x /usr/local/bin/*.sh
  • udev规则生效需要重新加载:udevadm control --reload-rules
  • autofs服务需要正确配置:rc-service autofs restart

扩展优化

对于需要更精细控制的场景,可以结合DBus监控:

#!/bin/bash
# 监控udisks2事件
dbus-monitor --system \
    "interface='org.freedesktop.UDisks2'" \
    "type='signal',member='InterfacesAdded'" |
while read -r line; do
    if [[ $line == *"org.freedesktop.UDisks2.Filesystem"* ]]; then
        DEVICE=$(echo "$line" | grep -oP "/org/freedesktop/UDisks2/block_devices/\K\w+")
        LABEL=$(udisksctl info -b "/dev/$DEVICE" | grep IdLabel | cut -d: -f2 | tr -d ' ')
        notify-send "设备检测" "准备挂载 $LABEL"
    fi
done