免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
123下一页
最近访问板块 发新帖
查看: 8582 | 回复: 23
打印 上一主题 下一主题

[内核入门] 开一贴记录看mount源码的过程,欢迎大家拍砖 [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2012-05-23 20:00 |只看该作者 |倒序浏览
本帖最后由 testh 于 2012-05-31 15:30 编辑

写的不好的地方欢迎拍砖。
=========================================================
Busybox-1.9.1
在util-linux/mount.c的line:1609行首先映入眼帘的是:
int mount_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
由于busybox是一个box,里面包含很多的可执行程序,如果cp,mount,umount等我们常用的一些命令,所以每个命令单独写入一个文件,而每个文件中也用类似mount_main()这样的命名方法作为局部的main函数。
MAIN_EXTERNALLY_VISIBLE的定义在 busybox-1.9.1/include/libbb.h中
如下:
  1. /* We need to export XXX_main from libbusybox
  2. * only if we build "individual" binaries
  3. */
  4. #if ENABLE_FEATURE_INDIVIDUAL
  5. #define MAIN_EXTERNALLY_VISIBLE EXTERNALLY_VISIBLE
  6. #else
  7. #define MAIN_EXTERNALLY_VISIBLE
  8. #endif
  9. 而 EXTERNALLY_VISIBLE的定义在 busybox-1.9.1/include/platform.h中,line:73如下

  10. /* -fwhole-program makes all symbols local. The attribute externally_visible
  11.    forces a symbol global.  */
  12. # if __GNUC_PREREQ (4,1)
  13. #  define EXTERNALLY_VISIBLE __attribute__(( visibility("default") ));
  14. //__attribute__ ((__externally_visible__))
  15. # else
  16. #  define EXTERNALLY_VISIBLE
  17. # endif /* GNUC >= 4.1 */
复制代码
其中,__GNUC_PREREQ() 是什么意思呢? 在 busybox-1.9.1/include/platform.h,line:10
  1. /* Convenience macros to test the version of gcc. */
  2. #undef __GNUC_PREREQ
  3. #if defined __GNUC__ && defined __GNUC_MINOR__
  4. # define __GNUC_PREREQ(maj, min) \
  5. ((__GNUC__ << 16) + __GNUC_MINOR__ >= ((maj) << 16) + (min))
  6. #else
  7. # define __GNUC_PREREQ(maj, min) 0
  8. #endif
复制代码
首先取消  __GNUC_PREREQ原来的宏定义,然后再根据__GNUC__ 和__GNUC_MINOR__的情况重新定义 __GNUC_PREREQ。
#undef 是在后面取消以前定义的宏定义
其中, __GNUC__  是gcc编译器编译代码时预定义的一个宏,他的值表示当前GCC的版本号,可以通过查看gcc版确定一下。
然后 __GNUC_MINOR__的含义也就可以推出了。 The macro contains the minor version number of the compiler. This can be used to work around differences between different releases of the compiler. It must always be used together with __GNUC__.  

返回去看  
# if __GNUC_PREREQ (4,1)
其实就是看当前的GCC版本是否>=4.1然后再做下一步判断。
接下来的:
#define EXTERNALLY_VISIBLE __attribute__(( visibility("default" ));
重点在于:
__attribute__(( visibility("default" ));
通过这个链接:http://gcc.gnu.org/onlinedocs/gc ... ion-Attributes.html可知__attribute__ 的强大,可对变量,函数等symbols 对外的可见属性进行修改:

  1. visibility ("visibility_type")
  2. The visibility attribute on ELF targets causes the declaration to be emitted with default, hidden, protected or internal visibility.
  3.           void __attribute__ ((visibility ("protected")))
  4.           f () { /* Do something. */; }
  5.           int i __attribute__ ((visibility ("hidden")));
  6.      
  7. See the ELF gABI for complete details, but the short story is:
  8. default
  9. Default visibility is the normal case for ELF. This value is available for the visibility attribute to override other options that may change the assumed visibility of symbols.[软间隔]
  10. hidden
  11. Hidden visibility indicates that the symbol will not be placed into the dynamic symbol table, so no other module (executable or shared library) can reference it directly.[软间隔]
  12. internal
  13. Internal visibility is like hidden visibility, but with additional processor specific semantics. Unless otherwise specified by the psABI, GCC defines internal visibility to mean that the function is never called from another module. Note that hidden symbols, while they cannot be referenced directly by other modules, can be referenced indirectly via function pointers. By indicating that a symbol cannot be called from outside the module, GCC may for instance omit the load of a PIC register since it is known that the calling function loaded the correct value.[软间隔]
  14. protected
  15. Protected visibility indicates that the symbol will be placed in the dynamic symbol table, but that references within the defining module will bind to the local symbol. That is, the symbol cannot be overridden by another module.
  16. Not all ELF targets support this attribute.

复制代码
接下来

  1. /* parse long options, like --bind and --move.  Note that -o option
  2. * and --option are synonymous.  Yes, this means --remount,rw works. */

  3. for (i = j = 0; i < argc; i++)  
  4. {
  5. if (argv[i][0] == '-' && argv[i][1] == '-')  
  6. {
  7. append_mount_options(&cmdopts, argv[i]+2);
  8. }  
  9. else  
  10. {
  11. argv[j++] = argv[i];
  12. }
  13. }
  14. argv[j] = 0;
  15. argc = j;
复制代码
主要目的是解析命令行中的参数和选项,针对的是带有 "- -" 类型的长选项,实际上,- - 和 - 是一样的。主要是通过 append_mount_options()这个函数完成,进入 append_mount_options()。
其中,cmdopts是一个指针,它通过
char *cmdopts = xstrdup("",

busybox-1.9.1/util-linux/mount.c line:170

  1. /* Append mount options to string */
  2. static void append_mount_options(char **oldopts, const char *newopts)
  3. {
  4. if (*oldopts && **oldopts) {
  5. /* do not insert options which are already there */
  6. while (newopts[0]) {
  7. char *p;
  8. int len = strlen(newopts);
  9. p = strchr(newopts, ',');
  10. if (p) len = p - newopts;
  11. p = *oldopts;
  12. while (1) {
  13. if (!strncmp(p, newopts, len)
  14. && (p[len] == ',' || p[len] == '\0'))
  15. goto skip;
  16. p = strchr(p,',');
  17. if (!p) break;
  18. p++;
  19. }
  20. p = xasprintf("%s,%.*s", *oldopts, len, newopts);
  21. free(*oldopts);
  22. *oldopts = p;
  23. skip:
  24. newopts += len;
  25. while (newopts[0] == ',') newopts++;
  26. }
  27. } else {
  28. if (ENABLE_FEATURE_CLEAN_UP) free(*oldopts);
  29. *oldopts = xstrdup(newopts);
  30. }
  31. }
复制代码
未完待续。
之所以没有写完就贴上来,一是为了接受拍砖随时更正错误,二是为了自我监督。

当前更新时间:2012-05-31.有愿意共同研究的朋友可一同编写文档
mount-log_20120529.pdf (236.95 KB, 下载次数: 54)

评分

参与人数 1可用积分 +10 收起 理由
Godbach + 10 感谢分享

查看全部评分

论坛徽章:
16
2015亚冠之吉达阿赫利
日期:2015-08-17 11:21:462015年迎新春徽章
日期:2015-03-04 09:58:11酉鸡
日期:2014-12-07 09:06:19水瓶座
日期:2014-11-04 14:23:29天秤座
日期:2014-03-02 08:57:52双鱼座
日期:2014-02-22 13:07:56午马
日期:2014-02-14 11:08:18双鱼座
日期:2014-02-13 11:09:37卯兔
日期:2014-02-06 15:10:34子鼠
日期:2014-01-20 14:48:19戌狗
日期:2013-12-19 09:37:46射手座
日期:2013-12-19 09:33:47
2 [报告]
发表于 2012-05-23 20:24 |只看该作者
不懂,帮顶!

论坛徽章:
2
CU十二周年纪念徽章
日期:2013-10-24 15:41:34处女座
日期:2013-12-27 22:22:41
3 [报告]
发表于 2012-05-23 21:26 |只看该作者
无非是个解析参数的过程罢了。

论坛徽章:
0
4 [报告]
发表于 2012-05-24 07:13 |只看该作者
回复 3# tempname2


    是的

论坛徽章:
0
5 [报告]
发表于 2012-05-29 10:41 |只看该作者
近期遇到一个问题,就是在看busybox-1.9.1/util-linux/mount.c的时候,一直跟踪,发现最后竟是调用mount()来完成mount,就是说bash下的mount命令是通过调用mount()系统调用完成的,但是找了很多地方都没有找到系统的mount()在什么位置,有知道的朋友可否指点一下,先谢了。:wink:

论坛徽章:
0
6 [报告]
发表于 2012-05-29 10:45 |只看该作者
by the way: 2.6.14

论坛徽章:
0
7 [报告]
发表于 2012-05-29 10:56 |只看该作者
kernel\fs\namespace.c
SYSCALL_DEFINE5(mount, char __user *, dev_name, char __user *, dir_name,
                char __user *, type, unsigned long, flags, void __user *, data)

论坛徽章:
0
8 [报告]
发表于 2012-05-29 11:28 |只看该作者
senioryzc 发表于 2012-05-29 10:56
kernel\fs\namespace.c
SYSCALL_DEFINE5(mount, char __user *, dev_name, char __user *, dir_name,
                c ...


非常感谢

论坛徽章:
0
9 [报告]
发表于 2012-05-31 15:25 |只看该作者
2012-05-25 11:33
1747     if (!argc)                                                                                                                                 
1748     {   
1749         if (!(opt & OPT_ALL)) {
1750             FILE *mountTable = setmntent(bb_path_mtab_file, "r";
1751             printf("[%s:%d]bb_path_mtab_file=%s\n",__FILE__,__LINE__,bb_path_mtab_file);                                                        
1752            
1753             if (!mountTable) bb_error_msg_and_die("no %s", bb_path_mtab_file);                                                                  
1754            
1755             while (getmntent_r(mountTable, &mtpair[0], getmntent_buf,sizeof(getmntent_buf)))                                                   
1756             {   
1757                 // Don't show rootfs. FIXME: why??
1758                 // util-linux 2.12a happily shows rootfs...
1759                 //if (!strcmp(mtpair->mnt_fsname, "rootfs") continue;                                                                          
1760                 
1761                 if (!fstype || !strcmp(mtpair->mnt_type, fstype))                                                                              
1762                 {   
1763                     printf("%s on %s type %s (%s)\n", mtpair->mnt_fsname,mtpair->mnt_dir, mtpair->mnt_type,mtpair->mnt_opts);                  
1764                 }                                                                                                                              
1765             }
1766             if (ENABLE_FEATURE_CLEAN_UP)                                                                                                        
1767             {   
1768                 endmntent(mountTable);                                                                                                         
1769             }
1770             return EXIT_SUCCESS;                                                                                                               
1771         }                                                                                                                                       
1772     }
1773     else                                                                                                                                       
1774     {   
1775         storage_path = bb_simplify_path(argv[0]);                                                                                               
1776     }  
line:1755 line1765是依次从bb_path_mtab指向的文件中读取一行一行的数据,这些数据是 struct mntent格式的。Line1761 line1763是打印出来的信息,如在命令行下直接输入:mount则显示:
[zl@zhanglei ~]$ mount
proc on /proc type proc (rw,nosuid,nodev,noexec,relatime)
sysfs on /sys type sysfs (rw,nosuid,nodev,noexec,relatime,seclabel)
devtmpfs on /dev type devtmpfs (rw,nosuid,relatime,seclabel,size=956748k,nr_inodes=214073,mode=755)
devpts on /dev/pts type devpts (rw,nosuid,noexec,relatime,seclabel,gid=5,mode=620,ptmxmode=000)
tmpfs on /dev/shm type tmpfs (rw,nosuid,nodev,relatime,seclabel)
/dev/sda3 on / type ext4 (rw,relatime,seclabel,user_xattr,acl,barrier=1,data=ordered)
tmpfs on /run type tmpfs (rw,nosuid,nodev,relatime,seclabel,mode=755)
selinuxfs on /sys/fs/selinux type selinuxfs (rw,relatime)
tmpfs on /sys/fs/cgroup type tmpfs (rw,nosuid,nodev,noexec,relatime,seclabel,mode=755)
cgroup on /sys/fs/cgroup/systemd type cgroup (rw,nosuid,nodev,noexec,relatime,release_agent=/lib/systemd/systemd-cgroups-agent,name=systemd)
cgroup on /sys/fs/cgroup/cpuset type cgroup (rw,nosuid,nodev,noexec,relatime,cpuset)
cgroup on /sys/fs/cgroup/cpu,cpuacct type cgroup (rw,nosuid,nodev,noexec,relatime,cpuacct,cpu)
cgroup on /sys/fs/cgroup/memory type cgroup (rw,nosuid,nodev,noexec,relatime,memory)
cgroup on /sys/fs/cgroup/devices type cgroup (rw,nosuid,nodev,noexec,relatime,devices)
cgroup on /sys/fs/cgroup/freezer type cgroup (rw,nosuid,nodev,noexec,relatime,freezer)
cgroup on /sys/fs/cgroup/net_cls type cgroup (rw,nosuid,nodev,noexec,relatime,net_cls)
cgroup on /sys/fs/cgroup/blkio type cgroup (rw,nosuid,nodev,noexec,relatime,blkio)
cgroup on /sys/fs/cgroup/perf_event type cgroup (rw,nosuid,nodev,noexec,relatime,perf_event)
systemd-1 on /proc/sys/fs/binfmt_misc type autofs (rw,relatime,fd=21,pgrp=1,timeout=300,minproto=5,maxproto=5,direct)
mqueue on /dev/mqueue type mqueue (rw,relatime,seclabel)
debugfs on /sys/kernel/debug type debugfs (rw,relatime)
hugetlbfs on /dev/hugepages type hugetlbfs (rw,relatime,seclabel)
securityfs on /sys/kernel/security type securityfs (rw,relatime)
tmpfs on /media type tmpfs (rw,nosuid,nodev,noexec,relatime,rootcontext=system_ubject_r:mnt_t:s0,seclabel,mode=755)
sunrpc on /var/lib/nfs/rpc_pipefs type rpc_pipefs (rw,relatime)
/dev/sda5 on /mnt/sda5 type ext2 (rw,relatime,seclabel,user_xattr,acl,barrier=1)
/dev/sda6 on /mnt/sda6 type ext2 (rw,relatime,seclabel,user_xattr,acl,barrier=1)
binfmt_misc on /proc/sys/fs/binfmt_misc type binfmt_misc (rw,relatime)
fusectl on /sys/fs/fuse/connections type fusectl (rw,relatime)
gvfs-fuse-daemon on /home/zl/.gvfs type fuse.gvfs-fuse-daemon (rw,nosuid,nodev,relatime,user_id=1000,group_id=1000)
[zl@zhanglei ~]$
同时查看/etc/fstab的内容为:
[zl@zhanglei ~]$ cat /etc/fstab
#
# /etc/fstab
# Created by anaconda on Thu Dec  8 17:01:18 2011
#
# Accessible filesystems, by reference, are maintained under '/dev/disk'
# See man pages fstab(5), findfs(, mount( and/or blkid( for more info
#
UUID=a95fe862-ce64-485c-8bc6-10c3047b2fdb /                       ext4    defaults        1 1
UUID=869aca65-bf53-48e1-ab81-e6d2296cb818 swap                    swap    defaults        0 0
/dev/sda5                                 /mnt/sda5             ext2      defaults        1 1
/dev/sda6                                 /mnt/sda6               ext2    defaults        1 1
[zl@zhanglei ~]$ cat /proc/mounts
rootfs / rootfs rw 0 0
proc /proc proc rw,nosuid,nodev,noexec,relatime 0 0
sysfs /sys sysfs rw,seclabel,nosuid,nodev,noexec,relatime 0 0
devtmpfs /dev devtmpfs rw,seclabel,nosuid,relatime,size=956748k,nr_inodes=214073,mode=755 0 0
devpts /dev/pts devpts rw,seclabel,nosuid,noexec,relatime,gid=5,mode=620,ptmxmode=000 0 0
tmpfs /dev/shm tmpfs rw,seclabel,nosuid,nodev,relatime 0 0
tmpfs /run tmpfs rw,seclabel,nosuid,nodev,relatime,mode=755 0 0
/dev/sda3 / ext4 rw,seclabel,relatime,user_xattr,acl,barrier=1,data=ordered 0 0
tmpfs /run tmpfs rw,seclabel,nosuid,nodev,relatime,mode=755 0 0
selinuxfs /sys/fs/selinux selinuxfs rw,relatime 0 0
tmpfs /sys/fs/cgroup tmpfs rw,seclabel,nosuid,nodev,noexec,relatime,mode=755 0 0
cgroup /sys/fs/cgroup/systemd cgroup rw,nosuid,nodev,noexec,relatime,release_agent=/lib/systemd/systemd-cgroups-agent,name=systemd 0 0
cgroup /sys/fs/cgroup/cpuset cgroup rw,nosuid,nodev,noexec,relatime,cpuset 0 0
cgroup /sys/fs/cgroup/cpu,cpuacct cgroup rw,nosuid,nodev,noexec,relatime,cpuacct,cpu 0 0
cgroup /sys/fs/cgroup/memory cgroup rw,nosuid,nodev,noexec,relatime,memory 0 0
cgroup /sys/fs/cgroup/devices cgroup rw,nosuid,nodev,noexec,relatime,devices 0 0
cgroup /sys/fs/cgroup/freezer cgroup rw,nosuid,nodev,noexec,relatime,freezer 0 0
cgroup /sys/fs/cgroup/net_cls cgroup rw,nosuid,nodev,noexec,relatime,net_cls 0 0
cgroup /sys/fs/cgroup/blkio cgroup rw,nosuid,nodev,noexec,relatime,blkio 0 0
cgroup /sys/fs/cgroup/perf_event cgroup rw,nosuid,nodev,noexec,relatime,perf_event 0 0
systemd-1 /proc/sys/fs/binfmt_misc autofs rw,relatime,fd=21,pgrp=1,timeout=300,minproto=5,maxproto=5,direct 0 0
mqueue /dev/mqueue mqueue rw,seclabel,relatime 0 0
debugfs /sys/kernel/debug debugfs rw,relatime 0 0
hugetlbfs /dev/hugepages hugetlbfs rw,seclabel,relatime 0 0
securityfs /sys/kernel/security securityfs rw,relatime 0 0
tmpfs /media tmpfs rw,rootcontext=system_ubject_r:mnt_t:s0,seclabel,nosuid,nodev,noexec,relatime,mode=755 0 0
sunrpc /var/lib/nfs/rpc_pipefs rpc_pipefs rw,relatime 0 0
/dev/sda5 /mnt/sda5 ext2 rw,seclabel,relatime,user_xattr,acl,barrier=1 0 0
/dev/sda6 /mnt/sda6 ext2 rw,seclabel,relatime,user_xattr,acl,barrier=1 0 0
binfmt_misc /proc/sys/fs/binfmt_misc binfmt_misc rw,relatime 0 0
fusectl /sys/fs/fuse/connections fusectl rw,relatime 0 0
gvfs-fuse-daemon /home/zl/.gvfs fuse.gvfs-fuse-daemon rw,nosuid,nodev,relatime,user_id=1000,group_id=1000 0 0
也验证了mount是从/proc/mounts中读取的信息,这两个内容差不多。
2012-05-28 15:06
继续:
                                                                                                
1798     
1799     // When we have two arguments, the second is the directory and we can
1800     // skip looking at fstab entirely.  We can always abspath() the directory                                                                  
1801     // argument when we get it.                                                                                                                 
1802     
1803     if (argc == 2)                                                                                                                              
1804     {   
1805         if (nonroot)                                                                                                                           
1806         {   
1807             bb_error_msg_and_die(must_be_root);                                                                                                
1808         }
1809         mtpair->mnt_fsname = argv[0];                                                                                                           
1810         mtpair->mnt_dir = argv[1];                                                                                                              
1811         mtpair->mnt_type = fstype;
1812         mtpair->mnt_opts = cmdopts;
1813         printf("[%s:%d]...argv[0]=%s,argv[1]=%s,fstype=%s,cmdopts=%s\n",__FILE__,__LINE__,argv[0],argv[1],fstype,cmdopts);                     
1814         rc = singlemount(mtpair, 0);                                                                                                            
1815         goto clean_up;                                                                                                                          
1816     }                                                                                                                                          
1817     
接下来是对当参数为2的时候的处理。
Argc==2,通过上面的流程可知,到了当前的位置,只能是argc=2或者argc=1.
Line:1805root权限的检查。
line1809----line1813是将当前的有关mntent结构的参数复制到mtpairt中,然后调用singlemout().
这个函数就在mount.c中。
1510
1511 // Mount one directory.  Handles CIFS, NFS, loopback, autobind, and filesystem
1512 // type detection.  Returns 0 for success, nonzero for failure.
1513 // NB: mp->xxx fields may be trashed on exit
1514 static int singlemount(struct mntent *mp, int ignore_busy)
1515 {
1516     int rc = -1, vfsflags;
1517     char *loopFile = 0, *filteropts = 0;
1518     llist_t *fl = 0;
1519     struct stat st;
1520
1521     //filteropts为过滤指针
1522     vfsflags = parse_mount_options(mp->mnt_opts, &filteropts);
1523
1524     // Treat fstype "auto" as unspecified.
1525
1526     if (mp->mnt_type && strcmp(mp->mnt_type,"auto" == 0)
1527     {
1528         mp->mnt_type = 0;
1529     }
1530
1531     // Might this be a virtual filesystem?
1532
1533     if (ENABLE_FEATURE_MOUNT_HELPERS && (strchr(mp->mnt_fsname,'#')))
1534     {
1535         char *s, *p, *args[35];
1536         int n = 0;
1537         for (s = p = mp->mnt_fsname; *s && n < 35-3; ++s)
1538         {
1539             if (s[0] == '#' && s[1] != '#')
1540             {
1541                 *s = '\0';
1542                 args[n++] = p;
1543                 p = s + 1;
1544             }
1545         }
1546         args[n++] = p;
1547         args[n++] = mp->mnt_dir;
1548         args[n] = NULL;
1549         rc = wait4pid(xspawn(args));
1550         goto report_error;
1551     }
。。。。。。。

论坛徽章:
0
10 [报告]
发表于 2012-05-31 15:26 |只看该作者
line:1522 parse_mount_options();是对从命令行下输入的选项和参数的解析,这个接口有两个参数,一个就是mp->mnt_opts,令一个是filteropts,这是一个指针,将这个指针的地址作为参数传递给parser_mount_options()。

跟踪parser_mount_options()发现,他也在mount.c中,难道他们都是亲戚,全都住在附近。。。

240 /* Use the mount_options list to parse options into flags.

241  * Also return list of unrecognized options if unrecognized!=NULL */

242 static int parse_mount_options(char *options, char **unrecognized)

243 {   

244     int flags = MS_SILENT;

245         

246     // Loop through options

247     printf("[%s:%d]options=%s\n",__FILE__,__LINE__,options);

248     for (;;)

249     {      

250         int i;

251                 

252         char *comma = strchr(options, ',');     //从options中查找',',看是否有逗号,如上面的options=aaa,bbb,ccc,111,222,333,,nolock,在for()中

253                                                 //将会依次取出每个逗号分割的字符串

254         const char *option_str = mount_option_str;  //初始化mount_option_str字符串

255         

256         printf("[%s:%d] option_str=%s\n",__FILE__,__LINE__,option_str);

257         

258         if (comma)

259         {

260             printf("[%s:%d].comma=%s.options=%s\n",__FILE__,__LINE__,comma,options);

261             //*comma = '\0';

262             *comma=0x32;

263             printf("[%s:%d].comma=%s,options=%s\n",__FILE__,__LINE__,comma,options);

264

265         }

266      

267         // Find this option in mount_options

268         // 从options中查找option_str指向的字符串

269         // mount_options 与 mount_option_str是对应的关系

270         for (i = 0; i < ARRAY_SIZE(mount_options); i++)

271         {

272             printf("[%s:%d]option_str=%s,.....mount_options[%d]=0x%x\n",__FILE__,__LINE__,option_str,i,mount_options[i]);

273             if (!strcasecmp(option_str, options))

274             {

275                 //此时,option_str==options,我靠,竟然找到了

276                 long fl = mount_options[i];

277                 if (fl < 0)

278                 {

279                     flags &= fl;

280                     printf("[%s:%d]fl=%d\n",__FILE__,__LINE__,fl);

281                 }

282                 else

283                 {

284                     //将相应的标志置位

285                     flags |= fl;

286                     printf("[%s:%d]fl=%d\n",__FILE__,__LINE__,fl);

287                 }

288                 //退出循环

289                 break;

290             }

291             option_str += strlen(option_str) + 1;  //指向下一个字符串,从option_str中一个一个的取出来,然后与options比较

292         }

293         printf("[%s:%d]i=%d.........ARRAY_SIZE(mount_options)=%d\n",__FILE__,__LINE__,i,ARRAY_SIZE(mount_options));

294         // If unrecognized not NULL, append unrecognized mount options */

295         if (unrecognized && i == ARRAY_SIZE(mount_options))

296         {

297             // Add it to strflags, to pass on to kernel

298             i = *unrecognized ? strlen(*unrecognized) : 0;

299             printf("[%s:%d],i=%d\n",__FILE__,__LINE__,i);

300             *unrecognized = xrealloc(*unrecognized, i+strlen(options)+2);

301             printf("[%s:%d],i+strlen(options)+2=%d....options=%s...strlen(options)=%d\n",__FILE__,__LINE__,i+strlen(options)+2,options,strlen(options));

302

303             // Comma separated if it's not the first one

304             if (i)

305             {

306                 (*unrecognized)[i++] = ',';

307             }

308             strcpy((*unrecognized)+i, options);

309         }

310

311         if (!comma)

312         {

313             break;

314         }

315         // Advance to next option

316         printf("[%s:%d]comma=%s\n",__FILE__,__LINE__,comma);

317         *comma = ',';

318         printf("[%s:%d]comma=%s\n",__FILE__,__LINE__,comma);

319         options = ++comma;

320         printf("[%s:%d]options=%s\n",__FILE__,__LINE__,options);

321     }

322

323     return flags;

324 }

325

上面有一个是我作的注释。

这个函数的作用就是将options里面的字符串一个一个的拿出来,然后与mount合法的选项进行对比,看看是否有合法的选项,将不能识别的选项存起来。就这些。

其中有一个地方是关键,就是

252         char *comma = strchr(options, ',');

这个地方。主要是strchr()的用法。他的目的是从options指向的字符串中找出第一个','的地方,然后返回这个指针。也就是说comma和options其实指向相同地址的,知道这个关系下面的逻辑就好分析了。具体参考strchr()的实现代码:

linux-2.6.14/lib/string.h line:261

256 /**                                                                                                                                             

257  * strchr - Find the first occurrence of a character in a string                                                                                 

258  * @s: The string to be searched                                                                                                                 

259  * @c: The character to search for                                                                                                               

260  */                                                                                                                                             

261 char * strchr(const char * s, int c)                                                                                                            

262 {                                                                                                                                                

263   for(; *s != (char) c; ++s)                                                                                                                     

264     if (*s == '\0')                                                                                                                              

265       return NULL;                                                                                                                              

266   return (char *) s;                                                                                                                             

267 }                                                                                                                                                

268 EXPORT_SYMBOL(strchr);

其中,

254         const char *option_str = mount_option_str;  

所引用的mount_option_str的定义也在mount.c中。Line:121

121 static const char mount_option_str[] =

122     USE_FEATURE_MOUNT_LOOP(

123         "loop" "\0"

124     )      

125     USE_FEATURE_MOUNT_FSTAB(

126         "defaults" "\0"

127         /* "quiet" "\0" - do not filter out, vfat wants to see it */

128         "noauto" "\0"

129         "sw" "\0"

130         "swap" "\0"

131         USE_DESKTOP("user" "\0")

132         USE_DESKTOP("users" "\0")

133     )           

134     USE_FEATURE_MOUNT_FLAGS(

135         // vfs flags

136         "nosuid" "\0"

137         "suid" "\0"

138         "dev" "\0"

139         "nodev" "\0"

140         "exec" "\0"

141         "noexec" "\0"

142         "sync" "\0"

143         "async" "\0"

144         "atime" "\0"

145         "noatime" "\0"

146         "diratime" "\0"

147         "nodiratime" "\0"

148         "loud" "\0"

149            

150         // action flags

151         "bind" "\0"

152         "move" "\0"

153         "shared" "\0"

154         "slave" "\0"

155         "private" "\0"

156         "unbindable" "\0"

157         "rshared" "\0"

158         "rslave" "\0"

159         "rprivate" "\0"

160         "runbindable" "\0"

161     )

162

163     // Always understood.

164     "ro" "\0"        // vfs flag

165     "rw" "\0"        // vfs flag

166     "remount" "\0"   // action flag

167 ;

其中。1657 #define USE_FEATURE_MOUNT_LOOP(...) __VA_ARGS__的定义在

autoconf.h中。

而与static const char mount_optons_str[]对应的是static const int32_t mount_options[]

  69 static const int32_t mount_options[] = {

  70     // MS_FLAGS set a bit.  ~MS_FLAGS disable that bit.  0 flags are NOPs.

  71

  72     USE_FEATURE_MOUNT_LOOP(

  73         /* "loop" */ 0,

  74     )

  75

  76     USE_FEATURE_MOUNT_FSTAB(

  77         /* "defaults" */ 0,

  78         /* "quiet" 0 - do not filter out, vfat wants to see it */

  79         /* "noauto" */ MOUNT_NOAUTO,

  80         /* "sw"     */ MOUNT_SWAP,

  81         /* "swap"   */ MOUNT_SWAP,

  82         USE_DESKTOP(/* "user"  */ MOUNT_USERS,)

  83         USE_DESKTOP(/* "users" */ MOUNT_USERS,)

  84     )

  85

  86     USE_FEATURE_MOUNT_FLAGS(

  87         // vfs flags

  88         /* "nosuid"      */ MS_NOSUID,

  89         /* "suid"        */ ~MS_NOSUID,

  90         /* "dev"         */ ~MS_NODEV,

  91         /* "nodev"       */ MS_NODEV,

  92         /* "exec"        */ ~MS_NOEXEC,

  93         /* "noexec"      */ MS_NOEXEC,

  94         /* "sync"        */ MS_SYNCHRONOUS,

  95         /* "async"       */ ~MS_SYNCHRONOUS,

  96         /* "atime"       */ ~MS_NOATIME,

  97         /* "noatime"     */ MS_NOATIME,

  98         /* "diratime"    */ ~MS_NODIRATIME,

  99         /* "nodiratime"  */ MS_NODIRATIME,

100         /* "loud"        */ ~MS_SILENT,

101

102         // action flags

103         /* "bind"        */ MS_BIND,

104         /* "move"        */ MS_MOVE,

105         /* "shared"      */ MS_SHARED,

106         /* "slave"       */ MS_SLAVE,

107         /* "private"     */ MS_PRIVATE,

108         /* "unbindable"  */ MS_UNBINDABLE,

109         /* "rshared"     */ MS_SHARED|MS_RECURSIVE,

110         /* "rslave"      */ MS_SLAVE|MS_RECURSIVE,

111         /* "rprivate"    */ MS_SLAVE|MS_RECURSIVE,

112         /* "runbindable" */ MS_UNBINDABLE|MS_RECURSIVE,

113     )

114

115     // Always understood.

116     /* "ro"      */ MS_RDONLY,  // vfs flag

117     /* "rw"      */ ~MS_RDONLY, // vfs flag

118     /* "remount" */ MS_REMOUNT  // action flag

119 };

他们的暧昧关系显而易见。

接下来是对coma的修改,这个地方用了一个小技巧。

257

258         if (comma)

259         {

260             printf("[%s:%d].comma=%s.options=%s\n",__FILE__,__LINE__,comma,options);

261             //*comma = '\0';

262             *comma=0x32;

263             printf("[%s:%d].comma=%s,options=%s\n",__FILE__,__LINE__,comma,options);

264

265         }

上面的line:262是我自己改的,为了测试,原来的代码应该是261行。

比如以下命令执行:

./busybox mount --aaa,bbb,ccc --111,222,333 -t nfs -o nolock /dev/hda1 /hqdata/hda1

此时, char *comma = strchr(options, ',');之后,

options=aaa,bbb,ccc,111,222,333,nolock

[util-linux/mount.c:260].comma=,bbb,ccc,111,222,333,nolock.options=aaa,bbb,ccc,111,222,333,nolock

[util-linux/mount.c:263].comma=2bbb,ccc,111,222,333,nolock,options=aaa2bbb,ccc,111,222,333,nolock

注意,260和263的两个地方,红色的2的那个地方,本来那个地方应该是*comma='\0',也就是字符串的结束符,同时因为comma和options都指向同一个地址,所以,这个操作也将options改成options=aaa,而不是opionts=aaa2bbb,ccc,111,222,333,nolock,将逗号后面的都截断了。完了之后,经过层层处理之后,再将他复原。

315         // Advance to next option

316         printf("[%s:%d]comma=%s\n",__FILE__,__LINE__,comma);

317         *comma = ',';

318         printf("[%s:%d]comma=%s\n",__FILE__,__LINE__,comma);

319         options = ++comma;

320         printf("[%s:%d]options=%s\n",__FILE__,__LINE__,options);

即 line:317和 line:319.

复原之后,再回到strchr()那里,重复运行,此时options=bbb了,然后再对比option_str中,看有没有bbb这个选项,显然是没有的。

267         // Find this option in mount_options

268         // 从options中查找option_str指向的字符串

269         // mount_options 与 mount_option_str是对应的关系

270         for (i = 0; i < ARRAY_SIZE(mount_options); i++)

271         {

272             printf("[%s:%d]option_str=%s,.....mount_options[%d]=0x%x\n",__FILE__,__LINE__,option_str,i,mount_options[i]);

273             if (!strcasecmp(option_str, options))

274             {

275                 //此时,option_str==options,我靠,竟然找到了

276                 long fl = mount_options[i];

277                 if (fl < 0)

278                 {

279                     flags &= fl;

280                     printf("[%s:%d]fl=%d\n",__FILE__,__LINE__,fl);

281                 }

282                 else

283                 {

284                     //将相应的标志置位

285                     flags |= fl;

286                     printf("[%s:%d]fl=%d\n",__FILE__,__LINE__,fl);

287                 }

288                 //退出循环

289                 break;

290             }

291             option_str += strlen(option_str) + 1;  //指向下一个字符串,从option_str中一个一个的取出来,然后与options比较

292         }

没有就没有吧,没有的话就会导致i达到ARRAY_SIZE(mount_options)

294         if (unrecognized && i == ARRAY_SIZE(mount_options))

295         {

296             // Add it to strflags, to pass on to kernel

297             i = *unrecognized ? strlen(*unrecognized) : 0;

298             printf("[%s:%d],i=%d\n",__FILE__,__LINE__,i);

299             *unrecognized = xrealloc(*unrecognized, i+strlen(options)+2);

300             printf("[%s:%d],i+strlen(options)+2=%d....options=%s...strlen(options)=%d\n",__FILE__,__LINE__,i+strlen(options)+2,options,strlen(options));
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP