Linux 引导启动配置与关机

启动引导程序

目前在 Linux 下主要的引导启动程序是 Grub(Grand Unified Bootloader)或 Grub2。通常,Grub2 的主程序会将配置文件放到 /boot/grub2 目录下。而 Grub 则直接修改 /boot/grub/grub.conf,这是一个非常简单的配置文件。

Grub2 引导程序的特点有:

  • 它能够识别和支持更多的文件系统,并且可以使用 Grub2 的主程序在文件系统中直接搜索内核文件名。

  • 在启动时,可以自行编辑和修改启动设置项目,类似于 bash 的命令模式。

  • 它能够动态搜索配置文件,无需在修改配置后重新安装 Grub2。

Grub2 对硬盘的代号设置与 Linux 中不同,一般用下面代号:

  • (hd0,1):这是默认的语法,Grub2 会自动判断分区的格式。

  • (hd0,msdos1):这表示磁盘的分区采用传统的 MBR 模式。

  • (hd0,gpt1):这表示磁盘的分区采用 GPT 模式。

硬盘代号用小括号 () 括起来,并按搜索顺序对硬盘进行编号,第一个分区从 1 开始计算,与 Grub 的从 0 开始计算不同。

默认情况下,系统已经安装了 Grub2。在特殊情况下,如果需要手动安装 Grub2,可以使用 grub2-install 命令。例如,将其安装到 /dev/sdc 下:

[root@101c7 ~]$ grub2-install /dev/sdc
Installing for i386-pc platform.
Installation finished. No error reported.

Grub2 配置文件

Grub2 的配置文件路径为 /boot/grub2/grub.cfg

[root@101c7 ~]$ cat /boot/grub2/grub.cfg
#
# DO NOT EDIT THIS FILE
#
# It is automatically generated by grub2-mkconfig using templates
# from /etc/grub.d and settings from /etc/default/grub
#

### BEGIN /etc/grub.d/00_header ###
set pager=1

if [ -s $prefix/grubenv ]; then

此文件内容繁多,开头第一句就警告应该由 grub2-mkconfig 命令来创建配置,而不是直接修改它。

第一部分以 ### BEGIN /etc/grub.d/00_header ### 开头,包含了环境设置和默认值设置等内容。其中比较重要的是 set default 默认开机选项和 set timeout 默认超时时间。

第四部分以 ### BEGIN /etc/grub.d/10_linux ### 开头,设置了各个开机选择项 menuentry。每个选项都具有不同的启动参数和模块载入。其中比较重要的内容包括:

  • set root:设置 Grub2 配置文件所在的分区 (hd0,msdos1),可以使用 mount 命令查看挂载的分区。

    [root@101c7 ~]$ mount | grep boot
    /dev/sda1 on /boot type xfs (rw,relatime,seclabel,attr2,inode64,noquota)
    [root@101c7 ~]$ fdisk -l
    Disk /dev/sda: 21.5 GB, 21474836480 bytes, 41943040 sectors
    Units = sectors of 1 * 512 = 512 bytes
    Sector size (logical/physical): 512 bytes / 512 bytes
    I/O size (minimum/optimal): 512 bytes / 512 bytes
    Disk label type: dos

    结果显示 /boot 被挂载在 /dev/sda1 下,分区格式为 MBR。

  • linux16 /vmlinuz:指定内核文件以及内核文件运行时的参数。由于 /boot 是独立分区,这里的内核文件路径是 (hd0,msdos1)/vmlinuz。如果 /boot 挂载在根目录下,内核文件路径将变为 (hd0,msdos1)/boot/vmlinuz,即 linux16 /boot/vmlinuzroot 后面指定的是 Linux 系统中根目录挂载的设备。

  • initrd16 /initramfs:指定虚拟文件系统 img 的位置。

Grub2 配置维护

可以通过修改 /etc/default/grub 文件和 /etc/grub.d/ 目录内的相关配置文件来修改 Grub2 的配置。

查看 /etc/default/grub 文件的内容:

[root@101c7 ~]$ cat /etc/default/grub 
GRUB_TIMEOUT=5
GRUB_DISTRIBUTOR="$(sed 's, release .*$,,g' /etc/system-release)"
GRUB_DEFAULT=saved
GRUB_DISABLE_SUBMENU=true
GRUB_TERMINAL_OUTPUT="console"
GRUB_CMDLINE_LINUX="crashkernel=auto rd.lvm.lv=centos/root rd.lvm.lv=centos/swap rhgb quiet"
GRUB_DISABLE_RECOVERY="true"

