問題背景:用戶插入U盤后需要自動打開U盤目錄,但是發現U盤每次掛載點都不一樣,測試兩個U盤的掛載點分別是/media/sda1和/media/sda4,所以就需要了解一下linux的udev機制了
我們知道,每個設備注冊后會自動產生設備節點,以字符設備為例,不管是misc_register還是配合cdev_add接口注冊驅動,都需要調用device_create來創建設備節點,就從這個函數入手,看其在3.2.0內核版本的注冊流程
device_create
device_create_vargs
device_register(struct device *dev)
device_add(dev);
kobject_uevent(&dev->kobj, KOBJ_ADD);
kobject_uevent_env(kobj, action, NULL);
char *action_string = kobject_actions[action]; //action_string = "add"
struct kobj_uevent_env *env = kzalloc(sizeof(struct kobj_uevent_env), GFP_KERNEL);
add_uevent_var(env, "ACTION=%s", action_string); //env[0] = "ACTION=add"
add_uevent_var(env, "DEVPATH=%s", devpath); //這兩個先不關注
add_uevent_var(env, "SUBSYSTEM=%s", subsystem);
argv [0] = uevent_helper;
argv [1] = (char *)subsystem;
argv [2] = NULL;
add_uevent_var(env, "HOME=/"); //設置其他環境變量
add_uevent_var(env, "PATH=/sbin:/bin:/usr/sbin:/usr/bin");
//調用argv[0]指向的應用程序來根據環境變量env->envp一些參數來創建設備節點
call_usermodehelper(argv[0], argv, env->envp, UMH_WAIT_EXEC);
到這里,我們基本知道,內核在啟動時候已經設置了一些環境變量,可以在終端用命令env看一下
TSLIB_TSDEVICE=/dev/input/event0
QTDIR=/usr/gui/qt
PATH=/usr/local/bin:/usr/bin:/bin:/usr/local/sbin:/usr/sbin:/sbin
HOME=/home/root
我的板子由于需要QT,所以一些環境變量已經改過或者添加了新的
那么上面提到用戶空間的argv[0]即uevent_helper到底是什么呢?
從內核源碼看uevent_helper初始化地方看是全部設置為"/sbin/hotplug"
可是我在板子上執行 ls /sbin/hotplug 命令并沒有發現這個程序,簡單的辦法就是打印一下了。
在調用call_usermodehelper之前加上下面打印
printk("uevent_helper = %s\n", uevent_helper);
for(i=0; env->envp[i]; i++)
{
printk("envp[%d] = %s\n", i,env->envp[i]);
}
重新編譯內核然后啟動截取部分打印如下(每注冊一個驅動都會出現這一串打印):
看門狗注冊
uevent_helper = /sbin/hotplug
envp[0] = ACTION=add
envp[1] = DEVPATH=/devices/platform/omap/omap_wdt/misc/watchdog
envp[2] = SUBSYSTEM=misc
envp[3] = MAJOR=10
envp[4] = MINOR=130
envp[5] = DEVNAME=watchdog
envp[6] = SEQNUM=520
envp[7] = HOME=/
envp[8] = PATH=/sbin:/bin:/usr/sbin:/usr/bin
按鍵注冊
uevent_helper = /sbin/hotplug
envp[0] = ACTION=add
envp[1] = DEVPATH=/devices/platform/gpio-keys/input/input2
envp[2] = SUBSYSTEM=input
envp[3] = PRODUCT=19/1/1/100
envp[4] = NAME="gpio-keys" envp[5] = PHYS="gpio-keys/input0" envp[6] = PROP=0 envp[7] = EV=3 envp[8] = KEY=14001 40000000 envp[9] = MODALIAS=input:b0019v0001p0001e0100-e0,1,kramlsfw envp[10] = SEQNUM=572 envp[11] = HOME=/ envp[12] = PATH=/sbin:/bin:/usr/sbin:/usr/bin
我插入的2GB U盤 uevent_helper = /sbin/hotplug envp[0] = ACTION=add envp[1] = DEVPATH=/bus/hid/drivers/generic-usb envp[2] = SUBSYSTEM=drivers envp[3] = SEQNUM=551 envp[4] = HOME=/ envp[5] = PATH=/sbin:/bin:/usr/sbin:/usr/bin sd 0:0:0:0: [sda] 3919872 512-byte logical blocks: (2.00 GB/1.86 GiB)
uevent_helper仍然是hotplug,查了一些資料,貌似是說2.6以后udev機制替換了hotplug,而嵌入式中的udev即mdev,所以要去看下文件系統busybox的mdev源碼 相關資料鏈接:
//blog.chinaunix.net/uid-14753126-id-2978523.html
//www.cnblogs.com/hnrainll/archive/2011/06/23/2088250.html
mdev.c mdev_main action = getenv("ACTION"); //插入u盤就是"add" env_path = getenv("DEVPATH"); sprintf(temp, "/sys%s", env_path); //u盤的 temp = "/sys/bus/hid/drivers/generic-usb" make_device(temp, 0); device_name = bb_basename(path); //根據上面temp取出設備名字 if (ENABLE_FEATURE_MDEV_CONF) { //如果配置了支持mdev.conf選項,那么就解析里邊內容并執行 .... } type = path[5]=='c' ? S_IFCHR : S_IFBLK; //判斷是字符還是塊設備 sscanf(temp, "%d:%d", &major, &minor) //取出主次設備號 mknod(device_name, mode | type, makedev(major, minor)) //創建設備節點
這就是設備從內核到用戶空間創建設備節點的整個過程,而如果我們要對設備節點做手腳,就需要從mdev下手了 busybox源碼有個幫助文檔mdev.txt講了應該如何去操作mdev.conf,從而實現一些高級功能,比如U盤自動掛載
文檔很短,其中重要就是下面這段內容: ---------------------------------------------------------------------------- ------------- MDEV Config (/etc/mdev.conf) ------------- Mdev has an optional config file for controlling ownership/permissions of device nodes if your system needs something more than the default root/root 660 permissions. The file has the format:
] The special characters have the meaning: @ Run after creating the device. $ Run before removing the device. * Run both after creating and before removing the device. The command is executed via the system() function (which means you're giving a command to the shell), so make sure you have a shell installed at /bin/sh. For your convenience, the shell env var $MDEV is set to the device name. So if the device 'hdc' was matched, MDEV would be set to "hdc". ----------------------------------------------------------------------------
大體意思就是: 配置文件格式:
] 各個參數代表的含義如下: device regex:正則表達式,表示哪一個設備 uid: owner gid: 組ID octal permissions:以八進制表示的屬性 @:創建設備節點之后執行命令 $:刪除設備節點之前執行命令 *: 創建設備節點之后 和 刪除設備節點之前 執行命令 command:要執行的命令 所以如果要想讓U盤自動掛載怎么辦呢?就需要在/etc下建立mdev.conf文件,并編輯內容如下: sda[1-9]+ 0:3 660 * if [ $ACTION = "add" ]; then mount /dev/$MDEV /mnt; else umount /mnt; fi 其中sda[1-9]+是一個正則表達式,表示sda1...sda9(U盤默認設備節點名),0:3 660就是
---------------------------------------------------------------------------- 公司fs的配置非常麻煩,不符合上述流程,后是通過搜"mount"關鍵字找到其實是/etc/udev/scripts/mount.sh操控這個流程 那么需要做如下內容修改: 第23-25行: ! test -d "/media/$name" && mkdir -p "/media/$name" if ! $MOUNT -t auto $DEVNAME "/media/$name" 改為: ! test -d "/upan" && mkdir -p "/upan" if ! $MOUNT -t auto $DEVNAME "/upan" 這樣無論哪個u盤都會掛載到/upan目錄下了