详解Linux实现U盘⾃动挂载(图⽂教程)
1.当我们每次插⼊u盘后,都会⾃动创键U盘的设备节点/dev/sda%d
这是因为⾥⾯调⽤了device_create()实现的, busybox的mdev机制就会根据主次设备号等信息,在/dev下创建设备节点,如下图所⽰:
⽽想使⽤上⾯的sda1设备节点,读写数据时,还需要使⽤mount /dev/sda1 /mnt,来挂载u盘才⾏,会显得⾮常⿇烦,如下图所⽰:
2.其实,可以在/f⽂件⾥加⼊⼀⾏语句就能实现⾃动装载u盘,也可以在⾥⾯⼲其它与设备节点相关的事
2.1⽽/f⼜是什么?
它是属于mdev的⼀个配置⽂件,⽽mdev之前就讲过了,它主要的功能是管理/dev⽬录底下的设备节点
当系统中有⾃动注册设备节点的时候,mdev就会调⽤/f⼀次, 该⽂件可以实现与设备节点相关的事,⽐如⾃动装载usb,打印创建的设备节点信息等
3.我们⾸先来分析device_create(),是如何来调⽤到/f的,后⾯再讲如何使⽤f(也可以直接跳过,直接看下⾯第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       //类名
linux字符串转数组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/⽬录下的
/* 如果配置了⽀持f选项,那么就解析⾥边内容并执⾏ */
if (ENABLE_FEATURE_MDEV_CONF) {
/* mmap the config file */
fd = open("/f", O_RDONLY);  //调⽤/f配置⽂件
    ... ...  //开始操作 f配置⽂件
}
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");
/*若配置了⽀持f选项,则调⽤chown命令来改变属主,默认uid和gid=0 */
if (ENABLE_FEATURE_MDEV_CONF) chown(device_name, uid, gid);
}
if (delete) unlink(device_name);  //如果是卸载设备节点
}
从上⾯的代码和注释分析到,要使⽤f配置⽂件,还需要配置busybox的menuconfig, 使mdev⽀持f选项才⾏如下图,进⼊busybox⽬录,然后输⼊make menuconfig,发现我们已经配置过了该选项了
4.接下来,便来看看如何使⽤f, 参考busybox-1.7.0/⽂档
使⽤⽅法如下所⽰:
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>]
各个参数代表的含义如下:
deviceregex:
uid:
owner (uid,gid:注册设备节点时,就会被chown命令调⽤,来改变设备的属主,默认都填0即可)
gid:
组ID
octalpermissions:
以⼋进制表⽰的权限值,会被chmod命令调⽤,来更改设备的访问权限,默认填660即可
@ :创建设备节点之后执⾏命令
$ : 删除设备节点之前执⾏命令
* :创建设备节点之后和删除设备节点之前执⾏命令
command :要执⾏的命令
5.接下来便来使⽤f,实现u盘⾃动装载
vi /f
添加以下⼀句:
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便会进⼊/f配置⽂件,然后执⾏mount /dev/ 命令,即可⾃动装载U盘,如下图所⽰:
输⼊ls /dev/sda1 -l,可以看到都是通过f⾥配置信息来创建的设备节点,如下图所⽰:
⽽取出u盘时,同样⾃动umount /mnt来卸载。
总结
以上所述是⼩编给⼤家介绍的Linux实现U盘⾃动挂载,希望对⼤家有所帮助,如果⼤家有任何疑问请给我留⾔,⼩编会及时回复⼤家的。在此也⾮常感谢⼤家对⽹站的⽀持!

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。