详解Linux实现U盘自动挂载(图文教程)
1.当我们每次插入u盘后,都会自动创键U盘的设备节点/dev/sda%d 这是因为里面调用了device_create()实现的,busybox的mdev机制就会根据主次设备号等信息,在/dev下创建设备节点,如下图所示: 而想使用上面的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>] 各个参数代表的含义如下: deviceregex: 正则表达式,来表达哪一个设备,正则表达式讲解链接:https://deerchao.net/tutorials/regex/regex.htm uid: owner (uid,gid:注册设备节点时,就会被chown命令调用,来改变设备的属主,默认都填0即可) gid: 组ID octalpermissions: 以八进制表示的权限值,会被chmod命令调用,来更改设备的访问权限,默认填660即可 @ :创建设备节点之后执行命令 $ : 删除设备节点之前执行命令 * :创建设备节点之后和删除设备节点之前执行命令 command :要执行的命令 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盘,如下图所示: 输入ls /dev/sda1 -l,可以看到都是通过mdev.conf里配置信息来创建的设备节点,如下图所示: 而取出u盘时,同样自动umount /mnt来卸载。 总结 以上所述是小编给大家介绍的Linux实现U盘自动挂载,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对编程小技巧网站的支持! (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |