12.2. FreeBSD开机程序

打开电脑并启动操作系统的这个动作呈现了一个有趣的困境。照道理,电脑在启动操作系统之前并不知道要如何做任何事情,这些事情之中包括从磁盘执行程序。如果电脑无法在没有操作系统的情况下执行程序,而操作系统的程序本身又在磁盘上,那么操作系统要如何启动呢?

这个问题如同The Adventures of Baron Munchausen一书中的一个角色掉进了洞里,他抓住了靴子上的拔靴带(Bootstrap)才把自己拉了出来,因此在早期电脑领域用bootstrap一词来指加载操作系统的机制,后来被缩短为booting

在x86硬件上,基本输入/输出系统(Basic Input/Output System,BIOS)负责加载操作系统。BIOS会找到硬盘上的主开机记录区(Master Boot Record,MBR),该记录区必须位于磁盘上的特定位置。BIOS有足够的知识可以加载并执行这个MBR,并且假设这个MBRBIOS的协助下可以完成接下来加载操作系统的工作。

注意:

FreeBSD在较旧的MBR标准与较新的GUID分割区表(GUID Partition Table,GPT)上都能够开机(Booting)。GPT磁盘分割通常会在有支持统一可延伸固件界面(Unified Extensible Firmware Interface,UEFI)的电脑上找到。不论如何,FreeBSD即使在只有传统BIOS的机器上,也可以使用gptboot(8) GPT分割区开机。直接使用UEFI开机的开发工作正在进行中。

MBR中的程序通常会称作开机管理程序(Boot manager),特别是那些会与使用者互动的程序。开机管理程序通常会另一部份的程序会存放于磁盘的第一个磁道或文件系统。开机管理程序的例子有标准FreeBSD开机管理程序boot0又称Boot Easy以及Grub常用于各种Linux®发行版。

若只有安装一个操作系统,MBR会搜寻磁盘上第一个可开机的(使用中)切割区(Slice),然后执行在该切割区上的程序来加载剩下的操作系统。当有多个操作系统存在时,可以安装可显示操作系统清单的开机管理程序,以让使用者可以选择要启动的操作系统。

剩馀的FreeBSD开机系统分成三个阶段,第一个阶段只知道如何让电脑进入特定状态并执行第二阶段,第二个阶段在执行第三阶段之前会做的事比较多一点,第三个阶段会完成加载操作系统的工作。把工作分成三个阶段的原因是MBR有限制在阶段一与阶段二能够执行程序的大小。将这些工作连接在一起让FreeBSD能够提供更有弹性的加载程序。

核心会接着开始侦测装置并初始化这些装置供使用。核心开机程序完成之后,核心便会传送控制权给使用者程序init(8),这个程序会确保磁盘在可以使用的状态,然后启动使用者层级的资源设置来挂载文件系统、设定网络卡以能够联机网络、启动那些被设定在开机时要启动的程序。

本章节将更详细介绍这些阶段并示范如何与FreeBSD开机程序互动。

12.2.1. 开机管理程序

有时会称在MBR中的开机管理程序为开机程序的第零阶段(Stage zero),FreeBSD预设会使用boot0开机管理程序。

由FreeBSD安装程序所安装的MBR便是以/boot/boot0为基础。boot0的大小与容量被限制在446个位元组是由于切割表与0x55AA识别码位于MBR的最末端。若安装多个操作系统使用boot0,则会在开机时显示如下示例的信息:

例 12.1. boot0屏幕截图
F1 Win
F2 FreeBSD

Default: F2

其作他作业统若在FreeBSD之后才安装则会覆盖现有的MBR,若这件事发生了,或者要使用FreeBSD MBR取代现有的MBR可使用以下指令:

# fdisk -B -b /boot/boot0 device

其中device开机磁盘,例如第一个IDE磁盘为ad0,第二个IDE控制器的第一个IDE磁盘为ad2,第一个SCSI磁盘为da0。要建立自定义的MBR设定请参考boot0cfg(8)

12.2.2. 阶段一与阶段二

概念上,第一与第二个阶段均为磁盘上同一个区域上同一个程序的一部份,由于空间上的限制,它们被分成两部份,但是会一并安装。它们会由FreeBSD安装程序或bsdlabel/boot/boot复制而来。

这两个阶段均位于文件系统之外,在开机切割区的第一个磁道,从第一个磁盘扇区(Sector)开始,这个位置便是boot0或其他开机管理程序所会储存的地方,并会寻找可以执行的程序以继续开机程序。

第一个阶段的boot1非常的简单,因为它只能有512字节的大小。它只能认得储存切割区信息的FreeBSD bsdlabel以及寻找并执行boot2

阶段二boot2稍微复杂一点,能够理解FreeBSD文件系统来搜寻档案。它可以提供一个简单的界面来选择要执行的核心或加载程序。它所执行的加载程序(loader)更复杂并能读取开机配置文件。若开机程序在阶段二中断,则会显示以下的互动画面:

例 12.2. boot2屏幕截图
>> FreeBSD/i386 BOOT
Default: 0:ad(0,a)/boot/loader
boot:

要更换已安装的boot1boot2可使用bsdlabel,其中diskslice是要开机的磁盘与切割区,例如ad0s1代表第一个IDE磁盘的第一个切割区:

# bsdlabel -B diskslice

警告:

若只使用磁盘名称,如ad0bsdlabel便会以危险专用的模式来建立磁盘,而不会建立任何分割区。这个可能与预期的动作不同,所以在按下Return键之前请再次确认diskslice

12.2.3. 阶段三

loader是三阶段开机程多的最后一个阶段,加载程序位于文件系统之中,通常在/boot/loader

loader主要目地是利用拥有更复杂指令集的强大直译器做为基础的内置指令集提供一个互动的方式来做设定。

在初始化的过程中,loader会侦测Console与磁盘,并找出可以用来开机的磁盘。在由Script或互动输入使用者指令的地方会设定相对的变数并启动直译器。

loader接着会读取/boot/loader.rc,这个程序预设又会读取/boot/defaults/loader.conf来设定合理的变数预设值以及读取/boot/loader.conf来对这些变数做本地的更改。loader.rc接着会依这些变数来运作,读取选择模块与核心。

最后,预设情况下loader会待候键盘输入10秒钟,若没有被中断的话会接着启动核心。若被使用者中断,则会向使用者显示提示字元,此时使用可以使用指令集来调整变数、卸载所有模块、加载模块,然后最后开机或重启。表 12.1 “加载程序内置指令”中列出了最常使用的loader指令。要完整了解所有可用的指令,请参考loader(8)

表 12.1. 加载程序内置指令
变量描述
autoboot seconds若在指定时间(秒)内没有中断,会继续启动核心。此指令会显示倒数,预设的时间为10秒钟。
boot [-options] [kernelname]使用任何指定的选项或核心名称立即启动核心,要由指令列指定核心名称必须先执行unload,否则会使用先前加载过的核心。若kernelname不是完整的路径则会搜寻/boot/kernel/boot/modules底下。
boot-conf依据指定的变数及最常用的kernel再做一次相同的自动模块设置。这只有在执行unload之后,尚未变更变数之前方可使用。
help [topic]显示自/boot/loader.help取得的说明信息。若指定的主题为index则会显示所有可用的主题。
include filename读取指定的档案并直译每一行。若有错误则会立即中止include
load [-t type] filename由指定的档案名称加载核心、核心模块或指定类型的档案。任何于filename之后的参数都会被传递到该档案。若filename不是绝对位置则会搜寻/boot/ kernel/boot/modules底下。
ls [-l] [path]显示指定路径中的档案,若未指定路径则会显示根目录中的档案。若有指定-l,则会连档案大小一同显示。
lsdev [-v]列出所有的装置,这些装置可能可以用来加载模块。若有指定-v则会显示更详细的信息。
lsmod [-v]显示已加载的模块。若有指定-v则会显示更详细的信息。
more filename显示指定的档案,并于每LINES行显示后会暂停。
reboot立即重新启动系统。
set variable, set variable=value设定指定的环境变数。
unload移除所有已加载的模块。

