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函数。
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则显示:

[[email protected] ~]$ 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)
[[email protected] ~]$

同时查看/etc/fstab的内容为:

[[email protected] ~]$ 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   
时间: 2024-08-01 18:14:07

mount源码分析 【转】的相关文章

【React源码分析】组件通信、refs、key和ReactDOM

React源码系列文章,请多支持:React源码分析1 - 组件和对象的创建(createClass,createElement)React源码分析2 - React组件插入DOM流程React源码分析3 - React生命周期详解React源码分析4 - setState机制React源码分析5 -- 组件通信,refs,key,ReactDOMReact源码分析6 - React合成事件系统 1 组件间通信 父组件向子组件通信 React规定了明确的单向数据流,利用props将数据从父组件传

openstack swift 源码分析之swift单机部署

本文对在单机部署swift 其中每一个细节做详细的介绍,并对配置做相应的解释 PC物理机    Ubuntu-12.04-desktop-64位 Swift 版本:1.13.1 Swift-client   1.2.0 注意:本文所有操作都是在root权限下进行的. 1 .下载swift 和swift-client 源代码,本文利用git从github获取其源代码 获取swift源代码 git clone https://github.com/openstack/swift.git 获取pyth

Android 上千实例源码分析以及开源分析

Android 上千实例源码分析以及开源分析(百度云分享) 要下载的直接翻到最后吧,项目实例有点多. 首先 介绍几本书籍(下载包中)吧. 01_Android系统概述 02_Android系统的开发综述 03_Android的Linux内核与驱动程序 04_Android的底层库和程序 05_Android的JAVA虚拟机和JAVA环境 06_Android的GUI系统 07_Android的Audio系统 08_Android的Video 输入输出系统 09_Android的多媒体系统 10_

Docker源码分析(九):Docker镜像

1.前言 回首过去的2014年,大家可以看到Docker在全球刮起了一阵又一阵的“容器风”,工业界对Docker的探索与实践更是一波高过一波.在如今的2015年以及未来,Docker似乎并不会像其他昙花一现的技术一样,在历史的舞台上热潮褪去,反而在工业界实践与评估之后,显现了前所未有的发展潜力. 究其本质,“Docker提供容器服务”这句话,相信很少有人会有异议.那么,既然Docker提供的服务属于“容器”技术,那么反观“容器”技术的本质与历史,我们又可以发现什么呢?正如前文所提到的,Docke

Solr初始化源码分析-Solr初始化与启动

用solr做项目已经有一年有余,但都是使用层面,只是利用solr现有机制,修改参数,然后监控调优,从没有对solr进行源码级别的研究.但是,最近手头的一个项目,让我感觉必须把solrn内部原理和扩展机制弄熟,才能把这个项目做好.今天分享的就是:Solr是如何启动并且初始化的.大家知道,部署solr时,分两部分:一.solr的配置文件.二.solr相关的程序.插件.依赖lucene相关的jar包.日志方面的jar.因此,在研究solr也可以顺着这个思路:加载配置文件.初始化各个core.初始化各个

TeamTalk源码分析之login_server

login_server是TeamTalk的登录服务器,负责分配一个负载较小的MsgServer给客户端使用,按照新版TeamTalk完整部署教程来配置的话,login_server的服务端口就是8080,客户端登录服务器地址配置如下(这里是win版本客户端): 1.login_server启动流程 login_server的启动是从login_server.cpp中的main函数开始的,login_server.cpp所在工程路径为server\src\login_server.下表是logi

Android触摸屏事件派发机制详解与源码分析二(ViewGroup篇)

1 背景 还记得前一篇<Android触摸屏事件派发机制详解与源码分析一(View篇)>中关于透过源码继续进阶实例验证模块中存在的点击Button却触发了LinearLayout的事件疑惑吗?当时说了,在那一篇咱们只讨论View的触摸事件派发机制,这个疑惑留在了这一篇解释,也就是ViewGroup的事件派发机制. PS:阅读本篇前建议先查看前一篇<Android触摸屏事件派发机制详解与源码分析一(View篇)>,这一篇承接上一篇. 关于View与ViewGroup的区别在前一篇的A

HashMap与TreeMap源码分析

1. 引言     在红黑树--算法导论(15)中学习了红黑树的原理.本来打算自己来试着实现一下,然而在看了JDK(1.8.0)TreeMap的源码后恍然发现原来它就是利用红黑树实现的(很惭愧学了Java这么久,也写过一些小项目,也使用过TreeMap无数次,但到现在才明白它的实现原理).因此本着"不要重复造轮子"的思想,就用这篇博客来记录分析TreeMap源码的过程,也顺便瞅一瞅HashMap. 2. 继承结构 (1) 继承结构 下面是HashMap与TreeMap的继承结构: pu

Linux内核源码分析--内核启动之(5)Image内核启动(rest_init函数)(Linux-3.0 ARMv7)【转】

原文地址:Linux内核源码分析--内核启动之(5)Image内核启动(rest_init函数)(Linux-3.0 ARMv7) 作者:tekkamanninja 转自:http://blog.chinaunix.net/uid-25909619-id-4938395.html 前面粗略分析start_kernel函数,此函数中基本上是对内存管理和各子系统的数据结构初始化.在内核初始化函数start_kernel执行到最后,就是调用rest_init函数,这个函数的主要使命就是创建并启动内核线