其中,重要选项的含义如下:

  • GRUB_TIMEOUT:设置选择菜单等待超时的秒数。设为 0 表示不等待,设为 -1 表示必须手动选择。

  • GRUB_TIMEOUT_STYLE:可以设置的值为 menucountdownhidden 等,默认为 menu。该参数用于确定是否显示菜单。将其设置为 countdownhidden 可使用户看不到任何内容。

  • GRUB_DEFAULT:菜单默认选择的项目。可以设置为 saved、数字、title 名、ID 名等,具体取决于 menuentry 的设置。例如,如果配置中定义了三个 menuentry

    menuentry 'CentOS' --unrestricted $menuentry_id_option 'linux-1'
    menuentry 'Debian' --unrestricted $menuentry_id_option 'gnulinux'
    menuentry 'Windows' --unrestricted $menuentry_id_option 'win'

    那么对应 GRUB_DEFAULT 的值:

    • 值为 1 表示选择排在第二个定义的 Debian 系统,因为数字编号从 0 开始。
    • 值为 win 表示选择排在第三个定义的 Windows 系统,通过 ID 选取。
    • 值为 saved 表示使用 grub2-set-default 来设置默认值,通常默认为 0。
  • GRUB_TERMINAL_OUTPUT:信息输出的终端模式。可以设置的值有 consoleserialgfxtermvga_text 等。

  • GRUB_CMDLINE_LINUX:内核的额外参数功能,用于设置内核启动时需要添加的额外参数。

例如,将菜单等待时间修改为 30 秒,然后使用 grub2-mkconfig 命令重建 grub.cfg

[root@101c7 ~]$ sed -i 's/GRUB_TIMEOUT=5/GRUB_TIMEOUT=30/g' /etc/default/grub ; head -1 /etc/default/grub
GRUB_TIMEOUT=30
[root@101c7 ~]$ grub2-mkconfig -o /boot/grub2/grub.cfg
Generating grub configuration file ...
Found linux image: /boot/vmlinuz-3.10.0-1160.41.1.el7.x86_64
Found initrd image: /boot/initramfs-3.10.0-1160.41.1.el7.x86_64.img
Found linux image: /boot/vmlinuz-3.10.0-862.el7.x86_64
Found initrd image: /boot/initramfs-3.10.0-862.el7.x86_64.img
Found linux image: /boot/vmlinuz-0-rescue-77a36143eb014dd5a0d6e738b1d84778
Found initrd image: /boot/initramfs-0-rescue-77a36143eb014dd5a0d6e738b1d84778.img
done
[root@101c7 ~]$ grep timeout /boot/grub2/grub.cfg
if [ x$feature_timeout_style = xy ] ; then
  set timeout_style=menu
  set timeout=30
# Fallback normal timeout code in case the timeout_style feature is
  set timeout=30

接下来看一下 /etc/grub.d 文件夹的内容:

[root@101c7 ~]$ ll /etc/grub.d
total 72
-rwxr-xr-x. 1 root root  8702 Mar 16  2021 00_header
-rwxr-xr-x. 1 root root  1043 Mar 21  2019 00_tuned
-rwxr-xr-x. 1 root root   232 Mar 16  2021 01_users
-rwxr-xr-x. 1 root root 10781 Mar 16  2021 10_linux
-rwxr-xr-x. 1 root root 10275 Mar 16  2021 20_linux_xen
-rwxr-xr-x. 1 root root  2559 Mar 16  2021 20_ppc_terminfo
-rwxr-xr-x. 1 root root 11169 Mar 16  2021 30_os-prober
-rwxr-xr-x. 1 root root   214 Mar 16  2021 40_custom
-rwxr-xr-x. 1 root root   216 Mar 16  2021 41_custom
-rw-r--r--. 1 root root   483 Mar 16  2021 README

