mount源码分析 【转】

简介: 转自:http://blog.chinaunix.net/uid-10769062-id-3230811.html 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函数。

转自:http://blog.chinaunix.net/uid-10769062-id-3230811.html

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中
如下:
/* We need to export XXX_main from libbusybox
 * only if we build "individual" binaries
 */
#if ENABLE_FEATURE_INDIVIDUAL
#define MAIN_EXTERNALLY_VISIBLE EXTERNALLY_VISIBLE
#else
#define MAIN_EXTERNALLY_VISIBLE
#endif
而 EXTERNALLY_VISIBLE的定义在 busybox-1.9.1/include/platform.h中,line:73如下
 
/* -fwhole-program makes all symbols local. The attribute externally_visible
   forces a symbol global.  */
# if __GNUC_PREREQ (4,1)
#  define EXTERNALLY_VISIBLE __attribute__(( visibility("default") ));
//__attribute__ ((__externally_visible__))
# else
#  define EXTERNALLY_VISIBLE
# endif /* GNUC >= 4.1 */
 
其中,__GNUC_PREREQ() 是什么意思呢? 在 busybox-1.9.1/include/platform.h,line:10
/* Convenience macros to test the version of gcc. */
#undef __GNUC_PREREQ
#if defined __GNUC__ && defined __GNUC_MINOR__
# define __GNUC_PREREQ(maj, min) \
              ((__GNUC__ << 16) __GNUC_MINOR__ >= ((maj) << 16) (min))
#else
# define __GNUC_PREREQ(maj, min) 0
#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/gcc-4.0.0/gcc/Function-Attributes.html可知__attribute__ 的强大,可对变量,函数等symbols 对外的可见属性进行修改:
visibility ("visibility_type")
The visibility attribute on ELF targets causes the declaration to be emitted with default, hidden, protected or internal visibility.
          void __attribute__ ((visibility ("protected")))
          f () { /* Do something. */; }
          int i __attribute__ ((visibility ("hidden")));
   
See the ELF gABI for complete details, but the short story is:
default
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.

hidden
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.

internal
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.

protected
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.
Not all ELF targets support this attribute.
 
 
接下来
       /* parse long options, like --bind and --move.  Note that -o option
        * and --option are synonymous.  Yes, this means --remount,rw works. */
 
       for (i = j = 0; i < argc; i )
       {
              if (argv[i][0] == '-' && argv[i][1] == '-')
              {
                     append_mount_options(&cmdopts, argv[i] 2);
              }
              else
              {
                     argv[j ] = argv[i];
              }
       }
       argv[j] = 0;
       argc = j;
主要目的是解析命令行中的参数和选项,针对的是带有 "- -" 类型的长选项,实际上,- - 和 - 是一样的。主要是通过 append_mount_options()这个函数完成,进入 append_mount_options()。
其中,cmdopts是一个指针,它通过
char *cmdopts = xstrdup(""),
 
busybox-1.9.1/util-linux/mount.c line:170
 
/* Append mount options to string */
static void append_mount_options(char **oldopts, const char *newopts)
{
       if (*oldopts && **oldopts) {
              /* do not insert options which are already there */
              while (newopts[0]) {
                     char *p;
                     int len = strlen(newopts);
                     p = strchr(newopts, ',');
                     if (p) len = p - newopts;
                     p = *oldopts;
                     while (1) {
                            if (!strncmp(p, newopts, len)
                             && (p[len] == ',' || p[len] == '\0'))
                                   goto skip;
                            p = strchr(p,',');
                            if (!p) break;
                            p ;
                     }
                     p = xasprintf("%s,%.*s", *oldopts, len, newopts);
                     free(*oldopts);
                     *oldopts = p;
 skip:
                     newopts = len;
                     while (newopts[0] == ',') newopts ;
              }
       } else {
              if (ENABLE_FEATURE_CLEAN_UP) free(*oldopts);
              *oldopts = xstrdup(newopts);
       }
}
 
 
 
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_u:object_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(8), mount(8) and/or blkid(8) for more info
#
UUID=a95fe862-ce64-485c-8bc6-10c3047b2fdb /                       ext4    defaults        1 1
UUID=869aca65-bf53-48e1-ab81-e6d2296cb818 swap                    swap   

 

【作者】 张昺华
【新浪微博】 张昺华--sky
【twitter】 @sky2030_
【facebook】 张昺华 zhangbinghua
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利.
目录
相关文章
|
存储 缓存 Linux
free命令详解
`free`命令在Linux中显示内存使用详情,包括总内存(`total`)、已用(`used`,含缓存`buffers/cache`)、空闲(`free`)、共享(`shared`)和可用(`available`)内存。交换空间显示其总量、使用量和剩余量。`-h`选项以易读格式显示,`-m`以MB显示,`-t`显示总和,`-s`定时刷新。例如,`free -ht 5`每5秒更新内存和交换空间的总览。
506 3
|
安全 API 数据安全/隐私保护
微服务的安全性考虑
【8月更文第29天】随着微服务架构的流行,确保这些服务的安全性成为了系统设计中的一个关键因素。本文将探讨微服务环境下如何确保数据安全、API 安全以及网络通信的安全,并提供相应的代码示例。
286 1
|
2月前
|
安全 Shell Linux
深入剖析Sudo提权:白帽子的防御视角与审计指南
本文深入解析Linux系统中`sudo`提权的常见手法,从白帽子视角出发,剖析攻击原理并提供实用防御与审计策略,助力加固系统权限安全。
389 1
|
8月前
|
存储 人工智能 自然语言处理
智能系统的知识库管理技术
本方案聚焦智能系统的知识库管理,深度融合AI技术与精细化流程控制。通过多模态数据统一存储,实现文本、语音、图像等全格式兼容与智能解析;构建全流程内容管理体系,涵盖创建、审核、更新环节,确保信息精准可靠;提供智能标签分类、版本追溯功能,支持秒级定位与历史对比;采用语义检索技术,打破数据孤岛,助力企业高效利用与优化知识资产,保障安全存储及持续增值。
386 1
|
网络协议 Linux 网络安全
如何用阿里云实现内网穿透?如何在外网访问家里内网设备?
使用NPS自建内网穿透服务器教程,带WEB管理
35616 12
|
关系型数据库 MySQL
MySQL 8.0 - Authentication plugin ‘caching_sha2_password‘ cannot be loaded 原因及解决办法
MySQL 8.0 - Authentication plugin ‘caching_sha2_password‘ cannot be loaded 原因及解决办法
433 1
Sublime Text 16进制显示
Sublime Text 16进制显示
875 0
|
安全 网络协议 网络虚拟化
|
运维 安全 网络安全
|
存储 监控 Linux
在 CentOS 7 中如何对新硬盘进行分区、格式化、挂载及配置最佳实践
本文详细介绍了在 CentOS 7 中如何对新硬盘进行分区、格式化、挂载及配置最佳实践,包括使用 `fdisk` 创建分区、`mkfs` 格式化分区、创建挂载点、编辑 `/etc/fstab` 实现永久挂载等步骤,旨在有效管理服务器磁盘空间,提高系统稳定性和可维护性。
2782 1