系统开机其实是一项非常复杂的程序,因为核心得要侦测硬件并加载适当的驱动程序后,接下来则必须要呼叫程序来准备好系统运作的环境,以让使用者能够顺利的操作整部主机系统。

Linux 的开机流程分析

开机流程

按下电源按键后计算机硬件会主动的读取 BIOS 或 UEFI BIOS 来加载硬件信息及进行硬件系统的自我测试,之后系统会主动的去读取第一个可开机的装置(由 BIOS设定的),此时就可以读入开机管理程序了。

开机管理程序可以指定使用哪个核心文件来开机,并实际加载核心到内存当中解压缩与执行,此时核心就能够开始在内存内活动,并侦测所有硬件信息与加载适当的驱动程序来使整部主机开始运作,等到核心侦测硬件与加载驱动程序完毕后,操作系统就开始在PC 上面跑了。

主机系统开始运作后,此时 Linux 才会呼叫外部程序开始准备软件执行的环境,并且实际的加载所有系统运作所需要的软件程序。最后系统就会开始等待你登入与操作。

开机流程总结:
1.加载BIOS的硬件信息与进行自我测试,并依据设定取得第一个可开机的装置;
2.读取并执行第一个开机装置内 MBR 的 boot Loader (亦即是 grub2, spfdisk 等程序);
3.依据 boot loader 的设定加载 Kernel , Kernel会开始侦测硬件与加载驱动程序;
4.在硬件驱动成功后,Kernel会主动呼叫 systemd_ 程序,并以 default.target 流程开机:
systemd 执行 sysinit.target 初始化系统及 basic.target 准备操作系统;
systemd 启动 multi-user.target 下的本机与服务器服务;
systemd 执行 multi-user.target下的/etc/rc.d/rc.local 文件;
systemd 执行 multi-user.target下的 getty.target 及登入服务;
systemd 执行 graphical 需要的服务。

BIOS, boot loader 与 kernel 载入

BIOS:不论传统 BIOS 还是 UEFI BIOS 都会被简称为BIOS;
MBR:虽然分区表有传统 MBR 以及新式 GPT,不过 GPT 也有保留一块兼容 MBR 的区块。MBR就代表该磁盘的最前面可安装boot loader的那个区块。

BIOS, 开机自我测试与 MBR/GPT

在个人计算机架构下,想要启动整部系统首先就得要让系统去加载BIOS(Basic Input Output System),并透过 BIOS 程序去加载 CMOS 的信息,并且由 CMOS 内的设定值取得主机的各项硬件配置,例如 CPU 与接口设备的沟通频率啊、开机装置的搜寻顺序啊、硬盘的大小与类型啊、系统时间啊、各周边总线的是否启动 Plug and Play(PnP,即插即用装置)啊、各接口设备的TO地址啊、以及与CPU沟通的 IRQ岔断等等的信息。在取得这些信息后,BIOS还会进行开机自我测试(Power-on SelfTest,POST)。然后开始执行硬件侦测的初始化,并设定 PnP 装置,之后再定义出可开机的装置顺序,接下来就会开始进行开机装置的数据读取了。

由于系统软件大多放置到硬盘中,所以 BIOS 会指定开机的装置读取磁盘中的操作系统核心文件。但由于不同的操作系统他的文件系统格式不相同,因此必须要以一个开机管理程序来处理核心文件加载(load)的问题,因此这个开机管理程序就被称为 Boot Loader了。Boot Loader 程序安装开机装置的第一个扇区(sector)内,MBR (Master Boot Record,主要启动记录区)。

核心文件需要 loader来读取,那每个操作系统的 loader 都不相同,BIOS是透过硬件的 INT 13 中断功能来读取MBR的,也就是说,只要 BIOS能够侦测磁盘(不论该磁盘是SATA还是 SAS 接口),那他就有办法透过INT 13这条信道来读取该磁盘的第一个扇区内的 MBR软件。

Boat Loader 的功能

Loader 的最主要功能是要认识操作系统的文件格式并据以加载核心到主存储器中去执行。由于不同操作系统的文件格式不一致,因此每种操作系统都有自己的 boot loader。

每个文件系统(filesystem,或者是 partition)都会保留一块启动扇区 (boot sector)提供操作系统安装 boot loader,而通常操作系统默认都会安装一份 loader 到他根目录所在的文件系统的 boot sector 上。

如果在一部主机上面安装 Windows 与 Linux 后,该 boot sector, boot loader 与 MBR 的相关性会有点像下图:

boot loader主要的功能如下:
1.提供选单:用户可以选择不同的开机项目,这也是多重引导的重要功能;
2.载入核心文件:直接指向可开机的程序区段来开始操作系统;
3.转交其他 loader:将开机管理功能转交给其他 loader负责。

