zoukankan      html  css  js  c++  java
  • Linux 的启动流程

    原文链接:http://www.ruanyifeng.com/blog/2013/08/linux_boot_process.html

    半年前,我写了《计算机是怎样启动的?》。探讨BIOS和主引导记录的作用。

    那篇文章不涉及操作系统。仅仅与主板的板载程序有关。

    今天,我想接着往下写,探讨操作系统接管硬件以后发生的事情。也就是操作系统的启动流程。

    这个部分比較有意思。由于在BIOS阶段,计算机的行为基本上被写死了,程序猿能够做的事情并不多;可是,一旦进入操作系统。程序猿差点儿能够定制全部方面。所以,这个部分与程序猿的关系更密切。

    我主要关心的是Linux操作系统,它是眼下server端的主流操作系统。以下的内容针对的是Debian发行版。由于我对其它发行版不够熟悉。

    第一步、载入内核

    操作系统接管硬件以后,首先读入 /boot 文件夹下的内核文件。

    以我的电脑为例,/boot 文件夹以下大概是这样一些文件:

    
      $ ls /boot
      
      config-3.2.0-3-amd64
      config-3.2.0-4-amd64
      grub
      initrd.img-3.2.0-3-amd64
      initrd.img-3.2.0-4-amd64
      System.map-3.2.0-3-amd64
      System.map-3.2.0-4-amd64
      vmlinuz-3.2.0-3-amd64
      vmlinuz-3.2.0-4-amd64
      
    

    第二步、启动初始化进程

    内核文件载入以后,就開始执行第一个程序 /sbin/init。它的作用是初始化系统环境。

    因为init是第一个执行的程序。它的进程编号(pid)就是1。其它全部进程都从它衍生,都是它的子进程。

    第三步、确定执行级别

    很多程序须要开机启动。

    它们在Windows叫做"服务"(service)。在Linux就叫做"守护进程"(daemon)。

    init进程的一大任务,就是去执行这些开机启动的程序。可是,不同的场合须要启动不同的程序,比方用作server时。须要启动Apache,用作桌面就不须要。Linux同意为不同的场合,分配不同的开机启动程序,这就叫做"执行级别"(runlevel)。也就是说,启动时依据"执行级别"。确定要执行哪些程序。

    Linux预置七种执行级别(0-6)。

    一般来说,0是关机,1是单用户模式(也就是维护模式),6是重新启动。

    执行级别2-5,各个发行版不太一样。对于Debian来说。都是相同的多用户模式(也就是正常模式)。

    init进程首先读取文件 /etc/inittab,它是执行级别的设置文件。假设你打开它,能够看到第一行是这种:

    
      id:2:initdefault:
      
    

    initdefault的值是2。表明系统启动时的执行级别为2。假设须要指定其它级别。能够手动改动这个值。

    那么,执行级别2有些什么程序呢,系统怎么知道每一个级别应该载入哪些程序呢?......回答是每一个执行级别在/etc文件夹以下,都有一个相应的子文件夹,指定要载入的程序。

    
      /etc/rc0.d
      /etc/rc1.d
      /etc/rc2.d
      /etc/rc3.d
      /etc/rc4.d
      /etc/rc5.d
      /etc/rc6.d
      
    

    上面文件夹名中的"rc"。表示run command(执行程序)。最后的d表示directory(文件夹)。以下让我们看看 /etc/rc2.d 文件夹中究竟指定了哪些程序。

    
      $ ls  /etc/rc2.d
      
      README
      S01motd
      S13rpcbind
      S14nfs-common
      S16binfmt-support
      S16rsyslog
      S16sudo
      S17apache2
      S18acpid
      ...
      
    

    能够看到,除了第一个文件README以外。其它文件名称都是"字母S+两位数字+程序名"的形式。字母S表示Start,也就是启动的意思(启动脚本的执行參数为start),假设这个位置是字母K。就代表Kill(关闭),即假设从其它执行级别切换过来,须要关闭的程序(启动脚本的执行參数为stop)。后面的两位数字表示处理顺序,数字越小越早处理,所以第一个启动的程序是motd,然后是rpcbing、nfs......数字同样时,则依照程序名的字母顺序启动,所以rsyslog会先于sudo启动。

    这个文件夹里的全部文件(除了README),就是启动时要载入的程序。

    假设想添加或删除某些程序,不建议手动改动 /etc/rcN.d 文件夹。最好是用一些专门命令进行管理(參考这里这里)。

    第四步、载入开机启动程序

    前面提到,七种预设的"执行级别"各自有一个文件夹。存放须要开机启动的程序。

    不难想到。假设多个"执行级别"须要启动同一个程序,那么这个程序的启动脚本。就会在每个文件夹里都有一个拷贝。这样会造成管理上的困扰:假设要改动启动脚本,岂不是每个文件夹都要改一遍?

    Linux的解决的方法,就是七个 /etc/rcN.d 文件夹里列出的程序。都设为链接文件。指向另外一个文件夹 /etc/init.d 。真正的启动脚本都统一放在这个文件夹中。

    init进程逐一载入开机启动程序,事实上就是执行这个文件夹里的启动脚本。

    以下就是链接文件真正的指向。

    
      $ ls -l /etc/rc2.d
      
      README
      S01motd -> ../init.d/motd
      S13rpcbind -> ../init.d/rpcbind
      S14nfs-common -> ../init.d/nfs-common
      S16binfmt-support -> ../init.d/binfmt-support
      S16rsyslog -> ../init.d/rsyslog
      S16sudo -> ../init.d/sudo
      S17apache2 -> ../init.d/apache2
      S18acpid -> ../init.d/acpid
      ...
      
    

    这样做的还有一个优点,就是假设你要手动关闭或重新启动某个进程,直接到文件夹 /etc/init.d 中寻找启动脚本就可以。比方,我要重新启动Apacheserver。就执行以下的命令:

    
      $ sudo /etc/init.d/apache2 restart
      
    

    /etc/init.d 这个文件夹名最后一个字母d。是directory的意思。表示这是一个文件夹,用来与程序 /etc/init 区分。

    第五步、用户登录

    开机启动程序载入完成以后,就要让用户登录了。

    一般来说。用户的登录方式有三种:

      (1)命令行登录

      (2)ssh登录

      (3)图形界面登录

    这三种情况,都有自己的方式对用户进行认证。

    (1)命令行登录:init进程调用getty程序(意为get teletype)。让用户输入username和password。输入完毕后,再调用login程序,核对password(Debian还会再多执行一个身份核对程序/etc/pam.d/login)。假设password正确。就从文件 /etc/passwd 读取该用户指定的shell。然后启动这个shell。

    (2)ssh登录:这时系统调用sshd程序(Debian还会再执行/etc/pam.d/ssh ),代替getty和login。然后启动shell。

    (3)图形界面登录:init进程调用显示管理器,Gnome图形界面相应的显示管理器为gdm(GNOME Display Manager),然后用户输入username和password。假设password正确,就读取/etc/gdm3/Xsession,启动用户的会话。

    第六步、进入 login shell

    所谓shell,简单说就是命令行界面,让用户能够直接与操作系统对话。

    用户登录时打开的shell。就叫做login shell。

    Debian默认的shell是Bash,它会读入一系列的配置文件。

    上一步的三种情况,在这一步的处理,也存在差异。

    (1)命令行登录:首先读入 /etc/profile,这是对全部用户都有效的配置;然后依次寻找以下三个文件,这是针对当前用户的配置。

    
      ~/.bash_profile
      ~/.bash_login
      ~/.profile
      
    

    须要注意的是,这三个文件仅仅要有一个存在,就不再读入后面的文件了。比方,要是 ~/.bash_profile 存在,就不会再读入后面两个文件了。

    (2)ssh登录:与第一种情况全然同样。

    (3)图形界面登录:仅仅载入 /etc/profile 和 ~/.profile。

    也就是说,~/.bash_profile 无论有没有,都不会执行。

    第七步,打开 non-login shell

    老实说,上一步完毕以后。Linux的启动过程就算结束了,用户已经能够看到命令行提示符或者图形界面了。

    可是。为了内容的完整,必须再介绍一下这一步。

    用户进入操作系统以后,经常会再手动开启一个shell。这个shell就叫做 non-login shell,意思是它不同于登录时出现的那个shell,不读取/etc/profile和.profile等配置文件。

    non-login shell的重要性,不仅在于它是用户最常接触的那个shell,还在于它会读入用户自己的bash配置文件 ~/.bashrc。大多数时候。我们对于bash的定制。都是写在这个文件中面的。

    你或许会问,要是不进入 non-login shell,岂不是.bashrc就不会执行了,因此bash 也就不能完毕定制了?其实,Debian已经考虑到这个问题了。请打开文件 ~/.profile,能够看到以下的代码:

    
      if [ -n "$BASH_VERSION" ]; then
        if [ -f "$HOME/.bashrc" ]; then
          . "$HOME/.bashrc"
        fi
      fi
      
    

    上面代码先推断变量 $BASH_VERSION 是否有值。然后推断主文件夹下是否存在 .bashrc 文件,假设存在就执行该文件。第三行开头的那个点,是source命令的简写形式,表示执行某个文件,写成"source ~/.bashrc"也是能够的。

    因此,仅仅要执行~/.profile文件,~/.bashrc文件就会连带执行。可是上一节的第一种情况提到过,假设存在~/.bash_profile文件,那么有可能不会执行~/.profile文件。

    解决问题非常easy。把以下代码写入.bash_profile即可了。

    
      if [ -f ~/.profile ]; then
        . ~/.profile
      fi
      
    

    这样一来,无论是哪种情况,.bashrc都会运行,用户的设置能够放心地都写入这个文件了。

    Bash的设置之所以如此繁琐,是因为历史原因造成的。

    早期的时候。计算机执行速度非常慢,加载配置文件须要非常长时间,Bash的作者仅仅好把配置文件分成了几个部分,阶段性加载。

    系统的通用设置放在 /etc/profile。用户个人的、须要被全部子进程继承的设置放在.profile,不须要被继承的设置放在.bashrc。

    顺便提一下,除了Linux以外, Mac OS X 使用的shell也是Bash。

    可是,它仅仅载入.bash_profile,然后在.bash_profile里面调用.bashrc。并且,无论是ssh登录,还是在图形界面里启动shell窗体,都是如此。

    參考链接

    [1] Debian Wiki, Environment Variables

    [2] Debian Wiki, Dot Files

    [3] Debian Administration, An introduction to run-levels

    [4] Debian Admin,Debian and Ubuntu Linux Run Levels

    [5] Linux Information Project (LINFO), Runlevel Definition

    [6] LinuxQuestions.org, What are run levels?

    [7] Dalton Hubble, Bash Configurations Demystified

    (完)


  • 相关阅读:
    Mybatis resultMap和resultType的区别
    根据xml文件生成javaBean
    WebService如何封装XML请求 以及解析接口返回的XML
    Java SE练习
    Maven手动将jar导入本地仓库
    【公告】【公告】【公告】【公告】
    【题解】SDOI2010地精部落
    【题解】CF559C C. Gerald and Giant Chess(容斥+格路问题)
    【题解】任务安排(斜率优化)
    【题解】Cats Transport (斜率优化+单调队列)
  • 原文地址:https://www.cnblogs.com/claireyuancy/p/6874298.html
Copyright © 2011-2022 走看看