RK3576開發(fā)板外設管理:Udev實現(xiàn)U盤自動掛載的標準化方案

原創(chuàng) 作者 Forlinx 2026-03-05 14:44:00 RK3576開發(fā)板

我是燕南無聲,一個在嵌入式領域摸爬滾打了12年的工程師。平時喜歡琢磨底層系統(tǒng)機制,也愛把實際項目中踩過的坑、填過的土記錄下來。今天要分享的是基于飛凌RK3576開發(fā)板(OK3576-C)Ubuntu24.04環(huán)境,深入解析Udev設備事件監(jiān)聽機制與Systemd服務協(xié)同邏輯,提供U盤自動掛載標準化實現(xiàn)方案。從Udev配置、規(guī)則編寫,到Systemd服務創(chuàng)建、掛載/卸載腳本開發(fā),全流程拆解,解決路徑亂碼、腳本執(zhí)行失效等行業(yè)常見問題,為RK3576開發(fā)板嵌入式項目提供可復用的外設管理模板。

項目背景與需求

本次項目是基于RK3576開發(fā)板(型號:OK3576-C)開發(fā)自助終端設備,客戶核心需求是 系統(tǒng)啟動后插入U盤可自動掛載到固定目錄,且目錄名無亂碼。Ubuntu 24.04桌面版自帶的文件管理器(如nautilus)雖支持U盤自動掛載,但掛載點路徑會包含UUID或中文卷標,在終端操作時極易出現(xiàn)亂碼,直接干擾后續(xù)自動化腳本的執(zhí)行。

RK3576開發(fā)板

由于終端環(huán)境對路徑的 固定性和可預測性要求極高,因此決定拋棄文件管理器的默認掛載機制,改用udev接管U盤的插拔事件,自定義掛載/卸載腳本,實現(xiàn)標準化的U盤掛載管理。

實現(xiàn)思路與核心邏輯

首先明確核心實現(xiàn)思路:udev是Linux內核設備管理器的用戶空間守護進程,核心負責管理/dev目錄下的設備節(jié)點,并能在設備插入/移除時觸發(fā)自定義動作。我們的核心目標是—— U盤插入時自動執(zhí)行掛載腳本,U盤拔出時自動執(zhí)行卸載腳本。

需要注意的是,Ubuntu 24.04這類高版本系統(tǒng)中,直接在udev規(guī)則里調用shell腳本大概率會失效:一方面udev事件觸發(fā)的運行環(huán)境極度受限,另一方面腳本執(zhí)行為異步模式,易出現(xiàn)競爭條件導致執(zhí)行失敗。Linux官方推薦的最優(yōu)方案是 通過systemd服務包裝腳本,在udev規(guī)則中通過TAG+="systemd"和ENV{SYSTEMD_WANTS}觸發(fā)服務,讓腳本在systemd管理的干凈環(huán)境中運行,從根本上規(guī)避權限、路徑等問題。

基于此,梳理出本次改造需要修改/新增的核心文件,所有操作均基于飛凌RK3576開發(fā)板的Ubuntu 24.04環(huán)境:

  • /etc/udev/udev.conf:確認udev基礎配置,指向正確的規(guī)則目錄;
  • /etc/udev/rules.d/95-usb-mount.rules:編寫udev核心規(guī)則,捕獲U盤分區(qū)插拔事件,觸發(fā)對應systemd服務;
  • /etc/systemd/system/mount.service/umount.service:創(chuàng)建兩個systemd服務單元,分別承載U盤掛載、卸載邏輯;
  • /etc/systemd/system/mount.sh/umount.sh:編寫實際的掛載、卸載腳本,由上述systemd服務調用。

分步實操實現(xiàn)方案

以下為分步實現(xiàn)步驟,所有配置命令、腳本代碼均經(jīng)過實際環(huán)境驗證,直接復制即可使用,僅在格式上做縮進和注釋優(yōu)化,未改動任何核心參數(shù)。

1

確認udev基礎配置

首先檢查并確認/etc/udev/udev.conf配置文件,確保udev的規(guī)則目錄、設備根目錄指向正確,無需新增配置,僅啟用必要項即可:

# /etc/udev/udev.conf
# 參考udev.conf(5)獲取詳細配置說明
# udevd會在initrd中啟動,修改此文件后建議重建initrd使配置生效
#udev_log=info
#children_max=
#exec_delay=
#event_timeout=180
#timeout_signal=SIGKILL
#resolve_names=early
# 設備根目錄
udev_root="/dev/"
# udev規(guī)則文件存放目錄
udev_rules="/etc/udev/rules.d/"
# 日志級別設為錯誤,減少冗余日志
udev_log="err"

