概述本文简单分析了init进程的源码,梳理了它的处理流程,重点介绍了init进程是如何启动应用的,并总结了启动脚本的编写思路文件。init进程源码分析init进程如何知道linux内核启动的第一个进程?从内核源码linux-2.6.xxx/init/main.c的kernel_init()函数分析可以发现,内核会根据uboot传入的参数启动第一个进程。一般init是怎么启动的呢?调用kernel_execve()函数完成。猜测是从根文件系统的/sbin/init启动的。Linux中的任何应用程序都是基于文件系统的。启动应用程序的前提条件是已经挂载了根文件系统。好的,那么根文件系统是从哪里来的呢?它是由工具busybox编译生成的,所以要分析init源码,去busybox找到init的源码源位置:/busybox/init/init.c,在里面找到main()函数,并发现只有init_main(),没有main()。可以猜测是busybox通过一些方法修改了init进程的入口为init_main()。其实busybox的所有命令工具都是一个busybox程序。cd/sbinls-linitlrwxrwxrwx1root014Nov162016init->../bin/busybox可以看到init进程其实是一个busybox的链接。别担心。你知道init进程的入口是init_main()函数在#ifDEBUG_SEGV_HANDLER{structsigactionsa;memset(&sa,0,sizeof(sa));sa.sa_sigaction=handle_sigsegv;sa.sa_flags=SA_SIGINFO;sigaction(SIGSEGV,&sa,NULL);......}#endif......console_init();set_sane_term();....../*确保environs设置为合理的*/putenv((char*)"HOME=/");putenv((char*)bb_PATH_root_path);putenv((char*)"SHELL=/bin/sh");putenv((char*)"USER=root");/*需要吗?为什么?*/这一段是init进程首先要做的是设置一些信号相关的东西,初始化控制台,然后设置环境变量。似乎与启动应用程序无关。别担心。继续往下看/*检查我们是否应该处于单用户模式??/if(argv[1]&&(strcmp(argv[1],"single")==0||strcmp(argv[1],"-s")==0||LONE_CHAR(argv[1],'1'))){/*???我们不应该在这里设置RUNLEVEL="b"吗?*//*在控制台上启动一个shell*/new_init_action(RESPAWN,bb_default_login_shell,"");}else{/*不是单用户模式??-看看inittab说的是什么*//*注意如果CONFIG_FEATURE_USE_INITTAB没有定义,*然后parse_inittab()只是加入了一些默认的*动作(即INIT_SCRIPT和一对*"askfirst"shell)*/parse_inittab();}这段代码是一个if判断。注释说如果是单用户模式,就看前半部分代码。如果不是单用户模式,调用parse_inittab()函数,因为内核启动init进程时没有传入额外的参数,所以argv[1]不是Existence,程序通过parse_inittab()注释说如果CONFIG_FEATURE_USE_INITTAB这个宏没有定义,程序会执行一些默认的动作,那么怎么知道这个宏有没有定义呢?猜猜这个宏应该是配置busybox时的一个选项。好吧怎么办?查看busybox配置,和linux内核配置一致。结合各级makemenuconfig和config文件,看看是否定义了宏CONFIG_FEATURE_USE_INITTAB?在busybox中执行makemeunconfig,进入熟悉的配置界面,四处浏览,好像有一个和init相关的InitUtilities项,还有一项“Supportreadinganinittab”file”,这个配置项被选中,在描述中加入了“inittab”二字,和init源码中提到的parse_inittab()非常相似。好了,先把makemenuconfig放一边,我们来看看配置文件,并打开顶层??目录Config.in,全局搜索“init”,只找到最下面:sourceinit/Config.in进入init文件夹,打开Config.in文件,找到配置itemconfigFEATURE_USE_INITTABbool"Supportreadinganinittabfile"defaultydependsINIThelp允许init在系统启动时读取一个inittab文件猜的没错,确实定义了CONFIG_FEATURE_USE_INITTAB宏,返回init源码分析,进入parse_inittab()函数首先看到这个函数之前有一个大注释,看看它说了什么/*注意如果CONFIG_FEATURE_USE_INITTAB没有定义,*然后parse_inittab()简单地添加一些默认*操作(即运行INIT_SCRIPT然后启动一对*“先问”炮弹)。如果CONFIG_FEATURE_USE_INITTAB*_is_已定义,但缺少/etc/inittab,则此*会导致相同的一组默认行为。*/前面的话和前面的if判断意义相同。如果定义了宏XXX,但没有/etc/inittab文件,将执行默认操作。嗯,我猜,parse_inttab()函数好像和要分析的app的启动有关。如果定义了XXX宏,就会解析/etc/inittab这个文件的内容来执行。如果没有定义XXX宏或者/etc/inittab文件不存在,执行一些默认的东西就好了。搞清楚一件事,/etc/inittab这个文件很重要,你可能需要自己创建一个文件,在里面写点东西,但是写什么呢?还不知道。那么如果不走/etc/inittab这个路径,默认会执行的动作是什么意思呢?我们来分析函数parse_inittab()staticvoidparse_inittab(void){#ifENABLE_FEATURE_USE_INITTABchar*token[4];parser_t*parser=config_open2("/etc/inittab",fopen_for_read);if(parser==NULL)#endif{/*没有inittab文件-设置一些默认行为*//*Sysinit*/new_init_action(SYSINIT,INIT_SCRIPT,"");/*Askfirstshellontty1-4*/new_init_action(ASKFIRST,bb_default_login_shell,"");//TODO:VC_1而不是""?“”是控制台->ctty问题->愤怒的用户new_init_action(ASKFIRST,bb_default_login_shell,VC_2);new_init_action(ASKFIRST,bb_default_login_shell,VC_3);new_init_action(ASKFIRST,bb_default_login_shell,VC_3);按Ctrl-Alt-Del重启*/new_init_action(CTRLALTDEL,"reboot","");/*在停止/重启时卸载所有文件系统*/new_init_action(SHUTDOWN,"umount-a-r","");/*交换在停止/重启时*/new_init_action(SHUTDOWN,"swapoff-a","");/*当收到QUIT时重启init*/new_init_action(RESTART,"init","");返回;}#ifENABLE_FEATURE_USE_INITTAB/*optional_tty:ignored_runlevel:action:command*Delims不会折叠并且需要恰好4个标记*/while(config_read(parser,token,4,0,"#:",PARSE_NORMAL&~(PARSE_TRIM|PARSE_COLLAPSE))){/*命令必须对应于SYSINIT..RESTART常量*/staticconstcharactions[]ALIGN1="sysinit\0""wait\0""once\0""respawn\0""askfirst\0""ctrlaltdel\0""关机\0""重启\0";内部行动;char*tty=token[0];if(!token[3])/*少于4个标记*/gotobad_entry;action=index_in_strings(actions,token[2]);if(action<0||!token[3][0])/*token[3]:命令*/gotobad_entry;/*转动。*TTY->/dev/TTY*/if(tty[0]){tty=concat_path_file("/dev/",skip_dev_pfx(tty));}new_init_action(1<
