修改mdev的配置以支持U盤的自動掛載


原文:https://www.cnblogs.com/lifexy/p/7891883.html

1.當我們每次插入u盤后,都會自動創鍵U盤的設備節點/dev/sda%d

這是因為里面調用了device_create()實現的, busybox的mdev機制就會根據主次設備號等信息,在/dev下創建設備節點,如下圖所示:

 

/dev/sda:表示整個U盤
/dev/sda1:表示U盤的第一個分區

而想使用上面的sda1設備節點,讀寫數據時,還需要使用mount /dev/sda1  /mnt,來掛載u盤才行,會顯得非常麻煩,如下圖所示:

 

2.其實,可以在/etc/mdev.conf文件里加入一行語句就能實現自動裝載u盤,也可以在里面干其它與設備節點相關的事

2.1而/etc/mdev.conf又是什么?

它是屬於mdev的一個配置文件,而mdev之前就講過了,它主要的功能是管理/dev目錄底下的設備節點

當系統中有自動注冊設備節點的時候,mdev就會調用/etc/mdev.conf一次, 該文件可以實現與設備節點相關的事,比如自動裝載usb,打印創建的設備節點信息等

3.我們首先來分析device_create(),是如何來調用到/etc/mdev.conf的,后面再講如何使用mdev.conf(也可以直接跳過,直接看下面第4小節,如何使用)

(PS: 之前創建字符設備節點用的class_device_create(),其實是和device_create功能差不多)

3.1 device_create()最終調用了:device_create()->device_register()->device_add():

