Linux Command Line 解析

0 处理模型

Linux kernel的启动包括很多组件的初始化和相关配置,这些配置参数一般是通过command line进行配置的。在进行后续分析之前,先来理解一下command line的处理模型:
要处理的对象是一个字符串,其中包含了各种配置信息,通常各个配置之间通过空格进行分离,每个配置的表达形式是如:param=value1,value2 或者很简单就是一个rw。
那么kernel就需要提供对这些参数进行处理的处理函数列表。根据参数的作用以及执行期的先后不同,这些处理函数被定义到不同的段中。针对每一个参数,Kernel都会到相应的段中查找相应的处理函数,最终进行各个组件的配置。

1 配置格式

常见的配置格式如:
 
console=ttySAC0,115200 root=nfs nfsroot=192.168.1.9:/source/rootfs initrd=0x10800000,0x14af47
 

2 配置方式

2.1 Bootloader动态配置

由bootloader进行参数配置,command line将做为atag_list的一个节点传递到Kernel。

2.2 Kernel静态配置

通过make menuconfig进行配置:运行后配置boot options->Default kernel command string。该配置将被静态编译到Kernel中,通过变量default_command_line访问。

3  解析配置

3.1 相关定义

根据执行的先后顺序,可以将处理函数分为三个大类,他们分别存在于下面三个段中(参考top/arch/arm/kernel/vmlinux.lds):
 
__setup_start = .; *(.init.setup) __setup_end = .;
 
__early_begin = .; *(.early_param.init) __early_end = .;
 
__start___param = .; *(__param) __stop___param = .;
 
这三个段内存储的不是参数,而是command line参数所需要的处理函数。

3.1.1 .early_param.init段

“.early_param.init”所定义的处理相对靠前一些,它所处理的参数例如:initrd=,cachepolicy=,nocache, nowb, ecc=, vmalloc=, mem=,等等。
这些处理函数是通过__early_param宏来定义的,例如:
static void __init early_initrd(char **p)
{ …… }
__early_param("initrd=", early_initrd);
对于宏__early_param,可以在top/arch/arm/include/asm/Setup.h中找到如下定义:
 
struct early_params {
    const char *arg;
    void (*fn)(char **p);
};
#define __early_param(name,fn) \
static struct early_params __early_##fn __used \
__attribute__((__section__(".early_param.init"))) = { name, fn }
 
 
3.1.2 .init.setup
 
“.init.setup”定义的处理则要靠后一些,它所处理的参数例如:nfsroot=, ip=,等等。
这些处理函数是通过__setup宏来定义的,例如:
 
static int __init nfs_root_setup(char *line)
{ …… }
__setup("nfsroot=", nfs_root_setup);
 
对于宏__setup,可以在top/include/linux/Init.h中看到:
 