这里有一些loader用法的实务示例。要使用一般的核心开机进入单使用者模式(Single-user mode)可:

boot -s

要卸载一般的核心与模块,然后加载先前或另一个指定的核心可:

unload
load kernel.old

使用kernel.GENERIC来代表安装程序使用的预设核心,或kernel.old来代表在系统升级之前或设定自定义核心前安装的核心。

使用以下指令来使用另一个核心加载一般的模块:

unload
set kernel="kernel.old"
boot-conf

要加载一个已自动化的核心设置Script可:

load -t userconfig_script /boot/kernel.conf

12.2.4. 最终阶段

loader或由会绕开loaderboot2加载核心之后,加载程序便会检查是不有使用任何开机旗标,并根据需要调整开机的方式。表 12.2 “开机时核心互动参数”列出了常用的开机旗标,请参考boot(8)取得更多其他开机旗标的信息。

表 12.2. 开机时核心互动参数
选项描述
-a核心初始化时,会询问要挂载为根文件系统的装置。
-CCDROM做为根文件系统开机。
-s开机进入单使用者模式。
-v核心启动时提供更多详细信息。

一旦核心完成开机程序后,便会传送控制权给使用者程序init(8),该程序位于/sbin/init或在loader中的init_path变数所指的程序路径。这是开机程序的最后一个阶段。

开机程序会确保系统上的文件系统的一致性(Consistency),若UFS文件系统不一致且fsck无法修时,init会让系统进入单使用者模式,以让系统管理者能够直接解决问题,否则系统会开机进入多使用者模式。

12.2.4.1. 单使用者模式

使用者可以在开机时指定-s或在loader设定boot_single变数进入这个模式。也可以透过在多使用者模式执行shutdown now进入此模式。进入单使用者模式时会出现此信息:

Enter full pathname of shell or RETURN for /bin/sh:

若使用者按下Enter,系统便会进入预设的Bourne shell。要指定使用其他的Shell则输入该Shell的完整路径。

单使用者模式通常用来修复因文件系统不一致或开机配置文件发生错误造成的无法开机,也可以用来重设遗忘的root的密码,因为在单使用者模式会给予对本地系统及配置文件完整的存取权。在这个模式下没有网络功能。

虽然单使用者模式对修复系统很有帮助,但若系统放在不安全的场所便会有安全上的风险。预设,开机进入单使用者模式后,任何能够存取实体主机的使用者便拥有系统的完整控制权。

若在/etc/ttys系统console更改为insecure,系统便会在初始化单使用者模式前先询问root的密码。这可增加一定程度的安全性,但便无法在忘记root密码时重设密码。

例 12.3. 在/etc/ttys设定不安全的Console
# name  getty                           type    status          comments
#
# If console is marked "insecure", then init will ask for the root password
# when going to single-user mode.
console none                            unknown off insecure

不安全(insecure)console代表对Console的实体安全性评价为不安全(insecure),所以只有知道root密码的人可以使用单使用者模式。

12.2.4.2. 多使用者模式

init正常找到文件系统或在单使用者模式的使用者完成了操作并输入exit离开单使用者模式,系统便会进入多使用者模式,在这个模式便会开始系统的资源设置。

资源设置系统(Resource configuration system)会从/etc/defaults/rc.conf读取设定预设值以及从/etc/rc.conf读取系统特定的设定,接着会继续挂载系统列于/etc/fstab的文件系统,也会启动网络服务、其他的系统Daemon,然后执行本地已安装套件的启动Script。

要了解更多有关资源设置系统,请参考rc(8)以及查看位于/etc/rc.d的Script。

本文档和其它文档可从这里下载: ftp://ftp.FreeBSD.org/pub/FreeBSD/doc/.

如果对于FreeBSD有问题,请先阅读 文档,如不能解决再联系 <questions@FreeBSD.org>.

关于本文档的问题请发信联系 <doc@FreeBSD.org>.