核心關注udev_rules參數(shù),確保其指向/etc/udev/rules.d/,保持默認配置即可,無需額外修改。

2

編寫udevU盤插拔檢測規(guī)則

在/etc/udev/rules.d/目錄下創(chuàng)建95-usb-mount.rules文件(95為規(guī)則優(yōu)先級,數(shù)值越大優(yōu)先級越低),編寫U盤插拔的觸發(fā)規(guī)則,核心實現(xiàn) 插入創(chuàng)目錄+啟掛載服務,拔出啟卸載服務

# /etc/udev/rules.d/95-usb-mount.rules
# 為U盤主設備(sd[a-z])創(chuàng)建符號鏈接usb%m,%m為內核次要設備號,保證設備標識唯一
KERNEL=="sd[a-z]", NAME="%k", SYMLINK+="usb%m", OPTIONS="last_rule"
# U盤分區(qū)(sd[a-z][0-9])插入事件:創(chuàng)建符號鏈接
ACTION=="add", KERNEL=="sd[a-z][0-9]", SYMLINK+="usb%m", NAME="%k"
# U盤分區(qū)插入事件:自動創(chuàng)建掛載點目錄,路徑為/mnt/分區(qū)名(如/mnt/sda1)
ACTION=="add", KERNEL=="sd[a-z][0-9]", RUN+="/bin/mkdir -p /mnt/%k"
# U盤分區(qū)插入事件:核心觸發(fā)掛載服務,僅匹配USB塊設備,避免識別SATA等本地設備
ACTION=="add",KERNEL=="sd[a-z][0-9]",SUBSYSTEM=="block",ENV{ID_BUS}=="usb",TAG+="systemd", PROGRAM="/bin/systemd-escape -p %k", ENV{SYSTEMD_WANTS}+="mount.service"
# U盤分區(qū)移除事件:創(chuàng)建符號鏈接(保持與插入規(guī)則一致性,可省略)
ACTION=="remove", KERNEL=="sd[a-z][0-9]", SYMLINK+="usb%m", NAME="%k"
# U盤分區(qū)移除事件:觸發(fā)卸載服務,僅匹配USB塊設備
ACTION=="remove", KERNEL=="sd[a-z][0-9]", SUBSYSTEM=="block", ENV{ID_BUS}=="usb", PROGRAM="/usr/bin/systemctl start umount.service", TAG+="systemd"

規(guī)則關鍵說明:ENV{ID_BUS}=="usb"精準匹配USB設備,徹底排除本地SATA、NVMe等存儲設備;RUN+="/bin/mkdir -p /mnt/%k"自動創(chuàng)建掛載點;TAG+="systemd"告訴udev通過systemd管理后續(xù)觸發(fā)的服務。

3

創(chuàng)建systemd掛載/卸載服務單元

由于高版本Ubuntu無法直接在udev規(guī)則中執(zhí)行腳本,因此創(chuàng)建兩個systemd服務單元mount.service和umount.service,分別調用掛載、卸載腳本,服務文件存放于/etc/systemd/system/目錄。

掛載服務:mount.service

# /etc/systemd/system/mount.service
[Unit]
# 服務描述
Description=mountservice
# 服務啟動時機:在網(wǎng)絡服務后啟動(掛載無需網(wǎng)絡,僅為通用習慣,可省略)
After=network.target
[Service]
# 服務類型:forking表示腳本會以后臺進程模式運行
Type=forking
# 執(zhí)行用戶/用戶組:必須為root,掛載/卸載操作需要最高權限
User=root
Group=root
# 工作目錄:掛載點根目錄
WorkingDirectory=/mnt
# 服務執(zhí)行命令:調用掛載腳本,--log-target=journal讓日志寫入systemd日志,可通過journalctl查看
ExecStart=/etc/systemd/system/mount.sh start --log-target=journal
[Install]
# 服務安裝目標:多用戶模式下啟用
WantedBy=multi-user.target

卸載服務:umount.service

# /etc/systemd/system/umount.service
[Unit]
# 服務描述
Description=umountservice
# 服務啟動時機:在網(wǎng)絡服務后啟動
After=network.target
[Service]
# 服務類型:forking表示腳本會以后臺進程模式運行
Type=forking
# 執(zhí)行用戶/用戶組:root最高權限
User=root
Group=root
# 工作目錄:掛載點根目錄
WorkingDirectory=/mnt
# 服務執(zhí)行命令:調用卸載腳本
ExecStart=/etc/systemd/system/umount.sh start --log-target=journal
[Install]
# 服務安裝目標:多用戶模式下啟用
WantedBy=multi-user.target