由于具有选单功能,因此可以选择不同的核心来开机。而由于具有控制权转交的功能,因此可以加载其他boot sector 内的 loader。不过 Windows的 loader 预设不具有控制权转交的功能,因此不能使用 Windows 的 loader来加载 Linux 的 loader 。

开机管理程序的选单功能与控制权转交功能示意图:

MBR 使用 Linux 的 grub2这个开机管理程序,并且里面假设已经有了三个选单第一个选单可以直接指向Linux 的核心文件并且直接加载核心来开机;第二个选单可以将开机管理程控权交给 Windows 来管理,此时 Windows的 loader 会接管开机流程,这个时候他就能够启动windows了。第三个选单则是使用Linux在 boot sector 内的开机管理程序,此时就会跳出另一个grub2的选单。
选单一:MBR(grub2) –> kernel file –> booting
选单二:MBR(grub2) –> boot sector(Windows loader) –> Windows kernel –> booting
选单三:MBR(grub2) –> boot sector(grub2) –> kernel file –> booting
而最终 boot loader 的功能就是【加载 kernel 文件】。

加载核心侦测硬件与 initramfs 功能

由 boot loader 的管理而开始读取核心文件后,接下来,Linux就会将核心解压缩到主存储器当中,并且利用核心的功能,开始测试与驱动各个周边装置,包括储存装置、CPU、网络卡、声卡等等。此时 Linux 核心会以自己的功能重新侦测一次硬件,而不一定会使用 BIOS 侦测到的硬件信息。
也就是说,核心此时才开始接管 BIOS 后的工作了。一般来说,核心文件会被放置到 /boot 里面,并且取名为 /boot/vmlinuz。

CentOs 7.x 的 Linux核心为 3.10.0-229.el7.x86_64 这个版本。
Linux 核心是可以透过动态加载核心模块的(就请想成驱动程序即可),这些核心模块就放置在 /lib/modules/ 目录内。
由于模块放置到磁盘根目录内(要记得 /lib 不可以与 /分别放在不同的 partition),因此在开机的过程中核心必须要挂载根目录,这样才能够读取核心模块提供加载驱动程序的功能。而且为了担心影响到磁盘内的文件系统,因此开机过程中根目录是以只读的方式来挂载的喔。

一般来说,非必要的功能且可以编译成为模块的核心功能,目前的 Linux distributions 都会将他编译成为模块。因此 USB,SATA, SCS…等磁盘装置的驱动程序通常都是以模块的方式来存在的。
假 linux 是安装在 SATA 磁盘上面的,可以透过 BIOS的 INT 13取得 boot loader 与 kernel 文件来开机,然后kernel 会开始接管系统并且侦测硬件及尝试挂载根目录来取得额外的驱动程序。

问题是,核心根本不认识 SATA 磁盘,所以需要加载 SATA 磁盘的驱动程序,否则根本就无法挂载根目录。但是 SATA 的驱动程序在 /lib/modules 内,根本无法挂载根目录,无法读取到 /lib/modules/ 内的驱动程序。可以透过虚拟文件系统来处理这个问题。

虚拟文件系统 (Initial RAM Disk 或 Initial RAM Filesystem) 一般使用的档名为 /boot/initrd 或 /boot/initramfs,也能够透过 boot loader来加载到内存中,然后这个文件会被解压缩并且在内存当中仿真成一个根目录,且此仿真在内存当中的文件系统能够提供一支可执行的程序,透过该程序来加载开机过程中所最需要的核心模块,通常这些模块就是USB,RAID, LVM,SCSI等文件系统与磁盘接口的驱动程序。等载入完成后,会帮助核心重新呼叫 systemd 来开始后续的正常开机流程。

BIOS 与 boot loader 及核心加载流程示意图:
上图所示,boot loader 可以加载 kernel与 initramfs ,然后在内存中让 initramfs 解压缩成为根目录,kernel 就能够由此加载适当的驱动程序,最终释放虚拟文件系统,并挂载实际的根目录文件系统,就能够开始后续的正常开机流程。

initramfs文件内容:先是档头宣告的许多文件部份,再来才是真的会被核心取用的全部附加的文件数据。

其实 initramfs 就是一个小型的根目录,这个小型根目录里面也是透过 systemd 来进行管理,同时观察default.target 的链接,会发现其实这个小型系统就是透过 initrd.target 来开机,而 initrd.target 也是需要读入一堆例如 basic.target, sysinit.target 等等的硬件侦测、核心功能启用的流程,然后开始让系统顺利运作。最终才又卸除 initramfs的小型文件系统,实际挂载系统的根目录。

第一支程序 systemd 及使用 default.target 进入开机程序分析

在核心加载完毕、进行完硬件侦测与驱动程序加载后,此时主机硬件应该已经准备就绪了(ready),此时核心会主动的呼叫第一支程序,那就是 systemd。
systemd 最主要的功能就是准备软件执行的环境,包括系统的主机名、网络设定、语系处理、文件系统格式及其他服务的启动等。而所有的动作都会透过 systemd 的默认启动服务集合,亦即是 /etc/systemd/system/default.target 来规划。另外,systemd 已经舍弃了 system V 的 runlevel。

常见的操作环境 target 与兼容于 runlevel 的等级

可以作为预设的操作环境(default.target)的主要项目有:multi-user.target 以及 graphical.target 这两个。还有某些比较特殊的操作环境,包括 rescue.target,emergency.target,shutdown.target 等等。

过去的 systemV 使用的是一个称为 runlevel (执行等级)的概念来启动系统的,systemd 为了兼容于旧式的 systemV操作行为,所以也将 runlevel 与操作环境做个结合。
可以使用底下的方式来查询两者间的对应:
切换执行等级可以使用【init3】转成文字界面,【init 5】转成图形界面。这个 init 程序依旧是保留下来的,只是 init 3 会相当于systemctl isolate multi-user.target 。如果做个完整的迭代,这两个东西的对应为:

systemd 的处理流程

取得了 /etc/systemd/system/default.target 这一个预设操作界面的设定之后,接下来系统帮首先会链接到 /usr/lib/systemd/system/ 这个目录下去取得 multi-user.target 或 graphical.target 这两个其中的一(正常的进入Linux操作环境的情况下),假设是使用 graphical.target,接着下来 systemd 会去找两个地方的设定,就是如下的目录:
/etc/systemd/system/graphical.target.wants/:使用者设定加载的 unit;
/usr/lib/systemd/system/graphical.target.wants/:系统默认加载的 unit;
Unit 表示 graphical.target 必须要完成 multi-user.target 之后才能够进行,而进行完 graphical.target 之后,还得要启动 display-manager.service 才行的意思。

系统默认要加载的 unit:
使用者默认要加载的 unit:
multi-usre.target 需要在 basic.target 运作完毕才能够载入上述的许多unit。然后再去 basic.target 里头找数据等等~最终这些数据就可以透过【systemctl list-dependencies graphical.target】这个指令来列出所有的相关性的服务。这就是 systemd 的呼叫所需要的服务的流程。

CentOS 7.x 的 systemd 开机流程大约是这样:
1.local-fs.target + swap.target:这两个 target 主要在挂载本机 /etc/fistab 里面所规范的文件系统与相关的内存置换空间。
2.sysinit.target:这个 target 主要在侦测硬件,加载所需要的核心模块等动作。
3.basic.target:加载主要的外围硬件驱动程序与防火墙相关任务;
4.multi-user.target:底下的其它一般系统或网络服务的加载;
5.图形界面相关服务如 gdm.service 等其他服务的加载。

systemd 执行 sysinit.target 初始化系统、basic.target 准备系统