可以看到文件名与 grub.cfg 中的段头对应。其中主要的文件包括:

  • 00_header:用于创建初始的显示项目,包括需要加载的模块分析、屏幕终端格式、倒数秒数、菜单是否隐藏等。大部分设置在 /etc/default/grub 中的变量会在这个脚本中使用,用于重建 grub.cfg
  • 01_users:用于设置账号密码,以控制每个菜单选项的访问权限。权限分为三种:不受限(unrestricted)、用户(users)、超级用户(superusers)。只有超级用户可以使用启动项编辑模式。
  • 10_linux:根据分析 /boot 下面的文件,尝试找到正确的 Linux 内核文件与虚拟文件系统镜像等,脚本会将找到的文件路径写入到 grub.cfg 中。因为每一个内核文件都会建立一个启动选项,所以可以适当删除旧内核文件来精简启动菜单。
  • 30_os-prober:这个脚本用来找其他分区中可能存在的操作系统,如果找到则将其加入启动菜单中。可以在 /etc/default/grub 中加上 GRUB_DISABLE_OS_PROBER=true 参数来取消这一扫描。
  • 40_custom:用来手动添加菜单项目。例如想新增一个 menuentry 来指定开机进入图形模式,可以在 grub.cfg 中复制一个 menuentry 段,修改对应的 titleidlinux16 后面的参数(增加 systemd.unit=graphical.target),然后再用 grub2-mkconfig 命令重建 grub.cfg 即可。

设置多重引导

多重引导使用开机管理程序的链接(Chain Loader)功能,将开机引导程序指向其他位置。只需要设置另一个开机引导程序所在分区代号和所在扇区就可以了。

假设系统有一块硬盘两个分区,分别装了 Linux(sdb1)和 Windows(sdb2),我们需要增加两个开机选项,一个指向 Windows 开机菜单,一个回到 MBR 的默认环境。40_custom 文件内容大致如下:

