inittab脚本启动解析

  1. Linux 开机脚本启动顺序:   
  2.   
  3. 第一步:启动内核  
  4.   
  5. 第二步:执行init (配置文件/etc/inittab)  
  6.   
  7. 第三步:启动相应的脚本,执行inittab脚本,并且执行里面的脚本/etc/init.d rc.sysinit rc.d rc.local。。。  
  8.   
  9. 第四步:启动login登录界面 login  
  10.   
  11. 第五步:在用户登录的时候执行sh脚本的顺序:每次登录的时候都会完全执行的 /etc/profile /etc/bashrc /root/.bashrc /root/.bash_profile  
  12.   
  13.       
  14.   
  15. inittab脚本:  
  16.   
  17. init的进程号为1,是所有进程的父进程,内核初始化完毕之后,init程序开始运行。其他软件也同时开始运行。init程序通过/etc/inittab文件进行配置。  
  18.   
  19. /etc/inittab文件每一行包括四个字段:label:runlevel:action:process。详细解释如下。  
  20.   
  21. 1.label  
  22.   
  23. 登记项标志符,是一个任意指定的、4个字符以内的序列标号,在本文件内必须唯一。  
  24.   
  25. label是1到4个字符的标签,用来标示输入的值。一些系统只支持2个字符的标签。鉴于此原因,多数人都将标签字符的个数限制在2个以内。该标签可以是任意字符构成的字符串,但实际上,某些特定的标签是常用的,在Red Hat Linux中使用的标签是:  
  26.   
  27. id 用来定义缺省的init运行的级别  
  28.   
  29. si 是系统初始化的进程  
  30.   
  31. ln 其中的n从1~6,指明该进程可以使用的runlevel的级别  
  32.   
  33. ud 是升级进程  
  34.   
  35. ca 指明当按下Ctrl+Alt+Del是运行的进程  
  36.   
  37. pf 指当UPS表明断电时运行的进程  
  38.   
  39. pr 是在系统真正关闭之前,UPS发出电源恢复的信号时需要运行的进程  
  40.   
  41. x 是将系统转入X终端时需要运行的进程  
  42.   
  43.   
  44.   
  45. 2.runlevels  
  46.   
  47. 系统运行级,即执行登记项的init级别。用于指定相应的登记项适用于哪一个运行级,即在哪一个运行级中被处理。如果该字段为空,那么相应的登记项将适用于所有的运行级。在该字段中,可以同时指定一个或多个运行级,其中各运行级分别以数字0, 1, 2, 3, 4, 5, 6或字母a, b, c表示,且无须对其进行分隔。  
  48.   
  49. 0-->Halt,关闭系统.  
  50.   
  51. 1-->单用户,在grub启动时加上为kernel加上参数single即可进入此运行等级  
  52.   
  53. 2-->无网络多用户模式.  
  54.   
  55. 3-->有网络多用户模式.  
  56.   
  57. 4-->有网络多用户模式.  
  58.   
  59. 5-->X模式  
  60.   
  61. 6-->reboot重启系统  
  62.   
  63. S/s-->同运行等级1  
  64.   
  65. a,b,c-->自定义等级,通常不使用.  
  66.   
  67.   
  68.   
  69. 3.action  
  70.   
  71. 表示进入对应的runlevel时,init应该运行process字段的命令的方式,有效的action值如下。  
  72.   
  73. boot:只有在引导过程中,才执行该进程,但不等待该进程的结束。当该进程死亡时,也不重新启动该进程。  
  74.   
  75. bootwait:只有在引导过程中,才执行该进程,并等待进程的结束。当该进程死亡时,也不重新启动该进程。实际上,只有在系统被引导后,并从单用户模式进入多用户模式时,这些登记项才被处理;如果系统的默认运行级设置为2(即多用户模式),那么这些登记项在系统引导后将马上被处理。  
  76.   
  77. initdefault:指定系统的默认运行级。系统启动时,init将首先查找该登记项,如果存在,init将依据此决定系统最初要进入的运行级。具体来说,init将指定登记项"run_level"字段中的最大数字(即最高运行级)为当前系统的默认运行级;如果该字段为空,那么将其解释为"0123456",并以"6"作为默认运行级。如果不存在该登记项,那么init将要求用户在系统启动时指定一个最初的运行级。  
  78.   
  79. off:如果相应的进程正在运行,那么就发出一个告警信号,等待20秒后,再通过关闭信号强行终止该进程。如果相应的进程并不存在,那么就忽略该登记项。  
  80.   
  81. once:启动相应的进程,但不等待该进程结束便继续处理/etc/inittab文件中的下一个登记项;当该进程终止时,init也不重新启动该进程。在从一个运行级进入另一个运行级时,如果相应的进程仍然在运行,那么init就不重新启动该进程。  
  82.   
  83. ondemand:与"respawn"的功能完全相同,但只用于运行级为a、b或c的登记项。  
  84.   
  85. powerfail:只在init接收到电源失败信号时,才执行该进程,但不等待该进程结束。  
  86.   
  87. powerwait:只在init接收到电源失败信号时,才执行该进程,并在继续对/etc/inittab文件进行任何处理前等待该进程结束。  
  88.   
  89. respawn:如果相应的进程还不存在,那么init就启动该进程,同时不等待该进程的结束就继续扫描/etc/inittab文件;当该进程终止时,init将重新启动该进程。如果相应的进程已经存在,那么init将忽略该登记项并继续扫描/etc/inittab文件。  
  90.   
  91. sysinit:只有在启动或重新启动系统并首先进入单用户模式时,init才执行这些登记项。而在系统从运行级1~6进入单用户模式时,init并不执行这些登记项。"action"字段为"sysinit"的登记项在"run_level"字段不指定任何运行级。  
  92.   
  93. wait:启动进程并等待其结束,然后再处理/etc/inittab文件中的下一个登记项。  
  94.   
  95. ctrlaltdel:用户在控制台键盘上按下Ctrl+Alt+Del组合键时,允许init重新启动系统。注意,如果该系统放在一个公共场所,系统管理员可将Ctrl+Alt+Del组合键配置为其他行为,比如忽略等。  
  96.   
  97.   
  98.   
  99. 4.process  
  100.   
  101. 具体应该执行的命令。并负责在退出运行级时将其终止(当然在进入的runlevel中仍要运行的程序除外)。当运行级别改变,并且正在运行的程序并没有在新的运行级别中指定需要运行时,那么init会先发送一个SIGTERM 信号终止,然后是SIGKILL。  
  102.   
  103.   
  104.   
  105. 5.实例分析:  
  106.   
  107. /*************************/etc/inittab***********************************/  
  108.   
  109. //将系统切换到 initdefault 操作所定义的运行级别即运行级别5。我们可以将运行级别看作是系统的状态。运行级别 0 定义了系统挂起状态,运行级别 1 是单用户模式。运行级别 2 到 5 是多用户状态,运行级别 6 表示重启  
  110.   
  111. id:5:initdefault:  
  112.   
  113.   
  114.   
  115. //sysinit表示在进行其他工作之前先完成系统初始化.init在处理其它运行等级的脚本之前,首先会执行这一行.是系统的初始化进程.用于设置主机名,挂载文件系统,启动交换分区等.  
  116.   
  117. //rcS脚本会调用/etc/rcS.d目录下的所有脚本进行初始化  
  118.   
  119. si::sysinit:/etc/init.d/rcS //在运行boot或bootwait进程之前运行系统初始化的进程  
  120.   
  121.   
  122.   
  123. //下条语句可以让系统在重新启动、进入单用户模式的时候提示输入超级用户密码。  
  124.   
  125. //S同运行等级1,并等待其结束,然后再处理/etc/inittab文件中的下一个登记项。  
  126.   
  127. ~~:S:wait:/sbin/sulogin   
  128.   
  129.   
  130.   
  131. //当运行级别为5时,以5为参数运行/etc/rc5.d下的脚本,init将等待其返回(wait)  
  132.   
  133. //rc.sysinit,rcS,rc这些都是shell的脚本,完成大量的系统初始化的工作。  
  134.   
  135. //主要工作包括:激活交换分区,检查磁盘,加载硬件模块以及其它一些需要优先执行任务。  
  136.   
  137. //执行rc脚本,传入参数为0-6,即会调用/etc/rc0.d-rc6.d目录下的所有文件  
  138.   
  139. //initdefault 指定默认的 init 级别是 5(多用户模式)。在定义初始的运行级别之后,则调用rc脚本以及参数5(运行级别)来启动系统,即rc脚本(参数5)会调用/etc/rc5.d下的所有脚本。  
  140.   
  141. l0:0:wait:/etc/init.d/rc 0 //使用级别0运行此程序  
  142.   
  143. l1:1:wait:/etc/init.d/rc 1  
  144.   
  145. l2:2:wait:/etc/init.d/rc 2  
  146.   
  147. l3:3:wait:/etc/init.d/rc 3  
  148.   
  149. l4:4:wait:/etc/init.d/rc 4  
  150.   
  151. //会运行该/etc/rc5.d下的3个脚本:  
  152.   
  153. //S10telnetd脚本:开启telnetd服务 start-stop-daemon --start --quiet --exec $telnetd  
  154.   
  155. //S20syslog脚本:开启syslog服务start-stop-daemon -S -b -n syslogd -a /sbin/syslogd -- -n $SYSLOG_ARGS start-stop-daemon -S -b -n klogd -a /sbin/klogd -- -n  
  156.   
  157. //S99rmnologin脚本:删除/etc/nologin文件 rm -f /etc/nologin /etc/nologin.boot  
  158.   
  159. l5:5:wait:/etc/init.d/rc 5  
  160.   
  161. l6:6:wait:/etc/init.d/rc 6  
  162.   
  163.   
  164.   
  165. z6:6:respawn:/sbin/sulogin//脚本运行等级为6时才执行   
  166.   
  167.   
  168.   
  169. //在2、3、4、5级别上以ttyX为参数执行/sbin/mingetty程序,打开ttyX终端用于用户登录,  
  170.   
  171. //如果进程退出则再次运行mingetty程序(respawn),所以登录出错时,接着登录  
  172.   
  173. //缺省波特率是115200  
  174.   
  175. S2:2345:respawn:/sbin/mingetty ttyS2 //修改了mingetty和login程序,系统就可以在自动登录了  
  176.   
  177.   
  178.   
  179.   
  180.   
  181. /*************************etc/init.d/rcS***********************************/  
  182.   
  183. //设置PATH,runlevel,prevlevel环境变量,并export  
  184.   
  185. PATH=/sbin:/bin:/usr/sbin:/usr/bin  
  186.   
  187. runlevel=S  
  188.   
  189. prevlevel=N  
  190.   
  191. umask 022 //缺省的文件权限  
  192.   
  193. export PATH runlevel prevlevel  
  194.   
  195.   
  196.   
  197. if [ -x /sbin/unconfigured.sh ]//检查/sbin/unconfigured.sh是否可执行  
  198.   
  199. then  
  200.   
  201.   /sbin/unconfigured.sh//如果可执行就执行unconfigured.sh,我的根文件系统不存在此文件  
  202.   
  203. fi  
  204.   
  205.   
  206.   
  207. //执行default目录下的rcS,设置一些变量  
  208.   
  209. //即source /etc/default/rcS  
  210.   
  211. . /etc/default/rcS  
  212.   
  213.   
  214.   
  215. //trap可以使你在脚本中捕捉信号。该命令的一般形式为:trap name signal(s)  
  216.   
  217. //name是捕捉到信号以后所采取的一系列操作。实际应用中, name一般是一个专门来处理所捕捉信号的函数。  
  218.   
  219. //name需要用双引号( “ ” )引起来。signal就是待捕捉的信号。  
  220.   
  221. //这里就是捕捉INT QUIT TSTP三个信号,执行“:”,实际就是忽略这三个信号,防止脚本执行时使用ctrl-C 就退出脚本  
  222.   
  223. trap ":" INT QUIT TSTP  
  224.   
  225.   
  226.   
  227. //将执行/etc/init.d中rc,传入参数为“S”,目的就是为了执行/etc/init.d/rcS.d目录下的所有脚本文件,都是连接到/etc/init.d/目录下的链接  
  228.   
  229. //S02banner脚本建立tty设备节点:/bin/mknod -m 0666 /dev/tty c 5 0  
  230.   
  231. //S03sysfs脚本挂载proc和sysfs文件系统:mount -t proc proc /proc mount sysfs /sys -t sysfs  
  232.   
  233. //S03udev脚本:开启udev服务,后台运行udevd程序:/sbin/udevd -d  
  234.   
  235. //S06alignment脚本,输出cpu信息到proc文件系统  
  236.   
  237. //S10checkroot脚本  
  238.   
  239. //S20modutils.sh脚本:insmod module  
  240.   
  241. //S30ramdisk脚本:  
  242.   
  243. //S35mountall.sh脚本:挂载Mount all filesystems  
  244.   
  245. //S37populate-volatile.sh脚本  
  246.   
  247. //S38devpts.sh脚本:挂载mount -t devpts devpts /dev/pts  
  248.   
  249. //S39hostname.sh脚本:输出主机名称(arago)写入/etc/hostname文件:hostname -F /etc/hostname  
  250.   
  251. //S40networking脚本:开启网络服务  
  252.   
  253. //S45mountnfs.sh脚本:挂载nfs  
  254.   
  255. //S55bootmisc.sh脚本:  
  256.   
  257. //S98configure脚本:opkg-cl configure  
  258.   
  259. //S99finish.sh脚本:结束脚本  
  260.   
  261. exec /etc/init.d/rc S   
  262.   
  263.   
  264.   
  265. //若rc.boot是目录,则执行rc.boot所有的脚本程序  
  266.   
  267. [ -d /etc/rc.boot ] && run-parts /etc/rc.boot  
  268.   
  269.   
  270.   
  271. //若setup.sh可执行,就执行,没有此程序  
  272.   
  273. if [ -x /sbin/setup.sh ]  
  274.   
  275. then  
  276.   
  277.   /sbin/setup.sh  
  278.   
  279. fi  
  280.   
  281.   
  282.   
  283.   
  284.   
  285. /*************************etc/init.d/rc***********************************/  
  286.   
  287. //这个脚本作用主要是运行/etc/rcS.d目录下的文件,  
  288.   
  289. //其中在 /etc/rcS.d/ 的目录下有一个 README 文本来说明该 /etc/rcS.d/ 目录下脚本的作用:  
  290.   
  291. //即 /etc/rcS.d/ 中是一些到 /etc/init.d/ 中脚本的符号连接。  
  292.   
  293. //执行完 /etc/rcS.d/ 中的脚本后,触发相应的 runlevel 事件,开始运行 /etc/rc.conf 脚本  
  294.   
  295. . /etc/default/rcS  
  296.   
  297. export VERBOSE //etc/default/rcS这个脚本中定义的VERBOSE=no  
  298.   
  299.   
  300.   
  301. startup_progress() {  
  302.   
  303.     step=$(($step + $step_change))  
  304.   
  305.     if [ "$num_steps" != "0" ]; then  
  306.   
  307.         progress=$((($step * $progress_size / $num_steps) + $first_step))  
  308.   
  309.     else  
  310.   
  311.         progress=$progress_size  
  312.   
  313.     fi  
  314.   
  315.     if type psplash-write >/dev/null 2>&1; then  
  316.   
  317.         TMPDIR=/mnt/.psplash psplash-write "PROGRESS $progress" || true  
  318.   
  319.     fi  
  320.   
  321. }  
  322.   
  323.   
  324.   
  325.   
  326.   
  327. startup() {  
  328.   
  329.   [ "$VERBOSE" = very ] && echo "INIT: Running $@..."//VERBOSE=no,所以后边的不打印  
  330.   
  331.   
  332.   
  333.     //以.sh结尾的脚本是必须执行的脚本,不是以.sh结尾的脚本服务是可以开启或关闭的,通过start或stop参数  
  334.   
  335.   case "$1" in//传入的第一个参数是要执行的文件名,第二个参数是start  
  336.   
  337.     *.sh)  
  338.   
  339.         (//若文件名是以.sh结尾的则执行这个脚本  
  340.   
  341.             trap - INT QUIT TSTP  
  342.   
  343.             scriptname=$1  
  344.   
  345.             shift  
  346.   
  347.             . $scriptname //执行这个脚本,不带参数  
  348.   
  349.         )  
  350.   
  351.         ;;  
  352.   
  353.     *)//若不是以.sh结尾的  
  354.   
  355.         /*实际上rc进程调用的脚本都称为初始化脚本。每个在/etc/init.d下的脚本都可以在执行时带上以下参数,如:start、stop、restart、pause、zap、status、ineed、iuse、needsme、usesme或者broken。  
  356.   
  357.         要启动、停止或者重启一个服务(和所有依赖于它的服务),应该用参数start、stop和restart。*/  
  358.   
  359.         "$@"//执行这个脚本带参数,比如传入的是$@=“/etc/rcS.d/S02banner start”,即带start参数执行这个脚本,这样可以灵活的控制服务的start或者stop  
  360.   
  361.         ;;  
  362.   
  363.   esac  
  364.   
  365.   startup_progress  
  366.   
  367. }  
  368.   
  369.   
  370.   
  371.     //忽略这三个信号,防止脚本执行时使用ctrl-C 就退出脚本  
  372.   
  373.   trap ":" INT QUIT TSTP  
  374.   
  375.       
  376.   
  377.     //stty用于设置终端特性。在命令行中设置一个stty选项,一般格式为:stty name character  
  378.   
  379.     //以下将退格设置为^ H:stty erase '\^H',即ctrl+H在此脚本中是退格键  
  380.   
  381.   //设置终端,将 CR 字符映射为 NL 字符,避免阶梯效应  
  382.   
  383.   stty onlcr 0>&1  
  384.   
  385.   
  386.   
  387.   //Now find out what the current and what the previous runlevel are.  
  388.   
  389.   runlevel=$RUNLEVEL  
  390.   
  391.   //得到第一个参数是“S”,表示等级1,得到当前运行等级1,runlevel=S  
  392.   
  393.   [ "$1" != "" ] && runlevel=$1  
  394.   
  395.   if [ "$runlevel" = "" ]//运行等级为空的话,则退出  
  396.   
  397.   then  
  398.   
  399.     echo "Usage: $0 <runlevel>>&2  
  400.   
  401.     exit 1  
  402.   
  403.   fi  
  404.   
  405.   previous=$PREVLEVEL  
  406.   
  407.   [ "$previous" = "" ] && previous=N  
  408.   
  409.   
  410.   
  411.     //传入参数是S的话,则$runleve=S $previous=N  
  412.   
  413.   export runlevel previous  
  414.   
  415.   
  416.   
  417.   //若$runlevel=“S”,即检查rcS.d是否为目录。  
  418.   
  419.   if [ -d /etc/rc$runlevel.d ]  
  420.   
  421.   then  
  422.   
  423.     //rcS.d是目录  
  424.   
  425.     PROGRESS_STATE=0  
  426.   
  427.   
  428.   
  429.     //Split the remaining portion of the progress bar into thirds  
  430.   
  431.     progress_size=$(((100 - $PROGRESS_STATE) / 3))//progress_size = 100/3 =33  
  432.   
  433.   
  434.   
  435.     case "$runlevel" in//runlevel=S  
  436.   
  437.         0|6)  
  438.   
  439.             first_step=-100  
  440.   
  441.             progress_size=100  
  442.   
  443.             step_change=1  
  444.   
  445.             ;;  
  446.   
  447.      S)  
  448.   
  449.             //Begin where the initramfs left off and use 2/3of the remaining space  
  450.   
  451.             first_step=$PROGRESS_STATE ///progress_size = 100/3 =33  
  452.   
  453.             progress_size=$(($progress_size * 2))//progress_size=66  
  454.   
  455.             step_change=1  
  456.   
  457.             ;;  
  458.   
  459.         *)  
  460.   
  461.             //Begin where rcS left off and use the final 1/3 ofthe space (by leaving progress_size unchanged)  
  462.   
  463.             first_step=$(($progress_size * 2 + $PROGRESS_STATE))  
  464.   
  465.             step_change=1  
  466.   
  467.             ;;  
  468.   
  469.     esac  
  470.   
  471.   
  472.   
  473.     num_steps=0  
  474.   
  475.     for s in /etc/rc$runlevel.d/[SK]*; //s取/etc/rcS.d目录下以S或K开头的文件名  
  476.   
  477.     do  
  478.   
  479.         //这句话的含义去掉变量s中所有的/etc/rcS.d/S??的部分  
  480.   
  481.         //例:s=/etc/rc$runlevel.d/S10checkroot,那么去掉/etc/rc$runlevel.d/K??部分后,s为checkroot  
  482.   
  483.     case "${s##/etc/rc$runlevel.d/S??}" in  
  484.   
  485.         gdm|xdm|kdm|reboot|halt)//若s剩下的文件名中为这五个则跳出for语句  
  486.   
  487.             break  
  488.   
  489.             ;;  
  490.   
  491.     esac  
  492.   
  493.     num_steps=$(($num_steps + 1))//num_steps递加,表示查找到此目录下/etc/rcS.d有多少个脚本  
  494.   
  495.   done//for语句结束  
  496.   
  497.     
  498.   
  499.   step=0  
  500.   
  501.     //首先运行KILL脚本  
  502.   
  503.     if [ $previous != N ]//由于$previous=N,所以以下不执行  
  504.   
  505.     then  
  506.   
  507.         for i in /etc/rc$runlevel.d/K[0-9][0-9]*//取以K开头的文件名  
  508.   
  509.         do  
  510.   
  511.             //检查是否为常规文件  
  512.   
  513.             [ ! -f $i ] && continue  
  514.   
  515.             //Stop the service.  
  516.   
  517.             startup $i stop  
  518.   
  519.         done  
  520.   
  521.     fi  
  522.   
  523.   
  524.   
  525.     //然后运行这个级别的START脚本  
  526.   
  527.     for i in /etc/rc$runlevel.d/S*//取得S开头的脚本  
  528.   
  529.     do  
  530.   
  531.         [ ! -f $i ] && continue//检查是否为常规文件,不是则进行下次循环  
  532.   
  533.   
  534.   
  535.         if [ $previous != N ] && [ $previous != S ]//由于$previous=N,所以此if语句不执行  
  536.   
  537.         then  
  538.   
  539.             //Find start script in previous runlevel and stop script in this runlevel.  
  540.   
  541.             suffix=${i#/etc/rc$runlevel.d/S[0-9][0-9]}//获得i文件名的后缀,假如是S10checkroot,则suffix=checkroot  
  542.   
  543.             stop=/etc/rc$runlevel.d/K[0-9][0-9]$suffix //得到stop文件名,假如/etc/rc$runlevel.d/K[0-9][0-9]checkroot  
  544.   
  545.             previous_start=/etc/rc$previous.d/S[0-9][0-9]$suffix  
  546.   
  547.             //如果有起始脚本,并且没有停止脚本,则不进行这项服务,continue继续下一次循环  
  548.   
  549.             [ -f $previous_start ] && [ ! -f $stop ] && continue  
  550.   
  551.         fi  
  552.   
  553.           
  554.   
  555.         case "$runlevel" in//runlevel = S  
  556.   
  557.             0|6)  
  558.   
  559.                 startup $i stop  
  560.   
  561.                 ;;  
  562.   
  563.             *)  
  564.   
  565.                 startup $i start//调用start函数,参数就是脚本名称  
  566.   
  567.                 ;;  
  568.   
  569.         esac  
  570.   
  571.     done//for循环结束  
  572.   
  573.       
  574.   
  575.   fi  
  576.   
  577.   
  578.   
  579.   
  580.   
  581. /*************************etc/profile***********************************/  
  582.   
  583. //为启动shell设定一些环境变量  
  584.   
  585. PATH="/usr/local/bin:/usr/bin:/bin"   
  586.   
  587. EDITOR="/bin/vi"            //needed for packages like cron  
  588.   
  589. test -z "$TERM" && TERM="vt100"    //Basic terminal capab. For screen etc.  
  590.   
  591.   
  592.   
  593. //若此文件存在,则设置时区  
  594.   
  595. if [ ! -e /etc/localtime ]; then  
  596.   
  597.     TZ="UTC"                  
  598.   
  599.     export TZ  
  600.   
  601. fi  
  602.   
  603.   
  604.   
  605. //显示用户ID是否为0,是0则设置用户的PATH路径  
  606.   
  607. if [ "`id -u`" -eq 0 ]; then  
  608.   
  609.    PATH=$PATH:/usr/local/sbin:/usr/sbin:/sbin:  
  610.   
  611. fi  
  612.   
  613.   
  614.   
  615. //设置环境变量PS1  
  616.   
  617. if [ "$PS1" ]; then  
  618.   
  619.    PS1='\u@\h:\w\$ '  
  620.   
  621. fi  
  622.   
  623.   
  624.   
  625. // /etc/profile.d是否为目录  
  626.   
  627. if [ -d /etc/profile.d ]; then  
  628.   
  629.   for i in /etc/profile.d/*.sh /*遍历目录下所有以.sh结尾的脚本文件,并执行*/  
  630.   
  631.   do  
  632.   
  633.     if [ -r $i ]; then  
  634.   
  635.       . $i  
  636.   
  637.     fi  
  638.   
  639.   done  
  640.   
  641.   unset i  
  642.   
  643. fi  
  644.   
  645.   
  646.   
  647. //可以设置登录后自动运行的APP  
  648.   
  649. . /etc/init.d/autorun-f      
  650.   
  651.   
  652.   
  653. export PATH PS1 OPIEDIR QPEDIR QTDIR EDITOR TERM  
  654.   
  655.   
  656.   
  657. umask 022  
  658.   
  659.   
  660.   
  661.   
  662.   
  663. /*********************************************************mingetty.c**********************************************/  
  664.   
  665. /* name of this program (argv[0]) */  
  666.   
  667. static char *progname;  
  668.   
  669. /* on which tty line are we sitting? (e.g. tty1) */  
  670.   
  671. static char *tty;  
  672.   
  673. /* some information about this host */  
  674.   
  675. static struct utsname uts;  
  676.   
  677. /* the hostname */  
  678.   
  679. static char hn[MAXHOSTNAMELEN + 1];  
  680.   
  681. /* process and session ID of this program */  
  682.   
  683. static pid_t pid, sid;  
  684.   
  685. /* login program invoked */  
  686.   
  687. static char *loginprog = "/bin/login";  
  688.   
  689. /* Do not send a reset string to the terminal. */  
  690.   
  691. static int noclear = 0;  
  692.   
  693. /* Do not print a newline. */  
  694.   
  695. static int nonewline = 0;  
  696.   
  697. /* Do not print /etc/issue. */  
  698.   
  699. static int noissue = 0;  
  700.   
  701. /* Do not call vhangup() on the tty. */  
  702.   
  703. static int nohangup = 0;  
  704.   
  705. /* Do not print any hostname. */  
  706.   
  707. static int nohostname = 0;  
  708.   
  709. /* Print the whole string of gethostname() instead of just until the next "." */  
  710.   
  711. static int longhostname = 0;  
  712.   
  713. /* time to wait, seconds */  
  714.   
  715. static int delay = 0;  
  716.   
  717. /* chroot directory */  
  718.   
  719. static char *ch_root = NULL;  
  720.   
  721. /* working directory to change into */  
  722.   
  723. static char *ch_dir = NULL;  
  724.   
  725. /* 'nice' level of the program */  
  726.   
  727. static int priority = 0;  
  728.   
  729. /* automatic login with this user */  
  730.   
  731. static char *autologin = NULL;  
  732.   
  733.   
  734.   
  735. /* update_utmp() - update our utmp entry */  
  736.   
  737. static void update_utmp (void)  
  738.   
  739. {  
  740.   
  741.     struct utmp ut;  
  742.   
  743.     struct utmp *utp;  
  744.   
  745.     time_t cur_time;  
  746.   
  747.   
  748.   
  749.     setutent ();  
  750.   
  751.     while ((utp = getutent ()))  
  752.   
  753.         if (utp->ut_type == INIT_PROCESS && utp->ut_pid == pid)  
  754.   
  755.             break;  
  756.   
  757.   
  758.   
  759.     if (utp) {  
  760.   
  761.         memcpy (&ut, utp, sizeof (ut));  
  762.   
  763.     } else {  
  764.   
  765.         /* some inits don't initialize utmp... */  
  766.   
  767.         const char *x = tty;  
  768.   
  769.         memset (&ut, 0, sizeof (ut));  
  770.   
  771.         if (strncmp (x, "tty", 3) == 0)  
  772.   
  773.             x += 3;  
  774.   
  775.         if (strlen (x) > sizeof (ut.ut_id))  
  776.   
  777.             x += strlen (x) - sizeof (ut.ut_id);  
  778.   
  779.         strncpy (ut.ut_id, x, sizeof (ut.ut_id));  
  780.   
  781.     }  
  782.   
  783.   
  784.   
  785.     strncpy (ut.ut_user, "LOGIN", sizeof (ut.ut_user));  
  786.   
  787.     strncpy (ut.ut_line, tty, sizeof (ut.ut_line));  
  788.   
  789.     time (&cur_time);  
  790.   
  791.     ut.ut_time = cur_time;  
  792.   
  793.     ut.ut_type = LOGIN_PROCESS;  
  794.   
  795.     ut.ut_pid = pid;  
  796.   
  797.     ut.ut_session = sid;  
  798.   
  799.   
  800.   
  801.     pututline (&ut);  
  802.   
  803.     endutent ();  
  804.   
  805.   
  806.   
  807.     updwtmp (_PATH_WTMP, &ut);  
  808.   
  809. }  
  810.   
  811.   
  812.   
  813. /* open_tty - set up tty as standard { input, output, error } */  
  814.   
  815. static void open_tty (void)  
  816.   
  817. {  
  818.   
  819.     struct sigaction sa, sa_old;  
  820.   
  821.     char buf[40];  
  822.   
  823.     int fd;  
  824.   
  825.   
  826.   
  827.     //得到要打开的tty终端名  
  828.   
  829.     if (tty[0] == '/')  
  830.   
  831.         strcpy (buf, tty);  
  832.   
  833.     else {  
  834.   
  835.         strcpy (buf, "/dev/");  
  836.   
  837.         strcat (buf, tty);  
  838.   
  839.     }  
  840.   
  841.       
  842.   
  843.     //修改设备文件属性,使其可以访问  
  844.   
  845.     if (chown (buf, 0, 0) || chmod (buf, 0600))  
  846.   
  847.         if (errno != EROFS)  
  848.   
  849.             error ("%s: %s", tty, strerror (errno));  
  850.   
  851.   
  852.   
  853.     sa.sa_handler = SIG_IGN;  
  854.   
  855.     sa.sa_flags = 0;  
  856.   
  857.     sigemptyset (&sa.sa_mask);  
  858.   
  859.     sigaction (SIGHUP, &sa, &sa_old);//终端关闭发出SIGHUP信号,忽略此信号  
  860.   
  861.   
  862.   
  863.     //打开tty终端设备,缺省波特率是115200  
  864.   
  865.     if ((fd = open (buf, O_RDWR, 0)) < 0)  
  866.   
  867.         error ("%s: cannot open tty: %s", tty, strerror (errno));  
  868.   
  869.     if (ioctl (fd, TIOCSCTTY, (void *) 1) == -1)  
  870.   
  871.         error ("%s: no controlling tty: %s", tty, strerror (errno));  
  872.   
  873.     if (!isatty (fd))  
  874.   
  875.         error ("%s: not a tty", tty);  
  876.   
  877.       
  878.   
  879.     //  
  880.   
  881.     if (nohangup == 0) {  
  882.   
  883.         if (vhangup ())  
  884.   
  885.             error ("%s: vhangup() failed", tty);  
  886.   
  887.         close (2);  
  888.   
  889.         close (1);  
  890.   
  891.         close (0);  
  892.   
  893.         close (fd);  
  894.   
  895.         if ((fd = open (buf, O_RDWR, 0)) != 0)  
  896.   
  897.             error ("%s: cannot open tty: %s", tty,strerror (errno));  
  898.   
  899.         if (ioctl (fd, TIOCSCTTY, (void *) 1) == -1)  
  900.   
  901.             error ("%s: no controlling tty: %s", tty,strerror (errno));  
  902.   
  903.     }  
  904.   
  905.       
  906.   
  907.     //将标准输入输出出错都复制给tty终端  
  908.   
  909.     if (dup2 (fd, 0) != 0 || dup2 (fd, 1) != 1 || dup2 (fd, 2) != 2)  
  910.   
  911.         error ("%s: dup2(): %s", tty, strerror (errno));  
  912.   
  913.     if (fd > 2)  
  914.   
  915.         close (fd);  
  916.   
  917.   
  918.   
  919.     if (noclear == 0)  
  920.   
  921.         write (0, "\033c", 2);  
  922.   
  923.       
  924.   
  925.     //恢复原来SIGHUP的信号处理  
  926.   
  927.     sigaction (SIGHUP, &sa_old, NULL);  
  928.   
  929. }  
  930.   
  931.   
  932.   
  933. static void output_special_char (unsigned char c)  
  934.   
  935. {  
  936.   
  937.     switch (c) {  
  938.   
  939.     case 's':  
  940.   
  941.         printf ("%s", uts.sysname);  
  942.   
  943.         break;  
  944.   
  945.     case 'n':  
  946.   
  947.         printf ("%s", uts.nodename);  
  948.   
  949.         break;  
  950.   
  951.     case 'r':  
  952.   
  953.         printf ("%s", uts.release);  
  954.   
  955.         break;  
  956.   
  957.     case 'v':  
  958.   
  959.         printf ("%s", uts.version);  
  960.   
  961.         break;  
  962.   
  963.     case 'm':  
  964.   
  965.         printf ("%s", uts.machine);  
  966.   
  967.         break;  
  968.   
  969.     case 'o':  
  970.   
  971.         printf ("%s", uts.domainname);  
  972.   
  973.         break;  
  974.   
  975.     case 'd':  
  976.   
  977.     case 't':  
  978.   
  979.         {  
  980.   
  981.             time_t cur_time;  
  982.   
  983.             struct tm *tm;  
  984.   
  985. #if    0  
  986.   
  987.             char buff[20];  
  988.   
  989.   
  990.   
  991.             time (&cur_time);  
  992.   
  993.             tm = localtime (&cur_time);  
  994.   
  995.             strftime (buff, sizeof (buff),  
  996.   
  997.                 c == 'd'? "%a %b %d %Y" : "%X", tm);  
  998.   
  999.             fputs (buff, stdout);  
  1000.   
  1001.             break;  
  1002.   
  1003. #else  
  1004.   
  1005.             time (&cur_time);  
  1006.   
  1007.             tm = localtime (&cur_time);  
  1008.   
  1009.             if (c == 'd') /* ISO 8601 */  
  1010.   
  1011.                 printf ("%d-%02d-%02d", 1900 + tm->tm_year,tm->tm_mon + 1, tm->tm_mday);  
  1012.   
  1013.             else  
  1014.   
  1015.                 printf ("%02d:%02d:%02d", tm->tm_hour,tm->tm_min, tm->tm_sec);  
  1016.   
  1017.             break;  
  1018.   
  1019. #endif  
  1020.   
  1021.         }  
  1022.   
  1023.   
  1024.   
  1025.     case 'l':  
  1026.   
  1027.         printf ("%s", tty);  
  1028.   
  1029.         break;  
  1030.   
  1031.     case 'u':  
  1032.   
  1033.     case 'U':  
  1034.   
  1035.         {  
  1036.   
  1037.             int users = 0;  
  1038.   
  1039.             struct utmp *ut;  
  1040.   
  1041.             setutent ();  
  1042.   
  1043.             while ((ut = getutent ()))  
  1044.   
  1045.                 if (ut->ut_type == USER_PROCESS)  
  1046.   
  1047.                     users++;  
  1048.   
  1049.             endutent ();  
  1050.   
  1051.             printf ("%d", users);  
  1052.   
  1053.             if (c == 'U')  
  1054.   
  1055.                 printf (" user%s", users == 1 ? "" : "s");  
  1056.   
  1057.             break;  
  1058.   
  1059.         }  
  1060.   
  1061.     default:  
  1062.   
  1063.         putchar (c);  
  1064.   
  1065.     }  
  1066.   
  1067. }  
  1068.   
  1069.   
  1070.   
  1071. static void do_prompt (int showlogin)  
  1072.   
  1073. {  
  1074.   
  1075.     FILE *fd;  
  1076.   
  1077.     int c;  
  1078.   
  1079.   
  1080.   
  1081.     if (nonewline == 0)  
  1082.   
  1083.         putchar ('\n');  
  1084.   
  1085.     if (noissue == 0 && (fd = fopen ("/etc/issue", "r"))) {//存有Arago图案,打印此登录图案  
  1086.   
  1087.         while ((c = getc (fd)) != EOF) {  
  1088.   
  1089.             if (c == '\\')  
  1090.   
  1091.                 output_special_char (getc (fd));  
  1092.   
  1093.             else  
  1094.   
  1095.                 putchar (c);  
  1096.   
  1097.         }  
  1098.   
  1099.         fclose (fd);  
  1100.   
  1101.     }  
  1102.   
  1103.     if (nohostname == 0)  
  1104.   
  1105.         printf ("%s ", hn);  
  1106.   
  1107.     if (showlogin)  
  1108.   
  1109.         printf ("login: ");  
  1110.   
  1111.     fflush (stdout);  
  1112.   
  1113. }  
  1114.   
  1115.   
  1116.   
  1117. static char *get_logname (void)  
  1118.   
  1119. {  
  1120.   
  1121.     static char logname[40];  
  1122.   
  1123.     char *bp;  
  1124.   
  1125.     unsigned char c;  
  1126.   
  1127.   
  1128.   
  1129.     tcflush (0, TCIFLUSH);        /* flush pending input */  
  1130.   
  1131.     for (*logname = 0; *logname == 0;) {  
  1132.   
  1133.         do_prompt (1);//打印登录图案,argo:  
  1134.   
  1135.         for (bp = logname;;) {  
  1136.   
  1137.             if (read (0, &c, 1) < 1) {//从标准输入里读入一个字符  
  1138.   
  1139.                 if (errno == EINTR || errno == EIO|| errno == ENOENT)  
  1140.   
  1141.                     exit (EXIT_SUCCESS);  
  1142.   
  1143.                 error ("%s: read: %s", tty, strerror (errno));  
  1144.   
  1145.             }  
  1146.   
  1147.             if (c == '\n' || c == '\r') {//回车或换行符号表示结束  
  1148.   
  1149.                 *bp = 0;  
  1150.   
  1151.                 break;  
  1152.   
  1153.             } else if (!isprint (c))  
  1154.   
  1155.                 error ("%s: invalid character 0x%x in login"" name", tty, c);  
  1156.   
  1157.             else if ((size_t)(bp - logname) >= sizeof (logname) - 1)  
  1158.   
  1159.                 error ("%s: too long login name", tty);  
  1160.   
  1161.             else  
  1162.   
  1163.                 *bp++ = c;  
  1164.   
  1165.         }  
  1166.   
  1167.     }  
  1168.   
  1169.     return logname;  
  1170.   
  1171. }  
  1172.   
  1173.   
  1174.   
  1175. static struct option const long_options[] = {  
  1176.   
  1177.     { "autologin", required_argument, NULL, 'a' },  
  1178.   
  1179.     { "chdir", required_argument, NULL, 'w' },  
  1180.   
  1181.     { "chroot", required_argument, NULL, 'r' },  
  1182.   
  1183.     { "delay", required_argument, NULL, 'd' },  
  1184.   
  1185.     { "noclear", no_argument, &noclear, 1 },  
  1186.   
  1187.     { "nonewline", no_argument, &nonewline, 1 },  
  1188.   
  1189.     { "noissue", no_argument, &noissue, 1 },  
  1190.   
  1191.     { "nohangup", no_argument, &nohangup, 1 },  
  1192.   
  1193.     { "no-hostname", no_argument, &nohostname, 1 }, /* compat option */  
  1194.   
  1195.     { "nohostname", no_argument, &nohostname, 1 },  
  1196.   
  1197.     { "loginprog", required_argument, NULL, 'l' },  
  1198.   
  1199.     { "long-hostname", no_argument, &longhostname, 1 },  
  1200.   
  1201.     { "nice", required_argument, NULL, 'n' },  
  1202.   
  1203.     { 0, 0, 0, 0 }  
  1204.   
  1205. };  
  1206.   
  1207.   
  1208.   
  1209. int main (int argc, char **argv)  
  1210.   
  1211. {  
  1212.   
  1213.     char *logname, *s;  
  1214.   
  1215.     int c;  
  1216.   
  1217.   
  1218.   
  1219.     progname = argv[0];//程序名称,即mingetty  
  1220.   
  1221.     if (!progname)  
  1222.   
  1223.         progname = "mingetty";  
  1224.   
  1225.     /*struct utsname  
  1226.   
  1227.       {   
  1228.   
  1229.          char sysname[_UTSNAME_SYSNAME_LENGTH];//当前操作系统名  
  1230.   
  1231.          char nodename[_UTSNAME_NODENAME_LENGTH];//网络上的名称  
  1232.   
  1233.          char release[_UTSNAME_RELEASE_LENGTH];//当前发布级别  
  1234.   
  1235.          char version[_UTSNAME_VERSION_LENGTH];//当前发布版本  
  1236.   
  1237.          char machine[_UTSNAME_MACHINE_LENGTH];//当前硬件体系类型  
  1238.   
  1239.          char domainname[_UTSNAME_DOMAIN_LENGTH]; //当前域名  
  1240.   
  1241.       };*/  
  1242.   
  1243.     uname (&uts);//获取当前内核名称和其它信息,并存于utsname结构中  
  1244.   
  1245.     gethostname (hn, MAXHOSTNAMELEN);//本地主机的标准主机名,存到数组hn中  
  1246.   
  1247.     hn[MAXHOSTNAMELEN] = '\0';  
  1248.   
  1249.     pid = getpid ();//取得进程ID  
  1250.   
  1251.     sid = getsid (0);//get the process group ID of session leader  
  1252.   
  1253.     putenv ("TERM=linux");//把字符串加到当前环境中,设置的环境仅对程序本身有效  
  1254.   
  1255.       
  1256.   
  1257.     //解析命令行选项参数。  
  1258.   
  1259.     //字符串optstring可以下列元素:  
  1260.   
  1261.     //单个字符,表示选项,  
  1262.   
  1263.     //单个字符后接一个冒号:表示该选项后必须跟一个参数。参数紧跟在选项后或者以空格隔开。该参数的指针赋给optarg。  
  1264.   
  1265.     //单个字符后跟两个冒号,表示该选项后可以有参数也可以没有参数。如果有参数,参数必须紧跟在选项后不能以空格隔开。该参数的指针赋给optarg。(这个特性是GNU的扩张)。  
  1266.   
  1267.     while ((c = getopt_long (argc, argv, "a:d:l:n:w:r:", long_options,(int *) 0)) != EOF) {  
  1268.   
  1269.         switch (c) {  
  1270.   
  1271.         case 0:  
  1272.   
  1273.             break;  
  1274.   
  1275.         case 'a':  
  1276.   
  1277.             autologin = optarg;//获得参数-a后面的参数  
  1278.   
  1279.             break;  
  1280.   
  1281.         case 'd':  
  1282.   
  1283.             delay = atoi (optarg);  
  1284.   
  1285.             break;  
  1286.   
  1287.         case 'l':  
  1288.   
  1289.             loginprog = optarg;  
  1290.   
  1291.             break;  
  1292.   
  1293.         case 'n':  
  1294.   
  1295.             priority = atoi (optarg);  
  1296.   
  1297.             break;  
  1298.   
  1299.         case 'r':  
  1300.   
  1301.             ch_root = optarg;  
  1302.   
  1303.             break;  
  1304.   
  1305.         case 'w':  
  1306.   
  1307.             ch_dir = optarg;  
  1308.   
  1309.             break;  
  1310.   
  1311.         default:  
  1312.   
  1313.             usage ();  
  1314.   
  1315.         }  
  1316.   
  1317.     }  
  1318.   
  1319.       
  1320.   
  1321.     //s指针保存主机名  
  1322.   
  1323.     if (longhostname == 0 && (s = strchr (hn, '.')))  
  1324.   
  1325.         *s = '\0';  
  1326.   
  1327.           
  1328.   
  1329.     //获得终端结构,例如ttyS0等  
  1330.   
  1331.     tty = argv[optind];  
  1332.   
  1333.     if (!tty)  
  1334.   
  1335.         usage ();  
  1336.   
  1337.           
  1338.   
  1339.     //终端名添加"/dev/",变成/dev/ttyS0  
  1340.   
  1341.     if (strncmp (tty, "/dev/", 5) == 0)  
  1342.   
  1343.         tty += 5;  
  1344.   
  1345.   
  1346.   
  1347.     update_utmp ();//更新登录信息  
  1348.   
  1349.     if (delay)  
  1350.   
  1351.         sleep (delay);  
  1352.   
  1353.     open_tty ();//打开终端设备  
  1354.   
  1355.       
  1356.   
  1357.     if (autologin) { //如果前边参数为-a且-a后边带有登录名,则会设置autologin即自动登录  
  1358.   
  1359.         do_prompt (0);//打印登录图形  
  1360.   
  1361.         printf ("login: %s (automatic login)\n", autologin);  
  1362.   
  1363.         logname = autologin;//获得自动登录名  
  1364.   
  1365.     } else//不是自动登录  
  1366.   
  1367.         while ((logname = get_logname ()) == 0);//获得登录名  
  1368.   
  1369.       
  1370.   
  1371.     if (ch_root)  
  1372.   
  1373.         chroot (ch_root);  
  1374.   
  1375.     if (ch_dir)  
  1376.   
  1377.         chdir (ch_dir);  
  1378.   
  1379.     if (priority)  
  1380.   
  1381.         nice (priority);  
  1382.   
  1383.       
  1384.   
  1385.     //带着登录名参数,执行loginprog=/bin/login程序登录,即login--logname  
  1386.   
  1387.     execl (loginprog, loginprog, autologin? "-f" : "--", logname, NULL);  
  1388.   
  1389.     /*login函数片段  
  1390.   
  1391.     。。。。。。。      
  1392.   
  1393.     strcpy(buff, "exec ");  
  1394.   
  1395.     strcat(buff, pwd->pw_shell);  
  1396.   
  1397.     childArgv[childArgc++] = "/bin/sh";  
  1398.   
  1399.     childArgv[childArgc++] = "-sh";  
  1400.   
  1401.     childArgv[childArgc++] = "-c";  
  1402.   
  1403.     childArgv[childArgc++] = buff;  
  1404.   
  1405.     childArgv[childArgc++] = NULL;  
  1406.   
  1407.     //登录成功,执行/bin/sh进入shell  
  1408.   
  1409.   execvp(childArgv[0], childArgv + 1);  
  1410.   
  1411.     */  
  1412.   
  1413.     //启动shell后,首先启动 /etc/profile 文件,然后再启动用户目录下的 ~/.bash_profile、 ~/.bash_login或 ~/.profile文件中的其中一个,执行的顺序为:~/.bash_profile、 ~/.bash_login、 ~/.profile。如果 ~/.bash_profile文件存在的话,一般还会执行 ~/.bashrc文件。  
  1414.   
  1415.     error ("%s: can't exec %s: %s", tty, loginprog, strerror (errno));  
  1416.   
  1417.     sleep (5);  
  1418.   
  1419.     exit (EXIT_FAILURE);  
  1420.   
  1421. }  
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值