執(zhí)行以下命令為兩個服務文件添加可執(zhí)行權限:

chmod 777 /etc/systemd/system/mount.service
chmod 777 /etc/systemd/system/umount.service
4

編寫掛載/卸載核心腳本

創(chuàng)建與systemd服務對應的掛載腳本mount.sh和卸載腳本umount.sh,存放于/etc/systemd/system/目錄,腳本為實際執(zhí)行U盤掛載、卸載的核心邏輯。

掛載腳本:mount.sh

#!/bin/bash
# /etc/systemd/system/mount.sh
# U盤自動掛載腳本,掛載路徑/mnt/設備名(如/dev/sda1 → /mnt/sda1)
# 初始變量,后續(xù)會被遍歷結果覆蓋
var2="/mnt/sda"
# 遍歷所有/dev目錄下的USB分區(qū)設備
for V in $(ls /dev/sd[a-z][0-9])
do
  # 打印當前設備名(調試用)
  echo $V
  # 賦值當前設備路徑給變量
  var2=$V
  # 截取設備名(如從/dev/sda1中截取sda1)
  echo ${var2:5:4}
  # 執(zhí)行掛載:將設備掛載到/mnt/設備名目錄
  /bin/mount $V /mnt/${var2:5:4}
done

腳本關鍵說明:掛載點由udev規(guī)則提前創(chuàng)建,腳本直接執(zhí)行掛載即可;使用/bin/mount絕對路徑執(zhí)行,避免udev/systemd環(huán)境中PATH變量缺失導致的命令找不到問題。

卸載腳本:umount.sh

#!/bin/sh
# /etc/systemd/system/umount.sh
# U盤自動卸載腳本,檢測設備不存在則卸載并刪除掛載點
# 定義需監(jiān)控的USB設備節(jié)點
usb_device_1="/dev/sda1"
usb_device_2="/dev/sdb1"
usb_device_3="/dev/sdc1"
usb_device_4="/dev/sdd1"
# 定義設備對應的掛載點目錄
mount_dir_1="/mnt/sda1"
mount_dir_2="/mnt/sdb1"
mount_dir_3="/mnt/sdc1"
mount_dir_4="/mnt/sdd1"
# 延時1秒,等待設備徹底移除,避免競爭條件導致卸載失敗
sleep 1
# 檢測設備1是否存在,不存在則卸載并刪除掛載點
if [ ! -e "$usb_device_1" ];then
        umount $usb_device_1 > /dev/null 2>&1
        rm -rf $mount_dir_1 > /dev/null 2>&1
fi
# 檢測設備2是否存在,不存在則卸載并刪除掛載點
if [ ! -e "$usb_device_2" ];then
        umount $usb_device_2 > /dev/null 2>&1
        rm -rf $mount_dir_2 > /dev/null 2>&1
fi
# 檢測設備3是否存在,不存在則卸載并刪除掛載點
if [ ! -e "$usb_device_3" ];then
        umount $usb_device_3 > /dev/null 2>&1
        rm -rf $mount_dir_3 > /dev/null 2>&1
fi
# 檢測設備4是否存在,不存在則卸載并刪除掛載點
if [ ! -e "$usb_device_4" ];then
        umount $usb_device_4 > /dev/null 2>&1
        rm -rf $mount_dir_4 > /dev/null 2>&1
fi

腳本關鍵說明:sleep 1為核心延時操作,等待內核完成設備移除的底層操作;> /dev/null 2>&1重定向所有輸出和錯誤到空設備,保持系統(tǒng)日志干凈。

執(zhí)行以下命令為兩個腳本添加可執(zhí)行權限:

chmod 777 /etc/systemd/system/mount.sh
chmod 777 /etc/systemd/system/umount.sh
5

重載配置并測試驗證

完成所有配置和腳本編寫后,無需重啟系統(tǒng),手動重載udev規(guī)則和systemd配置即可生效:

# 重載udev規(guī)則,讓新編寫的U盤插拔規(guī)則生效
udevadm control --reload-rules
# 重載systemd配置,讓新創(chuàng)建的掛載/卸載服務生效
systemctl daemon-reload