[root@101c7 ~]$ vi /etc/grub.d/40_custom 
#!/bin/sh
exec tail -n +3 $0
# This file provides an easy way to add custom menu entries.  Simply type the
# menu entries you want to add after this comment.  Be careful not to change
# the 'exec tail' line above.
menuentry 'Windows' --id 'win' {
        insmod chain
        insmod ntfs
        set root=(hd0,msdos2)
        chainloader +1
menuentry 'MBR' --id 'mbr' {
        insmod chain
        set root=(hd0)
        chainloader +1
"/etc/grub.d/40_custom" 14L, 469C written

其中最重要的是载入 chainntfs 模块,由此 Grub2 才能正确读取文件系统执行 Chain Loader 功能。

启动项编辑模式

在启动菜单出现后,可以按下 e 进入启动项编辑模式。也就是直接编辑 grub.cfg 文件内容。

例如,可以在 systemd.unit 中指定为 rescue.target,这样就能直接进入救援模式,而不需要先进入系统。修改完毕后,使用快捷键 [Ctrl]+x 来执行。

启动异常处理

通常因为某些不正常的设置或不正常关机导致无法顺利开机时,可以进入 rescue 模式去处理.

忘记 root 密码

在使用 grub 做引导的系统可以这样处理:

  1. 启动系统,在选择启动项的界面下,按 e 进入默认启动项 grub 编辑模式。
  2. 移动到有 kernel 那行,再按一次 e 进入编辑界面,在最后方输入 single
  3. 按下回车,再按下 b 就可以进入单用户维护模式。
  4. 这一模式下可以直接用 passwd 命令修改 root 密码。

CentOS 7 中 rescue 模式也需要 root 密码才能登录,因此可以进入 emergency 救援模式:

  1. e 进入编辑默认启动项 grub,找到 linux16 那行,在最末尾输入 init=/bin/sh,按 [Ctrl]+x 执行;
  2. 进入 emergency 模式后,输入 mount -o remount,rw / 命令将根目录挂载为可读写模式;
  3. 然后使用 passwd 命令设置新的 root 密码;
  4. 最后输入 touch /.autorelabel 更新系统信息,让 SELinux 生效;
  5. 执行 exec /sbin/initreboot 即可退出救援模式。

通过 rd.break(Ram Disk 里面的操作系统)内核启动参数也可以处理:

  1. 同样在编辑默认启动项 grub,在 linux16 那行末尾加入 rd.break 参数,按 [Ctrl]+x 执行;
  2. 此时进入的是 Ram Disk 环境,系统被挂载到 /sysroot 目录下,用 mount -o remount,rw /sysroot 重新挂载;
  3. 用命令 chroot /sysroot 来切换根目录,并使用 passwd 命令修改密码;
  4. 同样用 touch /.autorelabel 来变回 SELinux 的安全标签。重启即可。

touch /.autorelabel 命令的作用:

  • 在救援模式下系统没有 SELinux,所以用 passwd 命令修改了 /etc/shadow 文件后,它的 SELinux 安全标签会被取消,在 SELinux 为 Enforcing 模式下会无法登录系统。

  • 创建 /.autorelabel 文件就是要让系统在开机时自动使用默认 SELinux 类型重写入 SELinux 安全标签到每个文件。

  • 如果不想让每个文件都更新标签,可以改完密码后,将 SELinux 运行模式改为 permissive(修改 /etc/selinux/config 文件)。再重新开机后运行 restorecon -Rv /etc 仅恢复 /etc 目录下的默认安全上下文类型。最后将 SELinux 配置文件的运行模式改回 enforcing,用 setenforce 1 来生效。

文件系统错误

断电或不正常关机会导致文件系统错误,通常是软件数据问题。如果根目录没有损坏,可以进入维护模式下使用fsck命令修复ext4格式的分区。修复完毕后以reboot重启即可:

[root@101c7 ~]$ fsck /dev/sda2
fsck from util-linux 2.23.2

如果是xfs格式分区则使用xfs_repair命令:

[root@101c7 ~]$ xfs_repair /dev/sda2
xfs_repair: cannot open /dev/sda2: Device or resource busy

如果整个硬盘只有一个大区,那文件系统错误一定是根目录的问题。这时候需要将硬盘拔下来,接到另外一台 Linux 系统的机器上,并且不要挂载,以root身份执行fsckxfs_repair命令修复。

还有一种方法是使用 U 盘刻成 Live CD,在 U 盘启动的系统中执行修复命令。

关机重启

切换运行级别和模式并不会重启.

查看用户在线状态

如果有其他用户在线,强制关机可能会导致用户文件丢失,可以先使用who命令查看当前已登录的用户信息:

[user1@101c7 root]$ who -Hu
NAME     LINE         TIME             IDLE          PID COMMENT
root     tty1         2021-09-11 09:35  old          897
root     pts/0        2021-09-15 12:12   .          5334 (192.168.2.101)
root     pts/1        2021-09-14 08:40  old        55207 (192.168.2.101)

数据写回

默认情况下,某些加载到内存中的数据不会直接被写回硬盘,而是暂存在内存中。可以手动同步将数据写入硬盘:

[user1@101c7 root]$ sync

使用重启或关机命令前也会自动调用sync命令。

当非管理员使用sync命令时,只会更新该用户的操作数据。

关机操作

通常使用 shutdown 命令来进行关机操作。

立即关机:

[user1@101c7 root]$ shutdown -h now

预定在 21:00 关机。如果当前时间超过 21:00 则会在隔天 21:00 才关机:

[user1@101c7 root]$ shutdown -h 21:00

预定 2 分钟后关机,并发送消息:

[root@101c7 ~]$ shutdown -P 120 "will  poweroff"
Shutdown scheduled for Wed 2021-09-15 16:01:48 EDT, use 'shutdown -c' to cancel.

取消即将进行的关机操作:

[root@101c7 ~]$ shutdown -c
[root@101c7 ~]$ 
Broadcast message from root@101c7 (Wed 2021-09-15 14:01:54 EDT):

The system shutdown has been cancelled at Wed 2021-09-15 14:02:54 EDT!

重启操作

重启命令可用 reboothalt,选择其一即可。

立即强制关机:

[root@101c7 ~]$ halt -P -f

同步后重启系统:

[root@101c7 ~]$ sync; sync; sync; reboot

切换执行等级

可以通过 init 命令来切换运行级别,例如进入单用户维护模式:

[root@localhost ~]$ init 1
Broadcast message from root@localhost.localdomain on pts/1 (Fri 2019-07-05 15:40:59 CST):

The system is going down to rescue mode NOW!

在 CentOS 7 中则是由 systemctl 来管理模式之间的切换,例如切换到救援模式:

[root@101c7 ~]$ systemctl isolate rescue.target