一、库相关内容

1. 基本概念

  • 库就是函数(function)的集合,可以把函数理解为一种功能,它内部是由很多代码段组成的,因此任何一个程序调用函数其实就是调用功能,为了方便调用会给每个函数都起个名字,通常都是通过函数名完成调用的。站在运行的角度看库,其实它也是二进制程序,唯一跟/bin目录下的程序不同的就在于库文件没有自我独立的执行入口,也就是说库要想运行起来必须要别的程序调用才行,因此无法单独执行,但可以作为有单独执行入口程序的代码片段,与别的程序一块存活,用户空间的库以文件.so结尾,shared object
  • 头文件:为了让函数拥有更灵活的功能,通常还要让函数能接受参数,不同的函数能接受参数类型与个数都不同。因此,每一个库当中有多少个函数,每一个函数能接受多少个参数,每一个参数都是什么类型等等,都应该有一个文件对其加以描述,而这个文件就叫头文件

2. 根据执行结果对库的分类

  • function:函数调用,调用完以后有返回值,这个返回值不是执行状态返回值,而是结果
  • procedure:过程调用,没有返回值的代码片段,这种代码片段其实并不是没做任何事,而只是完成后就结束了

二、centos系统启动流程

1. 第一步:加电自检(Post)

启动系统时,ROM会传递给CPU第一条叫醒指令,指引着CPU装载指定位置的指令完成CPU自举,接着CPU根据这个指令去完成一些自检等操作

2. 第二步:BOOT Sequence

完成加电自检后,根据BIOS中设置的引导加载次序查找各引导设备,第一个有引导程序(bootloader)的设备即为本次启动用到的设备

3. 第三步:kernel初始化

当用户选定内核后,内核就会被加载到内存中做解压、展开操作并获得控制权,接着内核开始完成自身初始化,比如探测各硬件、装载各硬件的驱动程序、挂载根文件系统、完成根文件系统切换、启动/sbin/init程序,需要注意的是,内核在开始挂载根的时候是以只读方式挂载的

ramdisk

在内核初始化过程中,会用到此文件,但这个文件不是必需的。因为内核引导完毕后需要去硬盘上寻找根文件系统,但是寻找根文件系统的前提条件是需要能驱动硬盘,不同用户使用的硬盘千差万别,我们为了保证内核轻量化又不能将各类硬盘的驱动做进内核,所以需要一个外部的辅助机制来帮助内核可以正确的识别硬盘,解决方式就是在安装完操作系统后,由一个命令工具生成这个文件用来提供硬盘驱动,这个文件会在启动系统时直接装入内存,假装一块硬盘使用,给内核模拟了一个精小的根文件系统,接着内核就借助这个微型的根文件系统去装载硬盘驱动,最后再将根文件系统从微型系统中切换到真正的根文件系统中。所以,如果内核中有你使用的硬盘驱动,那么就不需要这个文件。这个文件名称要与内核版本号完全匹配

  • centos 5系统中:文件/boot/initrd-VERSION-release.img,生成此文件的工具程序是mkinitrd,模拟成硬盘使用
  • centos 6、7:文件/boot/initramfs-VERSION-release.img,生成此文件的工具程序是:dracut,模拟成文件系统

Centos 5上将ramdisk模拟成硬盘,而Centos 6上是模拟成文件系统叫做ramfs, 这个改进是因为内核有个特性可以使用缓冲和缓存加速磁盘上文件的访问,所以,在系统启动时,ramdisk被加载至内存中,因它是模拟成硬盘使用的,而内核认为硬盘都比较慢,所以内核会将ramdisk中的文件再次加载至内核内存的缓冲区当中,等于多了一个步骤。如果模拟成文件系统就没问题了,因为文件系统自身可以完成缓冲和缓存管理的,所以Centos 6以后就变成了ramfs

制作ramdisk文件:~]# mkinitrd /boot/initramfs-$(uname -r).img $(uname -r)~]# dracut /boot/initramfs-$(uname -r).img $(uname -r)

4. 第四步:init程序初始化

当内核初始化完成后就会启动init程序,Centos 5、Centos 6、Centos 7用到的init程序各不相同,但是主要工作基本都按照配置文件中规定的步骤去完成相应的初始化工作,如启动默认运行级别、按照运行级别启动或关闭对应的服务、设定主机名称、设定时钟、启动SELinux、完成根文件系统重挂、启动登录程序等等。涉及概念较多,因此详细各步骤请查看本文后续详解

5. 第五步:用户登录

当init程序初始化完成后,会启动用户登录程序,在这个程序中完成用户认证并准许登录

运行级别相关的命令

  • 切换运行级别的命令:init #
  • 查看运行级别的命令:who -rrunlevel,输出的信息为两个字符,分别表示上一次运行的级别和当前运行的级别,如果上一次运行的级别为N,表示Null,意思是直接启动系统就是3级别

三、grub相关概念

1. grub版本

在系统启动流程的第二步中(Boot Sequence),根据引导次序去依次寻找各个设备的boot loader。而常见的Boot loader有两种,其一为Windows的NTloader,其二为linux的Grub

linux的引导加载器有两种,早期时候用的是LILO(Linux Loader),现在用于安卓。现使用Grub(GRand Unified Bootloader),大统一引导程序

  • grub:grub 0.x的版本,这种一般称为grub传统版(grub legacy)
  • grub2:grub 1.x,这种一般称为grub2