測試步驟

  1. 插入U盤(單分區(qū)/多分區(qū)均可),執(zhí)行l(wèi)s /mnt/,可看到自動創(chuàng)建的掛載點目錄(如sda1),執(zhí)行df -h可驗證U盤已成功掛載;
  2. 拔出U盤,執(zhí)行l(wèi)s /mnt/,對應的掛載點目錄已被自動刪除,執(zhí)行df -h可驗證U盤已成功卸載;
  3. 若需查看服務運行日志,可執(zhí)行journalctl -u mount.service或journalctl -u umount.service。

驗證總結

在飛凌RK3576開發(fā)板的Ubuntu 24.04桌面版環(huán)境中,經(jīng)過多次實際插拔測試,該方案可實現(xiàn) U盤插入自動掛載到/mnt/設備名固定目錄,拔出自動卸載并刪除掛載點,掛載點路徑無任何UUID或中文卷標,徹底解決了默認掛載的亂碼問題,完全滿足自助終端設備的自動化腳本操作需求。

執(zhí)行以下調試命令,可驗證掛載/卸載服務是否已正常啟用:

# 查看掛載服務啟用狀態(tài)
systemctl is-enabled mount.service
# 查看卸載服務啟用狀態(tài)
systemctl is-enabled umount.service

正常情況下,兩個命令的輸出均為enabled,表示服務已成功啟用并隨系統(tǒng)開機自啟。

經(jīng)驗反思

本次基于udev+systemd實現(xiàn)U盤自動掛載,踩過了高版本Ubuntu的環(huán)境坑,也積累了嵌入式Linux外設管理的實用經(jīng)驗,核心總結三點:

規(guī)避udev直接調用腳本的坑 Ubuntu 20.04及以上版本中,udev的RUN指令運行環(huán)境受限,且受SELinux/AppArmor權限管控。通過systemd服務包裝腳本是官方推薦的穩(wěn)健方案。
卸載腳本的局限性需知曉 本次方案中的卸載腳本采用硬編碼設備節(jié)點方式,僅支持sda1~sdd1四個設備。若需同時插入多個U盤或U盤有多個分區(qū),可優(yōu)化為動態(tài)遍歷設備的方式。
固定路徑是解決亂碼的核心 默認掛載的亂碼根源是路徑包含UUID/中文卷標,而udev規(guī)則中通過%k獲取設備名,掛載點固定為/mnt/%k,完全脫離卷標和UUID的影響。

對于飛凌嵌入式RK3576開發(fā)板,Ubuntu 24.04桌面版的整體運行表現(xiàn)穩(wěn)定,結合udev的設備事件監(jiān)聽和systemd的服務管理,可靈活定制USB、串口、網(wǎng)卡等各類外設的自動處理邏輯。本次U盤自動掛載的改造方案,也為后續(xù)嵌入式項目中的外設管理提供了可直接復用的模板。

rk3576核心板

咨詢立即獲得專屬報價

華北區(qū)負責人二維碼

華北區(qū)負責人

華東區(qū)負責人二維碼

華東區(qū)負責人

華南區(qū)負責人二維碼

華南區(qū)負責人

中西區(qū)負責人二維碼

中西區(qū)負責人

相關產(chǎn)品 >

  • FET3576-C核心板

    飛凌嵌入式RK3576核心板集成了強大的處理器和豐富的接口,提供出色的計算能力和擴展性。RK3576核心板以其卓越的性能、低功耗和穩(wěn)定性,成為工業(yè)、AIoT、邊緣計算、智能移動終端等領域的理想選擇。無論是數(shù)據(jù)處理還是邊緣計算,RK3576都能為項目提供強大的硬件支持。核心板推薦選擇飛凌嵌入式瑞芯微系列RK3576J業(yè)級核心板、RK3576高性能核心板 了解詳情
    FET3576-C核心板
  • OK3576-C開發(fā)板

    RK3576開發(fā)板CPU選用瑞芯微RK3576,采用核心板+底板分體式設計,采用4個100Pin板對板連接器的方式將處理器的功能引腳以最便利的方式全部引出,并針對不同的功能做了深度優(yōu)化,方便用戶二次開發(fā)的同時簡化用戶設計,為您的項目提供良好的評估及設計依據(jù)。RK3576是瑞芯微專為AIoT市場打造的一款高算力、高性能、低功耗的國產(chǎn)化應用處理器,集成了4個ARM Cortex-A72和4個 ARM Cortex-A53高性能核;內置6TOPS超強算力NPU;嵌入式3D GPU加之帶有MMU的專用2D硬件引擎,最大限度提升顯示性能;H.265超清硬解碼,最高支持8K分辨率。 了解詳情
    OK3576-C開發(fā)板

推薦閱讀 換一批 換一批