使用【systemctl list-dependencies sysinit.target】会看到很多相依的服务,可以将这些服务归类成几个大项:
特殊文件系统装置的挂载:包括 dev-hugepages.mount dev-mqucue.mount 等挂载服务,主要在挂载跟巨量内存分页使用与消息队列的功能。挂载成功后,会在 /dev 底下建立 /dev/hugepages/ , /dev/mqueue/ 等目录;
特殊文件系统的启用:包括磁盘阵列、网络驱动器(iscsi)、LVM 文件系统、文件系统对照服务(multipath)等等,也会在这里被侦测与使用到;
开机过程的讯息传递与动画执行:使用 plymouthd 服务搭配 plymouth 指令来传递动画与讯息
日志式登录文件的使:就是systemd-journald这个服务的启用;
加载额外的核心模块:透过 /etc/modulcs-load.d/*.conf 文件的设定,让核心额外加载管理员所需要的核心模块;
加载额外的核心参数设定:包括 /etc/sysctl.conf 以及 /etc/sysctl.d/*.conf 内部设定;
启动系统的随机数生成器:随机数生成器可以帮助系统进行一些密码加密演算的功能
设定终端机(console)字形;
启动动态设备管理器:就是 udevd 用在动态对应实际装置存取与装置文件名对应的一个服务。

不论即将使用哪种操作环境来使用系统,这个 sysinit.target 几乎都是必要的工作。
执行完 sysinit.target 之后,再来则是 basic.target 这个项目了。basic.target的阶段主要启动的服务大概有这些:
加载 alsa 音效驱动程序:这个alsa是个音效相关的驱动程序,会让系统有音效产生;
载入 firewalld 防火墙:CentOS 7.x 以后使用 firewalld 取代 iptables 的防火墙设定,虽然最终都是使用iptables 的架构,不过在设定上面差很多;
加载CPU的微指令功能;
启动与设定 SELinux 的安全本文:如果由 disable 的状态改成 enable 的状态,或者是管理员设定强制重新设定一次 SELinux 的安全本文,也在这个阶段处理;
将目前的开机过程所产生的开机信息写入到 /var/log/dmesg 当中;
由 /etc/sysconfig/modules/*.modules 及 /etc/rc.modules 加载管理员指定的模块;
加载 systemd 支持的 timer 功能;

systemd 启动 multi-user.target 下的功能

在加载核心驱动硬件后,经过 sysinit.target 的初始化流程让系统可以存取之后,加上 basic.target 让系统成为操作系统的基础,之后就是服务器要顺利运作时,需要的各种主机服务以及提供服务器功能的网络服务的启动了。这些服务的启动则大多是附挂在 multi-user.target 这个操作环境底下,可以到 /etc/systemd/system/multi-user.target.wants/ 里头去查看预设要被启动的服务。也就是说,一般来说服务的启动脚本设定都是放在底下的目录内:
./usr/lib/systemd/system (系统默认的服务启动脚本设定);
./etc/systemd/system(管理员自己开发与设定的脚本设定);

而用户针对主机的本地服务与服务器网络服务的各项 unit 若要 enable 的话,就是将它放到 /etc/systemdsystem/multi-user.target.wants/ 这个目录底下做个链接,这样就可以在开机的时候去启动它。

相容 systemV 的 re-local.service

当系统完成开机后,还想要让系统额外执行某些程序的话,可以将该程序指令或脚本的绝对路径名称写入到 /etc/rc.d/rc.local 这个文件去。
新的 systemd 机制中,它建议直接写一个 systemd 的启动脚本配置文件到 /etc/systemd/system 底下,然后使用 systemctl enable 的方式来设定启用它,而不要直接使用rc.local这个文件。

有这个服务,但是 rc.local不具有可执行(x)的权限,因此这个服务不会被执行。
透过这个 chmod a+x /etc/rc.d/rc.local 的步骤,许多脚本就可以放在 /etc/rc.d/rc.local 这个文件内,系统在每次开机都会去执行这文件内的指令。

提供 tty 界面与登入的服务
在 multi-user.target 底下还有个 getty.target 的操作界面项目,能不能提供适当的登入服务也是 multi-user.target 底下的内容。包括 systemd-logind.service, systemd-user-sessions.service 等服务。
由于服务都是同步运作,不一定哪个服务先启动完毕。如果 getty 服务先启动完毕时,会发现到有可用的终端机尝试让你登入系统了。问题是,如果 systemd-logind.service 或 systemd-user-sessions.service 服务尚未执行完毕的话,那么还是无法登入系统的。

systemd 启动 graphical.target 底下的服务

如果 default.target 是 multi-user.target 的话,那么这个步骤就不会进行。反之,如果是 graphical.target 的话,那么 systemd 就会开始加载用户管理服务与图形界面管理员(window displaymanager, DM)等,启动图形界面来让用户以图形界面登入系统。
gdm.service 的最重要的执行档是/usr/lsbin/gdm,让用户可以利用图形界面登入的最重要服务。

开机过程会用到的主要配置文件

基本上,systemd 有自己的配置文件处理方式,不过为了兼容于 systemV ,其实很多的服务脚本设定还是会读取位于 /etc/sysconfig 底下的环境配置文件。

关于模块:/etc/modprobe.d/*.conf 及 /etc/modules-load.d/*.conf
加载用户自定义模块的地方吗,有两个地方可以处理模块加载的问题,包括:
./etc/modules-load.d/*.conf:单纯要核心加载模块的位置;
/etc/modprobe.d/*.conf:可以加上模块参数的位置;
基本上 systemd 已经将开机会用到的驱动程序全部加载了,如果有某些特定的参数要处理时,应该就得要在这里进行了。

/etc/sysconfig/*
authconfig:
这个文件主要在规范使用者的身份认证的机制,包括是否使用本机的 /etc/passwd,/etc/shadow 等,以及 /etc/shadow 密码记录使用何种加密算法,还有是否使用外部密码服务器提供的账号验证(NIS,LDAP)等。系统默认使用 SHA512 加密算法,并且不使用外部的身份验证机制;另外,不建议手动修改这个文件,应该使用【authconfig-tui】指令来修改更好。
cpupower:
如果有启动 cpupower.service 服务时,就会读取这个配置文件。主要是 Linux核心如何操作CPU的原则。一般来说,启动 cpupower.service 之后,系统会让 CPU 以最大效能的方式来运作,否则预设就是用多少算多少的模式来处理的。
firewalld, iptables-config, iptables-config, ebtables-config:
与防火墙服务的启动外带的参数有关;
network-scripts/:
至于network-scripts 里面的文件,则是主要用在设定网络卡;

核心与核心模块

在整个开机的过程当中,是否能够成功的驱动主机的硬件配备,是核心(kernel)的工作。而核心一般都是压缩文件,因此在使用核心之前,就得要将他解压缩后,才能加载主存储器当中。
目前的核心都是具有【可读取模块化驱动程序】的功能,亦即是所谓的【modules (模块化)】的功能。所谓的模块化可以将他想成是一个【插件】,该插件可能由硬件开发厂商提供,也有可能核心本来就支持。不过,较新的硬件,通常都需要硬件开发商提供驱动程序模块。

核心与核心模块存放地址:
核心:/boot/vmlinuz 或 /boot/vmlinuz-version;
核心解压缩所需 RAM Disk:/boot/initramfs (boot/initramfs-version);
核心模块:/lib/modules/version/kernel 或 /lib/modules/S(uname -r)/kernel;
核心原始码:/usr/src/linux 或 /usr/src/kernels/(要安装才会有,预设不安装)

如果该核心被顺利的加载系统当中了就会有几个信息纪录下来:
核心版本:/proc/version
系统核心功能:/proc/sys/kernel/

如果有个新的硬件,偏偏操作系统不支持,可以:
重新编译核心,并加入最新的硬件驱动程序原始码;
将该硬件的驱动程序编译成为模块,在开机时加载该模块;

核心模块与相依性

基本上,核心模块的放置处是在 /lib/modules/$(uname -r)/kernel 当中,里面主要还分成几个目录:


/lib/modules/$(uname -r)modules.dep 这个文件记录了在核心支持的模块的各项相依性。
建立这个文件可以使用 depmod 指令:

depmod


kernel 核心模块扩展名一定是 .ko 结尾的,使用 depmod 之后,该程序会跑到模块标准放置目录 /lib/modules/$(uname -r)/kernel,并依据相关目录的定义将全部的模块捉出来分析,最终才将分析的结果写入 modules.dep 文件中。

核心模块的观察

利用 lsmod 可以知道目前核心加载了多少的模块。

使用 Ismod 之后,系统会显示出目前已经存在于核心当中的模块,显示的内容包括有:
模块名称(Module);
模块的大小(size);
此模块是否被其他模块所使用(Used by)。

读出某个模块的信息:modinfo

modinfo [-adln] [module_name|filename]


核心模块的加载与移除

使用 modprobe 可以加载模块,这是因为 modprobe 会主动的去搜寻 modules.dep 的内容,先克服了模块的相依性后,才决定需要加载的模块有哪些。
至于 insmod 则完全由使用者自往加载一个完整文件名的模块,并不会主动的分析模块相依性。

insmod [/full/path/module_name] [parameters]

移除:

rmmod [-fw] module_name# -f:强制将该模块移除掉,不论是否正被使用。

使用 insmod 与 rmmod 必须要自行找到模块的完整文件名才行。 万一模块有相依属性的问题时,将无法直接加载或移除该模块。
因此,推荐使用 modprobe 来处理模块加载问题:

modprobe [-cfr] module_name

不需要知道完整的模块文件名,这是因为该完整文件名已经记录到 /lib/modules/‘uname -r’/modules.dep当中了。

Boot Loader:Grub2

【boot loader 是载入核心的重要工具】没有 boot loader,kernel 根本就没有办法被系统加载。

boot loader 的两个 stage

在 BIOS 读完信息后,接下来就是会到第一个开机装置的 MBR 去读取 boot loader了。这个 boot loader可以具有选单功能、直接加载核心文件以及控制权移交的功能等,系统必须要有 loader才有办法加载该操作系统的核心。
但是 MBR 是整个硬盘的第一个 sector 内的一个区块,充其量整个大小也才 446 bytes而已。即使是GPT也没有很大的扇区来储存 loader 的数据。

Linux 将 boot loader 的程序代码执行与设定值加载分成两个阶段(stage)来执行:
stage1:执行 boot loader 的主程序:
第一阶段为执行 boot loader 的主程序,这个程序必须要被安装在开机区,亦即是 MBR 或者是 boot sector。但因为 MBR实在太小了,所以,MBR 或b oot sector 通常仅安装 boot loader 的最小主程序,并没有安装loader 的相关配置文件;
stage2:主程序加载配置文件:
第二阶段为透过 boot loader 加载所有配置文件与相关的环境参数文件(包括文件系统定义与主要配置文件 grub.cfg),一般来说,配置文件都在 /boot 下。


boot/grub2/ 目录下最重要的就是配置文件(grub2.cfg)以及各种文件系统的定义。
loader 读取了这种文件系统定义数据后,就能够认识文件系统并读取在该文件系统内的核心文件了。
所以,grub2 认识的文件系统与磁盘分区格式非常多。

grub2 的配置文件 /boot/grub2/grub.cfg 初探

grub2 的优点包括有:
1.认识与支持较多的文件系统,并且可以使用 grub2 的主程序直接在文件系统中搜寻核心档名;
2.开机的时候,可以【自行编辑与修改开机设定项目】,类似 bash 的指令模式;
3.可以动态搜寻配置文件,而不需要在修改配置文件后重新安装 grub2。亦即是只要修改完 /boot/grub2/grub.cfg 里头的设定后,下次开机就生效了。
第三点其实就是 Stage 1, Stage 2 分别安装在 MBR(主程序)与文件系统当中(配置文件与定义档)的原因。

磁盘与分区槽在 grub2 中的代号

安装在 MBR 的 grub2 主程序,最重要的任务之一就是从磁盘当中加载核心文件,以让核心能够顺利的驱动整个系统的硬件。所以,grub2 必须要认识硬盘才行。
grub2 对硬盘的代号设定与传统的 Linux磁盘代号完全是不同的。
grub2 对硬盘的识别使用的是如下的代号:

硬盘代号以小括号 () 包起来;
硬盘以 hd 表示,后面会接一组数字;
以【搜寻顺序】做为硬盘的编号(这个重要);
第一个搜寻到的硬盘为 0 号,第二个为1 号,以此类推;
每颗硬盘的第一个 partition代号为1,依序类推。

第一颗【搜寻到的硬盘】代号为:【(hd0)】,而该颗硬盘的第一号分区槽为【(hd0,1)】。为了区分不同的分区格式,因此磁盘后面的分区号码可以使用类似 msdos1 与 gpt1 的方式来调制。

磁盘的号码是由О开始编号,分区槽的号码则与Linux 一样,是由 1 号开始编号。两者不同! 旧版的 grub 不论磁盘还是分区槽的起始号码都是 0 号,而 grub2 在分区槽的部份是以 1号开始编。
此外,由于 BIOS 可以调整磁盘的开机顺序,因此上述的磁盘对应的(hdN)那个号码 N 是可能会变动的。

整个硬盘代号为:

/boot/grub2/grub.cfg 配置文件(不要随便改):


在 grub.cfg 最开始的部份,其实大多是环境设定与默认值设定等,比较重要的当然是默认由哪个选项开机 (set default)以及预设的秒数(set timeout)。

grub2 配置文件维护 /etc/default/grub 与 /etc/grub.d

/etc/default/grub 主要环境配置文件


倒数时间参数:GRUB_TIMEOUT
这个设定值相当简单,后面就是接要倒数的秒数即可~例如要等待30秒,就在这边改成【GRUB_TIMEOUT=30】即可。如果不想等待则输入 0,如果一定要使用者选择,则填 -1 即可;
是否隐藏选单项目:GRUB_TIMEOUT_STYLE
这个项目可选择的设定值有 menu, countdown, hidden等等。如果没有设定,预设是menu的意思。这个项目主要是在设定要不要显示选单。如果不想要让使用者看到选单,这里可以设定为 countdown。 countdown 会在屏幕上显示剩余的等待秒数,而hidden则空空如也。
讯息输出的终端机模式:GRUB_TERMINAL_OUTPUT
这个项目是指定输出的画面应该使用哪一个终端机来显示的意思,主要的设定值有【console, serial, gfxterm, vga_text】等等。除非有特别的需求,否则一般使用console即可;
默认开机选单项目:GRUB_DEFAULT
这个项目在指定要用哪一个选单(menuentry)来作为默认开机项目的意思。
能使用的设定值包括有【saved, 数字, title 名, ID 名】等等。
核心的外加参数功能:GRUB_CMDLINE_LINUX
如果核心在启动的时候还需要加入额外的参数,就在这里加入。举例来说,如果除了预设的核心参数之外,还需要让磁盘读写机制为deadline这个机制时,可以这样处理:

GRUB_CMDLINE_LINUX="......crashkernel=auto rhgb quiet elevator=deadline"

选单建置的脚本 /etc/grub.d/*

grub2-mkconfig 执行之后,grub2-mkconfig 会去分析 /etc/grub.d/*里面的文件,然后执行该文件来建置grub.cfg。
/etc/grub.d/* 目录下会有这些文件存在:
00_header:主要在建立初始的显示项目,包括需要加载的模块分析、屏幕终端机的格式、倒数秒数、选单是否需要隐藏等等,大部分在 /etc/default/grub 里面所设定的变量,大概都会在这个脚本当中被利用来重建 grub.cfg 。
10_linux:根据分析 /boot 底下的文件,尝试找到正确的 linux 核心与读取这个核心需要的文件系统模块与参数等,都在这个脚本运作后找到并设定到 grub.cfg 当中。因为这个脚本会将所有在 /boot 底下的每一个核心文件都对应到一个选单,因此核心文件数量越多,开机选单项目就越多了。如果未来不想要旧的核心出现在选单上,那可以透过移除旧核心来处理即可。
30_os-prober:这个脚本默认会到系统上找其他的 partition 里面可能含有的操作系统,然后将该操作系统做成选单来处理。如果不想要让其他的操作系统被侦测到并拿来开机,那可以在 /etc/default/grub 里面加上【GRUB_DISABLE_OS_PROBER=true】取消这个文件的运作。
40_custom:如果还有其他想要自己手动加上去的选单项目,或者是其他的需求,那么建议在这里补充即可。

所以,一般来说,会更动到的就是仅有 40_custom 这个文件即可。这个文件内容也大多在放置管理员自己想要加进来的选单项目。

menuentry 有几种常见的设定” />initramfs 的重要性与建立新 initramfs 文件

initramfs 在于提供开机过程中所需要的最重要核心模块,以让系统开机过程可以顺利完成。
需要 initramfs 的原因,是因为核心模块放置于 /lib/modules/$(uname -r)/kernel/ 当中,这些模块必须要根目录(/) 被挂载时才能够被读取。但是如果核心本身不具备磁盘的驱动程序时,当然无法挂载根目录,也就没有办法取得驱动程序,因此造成两难的地步。

initramfs 可以将 /lib/modules/… 内的【开机过程当中一定需要的模块】包成一个文件(档名就是 initramfs),然后在开机时透过主机的 INT 13 硬件功能将该文件读出来解压缩,并且 initramfs 在内存内会仿真成为根目录,由于此虚拟文件系统(Initial RAM Disk)主要包含磁盘与文件系统的模块,因此核心最后就能够认识实际的磁盘,那就能够进行实际根目录的挂载啦。
所以说:【initramfs 内所包含的模块大多是与开机过程有关,而主要以文件系统及硬盘模块(如usb, SCSI等)为主】的。

一般来说,需要 initramfs 的时刻为:
根目录所在磁盘为 SATA、USB 或 SCSI 等连接接口;
根目录所在文件系统为 LVM, RAID 等特殊格式;
根目录所在文件系统为非传统 Linux 认识的文件系统时;
其他必须要在核心加载时提供的模块。

一般来说,各 distribution 提供的核心都会附上 initramfs 文件,但如果有特殊需要所以想重制 initramfs 文件的话,可以使用 dracut / mkinitrd 来处理的。

dracut [-fv] [--add-drivers 列表] initramfs 档名 核心版本

使用 grub2

1.如果是从其他 boot loader 转成 grub2 时,得先使用 grub2-install 安装 grub2 配置文件;
2.承上,如果安装到 partition 时,可能需要加上额外的许多参数才能够顺利安装上去;
3.开始编辑 /etc/default/grub 及 /etc/grub.d/* 这几个重要的配置文件;
4.使用 grub2-mkconfig -o /boot/grub2/grub.cfg 来建立开机的配置文件。

开机前的额外功能修改

可以在预设选单按下任意键,还可以进行 grub2的【在线编修】功能。
grub2 开机画面:

由于预设选单就没有隐藏,因此会直接看到这 5 个选单而已,同时会有读秒在倒数。选单部分的画面其实就是 menuentry 后面的文字。

grub2额外的指令编辑模式:

关于开机画面与终端机画面的图形显示方式

修改 grub.cfg:

vim /etc/default/grub

为个别选单加上密码

使用者可以在开机的过程中于 grub2 内选择进入某个选单,以及进入 grub2 指令模式去修改选单的参数数据等。也就是说,主要的 grub2 控制有: (1)grub2 的选单指令列修改与(2)进入选择的选单开机流程。

grub2 的账号、密码与选单设定
grub2 有点在模拟 Linux 的账号管理方案。因为在 grub2的选单管理中,有针对两种身份进行密码设定:
superusers:设定系统管理员与相关参数还有密码等,使用这个密码的用户,将可在 grub2 内具有所有修改的权限。但一旦设定了这个 superusers 的参数,则所有的指令修改将会被变成受限制的;
users:设定一般账号的相关参数与密码,可以设定多个用户。使用这个密码的用户可以选择要进入某些
选单项目。不过,选单项目也得要搭配相对的账号才行。(一般来说,使用这种密码的账号并不能修改选单的内容,仅能选择进入选单去开机而已)

得要使用 superuses 来指定哪个账号是管理员。另外,这个账号与 Linux 的实体账号无关,这仅是用来判断密码所代表的意义而已。密码的给予有两种语法:
password_pbkdf2 账号【使用 grub2-mkpasswd-pbkdf2 所产生的密码】;
password 账号【没加密的明码】;
有了账号与密码之后,在来就是在个别的选单上面加上是否要取消限制(–unrestricted)或者是给予哪个用户(–users)的设定项目。要注意的是,所有的系统管理员所属的密码应该是能够修改所有的选单。

grub2 密码设定的文件位置与加密的密码
主要的环境设定是在 /etc/ grub.d/* 里。里面的文件文件名有用数字开头,那些数字照顺序,就是grub.cfg 的来源顺序。因此最早被读的应该是 00_header,但是那个文件的内容挺重要的,所以 CentOS 7 不建议修改。就自己建立一个名为 01_users 的文件即可,然后将账号与密码参数给它补进去。

开机过程的问题解决

忘记 root 密码

在 Linux 环境中 root 密码忘记时还是可以救回来的。只要能够进入并且挂载/,然后重新设定一下 root 的密码,就救回来了。

新版的 systemd 的管理机制中,默认的 rescue 模式是无法直接取得 root 权限的。还是得要使用 root 的密码才能够登入rescure环境。此时可以透过一个名为【rd.break】的核心参数来处理。需要注意的是,rd.break 是在 Ram Disk 里面的操作系统状态,因此不能直接取得原本的 linux 系统操作环境。所以,还需要 chroot 的支持。更由于 SELinux 的问题,可能还得要加上某些特殊的流程才能顺利的搞定root密码的救援。

进入到开机画面,在可以开机的选单上按下 e 来进入编辑模式,然后就在 linux16 的那个核心项目上面使用这个参数来处理:
改完之后按下 [crtl]+x 开始开机,开机完成后屏幕会出现如下的类似画面,此时请注意,应该是在 RAM Disk 的环境,并不是原本的环境,因此根目录底下的东西跟原本的系统无关。而且,系统应该会被挂载到 /sysroot 目录下,因此,得:

chroot 目录 :代表将根目录【暂时】切换到 chroot 之后所接的目录。因此,以上表为例,那个 /sysroot 将会被暂时作为根目录,而那个目录其实就是最原先的系统根目录,所以当然就能够用来处理文件系统与相关的账号管理。
需要 /.autorelabel 的原因 :在 rd.break 的 RAM Disk 环境下系统是没有 SELinux 的,而刚刚更改了 /etc/shadow(因为改密码),所以【这个文件的SELinux安全本文的特性将会被取消】。如果没有让系统于开机时自动的回复 SELinux 的安全本文,系统将产生【无法登入】的问题(在SELinux为Enforcing 的模式下 ),加上 /.autorelabel 就是要让系统在开机的时候自动的使用预设的 SELinux type 重新写入 SELinux 安全本文到每个文件去。

直接开机就以 root 执行 bash

可以直接开机取得系统根目录后,让系统直接丢一个 bash 给用户使用:就同样在开机的过程中,同在 linux16 的那一行,最后面不要使月rd.break而是使用【init=/bin/bash】即可。最后开机完成就会丢一个bash 给用户,同样不需要 root 密码而有 root 权限。

但是要完整的操作该系统是不可能的,因为将PID一号更改为 bash 。所以,最多还是用在救援方面就是了!而且,同样的,要操作该系统还是得要 remount 根目录才行。否则无法更改文件系统。、

如上图的完整截图,会发现由于是最预设的 bash 环境,所以连 PATH 都仅有 /bi n而已;所以不能下达 reboot。同时,由于没有 systemd 或者是 init 的存在,所以真的使用绝对路径来下达 reboot 时,系统也是无法协助用户重新启动。此时只能按下reset或者是强制关机后,才能再次开机。

因文件系统错误而无法开机

最容易出错的设定而导致无法顺利开机的步骤,通常就是 /etc/fstab这个文件,尤其是使用者容易写错参数,没有经过 mount -a 来测试挂载,就立刻直接重新启动。这种情况的问题大多如下面的画面所示:
输入root的密码来取得 bash 并以 mount -o remount,rw/ 将根目录挂载成可擦写后,继续处理。
除了 /etc/fstab 编辑错误之外,如果曾经不正常关机后,也可能导致文件系统不一致(Inconsistent)的情况,也有可能会出现相同的问题。
如果是扇区错乱的情况,请看到上图中的第二行处, fsck告知其实是 /dev/md0出错,此时就应该要利用 fsck.ext3 去检测 /dev/md0 ,等到系统发现错误,并且出现【clear [Y/N]】时,输入【y】。
如果是 XFS 文件系统的话,可能就得要使用 xfs_repair 这个指令来处理。

《鸟哥的Linux私房菜-基础篇》学习笔记