#define __setup_param(str, unique_id, fn, early) \
    static char __setup_str_##unique_id[] __initdata __aligned(1) = str; \
    static struct obs_kernel_param __setup_##unique_id \
           __used __section(.init.setup) \
           __attribute__((aligned((sizeof(long))))) \
           = { __setup_str_##unique_id, fn, early }

#define __setup(str, fn) \
    __setup_param(str, fn, fn, 0)

/* NOTE: fn is as per module_param, not __setup! Emits warning if fn
 * returns non-zero. */
#define early_param(str, fn) \
    __setup_param(str, fn, fn, 1)

 
注意看的话,可以看到还有一个宏 early_param,它与宏__setup的定义相似,只不过最后一个宏参数是1而不是0。1表示需要提前处理的参数。

3.1.3  __param段

这个段中保存的是build-in类型module的配置参数。该宏直接用来修饰需要的变量。

3.2  解析

3.2.1 相关变量

相关的变量包括:
default_command_line
保存memuconfig配置的参数,如果bootloader传入了命令行参数,那么这个新的配置将被更新到该变量中。
boot_command_line
存在于.init.data段。最初是default_command_line的拷贝。
command_line
存在于.init.data段。在parse_cmdline()中被赋值,数据来源是default_command_line。
saved_command_line
用于保存没有处理过的命令行参数,是boot_caommand_line的拷贝。
static_command_line
是command_line的拷贝。

3.2.2 主要函数

函数名称:parse_cmdline()
操作数据:default_command_line
函数列表:.early_param.init段(在__early_begin和__early_end之间)。
函数功能:依据函数列表对default_command_line中的参数进行处理。
 
 
函数名称:parse_early_param()
操作数据:boot_command_line
函数列表:.init.setup段中(__setup_start和__setup_end之间),主要是通过宏early_param定义的部分。
函数功能:依据函数列表对boot_command_line中的参数进行处理。
注意parse_one()的第四个入参是0,而且第五个参数是NULL。这里没有给出参数队列,不会对boot_command_line的每个参数在参数队列中进行对比查找,而是直接在do_early_param()中进行条件判断,如果满足下面的条件,那么对该参数进行对应的操作:
 
if ((p->early && strcmp(param, p->str) == 0) ||
                  (strcmp(param, "console") == 0 &&
                   strcmp(p->str, "earlycon") == 0)
              )
 
 
函数名称:parse_args()
操作数据:static_command_line
函数列表:__param段(__start___param和__stop___param之间)。
函数功能:该操作将依据函数列表,对static_command_line中的参数进行相应的操作。这个操作在parse_one()的第一部分代码完成:
 
for (i = 0; i < num_params; i++) {
          if (parameq(param, params[i].name)) {
                 DEBUGP("They are equal! Calling %p\n",
                        params[i].set);
                 return params[i].set(val, ¶ms[i]);
          }
   }
 
接下来对于不被这个列表所支持的参数,将在unknown_bootoption()中进行处理。在unknown_bootoption()中主要是obsolete_checksetup()的操作。
 
 
函数名称:obsolete_checksetup()
操作数据:static_command_line
函数列表:.init.setup段中(__setup_start和__setup_end之间),主要是通过宏__setup定义的部分。
函数功能:该操作将依据函数列表,对static_command_line中的参数进行相应的操作。如果是在parse_early_param()中已经处理的操作,那么这里不再处理;如果是查找到的条目中没有操作函数,那么这表示是过时的数据定义(有些早期的代码,没有定义这个函数);如果不是以上两种情形,那么利用找到的函数对参数进行处理。

Linux Command Line 解析的更多相关文章

  1. 《The Linux Command Line》 读书笔记04 Linux用户以及权限相关命令

    Linux用户以及权限相关命令 查看身份 id:Display user identity. 这个命令的输出会显示uid,gid和用户所属的组. uid即user ID,这是账户创建时被赋予的. gi ...

  2. 《The Linux Command Line》 读书笔记02 关于命令的命令

    <The Linux Command Line> 读书笔记02 关于命令的命令 命令的四种类型 type type—Indicate how a command name is inter ...

  3. 《The Linux Command Line》 读书笔记01 基本命令介绍

    <The Linux Command Line> 读书笔记01 基本命令介绍 1. What is the Shell? The Shell is a program that takes ...

  4. Linux Command Line Basics

    Most of this note comes from the Beginning the Linux Command Line, Second Edition by Sander van Vugt ...

  5. 15 Examples To Master Linux Command Line History

    When you are using Linux command line frequently, using the history effectively can be a major produ ...

  6. 10 Interesting Linux Command Line Tricks and Tips Worth Knowing

    I passionately enjoy working with commands as they offer more control over a Linux system than GUIs( ...

  7. Reso | The Linux Command Line 的中文版

    http://book.haoduoshipin.com/tlcl/book/zh/ 本书是 The Linux Command Line 的中文版, 为大家提供了多种不同的阅读方式. 中英文双语版- ...

  8. [笔记]The Linux command line

    Notes on The Linux Command Line (by W. E. Shotts Jr.) edited by Gopher 感觉博客园是不是搞了什么CSS在里头--在博客园显示效果挺 ...

  9. Linux Command Line(II): Intermediate

    Prerequisite: Linux Command Line(I): Beginner ================================ File I/O $ cat > a ...

随机推荐

  1. [转]ubuntu server上网配置

    [转]ubuntu server上网配置 http://blog.sina.com.cn/s/blog_6c9d65a101011pyt.html 今天我的ubuntu server上不去网了,所以重 ...

  2. 44.do文件格式

    style1: transcript onif {[file exists rtl_work]} {<span style="white-space:pre"> < ...

  3. WIN7笔记本利用命令AP热点

    第一步:以管理员身份运行命令提示符:开始”---搜索栏输入“cmd----右键以“管理员身份运行”自己随便命名,第二步:运行命令:netsh wlan set hostednetwork mode=a ...

  4. mongodb修改器

    mongodb修改器 转载自:http://blog.csdn.net/mcpang/article/details/7752736 mongodb修改器(\(inc/\)set/\(unset/\) ...

  5. Ubuntu 部署 Redmine

    我是在虚拟机种安装的Ubuntu,原因是装双系统太麻烦,虚拟机有问题的话删除容易. 首选保证主机中能ping 通虚拟机.我是用的桥接. 1.ubuntu安装必备的软件: sudo apt-get in ...

  6. Posix线程编程指南(2) 线程私有数据

    概念及作用 在单线程程序中,我们经常要用到"全局变量"以实现多个函数间共享数据.在多线程环境下,由于数据空间是共享的,因此全局变量也为所有线程所共有.但有时应用程序设计中有必要提供 ...

  7. bzoj 3142 数学

    找规律后可以之后答案就是 k^(m-1)*(n-(m-1)*k)+(m+(m-1)*k+1)*k^(m-1) div 2 /************************************** ...

  8. go lang学习笔记——channel机理及调度理解

    <Go语言编程>一书介绍了libtask库,可以认为这个库等同于go的底层goroutine实现. libtask库的channel的数据结构如下: struct Alt { Channe ...

  9. mysql查看连接数和状态,设置连接数和超时时间

    1.mysql> show status like '%connect%'; Connections,试图连接到(不管是否成功)MySQL服务器的连接数.   Max_used_connecti ...

  10. Oracle 导入导出数据 imp/exp impdp/expdp

    IMPDP/EXPDP 一.创建逻辑目录,该命令不会在操作系统创建真正的目录,最好以system等管理员创建.         create directory dpdata as '/opt'; 二 ...