復制代碼
device_create()->device_register()->device_add()函數如下所示: int class_device_add(struct class_device *class_dev) { ... ... kobject_uevent(&class_dev->kobj, KOBJ_ADD);         // KOBJ_ADD是一個枚舉值 //調用了kobject_uevent_env(kobj, action, NULL); // action=KOBJ_ADD }
復制代碼

3.2 device_create()->device_register()->device_add()->kobject_uevent_env()函數如下所示:

復制代碼
int kobject_uevent_env(struct kobject *kobj, enum kobject_action action,char *envp_ext[]) { char **envp; char *buffer; char *scratch; int i = 0; ... ... /* 通過KOBJ_ADD獲取字符串"add",所以action_string="add" */ action_string = action_to_string(action);              // action=KOBJ_ADD

                                                       
       /* environment index */ envp = kzalloc(NUM_ENVP * sizeof (char *), GFP_KERNEL);      //分配一個環境變量索引值

       /* environment values */     buffer = kmalloc(BUFFER_SIZE, GFP_KERNEL);     //分配一個環境變量緩沖值      

/* event environemnt for helper process only */
/*設置環境變量*/ envp[i++] = "HOME=/"; envp[i++] = "PATH=/sbin:/bin:/usr/sbin:/usr/bin"; scratch = buffer; envp [i++] = scratch; scratch += sprintf(scratch, "ACTION=%s", action_string) + 1;  //"ACTION= add" envp [i++] = scratch; scratch += sprintf (scratch, "DEVPATH=%s", devpath) + 1; envp [i++] = scratch; scratch += sprintf(scratch, "SUBSYSTEM=%s", subsystem) + 1; ... ... /*調用應用程序,比如mdev*/
       if (uevent_helper[0]) { char *argv [3]; argv [0] = uevent_helper;       // uevent_helper[]= "/sbin/hotplug"; argv [1] = (char *)subsystem; argv [2] = NULL; call_usermodehelper (argv[0], argv, envp, 0);        //調用應用程序,根據傳入的環境變量參數來創建設備節點 } }
復制代碼

從上面的代碼和注釋來看,最終通過*argv[], *envp[]兩個字符串數組里面存的環境變量參數來創建設備節點的

3.2接下來便在kobject_uevent_env()函數里添加打印信息, 然后重新燒內核:

 

3.3然后我們以注冊一個按鍵驅動為例 

輸入 insmod key.ko,打印了以下語句:

復制代碼
class_device: argv[0]=/sbin/mdev                 //調用mdev
 class_device: argv[1]=sixth_dev                      //類名
 class_device: envp[0]=HOME=/ class_device: envp[1]=PATH=/sbin:/bin:/usr/sbin:/usr/bin class_device: envp[2]=ACTION=add             //add:表示添加設備節點,  若=remove:表示卸載設備節點
 class_device: envp[3]=DEVPATH=/class/sixth_dev/buttons   //設備的路徑
 class_device: envp[4]=SUBSYSTEM=sixth_dev                //類名
 class_device: envp[5]=SEQNUM=745 class_device: envp[6]=MAJOR=252                          //主設備號
 class_device: envp[7]=MINOR=0
復制代碼

3.4最終這些參數根據/sbin/mdev就進入了busybox的mdev.c的mdev_main()函數里:

復制代碼
int mdev_main(int argc, char **argv) { ... ... action = getenv("ACTION");           //獲取傳進來的執行參數,它等於“add”,則表示創建設備節點 env_path = getenv("DEVPATH");      //獲取設備的路徑“/class/sixth_dev/buttons” sprintf(temp, "/sys%s", env_path);   //指定temp (真正設備路徑)為“/sys/class/sixth_dev/buttons”

if (!strcmp(action, "remove"))           //卸載設備節點 make_device(temp, 1); else if (!strcmp(action, "add")) {       //創建設備節點 make_device(temp, 0); ... ... }
復制代碼

3.5最終調用mdev_main ()->make_device()函數來創建/卸載設備節點,該函數如下所示:

復制代碼
static void make_device(char *path, int delete) //delete=0:創建, delete=1:卸載 { /*判斷創建的設備節點是否是有效的設備*/
       if (!delete) { strcat(path, "/dev"); len = open_read_close(path, temp + 1, 64); *temp++ = 0; if (len < 1) return; } device_name = bb_basename(path);    //通過設備路徑,來獲取要創建/卸載的設備節點名稱 //例: path =“/sys /class/sixth_dev/buttons”,那么device_name=“buttons”
 type = path[5]=='c' ? S_IFCHR : S_IFBLK;     //判斷如果是在/sys/class/目錄下,那么就是字符設備 //因為塊設備,是存在/sys/block/目錄下的


/* 如果配置了支持mdev.conf選項,那么就解析里邊內容並執行 */
 if (ENABLE_FEATURE_MDEV_CONF) { /* mmap the config file */ fd = open("/etc/mdev.conf", O_RDONLY);     //調用/etc/mdev.conf配置文件 
     ... ...
//開始操作 mdev.conf配置文件 } if (!delete) { //如果是創建設備節點 if (sscanf(temp, "%d:%d", &major, &minor) != 2) return; //獲取主次設備號

        /*調用mknod ()創建字符設備節點*/ if (mknod(device_name, mode | type, makedev(major, minor)) && errno != EEXIST) bb_perror_msg_and_die("mknod %s", device_name); if (major == root_major && minor == root_minor) symlink(device_name, "root"); /*若配置了支持mdev.conf選項,則調用chown命令來改變屬主,默認uid和gid=0 */ if (ENABLE_FEATURE_MDEV_CONF) chown(device_name, uid, gid); } if (delete) unlink(device_name); //如果是卸載設備節點 }
復制代碼

從上面的代碼和注釋分析到,要使用mdev.conf配置文件,還需要配置busybox的menuconfig, 使mdev支持mdev.conf選項才行

如下圖,進入busybox目錄,然后輸入make menuconfig,發現我們已經配置過了該選項了

 

4.接下來,便來看看如何使用mdev.conf,  參考busybox-1.7.0/docs/mdev.txt文檔

使用方法如下所示:

the format:

       <device regex> <uid>:<gid> <octal permissions> [<@|$|*> <command>]

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.

大概就是:

配置文件格式:

<device regex> <uid>:<gid> <octal permissions> [<@|$|*> <command>]  

各個參數代表的含義如下:  

device regex:

設備的正則表達式,來表達哪一個設備 ,正則表達式講解鏈接:https://deerchao.net/tutorials/regex/regex.htm

插講:掌握下面幾個簡單的規則基本上就可以了

 

.  表示任意字符(換行符除外)
* 表示重復0次或更多次
+表示重復1次或更多次
?表示重復0次或1次
[ ]表示這些字符里的某一個。例如[abc],就表示abc中的某一個。[1-9],就表示1到9中的某一個

uid: 

owner       (uid,gid:注冊設備節點時,就會被chown命令調用,來改變設備的屬主,默認都填0即可)

gid: 

組ID  

octal permissions:

以八進制表示的權限值,會被chmod命令調用,來更改設備的訪問權限,默認填660即可

@ : 創建設備節點之后執行命令  

$  :  刪除設備節點之前執行命令  

*   : 創建設備節點之后 和 刪除設備節點之前 執行命令  

command : 要執行的命令 。

以加載/卸載myleds為例,介紹上面的規則。

//寫mdev.conf //leds led1 led2 led3,如何用一個正則表達式來表示它們。 //寫法1:
vim /ect/mdev.conf leds 0:0  777 led2 0:0  777 led3 0:0  777 led4 0:0  777

//執行insmod myleds.ko
ls -l /dev/led*
//可以看到
crwxrwxrwx  1 0    0   231, ..... /dev/led1 crwxrwxrwx 1 0    0   231, ..... /dev/led2 crwxrwxrwx 1 0    0   231, ..... /dev/led3 crwxrwxrwx 1 0    0   231, ..... /dev/leds //從上面可以看出,這么寫沒有問題,但是就是非常麻煩。最笨的一種方法。 //寫法2:利用規則來匹配這4個設備節點
vi /etc/mdev.conf leds?[123]?  0:0 777
//執行insmod myleds.ko
ls -l /dev/led*
//可以看到
crwxrwxrwx  1 0    0   231, ..... /dev/led1 crwxrwxrwx 1 0    0   231, ..... /dev/led2 crwxrwxrwx 1 0    0   231, ..... /dev/led3 crwxrwxrwx 1 0    0   231, ..... /dev/leds //3下面繼續改進:
leds?[123]? 0:0  777 @ echo create 某個設備,(//到底是哪個設備呢?可以用環境變量MDEV來表示是哪個設備節點) //即mdev.conf文件的內容如下:
 leds?[123]? 0:0  777 @ echo create /dev/$MDEV > /dev/console //當執行insmod myleds.ko時,將會打印下面的內容:
create       /dev/leds create /dev/led1 create /dev/led2 create /dev/led3 //4.繼續改進,加載的時候打印create,卸載的時候打印remove
vi /ect/mdev.conf leds?[123]? 0:0  777 * if [$ACTION = "add" ]; then echo create /dev/$MDEV > /dev/console; else echo remove /dev/$MDEV > /dev/console; fi insmod myleds.ko create /dev/leds create /dev/led1 create /dev/led2 create /dev/led3 rmmod myleds remove /dev/leds remove /dev/led1 remove /dev/led2 remove /dev/led3 //5.把命令寫入一個腳本
add_remove_led.sh #!/bin/sh if [$ACTION = "add" ]; then echo create /dev/$MDEV > /dev/console; else echo remove /dev/$MDEV > /dev/console; fi chmod +x /bin/add_remove_led.sh //將add_remove_led.sh腳本放入/bin目錄下
vi /etc/mdev.conf leds?[123]? 0:0  777 * /bin/add_remove_led.sh

 

5.接下來便來使用mdev.conf,實現u盤自動裝載

vi /etc/mdev.conf

添加以下一句:

sda[1-9]+ 0:0 660 * if [ $ACTION = "add" ]; then mount /dev/$MDEV /mnt; else umount /mnt; fi


[1-9] : 匹配1~9的數字,

+   :  重復匹配一次或更多次

$ACTION=="add"   :表示注冊設備節點,否則就是注銷設備節點

/dev/$MDEV      :表示要創建/注銷的那個設備節點

所以當我們插上u盤,自動創建了/dev/sda1時,mdev便會進入/etc/mdev.conf配置文件,然后執行mount /dev/ 命令,即可自動裝載U盤,如下圖所示:

 

可以利用cat /proc/mounts來進行查看

輸入ls /dev/sda1  -l,可以看到都是通過mdev.conf里配置信息來創建的設備節點,如下圖所示:

上面那種寫法不直觀,我們還是用一個腳本對命令來進行封裝。

vi  /bin/add_remove_udisk.sh

if [ $ACTION = "add" ]; then    mount /dev/$MDEV /mnt; else    umount /mnt; fi

chmod +x /bin/add_remove_udisk.sh

vi /etc/mdev.conf

sda[1-9]+ 0:0 660 * /bin/add_remove_udisk.sh

而取出u盤時,同樣自動umount  /mnt來卸載

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM