修改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来卸载

原文地址:https://www.cnblogs.com/-glb/p/12589926.html

时间: 2024-10-07 20:18:38

修改mdev的配置以支持U盘的自动挂载的相关文章

如何在openwrt上实现 U盘的自动挂载

U盘的自动挂载,分为两种场景 1.路由器先上电,然后插上U盘并自动挂载 2.路由器先插上U盘,然后上电并自动挂载 上述场景的实现,需要如下几个步骤: 1.支持如下模块: USB驱动模块:USB OHCI/USB 2.0/USB UHCI 文件系统支持:VFAT,ntfs-3g, 字符集支持:cp437/CP936/utf-8/iso8859-1 网络文件服务:samba server 2.使用hotplug机制,放入挂载脚本文件:/etc/hotplug.d/block/30-block_mou

openwrt U盘热插拔自动挂载

添加USB相关支持 Kernel modules -> USB Support -> <*> kmod-usb-core. ##默认已经选了 Kernel modules -> USB Support -> <*> kmod-usb-ohci. ##默认已选 old usb1.0 Kernel modules -> USB Support -> <*> kmod-usb-uhci. ## usb1.1 Kernel modules -

关于实现udev/mdev自动挂载与卸载

在网上有很多关于讲mdev的自动挂载基本上都是一个版本,经过测试自动挂载确实可行,但是关于自动卸载mdev似乎不能很好的支持,经过修改已经可以做到与udev的效果相似.不能在挂载的目录中进行热插拔,否则会出现问题,不过此问题在下次插入U盘时不会造成影响,可能对U盘有损坏. 本文介绍了mdev与udev两种方法来实现自动挂载,读者可根据需要任选其一即可. 首先介绍一下mdev与udev之间的关系: mdev是busybox中的一个udev管理程序的一个精简版,他也可以实现设备节点的自动创建和设备的

A20 sugar-standard 版本无法支持U盘自动挂载问题解决

前面硬件工程师在sugar-standard的基础上搞了个什么USB HUB的线路<我不是很明白>,但是这个时候的sugar-standard 依然能自动挂载U盘. 后面他又把USB接口的东西给弄成了 A20 sugar-cubieboard 2 的版本,于是这个时候原来的img烧进去,U口就没有任何反应,只有一个口能使用鼠标. 经过查资料得知:android系统自动挂载U盘,与一个叫 vold.fstab的文件有关. 于是在公司自己的源码  android/ 目录下   find ./ -n

Ubuntu14.04配置Apache支持多个站点

怎样在一个Ubuntu的机器上(虚拟机)配置Apache支持多个网站呢? 比如你有一台独立的Ubuntu虚拟机,配有一个外网的IP(45.46.47.48),并且注册了两个域名AAA.com和BBB.com,将这两个域名DNS解析到你虚机的IP地址.假设你已经安装好了Apache,一切都是默认的设置. 我们需要在这一个server上面,同时host AAA.com,BBB.com 第一步:修改hosts文件 在Ubuntu系统中,hosts文件目录为/etc/hosts,可以用vi编辑 sudo

JBoss7配置之支持IPv4和IPv6双栈环境

由于实验室项目需要,将EJB 3.0的程序部署在JBoss AS 7.1.1.Final中,并要求支持IPv4与IPv6.但其默认配置并不支持IPv6,于是查阅JBoss Community Documentation,即官方文档,在5.4.1 Interfaces and ports节中找到了相关介绍,研究后对JBoss进行配置修改,使JBoss中EJB 3.0的程序能够在IPv4和IPv6双栈环境下正常运行,包括客户端在IPv4环境下获取Remote远程接口对象,调用远程对象的方法收发IPv

1虚拟机下U盘或磁盘挂载,Ubuntu下的网络配置,图形化界面和命令界面之间的切换,软件源配置

 一设置磁盘挂载(磁盘默认挂载到了/media目录下了) A:插入移动硬盘 B:对虚拟机进行设置(虚拟机->可移动设备àtoshibaExternal USB 3.0(这个是我的移动硬盘插上去之后显示的一项)à连接) 有时候出现以下现象 C:检测存储设备名称 sudofdisk –l E:挂载存储设备sdb1到挂载点/mnt目录下 sudomount /dev/sdb1 /mnt F:访问/mnt cd/mnt G:卸载/mnt sudo umount /mnt 二虚拟机下U盘或磁盘挂载,步

配置nginx支持thinkphp框架

因为nginx本身没有支持pathinfo,所以无法使用thinkphp框架,不过我们可以在配置里进行修改使其能够正常使用thinkphp. 1.修改配置支持pathinfo vi /etc/nginx/cong.d/default.conf 在nginx的配置中添加 location ~ \.php/?.*$ {      root html;         #这里的路径需要注意一下,自己之前几次配置错误都是因为从网上直接粘贴的路径不对        fastcgi_pass   127.0

四、配置nginx支持php

                                四.配置nginx支持php     在Ubuntu下搭建LNMP环境.编译安装mysql,nginx,php.最后在LNMP前提下安装composer,并且安装laravel框架.第四步,配置nginx支持php. 首先建立存放网页文件的目录,执行"sudo mkdri /usr/local/server/www".然后进入到该目录中,"cd/usr/local/server/www". 修改ngin