Klipper
KlipperScreen HDMI 屏幕旋转
KlipperScreen 安装教程
Klipper——纵维立方Mega Zero 升级
CANOpen协议栈 —— CANOpenNode
MKS Robin Nano V3.1
KlipperScreen 的本地化——多语言支持
KlipperScreen 架构分析
Klipper 配置参考
Klipper参考文档
mainsail 前端界面语言选择
mainsail 前端控制界面源码分析
OracSlicer 编译环境搭建 —— windows
KlipperScreen 源码分析
BigTreeTECH 安装Klipper
Klipper 源码分析
OrcaSlicer 通过配置文件添加自定义打印机
Klipper 风扇/气泵/断料/堵料配置
Klipper 挤出头温度调节
如何覆盖Klipper 的G-code 指令
Klipper 3D打印机调试笔记
切片软件中挤出头移动速度的决定因素
螺杆挤出机生产过程中气泡问题的控制
自适应网床调平
Klipper 重新定义M84命令 强制移动
KlipperScreen 的Network 模块出现No module named 'sdbus'问题
klipper 自动配置 mcu 的串口id
使用 udisksctl 的可靠 USB 自动挂载方案(基于 systemd-run)
Klipper 断电续打
本文档使用 MrDoc 发布
-
+
首页
使用 udisksctl 的可靠 USB 自动挂载方案(基于 systemd-run)
以下是使用 `udisksctl` 的完整解决方案,通过 `systemd-run` 确保在正确的用户会话中执行: ``` # 安装必要的文件系统支持 sudo apt update sudo apt install -y exfat-fuse exfat-utils ntfs-3g # 安装缺失的依赖库 sudo apt install libblockdev-crypto2 libblockdev-mdraid2 sudo apt install -y udisks2 ``` 1. 创建主脚本 (`/usr/local/bin/udisks_usb_mount.sh`) ``` 217 sudo vim /usr/local/bin/udisks_usb_mount.sh 218 sudo apt install -y exfat-fuse exfat-utils ntfs-3g 219 sudo apt install -y udisks2 220 sudo systemctl enable udisks2 221 sudo systemctl start udisks2 222 sudo systemctl status udisks2 223 sudo apt install libblockdev-crypto2 libblockdev-mdraid2 224 sudo systemctl restart udisks2 225 sudo systemctl status udisks2 226 sudo udevadm control --reload-rules 227 sudo udevadm trigger ``` ``` #!/bin/bash # 日志函数 log() { logger -t "udisks_mount" "$@" echo "[$(date '+%Y-%m-%d %H:%M:%S')] $*" >> /var/log/udisks_mount.log } # 确保必要环境变量存在 if [ -z "$ACTION" ] || [ -z "$DEVNAME" ]; then log "错误: 缺少必要的环境变量 (ACTION=$ACTION, DEVNAME=$DEVNAME)" exit 1 fi # 获取当前活动用户 get_active_user() { # 尝试获取拥有桌面的用户 user=$(ps -eo user,cmd | grep -E 'Xorg|Xwayland' | grep -v grep | awk '{print $1}' | uniq | head -n 1) # 如果没有找到,使用第一个登录的用户 if [ -z "$user" ]; then user=$(who | awk '{print $1}' | head -n 1) fi # 默认使用 biqu 用户 [ -z "$user" ] && user="biqu" echo "$user" } # 在用户会话中执行命令 run_in_user_session() { local user="$1" local command="$2" # 获取用户ID user_id=$(id -u "$user") # 获取DBUS地址 dbus_address="unix:path=/run/user/$user_id/bus" # 执行命令 sudo -u "$user" DBUS_SESSION_BUS_ADDRESS="$dbus_address" sh -c "$command" } # 挂载USB设备 handle_mount() { device="$DEVNAME" # user=$(get_active_user) user="biqu" # 默认使用 biqu 用户 log "处理挂载事件: $device (用户: $user)" # 等待设备就绪 (最多3秒) for i in {1..6}; do if [ -b "$device" ]; then log "设备准备就绪: $device" break fi sleep 0.5 done if [ ! -b "$device" ]; then log "错误: 设备不存在或未就绪: $device" return 1 fi # 检查是否已挂载 mount_info=$(run_in_user_session "$user" "/usr/bin/udisksctl info -b $device") if echo "$mount_info" | grep -q "MountPoints:.*/"; then mount_point=$(echo "$mount_info" | awk -F': ' '/MountPoints:/ {print $2}') log "设备已挂载: $mount_point" return 0 fi # 执行挂载 log "执行挂载命令: udisksctl mount -b $device" mount_output=$(run_in_user_session "$user" "/usr/bin/udisksctl mount -b $device" 2>&1) if [ $? -eq 0 ]; then mount_point=$(echo "$mount_output" | awk -F' at ' '{print $2}' | tr -d '.') # 创建软链接 sudo ln -s $mount_point /home/biqu/printer_data/gcodes log "成功挂载 $device 到 $mount_point" return 0 else log "挂载失败: $mount_output" # 备选方案: 直接挂载 log "尝试备选挂载方案" mount_dir="/media/usb-$(basename "$device")" mkdir -p "$mount_dir" mount -o uid=$(id -u "$user"),gid=$(id -g "$user") "$device" "$mount_dir" 2>&1 | while read line; do log "$line"; done if [ $? -eq 0 ]; then # 创建软链接 sudo ln -s $mount_dir /home/biqu/printer_data/gcodes log "备选挂载成功: $mount_dir" return 0 else log "备选挂载失败" rmdir "$mount_dir" 2>/dev/null return 1 fi fi } # 卸载USB设备 handle_unmount() { device="$DEVNAME" user=$(get_active_user) log "处理卸载事件: $device (用户: $user)" # 获取挂载点 mount_info=$(run_in_user_session "$user" "/usr/bin/udisksctl info -b $device") mount_points=$(echo "$mount_info" | awk -F': ' '/MountPoints:/ {print $2}') # 卸载所有挂载点 if [ -n "$mount_points" ]; then log "卸载挂载点: $mount_points" run_in_user_session "$user" "/usr/bin/udisksctl unmount -b $device" 2>&1 | while read line; do log "$line"; done fi # 确保设备断电 log "安全移除设备" run_in_user_session "$user" "/usr/bin/udisksctl power-off -b $device" 2>&1 | while read line; do log "$line"; done # 清理备选挂载点 mount_dir="/media/usb-$(basename "$device")" if [ -d "$mount_dir" ]; then log "清理备选挂载点: $mount_dir" if mountpoint -q "$mount_dir"; then umount "$mount_dir" 2>&1 | while read line; do log "$line"; done fi rmdir "$mount_dir" 2>/dev/null fi log "设备已安全移除: $device" } # 主执行逻辑 case "$ACTION" in add) handle_mount ;; remove) handle_unmount ;; *) log "未知动作: $ACTION" exit 1 ;; esac exit 0 ``` ### 2. 创建 systemd 服务文件 (`/etc/systemd/system/udisks-mount@.service`) ``` [Unit] Description=USB Auto Mount Service for %i After=multi-user.target [Service] Type=oneshot Environment="ACTION=add" Environment="DEVNAME=/dev/%i" ExecStart=/usr/local/bin/udisks_usb_mount.sh [Install] WantedBy=multi-user.target ``` ### 3. 创建 udev 规则 (`/etc/udev/rules.d/99-udisks-usb-mount.rules`) ``` # 挂载事件 ACTION=="add", SUBSYSTEM=="block", KERNEL=="sd[a-z][0-9]*", ENV{ID_BUS}=="usb", \ TAG+="systemd", \ ENV{SYSTEMD_WANTS}="udisks-mount@%k.service" # 卸载事件 ACTION=="remove", SUBSYSTEM=="block", KERNEL=="sd[a-z][0-9]*", ENV{ID_BUS}=="usb", \ RUN+="/bin/systemd-run --uid=$(id -u biqu) --gid=$(id -g biqu) --property=Environment='ACTION=remove' --property=Environment='DEVNAME=/dev/%k' /usr/local/bin/udisks_usb_mount.sh" ``` ### 4. 设置权限和配置 ``` # 设置脚本权限 sudo chmod +x /usr/local/bin/udisks_usb_mount.sh # 创建日志文件 sudo touch /var/log/udisks_mount.log sudo chmod 644 /var/log/udisks_mount.log # 重载 systemd 配置 sudo systemctl daemon-reload # 重载 udev 规则 sudo udevadm control --reload-rules sudo udevadm trigger # 启用用户 linger (确保用户服务在无登录时也能运行) sudo loginctl enable-linger biqu ``` ### 5. 配置 sudoers (可选) ``` # 允许 biqu 用户无需密码运行 udisksctl echo "biqu ALL = NOPASSWD: /usr/bin/udisksctl" | sudo tee /etc/sudoers.d/biqu-udisks ``` ## 方案工作原理 ### 1. 设备插入流程 ``` sequenceDiagram participant UDEV participant Systemd participant MountScript UDEV->>Systemd: 检测到USB插入 (add事件) Systemd->>MountScript: 启动 udisks-mount@sda1.service MountScript->>MountScript: 获取活动用户 MountScript->>MountScript: 在用户会话中执行 udisksctl mount MountScript->>Systemd: 返回结果 Systemd->>UDEV: 完成处理 ``` ### 2. 设备移除流程 ``` sequenceDiagram participant UDEV participant SystemdRun participant MountScript UDEV->>SystemdRun: 检测到USB移除 (remove事件) SystemdRun->>MountScript: 立即执行脚本 (ACTION=remove) MountScript->>MountScript: 获取活动用户 MountScript->>MountScript: 在用户会话中执行 udisksctl unmount MountScript->>MountScript: 执行 udisksctl power-off MountScript->>SystemdRun: 返回结果 SystemdRun->>UDEV: 完成处理 ``` ## 关键优势 1. **正确的用户上下文**: - 通过 `systemd-run` 确保在用户会话中执行 - 自动设置 `DBUS_SESSION_BUS_ADDRESS` 2. **双重保障机制**: - 优先使用 `udisksctl` 进行挂载/卸载 - 提供备选直接挂载方案 3. **智能用户检测**: ``` get_active_user() { # 尝试获取桌面用户 # 回退到第一个登录用户 # 默认使用 biqu 用户 } ``` 4. **完善的日志系统**: - 记录所有操作到 `/var/log/udisks_mount.log` - 同时使用系统日志工具 `logger` 5. **安全移除保障**: ``` # 确保设备断电 run_in_user_session "$user" "/usr/bin/udisksctl power-off -b $device" ``` ## 调试与监控 ### 查看实时日志 ``` tail -f /var/log/udisks_mount.log ``` ### 检查服务状态 ``` # 查看挂载服务状态 systemctl status udisks-mount@sda1.service # 查看用户会话 loginctl list-sessions ``` ### 手动测试 ``` # 模拟设备添加 sudo ACTION=add DEVNAME=/dev/sdb1 /usr/local/bin/udisks_usb_mount.sh # 模拟设备移除 sudo ACTION=remove DEVNAME=/dev/sdb1 /usr/local/bin/udisks_usb_mount.sh ``` ### 验证挂载 ``` # 查看挂载点 udisksctl status lsblk -f # 检查权限 ls -ld /media/* ``` ## 常见问题解决 1. **挂载失败:Error looking up object for device** - 确保用户 linger 已启用:`sudo loginctl enable-linger biqu` - 检查 DBus 会话:`sudo -u biqu dbus-run-session -- echo OK` 2. **权限问题** - 添加用户到必要组: ``` sudo usermod -aG plugdev,disk biqu ``` 3. **设备未就绪** - 增加等待时间(修改脚本中的 sleep 参数) - 在 udev 规则中添加延迟: ``` ACTION=="add", SUBSYSTEM=="block", ..., RUN+="/bin/sleep 1" ``` 4. **卸载不完全** - 确保使用 ``` power-off ``` 命令: ``` udisksctl power-off -b $device ``` 这个方案结合了 `udisksctl` 的便利性和 `systemd-run` 的环境保障,确保 USB 设备在各种情况下都能正确挂载和卸载,同时提供详细的日志记录以便于调试。
qingkai
2025年11月13日 11:15
转发文档
收藏文档
上一篇
下一篇
手机扫码
复制链接
手机扫一扫转发分享
复制链接
Markdown文件
分享
链接
类型
密码
更新密码