2. grub legacy的三个加载阶段

grub为了突破mbr446字节的限制,采用分段启动加载的方式。当启动系统时读取磁盘的mbr,因此可以加载到stage 1,stage 1加载完,它会尝试去加载随后扇区中的stage 1_5,当1_5阶段读取完后,从而就能驱动真正第二阶段的磁盘分区了。其实这个磁盘分区上不光有stage 2文件,还有内核文件及其ramdisk等等都在这个分区上放置着,其配置文位于/etc/grub/grub.conf,并有一个链接文件位于/etc/grub.conf

1st stage

位于MBR中,第一阶段的主要目的找到硬盘上的2st

1_5st stage

主板Bios必须能识别硬盘,才能够去加载硬盘中的BootLoader,不过硬盘上的BootLoader自身加载完以后也仅仅能够识别当前主机能识别到的硬盘设备,因为硬盘设备能识别并不意味着硬盘设备中的文件系统能识别,文件系统是额外附加的一层软件组织的文件结构,所以要想对接某种文件系统,通常必须要用到文件系统驱动,帮助对应的应用程序(这里指grub 1st stage)能识别和理解相应的文件系统才可以,这里的第1_5 stage也就是提供了让grub 1 stage能识别2阶段的文件系统驱动,从而就能访问对应的第二阶段和内核所在的分区了。通常grub第二阶段、ramdisk和内核文件都会放置在一个最基本分区上,毕竟grub 1_5 stage也不会做的特别复杂。grub会在系统安装时,将系统使用的文件系统驱动等必须组件做成1_5 stage文件,在启动时装载到mbr随后的一段空间中,从而使得第一阶段可以访问第二阶段的文件系统

2st stage

提供一个菜单和一个交互式接口、加载用户选择的内核且允许用户向内核传递参数、隐藏菜单、菜单编辑保护认证、为启用的内核添加认证、其文件存放在存放在/boot/grub

第二阶段的功用:

  • 提供一个菜单、交互接口,在这个交互接口中可以使用e键进入编辑模式,使用c键进入命令模式,在命令模式中,可以传递给grub一参数,从而使得grub不用读取配置文件就可以完成启动
  • 加载用户选则的内核或操作系统,并且允许用户通过编辑菜单传递参数,必要时还可以隐藏启动菜单
  • 为菜单提供了认证机制。第一,给编辑菜单提供认证,第二,启动内核前提供认证

3. grub legacy的配置文件内容

