RK3576開發(fā)板外設(shè)管理:Udev實現(xiàn)U盤自動掛載的標(biāo)準(zhǔn)化方案
Forlinx
2026-03-05 14:44:00
RK3576開發(fā)板
我是燕南無聲,一個在嵌入式領(lǐng)域摸爬滾打了12年的工程師。平時喜歡琢磨底層系統(tǒng)機制,也愛把實際項目中踩過的坑、填過的土記錄下來。今天要分享的是基于飛凌RK3576開發(fā)板(OK3576-C)Ubuntu24.04環(huán)境,深入解析Udev設(shè)備事件監(jiān)聽機制與Systemd服務(wù)協(xié)同邏輯,提供U盤自動掛載標(biāo)準(zhǔn)化實現(xiàn)方案。從Udev配置、規(guī)則編寫,到Systemd服務(wù)創(chuàng)建、掛載/卸載腳本開發(fā),全流程拆解,解決路徑亂碼、腳本執(zhí)行失效等行業(yè)常見問題,為RK3576開發(fā)板嵌入式項目提供可復(fù)用的外設(shè)管理模板。
項目背景與需求
本次項目是基于RK3576開發(fā)板(型號:OK3576-C)開發(fā)自助終端設(shè)備,客戶核心需求是 系統(tǒng)啟動后插入U盤可自動掛載到固定目錄,且目錄名無亂碼。Ubuntu 24.04桌面版自帶的文件管理器(如nautilus)雖支持U盤自動掛載,但掛載點路徑會包含UUID或中文卷標(biāo),在終端操作時極易出現(xiàn)亂碼,直接干擾后續(xù)自動化腳本的執(zhí)行。
由于終端環(huán)境對路徑的 固定性和可預(yù)測性要求極高,因此決定拋棄文件管理器的默認掛載機制,改用udev接管U盤的插拔事件,自定義掛載/卸載腳本,實現(xiàn)標(biāo)準(zhǔn)化的U盤掛載管理。
實現(xiàn)思路與核心邏輯
首先明確核心實現(xiàn)思路:udev是Linux內(nèi)核設(shè)備管理器的用戶空間守護進程,核心負責(zé)管理/dev目錄下的設(shè)備節(jié)點,并能在設(shè)備插入/移除時觸發(fā)自定義動作。我們的核心目標(biāo)是—— U盤插入時自動執(zhí)行掛載腳本,U盤拔出時自動執(zhí)行卸載腳本。
需要注意的是,Ubuntu 24.04這類高版本系統(tǒng)中,直接在udev規(guī)則里調(diào)用shell腳本大概率會失效:一方面udev事件觸發(fā)的運行環(huán)境極度受限,另一方面腳本執(zhí)行為異步模式,易出現(xiàn)競爭條件導(dǎo)致執(zhí)行失敗。Linux官方推薦的最優(yōu)方案是 通過systemd服務(wù)包裝腳本,在udev規(guī)則中通過TAG+="systemd"和ENV{SYSTEMD_WANTS}觸發(fā)服務(wù),讓腳本在systemd管理的干凈環(huán)境中運行,從根本上規(guī)避權(quán)限、路徑等問題。
基于此,梳理出本次改造需要修改/新增的核心文件,所有操作均基于飛凌RK3576開發(fā)板的Ubuntu 24.04環(huán)境:
- /etc/udev/udev.conf:確認udev基礎(chǔ)配置,指向正確的規(guī)則目錄;
- /etc/udev/rules.d/95-usb-mount.rules:編寫udev核心規(guī)則,捕獲U盤分區(qū)插拔事件,觸發(fā)對應(yīng)systemd服務(wù);
- /etc/systemd/system/mount.service/umount.service:創(chuàng)建兩個systemd服務(wù)單元,分別承載U盤掛載、卸載邏輯;
- /etc/systemd/system/mount.sh/umount.sh:編寫實際的掛載、卸載腳本,由上述systemd服務(wù)調(diào)用。
分步實操實現(xiàn)方案
以下為分步實現(xiàn)步驟,所有配置命令、腳本代碼均經(jīng)過實際環(huán)境驗證,直接復(fù)制即可使用,僅在格式上做縮進和注釋優(yōu)化,未改動任何核心參數(shù)。
確認udev基礎(chǔ)配置
首先檢查并確認/etc/udev/udev.conf配置文件,確保udev的規(guī)則目錄、設(shè)備根目錄指向正確,無需新增配置,僅啟用必要項即可:
# /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 # 設(shè)備根目錄 udev_root="/dev/" # udev規(guī)則文件存放目錄 udev_rules="/etc/udev/rules.d/" # 日志級別設(shè)為錯誤,減少冗余日志 udev_log="err"
核心關(guān)注udev_rules參數(shù),確保其指向/etc/udev/rules.d/,保持默認配置即可,無需額外修改。
編寫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)目錄+啟掛載服務(wù),拔出啟卸載服務(wù):
# /etc/udev/rules.d/95-usb-mount.rules
# 為U盤主設(shè)備(sd[a-z])創(chuàng)建符號鏈接usb%m,%m為內(nèi)核次要設(shè)備號,保證設(shè)備標(biāo)識唯一
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ā)掛載服務(wù),僅匹配USB塊設(shè)備,避免識別SATA等本地設(shè)備
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ā)卸載服務(wù),僅匹配USB塊設(shè)備
ACTION=="remove", KERNEL=="sd[a-z][0-9]", SUBSYSTEM=="block", ENV{ID_BUS}=="usb", PROGRAM="/usr/bin/systemctl start umount.service", TAG+="systemd"
規(guī)則關(guān)鍵說明:ENV{ID_BUS}=="usb"精準(zhǔn)匹配USB設(shè)備,徹底排除本地SATA、NVMe等存儲設(shè)備;RUN+="/bin/mkdir -p /mnt/%k"自動創(chuàng)建掛載點;TAG+="systemd"告訴udev通過systemd管理后續(xù)觸發(fā)的服務(wù)。
創(chuàng)建systemd掛載/卸載服務(wù)單元
由于高版本Ubuntu無法直接在udev規(guī)則中執(zhí)行腳本,因此創(chuàng)建兩個systemd服務(wù)單元mount.service和umount.service,分別調(diào)用掛載、卸載腳本,服務(wù)文件存放于/etc/systemd/system/目錄。
掛載服務(wù):mount.service
# /etc/systemd/system/mount.service [Unit] # 服務(wù)描述 Description=mountservice # 服務(wù)啟動時機:在網(wǎng)絡(luò)服務(wù)后啟動(掛載無需網(wǎng)絡(luò),僅為通用習(xí)慣,可省略) After=network.target [Service] # 服務(wù)類型:forking表示腳本會以后臺進程模式運行 Type=forking # 執(zhí)行用戶/用戶組:必須為root,掛載/卸載操作需要最高權(quán)限 User=root Group=root # 工作目錄:掛載點根目錄 WorkingDirectory=/mnt # 服務(wù)執(zhí)行命令:調(diào)用掛載腳本,--log-target=journal讓日志寫入systemd日志,可通過journalctl查看 ExecStart=/etc/systemd/system/mount.sh start --log-target=journal [Install] # 服務(wù)安裝目標(biāo):多用戶模式下啟用 WantedBy=multi-user.target
卸載服務(wù):umount.service
# /etc/systemd/system/umount.service [Unit] # 服務(wù)描述 Description=umountservice # 服務(wù)啟動時機:在網(wǎng)絡(luò)服務(wù)后啟動 After=network.target [Service] # 服務(wù)類型:forking表示腳本會以后臺進程模式運行 Type=forking # 執(zhí)行用戶/用戶組:root最高權(quán)限 User=root Group=root # 工作目錄:掛載點根目錄 WorkingDirectory=/mnt # 服務(wù)執(zhí)行命令:調(diào)用卸載腳本 ExecStart=/etc/systemd/system/umount.sh start --log-target=journal [Install] # 服務(wù)安裝目標(biāo):多用戶模式下啟用 WantedBy=multi-user.target
執(zhí)行以下命令為兩個服務(wù)文件添加可執(zhí)行權(quán)限:
chmod 777 /etc/systemd/system/mount.service chmod 777 /etc/systemd/system/umount.service
編寫掛載/卸載核心腳本
創(chuàng)建與systemd服務(wù)對應(yīng)的掛載腳本mount.sh和卸載腳本umount.sh,存放于/etc/systemd/system/目錄,腳本為實際執(zhí)行U盤掛載、卸載的核心邏輯。
掛載腳本:mount.sh
#!/bin/bash
# /etc/systemd/system/mount.sh
# U盤自動掛載腳本,掛載路徑/mnt/設(shè)備名(如/dev/sda1 → /mnt/sda1)
# 初始變量,后續(xù)會被遍歷結(jié)果覆蓋
var2="/mnt/sda"
# 遍歷所有/dev目錄下的USB分區(qū)設(shè)備
for V in $(ls /dev/sd[a-z][0-9])
do
# 打印當(dāng)前設(shè)備名(調(diào)試用)
echo $V
# 賦值當(dāng)前設(shè)備路徑給變量
var2=$V
# 截取設(shè)備名(如從/dev/sda1中截取sda1)
echo ${var2:5:4}
# 執(zhí)行掛載:將設(shè)備掛載到/mnt/設(shè)備名目錄
/bin/mount $V /mnt/${var2:5:4}
done
腳本關(guān)鍵說明:掛載點由udev規(guī)則提前創(chuàng)建,腳本直接執(zhí)行掛載即可;使用/bin/mount絕對路徑執(zhí)行,避免udev/systemd環(huán)境中PATH變量缺失導(dǎo)致的命令找不到問題。
卸載腳本:umount.sh
#!/bin/sh
# /etc/systemd/system/umount.sh
# U盤自動卸載腳本,檢測設(shè)備不存在則卸載并刪除掛載點
# 定義需監(jiān)控的USB設(shè)備節(jié)點
usb_device_1="/dev/sda1"
usb_device_2="/dev/sdb1"
usb_device_3="/dev/sdc1"
usb_device_4="/dev/sdd1"
# 定義設(shè)備對應(yīng)的掛載點目錄
mount_dir_1="/mnt/sda1"
mount_dir_2="/mnt/sdb1"
mount_dir_3="/mnt/sdc1"
mount_dir_4="/mnt/sdd1"
# 延時1秒,等待設(shè)備徹底移除,避免競爭條件導(dǎo)致卸載失敗
sleep 1
# 檢測設(shè)備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
# 檢測設(shè)備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
# 檢測設(shè)備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
# 檢測設(shè)備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
腳本關(guān)鍵說明:sleep 1為核心延時操作,等待內(nèi)核完成設(shè)備移除的底層操作;> /dev/null 2>&1重定向所有輸出和錯誤到空設(shè)備,保持系統(tǒng)日志干凈。
執(zhí)行以下命令為兩個腳本添加可執(zhí)行權(quán)限:
chmod 777 /etc/systemd/system/mount.sh chmod 777 /etc/systemd/system/umount.sh
重載配置并測試驗證
完成所有配置和腳本編寫后,無需重啟系統(tǒng),手動重載udev規(guī)則和systemd配置即可生效:
# 重載udev規(guī)則,讓新編寫的U盤插拔規(guī)則生效 udevadm control --reload-rules # 重載systemd配置,讓新創(chuàng)建的掛載/卸載服務(wù)生效 systemctl daemon-reload
測試步驟:
- 插入U盤(單分區(qū)/多分區(qū)均可),執(zhí)行l(wèi)s /mnt/,可看到自動創(chuàng)建的掛載點目錄(如sda1),執(zhí)行df -h可驗證U盤已成功掛載;
- 拔出U盤,執(zhí)行l(wèi)s /mnt/,對應(yīng)的掛載點目錄已被自動刪除,執(zhí)行df -h可驗證U盤已成功卸載;
- 若需查看服務(wù)運行日志,可執(zhí)行journalctl -u mount.service或journalctl -u umount.service。
驗證總結(jié)
在飛凌RK3576開發(fā)板的Ubuntu 24.04桌面版環(huán)境中,經(jīng)過多次實際插拔測試,該方案可實現(xiàn) U盤插入自動掛載到/mnt/設(shè)備名固定目錄,拔出自動卸載并刪除掛載點,掛載點路徑無任何UUID或中文卷標(biāo),徹底解決了默認掛載的亂碼問題,完全滿足自助終端設(shè)備的自動化腳本操作需求。
執(zhí)行以下調(diào)試命令,可驗證掛載/卸載服務(wù)是否已正常啟用:
# 查看掛載服務(wù)啟用狀態(tài) systemctl is-enabled mount.service # 查看卸載服務(wù)啟用狀態(tài) systemctl is-enabled umount.service
正常情況下,兩個命令的輸出均為enabled,表示服務(wù)已成功啟用并隨系統(tǒng)開機自啟。
經(jīng)驗反思
本次基于udev+systemd實現(xiàn)U盤自動掛載,踩過了高版本Ubuntu的環(huán)境坑,也積累了嵌入式Linux外設(shè)管理的實用經(jīng)驗,核心總結(jié)三點:
對于飛凌嵌入式RK3576開發(fā)板,Ubuntu 24.04桌面版的整體運行表現(xiàn)穩(wěn)定,結(jié)合udev的設(shè)備事件監(jiān)聽和systemd的服務(wù)管理,可靈活定制USB、串口、網(wǎng)卡等各類外設(shè)的自動處理邏輯。本次U盤自動掛載的改造方案,也為后續(xù)嵌入式項目中的外設(shè)管理提供了可直接復(fù)用的模板。
咨詢立即獲得專屬報價
華北區(qū)負責(zé)人
華東區(qū)負責(zé)人
華南區(qū)負責(zé)人
中西區(qū)負責(zé)人
相關(guān)產(chǎn)品 >
-
FET3576-C核心板
飛凌嵌入式RK3576核心板集成了強大的處理器和豐富的接口,提供出色的計算能力和擴展性。RK3576核心板以其卓越的性能、低功耗和穩(wěn)定性,成為工業(yè)、AIoT、邊緣計算、智能移動終端等領(lǐng)域的理想選擇。無論是數(shù)據(jù)處理還是邊緣計算,RK3576都能為項目提供強大的硬件支持。核心板推薦選擇飛凌嵌入式瑞芯微系列RK3576J業(yè)級核心板、RK3576高性能核心板。 了解詳情
-
OK3576-C開發(fā)板
RK3576開發(fā)板CPU選用瑞芯微RK3576,采用核心板+底板分體式設(shè)計,采用4個100Pin板對板連接器的方式將處理器的功能引腳以最便利的方式全部引出,并針對不同的功能做了深度優(yōu)化,方便用戶二次開發(fā)的同時簡化用戶設(shè)計,為您的項目提供良好的評估及設(shè)計依據(jù)。RK3576是瑞芯微專為AIoT市場打造的一款高算力、高性能、低功耗的國產(chǎn)化應(yīng)用處理器,集成了4個ARM Cortex-A72和4個 ARM Cortex-A53高性能核;內(nèi)置6TOPS超強算力NPU;嵌入式3D GPU加之帶有MMU的專用2D硬件引擎,最大限度提升顯示性能;H.265超清硬解碼,最高支持8K分辨率。 了解詳情