default=#:默认启动的内核
timeout=#:设定超时时长
splashimage(hd#,#)/path:菜单的背景图片
hiddenmenu:隐藏菜单
password [--md5] PASSWD:添加菜单编辑认证,通过grub-md5-crypt命令生成密码
title:设定此内核的显示名称,此名称可以出现多个
root:指明grub查找stage2时用到的设备
kernel /path:指定内核文件
initrd /path:与内核匹配的ramdisk文件
password [--md5] PASSWD:添加启动内核认证

4. grub 命令行接口配置

在grub选择菜单中键入c键可进入命令行接口,常用命令如下

  • help [key_word]:获取帮助列表
  • root [DEVICE [HDBIAS]]:设置当前使用的根设备,对grub来讲,根设备不是用户进入系统后看到的根,而是第二阶段所在的磁盘分区才叫根
    对于grub legacy来讲磁盘设备都是使用hd来标识,后面跟上两个#号,用来标识第几块磁盘的第几个分区,用逗号分隔且用括号包含起来,如(hd0,0)
  • find DEVICE/FILE_NAME:通过find命令去查找文件,需要先指定硬件设备和分区
  • kernel /PATH:指明内核文件路径,额外和可以指定很多内核参数,如init=/pathselinux=0等等
  • initrd /PATH:设定为选定内核的ramdisk
  • boot:启动选定的内核

5. 进入单用户模式

如需进入grub编辑菜单,在需编辑的内核上键入e键进入二级菜单,接着在kernel选项上键入e键,进入三级菜单,补上进入单用户模式的参数1或s或S或single,键入完毕后敲回车键确定,最后在kernel选项上敲b键启动系统

6. grub 安装及修复

  • 情况一:重装本机的grub,适用于grub被破坏但未重启系统
1. 首先备份本机的grub,以免测试失败
[root@centos6 ~]# dd if=/dev/sda of=/root/grub.bak bs=512 count=1

2.破坏本机的grub
[root@centos6 ~]# dd if=/dev/zero of=/dev/sda bs=200 count=1

3. 使用grub-install命令进行重装
[root@centos6 ~]# grub-install --root-directory=/ /dev/sda
Installation finished. No error reported.
This is the contents of the device map //boot/grub/device.map.
Check if this is correct or not. If any of the lines is incorrect,
fix it and re-run the script `grub-install'.

# this device map was generated by anaconda
(hd0) /dev/sda

4. 或者使用grub命令,在grub命令行中完成重装
[root@centos6 ~]# grub
Probing devices to guess BIOS drives. This may take a long time.


GNU GRUB version 0.97 (640K lower / 3072K upper memory)

[ Minimal BASH-like line editing is supported. For the first word, TAB
lists possible command completions. Anywhere else TAB lists the possible
completions of a device/filename.]
grub> root (hd0,0)
root (hd0,0)
Filesystem type is ext2fs, partition type 0x83
grub> setup (hd0)
setup (hd0)
Checking if "/boot/grub/stage1" exists... no
Checking if "/grub/stage1" exists... yes
Checking if "/grub/stage2" exists... yes
Checking if "/grub/e2fs_stage1_5" exists... yes
Running "embed /grub/e2fs_stage1_5 (hd0)"... 27 sectors are embedded.
succeeded
Running "install /grub/stage1 (hd0) (hd0)1+27 p (hd0,0)/grub/stage2 /grub/grub.conf"... succeeded
Done.
grub> quit
quit
  • 情况二:使用紧急救援模式重装grub,适用于grub被破坏,并且已经重启系统了
1. 破坏本机grub(必要时先备份grub)
[root@centos6 ~]# dd if=/dev/sda of=/root/grub.bak bs=512 count=1

2. 装入安装光盘,重启选择进入紧急救援模式或则选择模式时按下Esc键,键入linux rescue

在这里插入图片描述

3. 按照提示选择语言、键盘类型、网络是否启用
4. rescue提示信息意为,会尝试在硬盘中查找文件系统,加入找到的话,就会把待修复文件系统的根挂载至
救援模式的/mnt/sysimage目录下,你可以去这个目录查看文件

在这里插入图片描述

5. 待查找完毕后,就可以使用grub-install完成修复,这里使用chroot命令先切换至待修复系统的根,
接着使用grub命令完成grub修复,修复完毕后退回紧急救援模式,重启即可

在这里插入图片描述

  • 情况三:向一个新的磁盘中安装grub用于引导其他机器上的系统,这里为了便于演示,都放置于一块硬盘

1. 首先在服务器中加入新的硬盘并完成分区格式化

[root@centos6 ~]# fdisk -l /dev/sdb
Device Boot Start End Blocks Id System
/dev/sdb1 1 654 5253223+ 83 Linux
/dev/sdb2 655 1308 5253255 83 Linux
/dev/sdb3 1309 1701 3156772+ 82 Linux swap / Solaris

将三个分区格式化
mkfs.ext4 /dev/sdb1
mkfs.ext4 /dev/sdb2
mkswap /dev/sdb3

查看分区类型
[root@centos6 ~]# blkid /dev/sdb1
/dev/sdb1: UUID="41467fe8-2b91-49d3-8b72-737a8e9d2c77" TYPE="ext4"
[root@centos6 ~]# blkid /dev/sdb2
/dev/sdb2: UUID="3ea414eb-d2e9-4f5d-b5e1-e578ae183faa" TYPE="ext4"
[root@centos6 ~]# blkid /dev/sdb3
/dev/sdb3: UUID="f97d20b2-baed-4906-b47e-5e6b2f4311a2" TYPE="swap"

重读分区表
[root@centos6 ~]# partx -a /dev/sdb
BLKPG: Device or resource busy
error adding partition 1
BLKPG: Device or resource busy
error adding partition 2
BLKPG: Device or resource busy
error adding partition 3

2. grub重装时必须要基于/boot目录进行,所以需要先手动创建一个/boot目录,且需要将/dev/sdb1挂载之,这里使用/mnt
目录进行演示

[root@centos6 ~]# mkdir /mnt/boot
[root@centos6 ~]# mount /dev/sdb1 /mnt/boot
[root@centos6 ~]# ls /mnt/boot
lost+found

3. 使用命令 grub-install 重装grub,--root-directory选项指定grub的根,但不要指定到/mnt/boot,因为
grub-install命令会自动去查找boot目录,所以指到/mnt即可,后面的/dev/sdb是指定向哪个设备安装grub,注意
千万别指定/dev/sdb1,因为grub第一阶段需要安装在mbr中

[root@centos6 mnt]# grub-install --root-directory=/mnt /dev/sdb
Probing devices to guess BIOS drives. This may take a long time.
Installation finished. No error reported.
This is the contents of the device map /mnt/boot/grub/device.map.
Check if this is correct or not. If any of the lines is incorrect,
fix it and re-run the script `grub-install'.

(fd0) /dev/fd0
(hd0) /dev/sda
(hd1) /dev/sdb
这时,grub就已经安装完成了

4. 准备内核文件、ramdisk、grub的配置文件

[root@centos6 mnt]# cp /boot/vmlinuz-2.6.32-696.el6.x86_64 /mnt/boot/vmlinuz
[root@centos6 mnt]# cp /boot/initramfs-2.6.32-696.el6.x86_64.img /mnt/boot/initramfs.img
这里为了简便没有注明版本号
[root@centos6 grub]# cat /mnt/boot/grub/grub.conf
default=0
timeout=5
title CentOS (Express)
root (hd0,0)
kernel /vmlinuz ro root=/dev/sda2 selinux=0 init=/bin/bash
initrd /initramfs.img
此处需要注意root参数后面指定的分区,因为这个硬盘是模拟一块新硬盘装到其他服务器上使用,所以
指定为/dev/sda2,而init参数是设定启动后的第一个进程,为了便于测试,将原来的init改成了/bin/bash

5.创建根文件系统中posix规范的目录结构
mkdir -pv /mnt/sysroot/{bin,sbin,lib,lib64,usr,home,root,tmp,var,media,dev,mnt,proc}
[root@centos6 sysroot]# ll /mnt/sysroot
total 76
drwxr-xr-x. 2 root root 4096 Jan 16 02:05 bin
drwxr-xr-x. 2 root root 4096 Jan 16 02:05 dev
drwxr-xr-x. 2 root root 4096 Jan 16 02:05 etc
drwxr-xr-x. 2 root root 4096 Jan 16 02:05 home
drwxr-xr-x. 2 root root 4096 Jan 16 02:05 lib
drwxr-xr-x. 2 root root 4096 Jan 16 02:05 lib64
drwx------. 2 root root 16384 Jan 16 01:21 lost+found
drwxr-xr-x. 2 root root 4096 Jan 16 02:05 media
drwxr-xr-x. 2 root root 4096 Jan 16 02:05 mnt
drwxr-xr-x. 2 root root 4096 Jan 16 02:05 proc
drwxr-xr-x. 2 root root 4096 Jan 16 02:05 root
drwxr-xr-x. 2 root root 4096 Jan 16 02:05 sbin
drwxr-xr-x. 2 root root 4096 Jan 16 02:05 sys
drwxr-xr-x. 2 root root 4096 Jan 16 02:05 tmp
drwxr-xr-x. 2 root root 4096 Jan 16 02:05 usr
drwxr-xr-x. 2 root root 4096 Jan 16 02:05 var

6. 为了测试复制一个bashell及其依赖环境至这个文件系统中,复制ls命令及其依赖环境至这个文件系统中

[root@centos6 ~]# cp /bin/bash /mnt/sysroot/bin/
[root@centos6 ~]# ldd /bin/bash
linux-vdso.so.1 => (0x00007ffe327f9000)
libtinfo.so.5 => /lib64/libtinfo.so.5 (0x00007f9521384000)
libdl.so.2 => /lib64/libdl.so.2 (0x00007f9521180000)
libc.so.6 => /lib64/libc.so.6 (0x00007f9520deb000)
/lib64/ld-linux-x86-64.so.2 (0x00007f95215aa000)
[root@centos6 ~]# cp /lib64/libtinfo.so.5 /mnt/sysroot/lib64/
[root@centos6 ~]# cp /lib64/libdl.so.2 /mnt/sysroot/lib64/
[root@centos6 ~]# cp /lib64/libc.so.6 /mnt/sysroot/lib64/
[root@centos6 ~]# cp /lib64/ld-linux-x86-64.so.2 /mnt/sysroot/lib64/

[root@centos6 ~]# cp /bin/ls /mnt/sysroot/bin
[root@centos6 ~]# ldd /bin/ls
linux-vdso.so.1 => (0x00007ffd852d6000)
libselinux.so.1 => /lib64/libselinux.so.1 (0x00007f36c1946000)
librt.so.1 => /lib64/librt.so.1 (0x00007f36c173e000)
libcap.so.2 => /lib64/libcap.so.2 (0x00007f36c1539000)
libacl.so.1 => /lib64/libacl.so.1 (0x00007f36c1331000)
libc.so.6 => /lib64/libc.so.6 (0x00007f36c0f9d000)
libdl.so.2 => /lib64/libdl.so.2 (0x00007f36c0d98000)
/lib64/ld-linux-x86-64.so.2 (0x00007f36c1b6a000)
libpthread.so.0 => /lib64/libpthread.so.0 (0x00007f36c0b7b000)
libattr.so.1 => /lib64/libattr.so.1 (0x00007f36c0976000)
[root@centos6 ~]# cp /lib64/libselinux.so.1 /mnt/sysroot/lib64
[root@centos6 ~]# cp /lib64/librt.so.1 /mnt/sysroot/lib64
[root@centos6 ~]# cp /lib64/libcap.so.2 /mnt/sysroot/lib64
[root@centos6 ~]# cp /lib64/libacl.so.1 /mnt/sysroot/lib64
[root@centos6 ~]# cp /lib64/libpthread.so.0 /mnt/sysroot/lib64
[root@centos6 ~]# cp /lib64/libattr.so.1 /mnt/sysroot/lib64

7. 新启动一台虚拟机,将磁盘安装之并启动

解释下grub的根为何如此诡异:这个根的设置取决于/boot目录是否被单独分区了,分别来说

  • 情况一:/boot目录被单独分区
    当用户选定内核时,grub通过1_5stage去寻找第二阶段,这时,如果/boot目录被单独分区了,那么1_5 stage就没必要去访问真正的根文件系统了,因为/boot目录被单独拿出来了,直接访问grub 2 stage所在的分区就可以了,这样的话,1_5stage就会把grub 2 stage所在的目录当成根,所以在这种情况下设置的路径应该使用/grub/grub.conf或者/vmlinuz这样的方式去指定第二阶段
  • 情况二:/boot没有被单独分区
    在这种情况下,/boot目录是和根放在一起的,stage1_5stage去访问stage 2的时候,就不可能绕过文件系统的根,所以在这种情况下,路径设置就应该使用/boot/grub/grub.conf/boot/vmlinux这种方式

所以,/boot目录有没有被单独分区决定了第二阶段的访问路径,grub命令行接口的root命令,就是用来指明这个根分区位置的,一般都可以在系统上看到/boot目录被单独分区了,但这并不意味着/boot目录不可以和根文件系统放置在同一个分区上

四、init程序的相关概念

1. init程序的类别

  • SysV:传统的init程序,Centos 5上用到的就是这个程序,由贝尔实验室研发,Sys为system的简写,而V是版本号(第五版),其配置文件/etc/inittab,这个init程序存在一个缺点,因其初始化操作都是用脚本实现的,初始化过程中会大量的启动进程、销毁进程,并且进程启动存在依赖关系,比如B进程需等待A进程启动后才能启动,这将极大降低启动速度
  • Upstart:Centos 6上用到的init程序,由Ubuntu研发。为改进SysV的缺点,Centos 6所以换成了Upstart,它可以基于总线的方式让进程之间互相通信,不用等待进程启动完成,只要命令一初始化就可以把自己的状态通知给其他进程,接近于并行的方式完成初始化,但是Upstart在设计上尽可能的兼容了SysV,所以在Centos5上可以使用的机制在Centos6上也依然可以使用,更重要的是Cenots6也并没有充分发挥Upstart的作用,依然通过脚本启动服务,配置文件/etc/inittab/etc/init/*.conf
  • Systemd:Centos 7用到的init程序,受启发于MacOS的启动灵感,仿照着做了Systemd,它自己就一个强大的解释器,不需要其他任何程序来启动服务,自行完成程序加载并提交给内核,并且它在init始化时不真正初始化任何服务,当用户第一次访问某个服务时,它才会真正启动,所以这就使得Centos 7 开机可以在秒级别完成,配置文件:/usr/lib/systemd/system//etc/systemd/system/

2. init程序的运行级别

类似Windows系统的安全模式、VAG模式,不同的模式意为着启动了不同的服务、加载了不同的驱动,所以使得我们能在故障出现时,可以提供给用户一个基本环境实现系统维护工作,Centos 5、6也一样也有运行模式的概念,只不过在Centos 5、6上不叫做模式,而称之为运行级别。但在Centos 7以后级别已经失去了它原本的意义了,仅仅是为了能兼容这个理念而采用的,并且配置方式已经有了巨大的变化

  • 级别0:关机
  • 级别1:单用户模式,也称为single级别,是一个维护模式,类似windows中的安全模式,单用户级别无需登录,直接以root用户切入,比如忘记管理员密码就直接进入1级别,就能够重置管理员密码,当然1级别不仅仅是能够重置密码的,在这个级别系统中大多数的服务都不会启动,它仅仅启动系统基本的运行环境,让我们进行维护工作
  • 级别2:多用户模式,也是一种维护模式,这个模式用户需要使用账号名、密码登录,此模式会启动网络功能,但不会启动网络文件系统(NFS),其实1级别模式也可以启动网络功能,但需要用户手动选定才可以
  • 级别3:多用户模式(正常模式),只不过使用文本界面
  • 级别4:4级别也是多用户模式,但事实上这个级别没定义,是个预留级别,可同3级别
  • 级别5:多用户模式,此级别是一个可以正常使用的级别,但在这个级别下将启动图形界面
  • 级别6:一旦将运行级别设置为6,就表示重启系统
Centos7中systemd与init运行级别的对应关系
级别0 ==> runlevel0.target或poweroff.target
级别1 ==> runlevel1.target或rescue.target
级别2 ==> runlevel2.target或multi-user.target
级别3 ==> runlevel3.target或multi-user.target
级别4 ==> runlevel4.target或multi-user.target
级别5 ==> runlevel5.target或graphical.target
级别6 ==> runlevel6.target或reboot.target
对于systemd中的运行级别来讲,级别2、级别3、级别4没什么区别,因为进程在没访问之前都是不会启动的

3. init的配置文件及意义及初始化时完成的操作

为了能完成系统初始化,init程序要指挥着很多进程在用户空间启动很多服务,到底启动哪些,取决于配置文件定义的不同初始化工作

(1)Centos 5:SysV

Centos 5的init的主配文件位于/etc/inittab,这个文件每行定义都遵循特定格式,都是由冒号隔开的四个字段组成

/etc/itittab 文件
----------------分割线----------------------------

id:3:initdefault:
si::sysinit:/etc/rc.d/rc.sysinit
l0:0:wait:/etc/rc.d/rc 0
l1:1:wait:/etc/rc.d/rc 1
l2:2:wait:/etc/rc.d/rc 2
l3:3:wait:/etc/rc.d/rc 3
l4:4:wait:/etc/rc.d/rc 4
l5:5:wait:/etc/rc.d/rc 5
l6:6:wait:/etc/rc.d/rc 6
tty1:2345:respawn:/sbin/mingetty tty1
tty2:2345:respawn:/sbin/mingetty tty2
tty3:2345:respawn:/sbin/mingetty tty3
tty4:2345:respawn:/sbin/mingetty tty4
tty5:2345:respawn:/sbin/mingetty tty5
tty6:2345:respawn:/sbin/mingetty tty6

-------------------------分割线---------------------

Centos 5 init 配置文件格式 id:runlevel:action:process

id:意思为这一行的标识,只要和其他的action不相同就可以,可以随意取
runlevel:标识process在那个级别会启动
action:启动process是按照什么模式去启动
wait:等待,意为等待切换到这个运行级别就运行一次process的指令
respawn:重新启动,意思是切换到这个运行级别时,只要指定的process终止,就重新启动
initdefault:设定默认运行级别
sysintit:设定系统初始化方式,通常依赖其他脚本完成系统初始化,一般为/etc/rc.d/rc.sysinit
process:真正采取的操作是什么

当内核启动/sbin/init开始初始化工作时,init程序就会基于配置文件/etc/inittab中的设定开始

  • 第一步:读取默认运行级别设定id:3:initdefault:,这个文件中第一行就是设定默认运行级别的,因为只有运行级别确定了,才能知道该启动哪些服务、运行哪些进程,在id:3:initdefault:中,id就是这行的标识,3标识运行级别,initdefault这个action就是设定默认运行级别的关键字
  • 第二步:si::sysinit:/etc/rc.d/rc.sysinit,这一行对应的运行级别段为空表示所有级别都需要运行,当默认运行级别确定后,init程序就会执行标识为si的设定,运行/etc/rc.d/rc.sysinit这个脚本,这个脚本当中会完成许多的初始化任务比如挂载/etc/fstab中所定义的每一个文件系统、读取/etc/sysctl文件中的内核参数对内核进行设定、激活交换分区、激活LVM设备、各种设备的额外驱动程序加载、设定系统时钟、设置主机名称、设置欢迎信息、激活udev和selinux、检测根文件系统并以读写方式重挂、
  • 第三步:当/etc/rc.d/rc.sysinit这些设定完成后,就会运行对应级别下的指定服务脚本,如l0:0:wait:/etc/rc.d/rc 0l1:1:wait:/etc/rc.d/rc 1l6:6:wait:/etc/rc.d/rc 6,从配置文件可以看出在每个rc后面都有一个数字,它们分别对应着/etc/rc.d/rc#.d这样的目录,数字是几就运行哪个目录下的脚本。假如默认设定的运行级别为3级别,那就会去执行l3:3:wait:/etc/rc.d/rc 3这一行对应的/etc/rc.d/rc3.d/目录下的脚本,而不管是数字几对应的目录,其中的文件都是脚本链接。并且它们都遵循统一的命名法则,要么以字母K##开头,要么以字母S##开头(##表示一个两位数字),接着通过脚本给对应目录下所有以K##开头的文件传递一个stop参数,给所有以S##开头的文件传递一个start参数,见下方脚本示例
#!/bin/bash
#
for srv in /etc/rc.d/rc3.d/K*; do
$srv stop
done
----------------------------------
#!/bin/bash
#
for srv in /etc/rc.d/rc3.d/S*; do
$srv start
done
  • 接上述第三步内容。在每个级别下,都会先执行K开头的文件,而不管是K开头还是S开头的文件,名称后面的数字至关重要,它决定了在脚本中的执行次序,所以数字小的一定会被先执行。反之,在关闭时,被依赖的反而要后关闭。将来如果想在级别3实现某个服务开机自动运行,就在/etc/rc.d/rc3.d/为这个服务创建一个以S##开头的链接文件即可,不过手动创建链接文件或删除链接文件这种方式确实挺低效的,有一个命令可以高效的实现这个操作chkconfig命令。无论是K开头还是S开头的脚本(LSB脚本),它后面的两位数字都源于脚本中的chkconfig提示信息,比如你应该曾经在某些脚本中看到过chkconfig: - 23 84这样的配置参数,这个参数就是用来设定S或K后面数字的
  • 第三步的补充说明:在正常级别下有一个特殊的服务,也是最后一个启动的服务/etc/rc.d/rc3.d/S99local,这个链接文件不同其它文件一样指向/etc/rc.d/init.d/目录中,而是指向了/etc/rc.d/rc.local,此文件中定义的命令执行时间是系统启动完成了,用户登录前。它还有个链接文件是/etc/rc.local。文件的意义是对于那些不便受chkconfig控制写成脚本放在/etc/rc.d/init.d/目录下,但是需要开机运行的命令,就可以写在这个文件中
  • 第四步:当将对应运行级别l3:3:wait:/etc/rc.d/rc 3规定服务初始化工作完成,接下来就该运行tty3:2345:respawn:/user/sbin/mingetty tty3这类操作了,类似的定义一共有6行,每行都在2、3、4、5级别下启动一个tty终端,所以会启动6个终端,而其中的action对应的respawn参数,表示每当这个终端关闭时,就自动重新启动一次。而在每一行process中对的/sbin/mingetty会自动调用login程序,login程序负责验证用户键入的账号、密码,当验证通过则启动默认shell进程,以此类推,如果默认运行级别是5级别,则会多启动一个图形界面。这里启动的虚拟终端可以同时按下Ctrl + Alt + F#调出,#对应一个数字

(2)Centos 6:Upstart

Centos 6的Upstart程序是向前兼容Centos 5的,但它依然将这个程序命名成init,其配置文件为/etc/inittab,但是这个配置文件是为了方便用户修改默认运行级别有意留在这里的,其实Upstart程序是不会用这个配置文件的,它用的配置文件在/etc/init/*.conf,Centos 6只不过是将Centos 5上的文件切分了。需要注意的是,Centos 6的启动初始化配置文件需要使用Upstart配置文件语法格式

(3)Centos 7:systemd

systemd引入了一个新的核心概念用于完成服务控制,我们称之为Unit(单元),由其相关的配置文件进行标识、配置。文件中主要包含了系统服务,监听的socket,保存的快照以及其他与init相关的信息

① systemd的新特性

  • 系统引导时实现服务并行启动
  • 按需激活进程:在启动之前让进程处于半活动状态。比如httpd服务,它会先帮httpd的端口注册且不启动进程,当第一次访问时再启动之
  • 系统状态快照:自我保存当前用户空间进程的运行状态快照,将来可以迅速恢复到过去某个状态
  • 基于依赖关系定义服务控制逻辑
  • 基于socket的激活机制:意为着socket与服务程序分离,socket由systemd待为监听,程序不用启动,当有进程访问套接字的时候,才临时的按需激活服务
  • 基于bus的激活机制:激活设备时还可以基于总线激活,如果这个总线上存在对某个服务的访问,那么就基于总线的请求将设备激活
  • 基于device的激活机制:时刻监控中硬件信息,一旦某个设备加入进来,先给它创建设备文件,在将其自动挂载至某路径,挂载点不存在还能自动创建
  • 基于path的激活机制:系统可以监控这某个目录或文件存在与否,如果路径变得可用会立刻激活某个服务
  • 系统快照:将所有unit当前状态临时保存在持久设备设备中,完成状态回滚
  • 向后兼容sysv init脚本:意为着放置于/etc/init.d/目录中的服务脚本也能靠systemd启动、控制

② 不兼容的特性

  • systemctl命令固定不变:此前的service脚本是用户可以自行定义的,比如支持start、stop、restart等等,如果想多增一个参数只需自定义即可。但对于systemctl就不可以,这些所有的unit文件都是由systemctl控制的,而systemclt命令对每个unit最多支持的参数是固定不可变的,除非去重新去编写systemd或systemctl这个程序
  • 非由systemd启动的服务,systemctl无法控制:比如直接通过绝对路径启动的服务,systemctl就无法与之通信,也就意味着systemctl就无法控制,不过可以通过自行编写unit脚本去控制

③ systemd配置文件的位置

  • /usr/lib/systemd/system
  • /run/systemd/system
  • /etc/systemd/system:设定默认运行级别和每个运行级别启动的及其依赖关系

④ 常见的unit文件类型类型

  • Service unit:服务unit,文件扩展名为.service,用于定义系统服务,替代了原/etc/init.d/下的服务脚本
  • Target unit:目标unit,文件扩展名为.target,用于模拟实现运行级别。其实对systemd来说没有运行级别,因为所有服务默认都是不启动的,只有第一次访问时才启动
  • Device unit:设备unit,文件扩展名为.device,用于定义内核识别的设备。对于Centos 6来讲,/dev目录下的设备文件是由udev根据内核探测输出到/sys目录的信息创建的,而Centos 7的系统设备文件是由udevsystemd联合创建的
  • Mount unit:挂载unit,文件扩展名为.mount,用于定义文件系统挂载点
  • Socket unit:套接字unit,文件扩展名为.socket,用于标识进程间通信用的socket文件
  • Snapshot unit:快照unit,文件扩展名为.snapshot,管理系统快照
  • Swap unit:交换unit,文件扩展名为.swap,用于标识、管理swap设备
  • Automount unit:文件扩展名为.automount,用于管理文件系统自动挂载点设置,比如用户插入U盘,要不要自动将U盘挂载上来
  • Path unit:文件扩展名为.path,用于定义文件系统中的一个文件或目录,它能够监控用户指定的一个特定文件或目录,如果不存在,systemd可以自动创建

⑤ unit文件的组织结构

/usr/lib/systemd/system/httpd.service为例,这个配置文件由三个配置段组成:Unit、Service、Install,其中第二个配置段是和文件类型相关的,我们这里使用的httpd的service unit文件,所以第二段为Service,那么如果查看的是target unit文件,第二段及为target。

[Unit]
Description=The Apache HTTP Server
After=network.target remote-fs.target nss-lookup.target
Documentation=man:httpd(8)
Documentation=man:apachectl(8)

[Service]
Type=notify
EnvironmentFile=/etc/sysconfig/httpd
ExecStart=/usr/sbin/httpd $OPTIONS -DFOREGROUND
ExecReload=/usr/sbin/httpd $OPTIONS -k graceful
ExecStop=/bin/kill -WINCH ${MAINPID}
# We want systemd to give httpd some time to finish gracefully, but still want
# it to kill httpd after TimeoutStopSec if something went wrong during the
# graceful stop. Normally, Systemd sends SIGTERM signal right after the
# ExecStop, which would kill httpd. We are sending useless SIGCONT here to give
# httpd time to finish.
KillSignal=SIGCONT
PrivateTmp=true

[Install]
WantedBy=multi-user.target
  • Unit配置段主要用来定义当前unit的描述信息、unit行为及依赖关系等。其中,
Description:意义性描述信息
After:定义这个unit的启动次序,表需要晚于哪些启动
Requies:强依赖,这里定义依赖的units必须全都启动,当前unit才能启动
Want:弱依赖,被依赖的unit未激活是并不影响当前unit的激活
Conflicts:定义当前unit的冲突关系
  • Service配置段主要用来定义与此类型文件相关的专用选项,这里以Service为例所以名称为Service,如果打开的是target unit文件,这里的名称即为Target。所以第二个配置段是定义与此类型unit相关的专用选项,这里说明Service的常用选项
Type:用于定义影响ExecStart及其相关参数功能的启动类型
simple(默认类型):表示由ExecStart启动的进程默认就主进程
forking表示由ExecStart启动的进程生成的子进程作为主进程,启动完成后父进程退出
oneshot:类似simple,但是在启动后续的unit之前,主进程将会退出
dbus:类似于simple,但是后续的unit仅在主进程得到dbus名称之后才能启动
notify:类似于simple,但是后续的unit仅在通过sdnotify函数发送通知以后才能运行这个命令
EnvironmentFile:启动时需要用到的环境配置文件,此文件会在ExecStart之前读取并为其提供一些变量
Exec[start|stop|reload]:指明当unit执行start、stop、reload时运行的脚本
Restart:如果这个程序意外终止了,systemd会把它重新启动起来
  • install配置段,定义由systemctl enable以及systemctl disable命令实现服务开机自启或禁用时用到的一些选项
Alias:定义别名
RequiredBy:定义被哪些unit强依赖
WantedBy:定义被哪些unit弱依赖

对于新创建或修改了Unit文件,必须要通知Systemd重载此配置文件,使用命令systemctl daemon-reload完成重载

⑥ systemctl命令的用法

对于Centos 7,系统服务主要就是靠service类型的unit文件来实现管控的,它可以兼容/etc/init.d/下的各类服务脚本
命令格式:systemctl commond NAME.service

服务管理相关commond

start | stop | restart | status:启动、停止、重启、查看状态
try-restart NAME.service:条件式重启服务,意思为查看当前服务是否启动,如果启动了就重启一下。如果没启动那就不管它了
reload-or-restart :重载或重启服务。当命令某个进程去重载配置文件时,进程如果支持重载就完成重载,如果不支持就重启
reload-or-try-restart:重载或条件式重启服务
is-active: 查看当前服务运行与否的命令,输出的信息很少
list-units [-t service_type] [--all]:查看所有以激活的服务,默认显示所有类型。--all可以显示已装载但是为激活的
systemctl list-unit-files --t service:查看所有服务的开机自启状态
enable | disable:设定服务开机启动或开机禁用
is-enabled:查看某个服务是否开机自启
mask | unmask:设置某个服务禁止设定或取消禁止设定开机自启
list-dependencies:查看某个服务的依赖关系

------------------分割线----------------------

target管理相关commond

isolate level.target:运行级别切换
list-units -t target [-a] 查看当前运行级别
get-default:查看默认运行级别
set-default level.target:修改默认运行级别
rescue:切换至紧急救援模式
emergency:切换至emergency模式,这个比紧急救援模式更彻底的模式
halt | poweroff:关机
reboot:重启
suspend:挂起系统
hibernate:创建系统快照
hybrid-sleep:完成快照后将系统挂起

4. chkconfig命令相关

在init程序初始化中,曾提到过chkconfig提示信息,本部分对chkcofnig相关概念加以说明

(1)chkconfig提示信息

chkconfig提示信息你应该曾经在某些脚本中看到过,如chkconfig: - 23 84这样的配置参数,这个参数就是用来设定init初始化工作中S或K后面数字的,下方为chkconfig提示信息示例

  • chkconfig提示信息示例1:
# chkconfig: - 23 84
------分割线-------
第一个位置的意义:当这个脚本受chkconfig工具控制时,在哪些级别设置为S,而横线表示所有级别都不为S
第二位:S后面对应的数字
第三位:K后面对应的数字
  • chkconfig提示信息示例2:
### BEGIN INIT INFO
# Provides: network_manager $network
# Required-Start:messagebus
# Required-Stop:messagebus
# Default-start:2 3 4 5
# Default-Stop: 0 1 6
# Short-Description:start and stopNetworkManager
# Description:NetworkManager is a tool for easily managing network connections
------分割线-------
Required-Start:messagebus 由消息总线控制启动
Required-Stop:messagebus 由消息总线控制关闭
Default-start:在哪个级别下自动运行
Required-Stop:在哪个级别的关闭

上述的两种chkconfig提示信息示例中,格式1是早期chkconfig命令所使用的格式,但它有点简陋。于是就出现了格式2,格式2是Upstart所使用的格式,不过这两种都可以被chkconfig所使用

(2)chkconfig命令 [–list] [name]命令

命令格式:chkconfig [option] [name]

option
--list:查看服务在所有级别的启动或运行情形
--level ### Commond <on|off|reset>:设定服务默认开始或关闭,省略级别是表示2345
reset:重置
示例:chkconfig --level 3 NetworkManager off
--add NAME:添加指定,需要先将脚本文件放至/etc/init.d/目录下
--del NAME:删除指定服务脚本

(3)自定义chkconfig初始化服务脚本

  • 编辑一个文件,放到/etc/init.d/下,如/etc/init.d/testsrv,文件内容如下
#!/bin/bash
#

# chkconfig: 345 88 22
# description: test srv scripts
echo 'hello srv'
  • 给定执行权限并添加至chkconfig命令管控
    ~]# chmod +x /etc/init.d/testsrv
    ~]# chkconfig --add /etc/init.d/testsrv

  • 查看结果
    ~]# chkconfig --list testsrv
    ~]# ll /etc/init.d/rc0.d/K22testsrv
    ~]# ll /etc/init.d/rc3.d/S88testsrv