RedHat / Centos   Linux  系统运维与管理实践技巧荟萃


磁盘分区相关

 Linux  fdisk 磁盘分区工具以及安装 GRUB 实战:


准备工作,前置知识

演示环境基于 centos6.5 虚拟机,假设系统上已经有一块分好区,并挂载文件系统的硬盘,分区信息如下所示:

[root@centos6-5vm 桌面]# fdisk -l

Disk /dev/sda: 42.9 GB, 42949672960 bytes
255 heads, 63 sectors/track, 5221 cylinders
Units = cylinders of 16065 * 512 = 8225280 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disk identifier: 0x00000000

   Device Boot      Start         End      Blocks   Id  System
/dev/sda1   *           1          64      512000   83  Linux
Partition 1 does not end on cylinder boundary.
/dev/sda2              64        5222    41430016   8e  Linux LVM


默认情况下,fdisk 将以 dos 兼容模式,显示磁盘分区信息,在 dos 兼容模式下,以“柱面”(cylinders)为单位来设置每个分区的大小,

在上面的输出信息中,磁盘 sda 有2个分区:sda1 与 sda2 ,

总大小是 42949672960 字节;

5521个柱面,每柱面 7779328 字节(约 7.7 MBytes);

每扇区 512 字节(逻辑大小与物理大小相等),一个磁道有 63 个扇区;

83886080 个扇区;1331525 个磁道;

分区 sda1 从 1 号柱面开始到 64 号柱面结束;

分区 sda2 从 64 号柱面开始到 5222 号柱面结束;

(刚好 5221 个柱面)

以默认的柱面为单位来显示,以及设置每个磁盘分区的大小虽然很方便,但是 fdisk 工具的开发者推荐使用“扇区”(sectors)为单位来显示,指定,修改磁盘分区大小,

因此,你在对一块刚买回来的硬盘(等同于下面我们即将在虚拟机中添加的第二块硬盘),使用 fdisk 进行分区时,该工具会给出警告信息说,以柱面为单位的 dos 兼容模式已不推荐使用,你可以添加 -c选项,关掉 dos 兼容模式

并且再添加 -u 选项,切换到以扇区为单位来显示,调整每个分区的大小

(补充内容:在现代硬盘的物理结构中,每个硬盘往往有多个盘片;每个盘片分两面;每面按照同心圆划分为若干个磁道;每个磁道划分为若干扇区。假设一个硬盘有2个盘片,每个盘“面”分65536个磁道,每个磁道1024个扇区,那么容量为

 2 * 2 * 65536 * 1024 * 512 = 128 GBytes)为了隐藏盘片,磁道,柱面这些复杂的硬件物理结构,现代硬盘普遍使用一种叫做LBA(Logical Block Address)的方式,将硬盘的总扇区数从0开始编号,直到最后一个扇区,称为逻辑扇区号。

现在假设在Linux下的应用程序要读取某个大小为4096字节的文件,4096字节为多数操作系统分页的大小,也就是说操作系统读写硬盘上的文件时,以4096字节为单位,即便文件的实际字节数不足4096字节,它也会被操作系统按4KBytes 分页的对齐方式存储在硬盘上。应用程序通过类UNIX的系统调用 read 请求操作系统内核读取该文件,作为内核模块(以及模式)一部分的“文件系统驱动”定位该文件的逻辑扇区号从1000~1007共8个512字节的扇区,8 * 512 = 4096;然后文件系统驱动再向硬盘驱动程序发出读这8个扇区的命令;硬盘驱动通过计算机系统的总线,以及总线上的SATA控制器(早期是IDE)发出读取命令;作为操作系统内核一部分的硬盘驱动应该知道每个SATA主控制器的I/O端口号,X86 处理器支持寻址最多65536个I/O端口,它提供两条专门的指令“in”(写)和“out”(读)用于对I/O端口的操作。对于早期有IDE接口的计算机系统而言,其2个IDE通道分别为IDE0和

IDE1;每通道上可以连接2个设备,分别为Master(主盘)与Slave(从盘),因此一个PC中最多可以有4个IDE设备。假设前面要读取的文件位于IDE0的主盘上,这也是第一个安装的硬盘的正常位置;在PC中,IDE0通道(或其上的控制器)的I/O端口地址为0x1F0~0x1F7;以及 0x376~0x377,通过向这些端口地址发送指令就能够与IDE硬盘通信。其中:

0x1F3~0x1F6 这4字节的端口地址用于写入LBA地址(即要读取的逻辑扇区号) ,第1000号逻辑扇区的LBA地址为16进制的0x000003E8,即需要往 0x1F3和0x1F4分别都写入0x00;往0x1F5写入0x03;往0x1F6写入0xE8;

0x1F2这1字节的端口地址用于写入需要读取的扇区数,比如8;

0x1F7这1字节的端口地址用于写入要执行的操作的16进制命令码,读取为0x20;

综上所述,发往IDE控制器的命令可能包括如下:

out 0x1f3, 0x00
out 0x1f4, 0x00
out 0x1f5, 0x03
out 0x1f6, 0xe8
out 0x1f2, 0x08
out 0x1f7, 0x20

除此之外,作为内核模块的硬盘驱动还要通过类似上面的通信机制,告诉IDE控制器,需要将文件数据读取到的内存地址范围,最后由read系统调用逻辑控制处理器从该内存地址范围读取数据。


所以,我们指定以扇区为基本单位,显示硬盘 sda 的分区情况:

[root@centos6-5vm 桌面]# fdisk -l -c -u

Disk /dev/sda: 42.9 GB, 42949672960 bytes
255 heads, 63 sectors/track, 5221 cylinders, total 83886080 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 identifier: 0x00000000

   Device Boot      Start         End      Blocks   Id  System
/dev/sda1   *        2048     1026047      512000   83  Linux
/dev/sda2         1026048    83886079    41430016   8e  Linux LVM

可以看到,输出的总扇区数量,与前面我们推测计算的相符,为 83886080 个扇区

注意,此时的 sda1 分区,从第 2048 个扇区开始,到第 1026047 个扇区结束;

sda2 分区,从第 1026048 个扇区开始,到第 83886079 个扇区结束;

第 1 个扇区到第 2047 个扇区保留未使用(总共 512 * 2047 = 1048064 字节,约 1 Mbytes 的磁盘空间)


你可能会说,以扇区为单位来设置磁盘的分区大小,不就变成要指定扇区的“数量”?而且要将希望设置的以 Mbytes ,Gbytes 为单位的大小,先除以 512 字节,换算成扇区数量 ,不是很麻烦 ?

不用担心,虽然我们显式的告诉 fdisk 以扇区为基本单位,但是 fdisk 也支持在设定分区大小的过程中,以千字节(Kbytes),百万字节(Mbytes,普遍的错误称呼为“兆”字节),以及 十亿字节(Gbytes)为基本单位,来指定分区大小,fdisk 会自动换算成扇区数量


有了上面的前置知识后,我们在 centos6.5 虚拟机上,添加第二块硬盘(不习惯的童鞋,请当作你从电脑城买回一块真实的物理硬盘)


wKioL1RfmL-i_wx_AAzoOlE1xbw098.jpg


添加完成后,保存 vmware workstation 软件对该虚拟机的设置,

注意,此时在虚拟机中,还不能识别新添加的 5 GB 硬盘,需要重启虚拟机后,虚拟机中的 fdisk ,以及其它磁盘分区管理工具,才能正确识别该硬盘

重启虚拟机后,系统已经可以识别新的硬盘,不过该硬盘是“全新的”,没有分区表,没有启动分区,没有主分区,没有文件系统信息,只有最基本的容量以及物理结构信息,此后我们将基于该硬盘,用不同工具对其进行分区实战,当然,利用了

vmware workstation 软件的 “快照”这一神奇的功能:


[root@centos6-5vm 桌面]# fdisk -c -u -l /dev/sdb

Disk /dev/sdb: 5368 MB, 5368709120 bytes
255 heads, 63 sectors/track, 652 cylinders, total 10485760 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 identifier: 0x00000000


接下来,以 fdisk 对 sdb 进行分区

[root@centos6-5vm 桌面]# fdisk /dev/sdb
Device contains neither a valid DOS partition table, nor Sun, SGI or OSF disklabel
Building a new DOS disklabel with disk identifier 0xc686cd1d.
Changes will remain in memory only, until you decide to write them.
After that, of course, the previous content won't be recoverable.

Warning: invalid flag 0x0000 of partition table 4 will be corrected by w(rite)

WARNING: DOS-compatible mode is deprecated. It's strongly recommended to
         switch off the mode (command 'c') and change display units to
         sectors (command 'u').

Command (m for help):

fdisk 提示设备 sdb 没有任何合法的 DOS 分区表,或者 Sun,SGI 或 OSF 磁盘标签,因此,fdisk 初次检测新磁盘时,它将会用一个磁盘标识符(这里是 0xc686cdld)创建一个 DOS 磁盘标签;

并且,用户在 fdisk 的交互模式下所做的任何设置,改动,都将保留在内存中,直到用户在交互模式按下 w 键,才会将变更写入磁盘,

(如果想放弃所做改动,可以在交互模式按下 q 键)

同时,我们关掉 dos 兼容模式,并且以扇区为基本单位调整分区大小:

Command (m for help): c
DOS Compatibility flag is not set

Command (m for help): u
Changing display/entry units to sectors

Command (m for help): p

Disk /dev/sdb: 5368 MB, 5368709120 bytes
255 heads, 63 sectors/track, 652 cylinders, total 10485760 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 identifier: 0xc686cd1d

   Device Boot      Start         End      Blocks   Id  System

Command (m for help):

眼尖的童鞋可能会发现,在使用 fdisk -l 列出系统上所有识别到的磁盘时,该工具并不会对新添加的磁盘创建磁盘标识符(Disk identifier);只有你实际要对某个新磁盘进行分区时,fdisk 就会创建磁盘标识符并且映射到一个 DOS  磁盘标签



Command (m for help): n
Command action
   e   extended
   p   primary partition (1-4)
p
Partition number (1-4): 1
First sector (2048-10485759, default 2048): 
Using default value 2048
Last sector, +sectors or +size{K,M,G} (2048-10485759, default 10485759): +100M

Command (m for help): p

Disk /dev/sdb: 5368 MB, 5368709120 bytes
255 heads, 63 sectors/track, 652 cylinders, total 10485760 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 identifier: 0x9c234ada

   Device Boot      Start         End      Blocks   Id  System
/dev/sdb1            2048      206847      102400   83  Linux

Command (m for help): w
The partition table has been altered!

Calling ioctl() to re-read partition table.
Syncing disks.
[root@centos6-5vm 桌面]#

我们首先以 n 键,新建立一个分区;以 p 键,指定该分区为主分区;数字键 1 指定该分区号为 1 (即该磁盘上的第一个分区);接着,可以看到 fdisk 要求以扇区数量来设置新建分区的大小,并且,fdisk 仅允许从第 2048 个扇区开始划分大小,换言之,前面包含 2047 个扇区的大约 1 Mbytes 磁盘空间,不属于任何分区;

当然,不同的分区工具对此的定义也不同,例如,可以使用 GNU 的 parted 分区工具,来查看 parted 是如何利用磁盘前面的 2047 个扇区;

如果我们直接回车,那么将使用默认设置,即从第 2048 个扇区开始,划分空间,

可以清楚的看到,fdisk 支持指定扇区数量(+sectors),或者 Kbytes,Mbytes,Gbytes(+size{K,M,G}) 

此处将其划分为 100 Mbytes 的大小(+100M)

该大小足够作为存放 GRUB(引导加载程序)以及 Linux 内核映像,虚拟磁盘映像的“启动分区”了

再次按下 p 键,将显示创建的分区信息:

设备 /dev/sdb1,没有启动标志(后面会演示如何设置启动分区的标识),从第 2048 个扇区开始,到第 206847 个扇区结束,分区标识符(Id 列)为 83,对应为

Linux 系统的分区;

可以在 fdisk 交互模式按下字母 l 键,查看所有操作系统使用的分区对应的 Id:


Command (m for help): l

 0  Empty           24  NEC DOS         81  Minix / old Lin bf  Solaris        
 1  FAT12           39  Plan 9          82  Linux swap / So c1  DRDOS/sec (FAT-
 2  XENIX root      3c  PartitionMagic  83  Linux           c4  DRDOS/sec (FAT-
 3  XENIX usr       40  Venix 80286     84  OS/2 hidden C:  c6  DRDOS/sec (FAT-
 4  FAT16 <32M      41  PPC PReP Boot   85  Linux extended  c7  Syrinx         
 5  Extended        42  SFS             86  NTFS volume set da  Non-FS data    
 6  FAT16           4d  QNX4.x          87  NTFS volume set db  CP/M / CTOS / .
 7  HPFS/NTFS       4e  QNX4.x 2nd part 88  Linux plaintext de  Dell Utility   
 8  AIX             4f  QNX4.x 3rd part 8e  Linux LVM       df  BootIt         
 9  AIX bootable    50  OnTrack DM      93  Amoeba          e1  DOS access     
 a  OS/2 Boot Manag 51  OnTrack DM6 Aux 94  Amoeba BBT      e3  DOS R/O        
 b  W95 FAT32       52  CP/M            9f  BSD/OS          e4  SpeedStor      
 c  W95 FAT32 (LBA) 53  OnTrack DM6 Aux a0  IBM Thinkpad hi eb  BeOS fs        
 e  W95 FAT16 (LBA) 54  OnTrackDM6      a5  FreeBSD         ee  GPT            
 f  W95 Ext'd (LBA) 55  EZ-Drive        a6  OpenBSD         ef  EFI (FAT-12/16/
10  OPUS            56  Golden Bow      a7  NeXTSTEP        f0  Linux/PA-RISC b
11  Hidden FAT12    5c  Priam Edisk     a8  Darwin UFS      f1  SpeedStor      
12  Compaq diagnost 61  SpeedStor       a9  NetBSD          f4  SpeedStor      
14  Hidden FAT16 <3 63  GNU HURD or Sys ab  Darwin boot     f2  DOS secondary  
16  Hidden FAT16    64  Novell Netware  af  HFS / HFS+      fb  VMware VMFS    
17  Hidden HPFS/NTF 65  Novell Netware  b7  BSDI fs         fc  VMware VMKCORE 
18  AST SmartSleep  70  DiskSecure Mult b8  BSDI swap       fd  Linux raid auto
1b  Hidden W95 FAT3 75  PC/IX           bb  Boot Wizard hid fe  LANstep        
1c  Hidden W95 FAT3 80  Old Minix       be  Solaris boot    ff  BBT            
1e  Hidden W95 FAT1


几个我们耳熟能详的分区,例如 windows 的 FAT16,FAT32,NTFS(Id 为 7);

Linux 的 swap 交换分区(虚拟内存),其 Id 为 82;

Linux 的 ext 系列分区,其 Id 为 83;

Linux 的 LVM 分区,其 Id 为 8e;


记得,到此为止所做的改动,仅仅是在 fdisk 的进程地址空间中生效,因此我们按下 w 键,通知 fdisk 将这些信息实际写入磁盘,可以看到, fdisk 执行 ioctl()

系统调用重载分区表(应该还有最重要的 sync() 系统调用,同步到磁盘,这里没有显示)

有一个相关的命令 sync ,用于手动将内存中的数据同步到硬盘,一般而言,只有在需要立即同步写入硬盘时,才执行该命令,否则应用程序会根据情况,在合适的时间自动执行 sync() 系统调用写入磁盘:


[root@centos6-5vm 桌面]# sync --help

用法:sync [选项]
强迫将已更改的数据写入磁盘,并更新超级块。

      --help        显示此帮助信息并退出
      --version        显示版本信息并退出

请向bug-coreutils@gnu.org 报告sync 的错误
GNU coreutils 项目主页:<http://www.gnu.org/software/coreutils/>




我们预定将这个新创建的分区作为该磁盘上的启动分区,用来引导操作系统,因此,需要将该分区设置为“可启动的”:

Command (m for help): m
Command action
   a   toggle a bootable flag
   
   
Command (m for help): a
Partition number (1-4): 1

Command (m for help): w
The partition table has been altered!

Calling ioctl() to re-read partition table.
Syncing disks.
[root@centos6-5vm 桌面]# fdisk -l -c -u /dev/sdb

Disk /dev/sdb: 5368 MB, 5368709120 bytes
224 heads, 19 sectors/track, 2463 cylinders, total 10485760 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 identifier: 0x9c234ada

   Device Boot      Start         End      Blocks   Id  System
/dev/sdb1   *        2048      206847      102400   83  Linux
[root@centos6-5vm 桌面]#

在交互模式中,按下 a 键,可以设置启动分区标识,保存更改后,再次查看 sdb 的分区表,此时发现,设备 sdb1 在 Boot 列中多了个星号,表明 sdb1 是一个可以启动(引导)的分区


创建分区并划分大小后,需要以特定文件系统对该分区进行格式化,由于 fdisk 工具仅用于分区,因此我们可以使用另一个叫做 mke2fs 的工具对其进行格式化,该工具的详细使用技巧,以后有机会介绍,这里仅演示简单的格式化分区操作:

[root@centos6-5vm 桌面]# mke2fs /dev/sdb1
mke2fs 1.41.12 (17-May-2010)
文件系统标签=
操作系统:Linux
块大小=1024 (log=0)
分块大小=1024 (log=0)
Stride=0 blocks, Stripe width=0 blocks
25688 inodes, 102400 blocks
5120 blocks (5.00%) reserved for the super user
第一个数据块=1
Maximum filesystem blocks=67371008
13 block groups
8192 blocks per group, 8192 fragments per group
1976 inodes per group
Superblock backups stored on blocks: 
    8193, 24577, 40961, 57345, 73729

正在写入inode表: 完成                            
Writing superblocks and filesystem accounting information: 完成

This filesystem will be automatically checked every 22 mounts or
180 days, whichever comes first.  Use tune2fs -c or -i to override.


mke2fs 默认使用 ext2 文件系统,对分区进行格式化处理,在分区中加入许多与“块”,“块组”相关的统计信息(用于存储文件必需的信息),最后的输出表明,该文件系统每隔三个月,或者每经历 22 次“挂载”后,将调用 fsck 工具对其进行检查,看有无错误,丢失的块,可以使用 tune2fs 来调整时间间隔或挂载次数;


使用 GNU parted 工具交叉验证该磁盘的分区与文件系统信息:

[root@centos6-5vm 桌面]# parted -l /dev/sdb

Model: VMware, VMware Virtual S (scsi)
Disk /dev/sdb: 5369MB
Sector size (logical/physical): 512B/512B
Partition Table: msdos

Number  Start   End    Size   Type     File system  标志
 1      1049kB  106MB  105MB  primary  ext2         启动

可以看到,1 号分区的文件系统确实是 ext2,并且为启动分区,

从 1049 Kbytes 开始(2047 sectors * 512 bytes = 1049 kbytes)

到 106 Mbytes 结束(206847 sectors * 512 bytes = 105905664 bytes = 106 Mbytes)


sdb1 为启动分区,并不意味着,该分区此时就可以引导操作系统,原因很简单:

一,启动分区上没有任何引导代码,我们需要将诸如 GRUB 的引导加载程序,安装 

    到该分区上,作为该磁盘的 MBR (主引导记录)

二,启动分区上没有 Linux 内核映像与虚拟磁盘映像


下面简单演示在 sdb1 上安装 GRUB,关于 Linux 内核映像,其实只要复制一个当前磁盘上 Linux 内核映像的副本,到 sdb1 的某个目录(通常为 /boot)即可,而在进行上述操作之前,需要先将 sdb1 挂载到当前运行的 Linux 内核维护的树形文件系统逻辑目录

(假设挂载到 /mnt/boot ,这样,当用户访问 /mnt/boot,内核就知道并会映射到第 2 块磁盘的第 1 个分区,即 /dev/sdb1 ):


[root@centos6-5vm 桌面]# mkdir /mnt/boot
[root@centos6-5vm 桌面]# mount /dev/sdb1 /mnt/boot
[root@centos6-5vm 桌面]# ll /mnt/boot
总用量 12
drwx------. 2 root root 12288 11月 11 10:35 lost+found

只要能在挂载的目录下查找到“lost+found”子目录,就表示操作挂载成功


[root@centos6-5vm 桌面]# 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-install 命令来安装 GRUB;

--root-directory=  指定挂载的目标目录;后接源磁盘,而是磁盘分区,因此这里是 /dev/sdb;

“Installation finished. No error reported”表明成功安装;


/mnt/boot/grub/device.map  这个文件中,存储着 GRUB 识别到的磁盘与 Linux 内核识别到的磁盘之间的映射关系;例如,Linux 内核的所谓 /dev/sdb,对 GRUB 而言,就是 hd1;如果发现该文件的映射不正确,重新执行 grub-install 命令,则可以解决这个问题;


再次查看 /mnt/boot,以及安装生成的 grub 子目录:

[root@centos6-5vm 桌面]# ll /mnt/boot
总用量 14
drwxr-xr-x. 2 root root  1024 11月 11 10:56 grub
drwx------. 2 root root 12288 11月 11 10:35 lost+found

[root@centos6-5vm 桌面]# ll /mnt/boot/grub/
总用量 274
-rw-r--r--. 1 root root     45 11月 11 10:56 device.map
-rw-r--r--. 1 root root  13392 11月 11 10:56 e2fs_stage1_5
-rw-r--r--. 1 root root  12632 11月 11 10:56 fat_stage1_5
-rw-r--r--. 1 root root  11760 11月 11 10:56 ffs_stage1_5
-rw-r--r--. 1 root root  11768 11月 11 10:56 iso9660_stage1_5
-rw-r--r--. 1 root root  13280 11月 11 10:56 jfs_stage1_5
-rw-r--r--. 1 root root  11968 11月 11 10:56 minix_stage1_5
-rw-r--r--. 1 root root  14424 11月 11 10:56 reiserfs_stage1_5
-rw-r--r--. 1 root root    512 11月 11 10:56 stage1
-rw-r--r--. 1 root root 126108 11月 11 10:56 stage2
-rw-r--r--. 1 root root  12036 11月 11 10:56 ufs2_stage1_5
-rw-r--r--. 1 root root  11376 11月 11 10:56 vstafs_stage1_5
-rw-r--r--. 1 root root  13976 11月 11 10:56 xfs_stage1_5


在上面输出中:

stage1 是 GRUB 的第一阶段引导程序;stage2 是第二阶段引导程序;带有 stage1_5 的,是 GRUB 内置的“文件系统驱动”,简单地讲,当这个“1.5 阶段”加载到内存后, GRUB 就应该能识别目标磁盘上的文件系统类型,

注意,此时 Linux 内核及其文件系统驱动还没有进驻内存,GRUB 不可能依赖于 Linux 内核实现的文件系统机制来访问磁盘,GRUB 必须有自己的识别机制,而这就是各种 stage1_5 文件存在的目的,可以看到,GRUB 支持多个操作系统使用的文件系统,包括 Linux 的 ext 系列文件系统,windows 的 fat 系列文件系统,

FreeBSD 的 ufs 文件系统,甚至还有光盘文件系统(iso9660);


GRUB 在启动时会根据 grub.conf 文件中的配置,来决定其行为模式,但是以 grub-install 命令安装时,并不会生成这个配置文件,我们需要手动创建并且编辑里面的内容,当然你也可以直接从第一块硬盘上的 grub.conf 中复制内容,然后将相应的部分修改即可:

假设 /dev/sda1 挂载到 /boot;/dev/sdb1 挂载到 /mnt/boot;这 2 个分区分别为 2 块硬盘各自的启动分区:

[root@centos6-5vm 桌面]# df -hT


/dev/sda1                         ext4   485M   37M  423M   9% /boot
/dev/sdb1                         ext2    97M   22M   71M  24% /mnt/boot

[root@centos6-5vm 桌面]# cp /boot/grub/grub.conf /mnt/boot/grub/grub.conf
[root@centos6-5vm 桌面]# vim /mnt/boot/grub/grub.conf

default=0
timeout=10
splashimage=(hd0,0)/grub/bootimg.xpm.gz
title shayiOS (test operation system VER 1.0)
        root (hd0,0)
        kernel /vmlinuz-2.6.32-431.el6.i686 ro root=/dev/sda2
        initrd /initramfs-2.6.32-431.el6.i686.img

这个是我们自定义的 grub.conf 配置文件; splashimage=  用于指定 GRUB 启动时,显示的图片,其存放位置,

注意,这里的 hd0,0  虽然以当前系统而言,它应该是第二块硬盘的第一个分区 hd1,0(即 sdb1),

但是在实际使用中,如果你把第二块硬盘接到一个没有硬盘的系统上,

对于该系统的主板 BIOS 芯片而言,它就成了第一块硬盘 hd0,0

即(sda1)

并且由于 GRUB 使用 BIOS 的磁盘分区驱动,所以这里配置成 hd0,0

后面的 root (hd0,0) 也是同样道理;参考下图:


wKioL1RiyPmxOQQjAAe8NL-xiR8945.jpg



kernel 条目后面的 root=/dev/sda2 ,用于定义第二块硬盘上的根分区,由于该分区目前还不存在,因此后面会创建,同时在第一个分区的 grub 目录下创建一张图片 bootimg.xpm.gz

并且,将第一块硬盘上第一个分区(以当前系统而言是 sda1)的 Linux 内核映像与虚拟磁盘文件,复制到第二块硬盘的第一个分区 (以当前系统而言是 sdb1 )

即可;

先检查一下,要创建分区所在的磁盘,是否已经挂载到树形文件目录的某个挂载点上,如果是,首先要卸载该磁盘,否则在后续使用 fdisk 分区时,会提示设备忙碌,无法重新写入分区表等错误提示:

[root@centos6-5vm 桌面]# fdisk  -c -u /dev/sdb

Command (m for help): w
The partition table has been altered!

Calling ioctl() to re-read partition table.

WARNING: Re-reading the partition table failed with error 16: 设备或资源忙.
The kernel still uses the old table. The new table will be used at
the next reboot or after you run partprobe(8) or kpartx(8)
Syncing disks.

[root@centos6-5vm 桌面]# df -hT
Filesystem                        Type   Size  Used Avail Use% Mounted on

/dev/sda1                         ext4   485M   37M  423M   9% /boot
/dev/sdb1                         ext2    97M   22M   71M  24% /mnt/boot

[root@centos6-5vm 桌面]# umount /mnt/boot
[root@centos6-5vm 桌面]# df -hT
Filesystem                        Type   Size  Used Avail Use% Mounted on

/dev/sda1                         ext4   485M   37M  423M   9% /boot

[root@centos6-5vm 桌面]# fdisk -c -u /dev/sdb

Command (m for help): n
Command action
   e   extended
   p   primary partition (1-4)
p
Partition number (1-4): 2
First sector (206848-10485759, default 206848): 
Using default value 206848
Last sector, +sectors or +size{K,M,G} (206848-10485759, default 10485759): +512M 

Command (m for help): w
The partition table has been altered!

Calling ioctl() to re-read partition table.
Syncing disks.


[root@centos6-5vm 桌面]# mke2fs /dev/sdb2

正在写入inode表: 完成                            
Writing superblocks and filesystem accounting information: 完成

This filesystem will be automatically checked every 38 mounts or
180 days, whichever comes first.  Use tune2fs -c or -i to override.

[root@centos6-5vm 桌面]# fdisk -c -u -l /dev/sdb

   Device Boot      Start         End      Blocks   Id  System
/dev/sdb1   *        2048      206847      102400   83  Linux
/dev/sdb2          206848     1255423      524288   83  Linux

在上面输出中,首先让 /dev/sdb 处于挂载状态,此时操作 fdisk 分区时,最后无法写入分区表;卸载 /dev/sdb 后,就可以成功对其进行分区;

出于演示目的,这里仅将 sdb2 划分 512 Mbytes 的空间,在实际使用时,由于 sdb2 是根文件系统,因此尽可能分配多一些空间(除非你愿意将 /etc,/var,/usr,/root,等目录单独分区);

限于篇幅,精简了上面执行 mke2fs 对 sdb2 以 ext2 文件系统进行格式化操作的部分输出信息;


接下来,重新挂载 /dev/sdb1  到  /mnt/boot,然后将第一块硬盘第一个分区上的

Linux 内核映像,虚拟磁盘文件,复制到第二块硬盘的第一个分区:

[root@centos6-5vm 桌面]# mount /dev/sdb1 /mnt/boot
[root@centos6-5vm 桌面]# df -hT

/dev/sda1                         ext4   485M   37M  423M   9% /boot
/dev/sdb1                         ext2    97M   22M   71M  24% /mnt/boot

[root@centos6-5vm 桌面]# cp /boot/{vmlinuz-2.6.32-431.el6.i686,initramfs-2.6.32-431.el6.i686.img} /mnt/boot/
[root@centos6-5vm 桌面]# ll /mnt/boot/
总用量 19916
drwxr-xr-x. 2 root root     1024 11月 11 22:01 grub
-rw-------. 1 root root 16290996 11月 11 22:40 initramfs-2.6.32-431.el6.i686.img
drwx------. 2 root root    12288 11月 11 10:35 lost+found
-rwxr-xr-x. 1 root root  4002656 11月 11 22:40 vmlinuz-2.6.32-431.el6.i686


如前所述,我们计划在 /mnt/boot/grub(即第二块硬盘第一分区的 grub 目录下 ),创建一张图片,用于在 GRUB 启动时显示背景画面;

GRUB 支持作为启动背景的图片,必须满足下述条件,才能正常显示(其实这里参考了 magedu 上的视频教程,有兴趣的童鞋可以访问相关站点学习):

一,图片分辨率最高支持到 640 * 480 像素

二,颜色深度(色深)为 14 位

三,必须为 xpm 格式


Linux 平台上,有一款优秀的图形图像编辑软件,堪比 windows 上的 photoshop,它就是 gimp (GNU 图像处理程序),限于篇幅,本博文不介绍详细的 gimp 安装与使用,有兴趣的童鞋可以自行搜索文章,教程;

gimp 强大的图形编辑功能,可以一次性满足上面列出的三个条件;


我们使用的测试图片为 AQUA(水叮当舞曲乐队)在 1997 年由环球音乐发售的专辑唱片 CD 的封面,


该乐队与专辑中的歌曲曾经红遍 1997~2001 年的全球各地,

其中《 My Oh My》,《 Barbie Girl》,《 Lollipop 》至今仍旧是令人怀念的动感舞曲,这里顺便向各位推荐,一天繁重的运维工作结束后,放松心情聆听一下,是不错的选择;


下面以截图方式介绍 GRUB 启动图片的整体制作过程:



wKiom1RiLRvACnrpAA-CJoBPRy4966.jpg



wKioL1RiMPigOTomAA7kYj5Rf64466.jpg


wKiom1RiMnXRaCRJAAuWVURwteM090.jpg



wKiom1RiNNmAwx2PAApef-m1g4M745.jpg



制作完成以后,将其存储在 /mnt/boot/grub/ 目录下,取名为 bootimage.xpm

注意,经过了上面的调整后,我们可以使用 gzip 进一步压缩该图像文件的大小,避免出现 GRUB 无法正常显示图片的情况;

然后编辑 /mnt/boot/grub/grub.conf ,加入相应的条目:

[root@centos6-5vm 桌面]# mv /root/桌面/bootimage.xpm /mnt/boot/grub/

[root@centos6-5vm 桌面]# du -k /mnt/boot/grub/bootimage.xpm 
229    /mnt/boot/grub/bootimage.xpm

[root@centos6-5vm 桌面]# gzip -9 /mnt/boot/grub/bootimage.xpm 
[root@centos6-5vm 桌面]# du -k /mnt/boot/grub/bootimage.xpm.gz 
30    /mnt/boot/grub/bootimage.xpm.gz

[root@centos6-5vm 桌面]# vim  /mnt/boot/grub/grub.conf

default=0
timeout=10
splashimage=(hd0,0)/grub/bootimage.xpm.gz
title shayiOS (test operation system VER 1.0)
        root (hd0,0)
        kernel /vmlinuz-2.6.32-431.el6.i686 ro root=/dev/sda2
        initrd /initramfs-2.6.32-431.el6.i686.img


可以看到,制作完成后的启动图片,大小为 229 Kbytes,经过 gzip 的最高比例压缩后,减少到 30 Kbytes,并且变成以 .gz 为后缀;

保存对 grub.conf 的修改并退出 vim ,此时的第二块硬盘第一分区应该有如下所示的结构:

[root@centos6-5vm 桌面]# ll /mnt/boot/
总用量 19916
drwxr-xr-x. 2 root root     1024 11月 12 00:38 grub
-rw-------. 1 root root 16290996 11月 11 22:40 initramfs-2.6.32-431.el6.i686.img
drwx------. 2 root root    12288 11月 11 10:35 lost+found
-rwxr-xr-x. 1 root root  4002656 11月 11 22:40 vmlinuz-2.6.32-431.el6.i686
[root@centos6-5vm 桌面]# ll /mnt/boot/grub/
总用量 306
-rw-r--r--. 1 root root  28249 11月 12 00:04 bootimage.xpm.gz
-rw-r--r--. 1 root root     45 11月 11 10:56 device.map
-rw-r--r--. 1 root root  13392 11月 11 10:56 e2fs_stage1_5
-rw-r--r--. 1 root root  12632 11月 11 10:56 fat_stage1_5
-rw-r--r--. 1 root root  11760 11月 11 10:56 ffs_stage1_5
-rw-r--r--. 1 root root    221 11月 12 00:32 grub.conf
-rw-r--r--. 1 root root  11768 11月 11 10:56 iso9660_stage1_5
-rw-r--r--. 1 root root  13280 11月 11 10:56 jfs_stage1_5
-rw-r--r--. 1 root root  11968 11月 11 10:56 minix_stage1_5
-rw-r--r--. 1 root root  14424 11月 11 10:56 reiserfs_stage1_5
-rw-r--r--. 1 root root    512 11月 11 10:56 stage1
-rw-r--r--. 1 root root 126108 11月 11 10:56 stage2
-rw-r--r--. 1 root root  12036 11月 11 10:56 ufs2_stage1_5
-rw-r--r--. 1 root root  11376 11月 11 10:56 vstafs_stage1_5
-rw-r--r--. 1 root root  13976 11月 11 10:56 xfs_stage1_5


Linux 内核映像;虚拟磁盘文件;grub 目录以及该目录下的 bootimage.xpm.gz 启动图片;grub.conf 配置文件;stage1;stage2 这两个核心的 GRUB 启动代码;


最后一步,只需要在第二分区(sdb2)中,构建根文件系统的树形结构,以及制作一个由 Linux 内核创建的第一个用户空间进程( init )读取的配置文件,即

/etc/inittab,以及由该文件所引用的启动脚本即可;这最后一步看起来异常复杂,在此之前,让我们先测试一下到 GRUB 引导 Linux 内核的过程是否正常:


我们在 vmware workstation 软件中,新建一个 RedHat Linux 系列的虚拟机,用来模拟将这块硬盘接到一个没有硬盘的 PC 主板上面,然后尝试从该硬盘的 MBR 来引导系统:


关于新建一个虚拟机的步骤,这里不费笔墨介绍,想必大家都很熟悉了,比较关键的一步是在设置硬盘参数的时候,要选择

“use an existing virtual disk”,换言之,该虚拟机的硬盘,将使用你的系统上其它已建立的虚拟机的硬盘(模拟无硬盘的系统接上一块硬盘并引导的情况),然后,在宿主机(真实机)的文件系统上,找出已建立的虚拟机的“vmdk(虚拟磁盘文件)”存储路径,将新建虚拟机的硬盘文件,定位到这个路径即可:


wKioL1RixRmA9AMrAAstqqH_Wrg864.jpg



现在,两个虚拟机使用了宿主机上同一个 vmdk(虚拟磁盘文件),这会导致资源冲突,新建的虚拟机将无法启动,

所以要把“共享” vmdk 的那个旧虚拟机“挂起”(在 vmware workstation 中,选定旧虚拟机的标签,在菜单中选择“vm”-> “power”-> “suspended”或者 “power off”)

最后,进入新建虚拟机的 BIOS,选择从共享的硬盘启动即可,下面是实际测试的效果,可以看到,前面我们的劳动有所回报:


wKiom1RiywWincr_AAiIiRxczeg374.jpg


回到主题,在 sdb2 中构建根文件系统:


[root@centos6-5vm 桌面]# mkdir /mnt/sdb2-sysroot
[root@centos6-5vm 桌面]# ll /mnt

总用量 12
drwxr-xr-x. 2 root root 4096 11月 11 10:37 boot
drwxr-xr-x. 2 root root 4096 6月  25 17:27 hgfs
drwxr-xr-x. 2 root root 4096 11月 12 12:12 sdb2-sysroot

[root@centos6-5vm 桌面]# mount /dev/sdb2 /mnt/sdb2-sysroot/
[root@centos6-5vm 桌面]# cd /mnt/sdb2-sysroot/
[root@centos6-5vm sdb2-sysroot]# ll
总用量 16
drwx------. 2 root root 16384 11月 11 22:17 lost+found

上面,我们创建一个一眼就能看出是 sdb2 的根分区的目录,名为 sdb2-sysroot,将 sdb2 挂载并进入该目录,在其中构建根文件系统的抽象树形结构;

再次强调,下面的操作,是把 /etc,/var,/home,等目录都放在与根( / )相同的分区,即 sdb2 中,你也可以把这些子目录,划分独立的分区,如 sdb3,sdb4 等等,

实际上服务器的硬盘正是这么做的,常见的解释是,如果把产生大量日志信息的 /var 目录与根放在同一个分区,海量日志信息会把该分区的根填满,导致系统性能下降(响应速度变慢)甚至停机;


[root@centos6-5vm sdb2-sysroot]# pwd
/mnt/sdb2-sysroot

[root@centos6-5vm sdb2-sysroot]# mkdir -pv {etc,lib,bin,sbin,proc,dev,home,root,tmp,mnt,media,misc,usr/{local,bin,sbin,lib,share},var/{log,run,spool},boot}
[root@centos6-5vm sdb2-sysroot]# ls

bin  boot  dev  etc  home  lib  lost+found  media  misc  mnt  proc  root  sbin  tmp  usr  var


由于 sdb1 的 Linux 内核在启动后,会通过从 sdb2 的 sbin 目录中加载可执行文件 init 至内存,来创建第一个用户空间进程 init,但此刻 sdb2 的 sbin 目录中没有相应的文件;

因此需要将 sda 根文件系统中的 init 可执行文件( /sbin/init ),复制到 sdb2 根文件系统的相应位置,并且检查 init 文件在加载时的动态依赖性,查看它都链接了那些共享库,将这些共享库也复制到 sdb2 根文件系统的相应位置,并且还要“递归”检查这些共享库之间的依赖关系,所有这些操作无非是为了确保 Linux 内核能够正常创建 init 进程并运行:


[root@centos6-5vm sdb2-sysroot]# pwd
/mnt/sdb2-sysroot

[root@centos6-5vm sdb2-sysroot]# cp /sbin/init /mnt/sdb2-sysroot/sbin/
[root@centos6-5vm sdb2-sysroot]# ldd /sbin/init

    linux-gate.so.1 =>  (0x00ab7000)
    libnih.so.1 => /lib/libnih.so.1 (0x00710000)
    libnih-dbus.so.1 => /lib/libnih-dbus.so.1 (0x008bd000)
    libdbus-1.so.3 => /lib/libdbus-1.so.3 (0x0018b000)
    libpthread.so.0 => /lib/libpthread.so.0 (0x00a3e000)
    librt.so.1 => /lib/librt.so.1 (0x0044f000)
    libgcc_s.so.1 => /lib/libgcc_s.so.1 (0x006d4000)
    libc.so.6 => /lib/libc.so.6 (0x00458000)
    /lib/ld-linux.so.2 (0x00698000)
    
    
[root@centos6-5vm sdb2-sysroot]# cp /lib/libnih.so.1 /mnt/sdb2-sysroot/lib/
[root@centos6-5vm sdb2-sysroot]# cp /lib/libnih-dbus.so.1 /mnt/sdb2-sysroot/lib/
[root@centos6-5vm sdb2-sysroot]# cp /lib/libpthread.so.0 /mnt/sdb2-sysroot/lib/
[root@centos6-5vm sdb2-sysroot]# cp /lib/librt.so.1 /mnt/sdb2-sysroot/lib/
[root@centos6-5vm sdb2-sysroot]# cp /lib/libgcc_s.so.1 /mnt/sdb2-sysroot/lib/
[root@centos6-5vm sdb2-sysroot]# cp /lib/libc.so.6 /mnt/sdb2-sysroot/lib/
[root@centos6-5vm sdb2-sysroot]# cp /lib/ld-linux.so.2 /mnt/sdb2-sysroot/lib/

[root@centos6-5vm sdb2-sysroot]# ll ./lib/

总用量 2492
-rwxr-xr-x. 1 root root  142536 11月 12 13:31 ld-linux.so.2
-rwxr-xr-x. 1 root root 1910572 11月 12 13:30 libc.so.6
-rwxr-xr-x. 1 root root  122232 11月 12 13:30 libgcc_s.so.1
-rwxr-xr-x. 1 root root   38768 11月 12 13:28 libnih-dbus.so.1
-rwxr-xr-x. 1 root root  100500 11月 12 13:28 libnih.so.1
-rwxr-xr-x. 1 root root  133312 11月 12 13:29 libpthread.so.0
-rwxr-xr-x. 1 root root   41724 11月 12 13:30 librt.so.1


我们知道,init 进程应该需要创建一个运行在用户空间的子进程,叫做 shell,来实现与终端用户的交互,用户通过 shell 与内核打交道;这里只假设最简单的情况,即 init 创建 BASH 进程,用户使用后者登录系统以及向内核传递要执行的命令等等,


因此,将 sda 的 bash 复制到 sdb2 的 bin 目录(取决于初始化脚本,init 会执行 /bin 下的 bash),检查并复制 sda 中所有 bash 可执行文件依赖的共享库到 sdb2 的相应目录,并且创建指向 bash 的软链接:


[root@centos6-5vm sdb2-sysroot]# pwd
/mnt/sdb2-sysroot

[root@centos6-5vm sdb2-sysroot]# cp /bin/bash /mnt/sdb2-sysroot/bin/

[root@centos6-5vm sdb2-sysroot]# ldd /bin/bash

    linux-gate.so.1 =>  (0x00a70000)
    libtinfo.so.5 => /lib/libtinfo.so.5 (0x00473000)
    libdl.so.2 => /lib/libdl.so.2 (0x00874000)
    libc.so.6 => /lib/libc.so.6 (0x006be000)
    /lib/ld-linux.so.2 (0x00698000)
    
[root@centos6-5vm sdb2-sysroot]# cp /lib/libtinfo.so.5 /mnt/sdb2-sysroot/lib/
[root@centos6-5vm sdb2-sysroot]# cp /lib/libdl.so.2 /mnt/sdb2-sysroot/lib/

[root@centos6-5vm sdb2-sysroot]# cd ./bin/
[root@centos6-5vm bin]# pwd

/mnt/sdb2-sysroot/bin

[root@centos6-5vm bin]# ll

总用量 864
-rwxr-xr-x. 1 root root 874472 11月 12 14:31 bash

[root@centos6-5vm bin]# ln -s bash sh
[root@centos6-5vm bin]# ll

总用量 868
-rwxr-xr-x. 1 root root 874472 11月 12 14:31 bash
lrwxrwxrwx. 1 root root      4 11月 12 14:38 sh -> bash

[root@centos6-5vm bin]# cd
[root@centos6-5vm ~]# pwd

/root

[root@centos6-5vm ~]# chroot /mnt/sdb2-sysroot/

bash-4.1# 
bash-4.1# 
bash-4.1# exit
exit
[root@centos6-5vm ~]#

使用 chroot 测试 bash 是否能正常工作,至此,实现了一个简化的根文件系统;


接下来,需要将前面复制到 sdb1 的初始虚拟磁盘文件,

initramfs-2.6.32-431.el6.i686.img 进行部分的修改


Linux 内核通常没有自带文件系统驱动,所以 GRUBinitramfs 加载到内存;此时 initramfs 正如其名字所暗示的,是内存中的虚拟文件系统;

 Linux 内核通过加载的 initramfs 中的“文件系统驱动”,识别 sdb2 的文件系统,

 并将 sdb2 以 rootfs (根文件系统)挂载,最后切换到真正的根文件系统,然后,Linux 内核才可以访问并加载 sdb2 的 sbin 目录下的  init 文件,创建相应进程,执行启动脚本;

(在真实情景中,Linux 内核还要加载 /lib/modules/ 目录下的各种模块,这些模块对应各种硬件的驱动,这里为了简化起见,并没有在 sdb2 的 lib 目录下创建 modules 子目录)


至于为什么要修改,

这是因为,我们直接从 sdb1 复制的初始虚拟磁盘文件,其配置是按照 sda 磁盘上的逻辑结构而定的,而 sda 与 sdb 两者的逻辑结构不同;或者也可以直接删除掉 sdb1 上的副本,然后从 sda1 上的原始文件出发,制作一个修改过的副本,直接保存到 sdb1 上,鉴于前面已经进行过复制操作,这里采用后面一种办法:

[root@centos6-5vm boot]# df -hT

/dev/sda1                         ext4   485M   37M  423M   9% /boot
/dev/sdb2                         ext2   504M  4.0M  475M   1% /mnt/sdb2-sysroot
/dev/sdb1                         ext2    97M  5.7M   87M   7% /mnt/boot

[root@centos6-5vm grub]# rm -rf /mnt/boot/initramfs-2.6.32-431.el6.i686.img

在 sda 的 /tmp 目录下,创建一个叫做 sdb1-initramfs 的目录,用于临时存放与修改将要复制到 sdb1 的 initramfs-2.6.32-431.el6.i686.img

[root@centos6-5vm boot]# mkdir /tmp/sdb1-initramfs
[root@centos6-5vm boot]# cd /tmp/sdb1-initramfs/
[root@centos6-5vm sdb1-initramfs]# pwd
/tmp/sdb1-initramfs


使用 zcat 命令,将 sda1 磁盘上的 initramfs-2.6.32-431.el6.i686.img

输出一份副本,将输出作为 cpio 命令的输入,

用于解压 initramfs-2.6.32-431.el6.i686.img 到当前目录,然后对解压后生成的各种子目录和文件进行编辑修改

[root@centos6-5vm sdb1-initramfs]# pwd
/tmp/sdb1-initramfs

[root@centos6-5vm sdb1-initramfs]# zcat /boot/initramfs-2.6.32-431.el6.i686.img | cpio -id 
76138 块
[root@centos6-5vm sdb1-initramfs]# ls

bin      dev                 emergency  init       initqueue-finished  initqueue-timeout  mount      pre-trigger  proc  sys      tmp  var
cmdline  dracut-004-335.el6  etc        initqueue  initqueue-settled   lib                pre-pivot  pre-udev     sbin  sysroot  usr

[root@centos6-5vm sdb1-initramfs]# file ./init

./init: POSIX shell script text executable

[root@centos6-5vm sdb1-initramfs]# vim ./init

NEWROOT="/"

上面在编辑 init 脚本时,搜索 NEWROOT 字串,找到后将其值改为 "/"

(原始值为 "/sysroot"),

前面提到, Linux 内核通过 GRUB 加载的 initramfs 文件系统驱动,将 sdb2 以 rootfs(根文件系统)挂载 ,但是挂载到哪里呢 ? 上面就指定将其挂载到 /


另外还需要注意一点,Linux 内核此时是以只读模式挂载到根分区(/),因为后面创建的 init 进程首先要调用 fsck 对其进行检查或修复(具体的操作在 init 执行的系统初始化脚本 rc.sysinit 中定义),

例如上一次关闭系统时,根文件系统没有正确卸载,fsck 就可以修复错误,

而 fsck 不能检查或修复以读写模式挂载的文件系统,这会因数据一致性问题导致文件系统损坏,

当 init 调用 fsck 执行检查或修复后,init 将以读写模式重新挂载根文件系统(以及挂载其它在 /etc/fstab 文件中定义的分区-文件系统);


通过查看 init 执行 rc.sysinit 脚本时,输出到 /var/log/boot.log  的日志信息,我们可以验证以上论述:

[root@centos6-5 桌面]# cat /var/log/boot.log 
        Welcome to CentOS 
Starting udev: /bin/chown: invalid group: `root:lp'


Setting hostname                                           [  OK  ]
Setting up Logical Volume Management:   No volume groups found
                                                           [  OK  ]
Checking filesystems
/dev/sda6: clean, 15357/6406144 files, 19563127/25600000 blocks
/dev/sda1: clean, 39/102400 files, 50423/409600 blocks
/dev/sda2: clean, 3433/25600000 files, 75276659/102400000 blocks
/dev/sda9: clean, 20/2910656 files, 228736/11638528 blocks
/dev/sda3: clean, 1321/9601024 files, 11571597/38400000 blocks
/dev/sda5: clean, 97915/9601024 files, 13340584/38400000 blocks
/dev/sda7: clean, 4896/6406144 files, 877993/25600000 blocks
                                                           [  OK  ]
Remounting root filesystem in read-write mode:             [  OK  ]


日志中的 checking filesystems,实际上就是以 fsck 对只读模式的文件系统进行检查或修复,然后以读写模式重新挂载;



保存修改后退出 vim,重新打包当前目录下的所有文件与子目录,可以通过 gzip 控制压缩的大小,

将生成的文件命名为 initramfs-2.6.32-431.el6.i686.img

并存储到 sdb1 :

[root@centos6-5vm sdb1-initramfs]# find . | cpio -o -H newc --quiet | gzip -9 > /mnt/boot/initramfs-2.6.32-431.el6.i686.img


假设到此为止的操作一切正常,那么 Linux 内核启动后,应该可以创建 init 进程,后者将读取 sdb2 的 etc 目录下的 inittab 文件,确定默认运行级别,以及根据哪个脚本来执行系统启动后的初始化任务:

[root@centos6-5vm ~]# cd /mnt/sdb2-sysroot/etc/
[root@centos6-5vm etc]# pwd
/mnt/sdb2-sysroot/etc

[root@centos6-5vm etc]# vim inittab 

id:3:initdefault:
si::sysinit:/etc/rc.d/rc.sysinit

[root@centos6-5vm etc]# mkdir rc.d
[root@centos6-5vm etc]# cd ./rc.d/
[root@centos6-5vm rc.d]# vim ./rc.sysinit

#!/bin/bash
echo -e "\tWelcome to shayiOS Linux !"
/bin/bash

:wq!

[root@centos6-5vm rc.d]# chmod +x ./rc.sysinit

上面配置默认运行级别为3,并且指示 init ,读取 /etc/rc.d/rc.sysinit 这个脚本,执行系统初始化,显示一个简单的欢迎信息,并且启动 bash


除此之外,为了实现能关闭系统,还需要作如下配置:

一,在 sdb2 的 etc/rc.d/  目录下创建一个脚本名为  rc.shutdown ,编辑该脚本添加进入运行级别 0 时,应该进行的操作:调用 sdb2 的 sbin/halt 程序关机;

二,将 sda 的 halt 程序,以及所有依赖的共享库复制到 sdb2 的 相应位置,

三,在 sdb2 的 etc/inittab 文件中添加一项条目,指示 init 进程,当进入级别 0 (例如用户执行 init 0 命令)时,应该执行的脚本(这里即执行 rc.shutdown)


[root@centos6-5vm ~]# cd /mnt/sdb2-sysroot/etc/rc.d/
[root@centos6-5vm rc.d]# pwd
/mnt/sdb2-sysroot/etc/rc.d

[root@centos6-5vm rc.d]# vim rc.shutdown 

#/bin/bash
exec /sbin/halt -p

:wq!

[root@centos6-5vm rc.d]# cp /sbin/halt /mnt/sdb2-sysroot/sbin/
[root@centos6-5vm rc.d]# ldd /sbin/halt

libaudit.so.1 => /lib/libaudit.so.1 (0x00122000)

[root@centos6-5vm rc.d]# cp /lib/libaudit.so.1 /mnt/sdb2-sysroot/lib/
[root@centos6-5vm rc.d]# cd /mnt/sdb2-sysroot/etc
root@centos6-5vm etc]# ls

inittab  rc.d  sysconfig

[root@centos6-5vm etc]# vim inittab 

id:3:initdefault:
si::sysinit:/etc/rc.d/rc.sysinit
l0:0:wait:/etc/rc.d/rc.shutdown


上面的 inittab 文件内容中,最后一项条目就是新添加的“关机脚本”存放路径;


对于真实的  Linux 发行版而言,内核创建 init 进程后,init 首先读取 /etc/inittab 文件中定义的默认运行级别,假设是运行级别 5 ,然后 init 将运行级别 5 传递给 /etc/rc.d/rc 脚本,后者进入 /etc/rc.d/rc5.d/ 目录,然后它根据该目录的内容,调用 init 启动或停止相应服务;

该目录中定义了一系列系统在运行级别 5 时,应该启动(以大写 S 开头)以及关闭(一大写 K 开头)的指向 /etc/rc.d/init.d/ 目录下相应的 bash  shell 脚本,或者POSIX 规范 shell 脚本的符号链接

例如,  /etc/rc.d/rc5.d/  目录下有一个符号链接为 S13rpcbind  ,表示在运行级别 5 时,以优先级 13 (优先级数字越小,该服务或守护进程越早启动)来启动 rpcbind 服务,

当然,实际执行启动 rpcbind 服务的脚本,位于 /etc/rc.d/init.d/rpcbind,而该脚本最终调用相应的命令(通常位于 /sbin,/bin,/usr/bin,/usr/sbin)来启动服务,如下所示:


[root@centos6-5vm /]# ls /etc/inittab 

/etc/inittab
[root@centos6-5vm /]# file /etc/inittab 

/etc/inittab: ASCII English text

[root@centos6-5vm /]# cd /etc/rc.d
[root@centos6-5vm rc.d]# ls

init.d  rc  rc0.d  rc1.d  rc2.d  rc3.d  rc4.d  rc5.d  rc6.d  rc.local  rc.sysinit

[root@centos6-5vm rc.d]# file ./rc

./rc: Bourne-Again shell script text executable

[root@centos6-5vm rc.d]# file ./rc5.d/

./rc5.d/: directory

[root@centos6-5vm rc.d]# cd ./rc5.d/
[root@centos6-5vm rc5.d]# ls

K01smartd        K15httpd       K60crond       K84wpa_supplicant  S01sysstat       
S12rsyslog       K10cups        K50dnsmasq     K73winbind     K89portreserve     
S08ip6tables     S13rpcbind
 
[root@centos6-5vm rc5.d]# file ./S13rpcbind 

./S13rpcbind: symbolic link to `../init.d/rpcbind'

[root@centos6-5vm rc5.d]# cd /etc/rc.d/init.d/
[root@centos6-5vm init.d]# ls

acpid      certmonger        functions  iptables      mdmonitor     nfs             postfix      rpcbind      saslauthd   sshd            wdaemon
atd        cpuspeed          haldaemon  irqbalance    messagebus    nfslock         psacct       rpcgssd

[root@centos6-5vm init.d]# file rpcbind 
rpcbind: POSIX shell script text executable


再看一个例子:postfix 服务, init 进程最终根据 /etc/rc.d/init.d/postfix

这个脚本文件中的指令,来启动,终止 2,3,4,5 运行级别下的 postfix 服务:

[root@centos6-5vm etc]# head -n 10 /etc/rc.d/init.d/postfix 

#!/bin/bash
#
# postfix      Postfix Mail Transfer Agent
#
# chkconfig: 2345 80 30
# description: Postfix is a Mail Transport Agent, which is the program \
#              that moves mail from one machine to another.
# processname: master
# pidfile: /var/spool/postfix/pid/master.pid
# config: /etc/postfix/main.cf


从上面我们可以获得几项非常关键的信息,首先是 chkconfig: 2345 80 30  这一条目,它表明执行 chkconfig 命令时,后者将在 /etc/rc.d/rcN.d/ 目录下,建立指向该脚本(即 /etc/rc.d/init.d/postfix )的符号链接,

rcN.d 中的 N ,取决于传递给 chkconfig 命令的参数 --level 的值; 并且该服务以优先级 80 启动(S)以优先级 30 终止(K)

换言之,当用户在 shell 终端执行 chkconfig --level 5 postfix on   命令时,

chkconfig 在 /etc/rc.d/rc5.d/  目录下,创建一个符号链接为 S80postfix;并且指向 /etc/rc.d/init.d/postfix;

类似地,当用户在 shell 终端执行 chkconfig --level 5 postfix off  命令时,

chkconfig 在 /etc/rc.d/rc5.d/  目录下,首先删除掉原有的 S80postfix 符号链接,然后创建一个 K30postfix 符号链接,

同样指向 /etc/rc.d/init.d/postfix;如下所示:

[root@centos6-5vm etc]# chkconfig --level 5 postfix on
[root@centos6-5vm etc]# ls  /etc/rc.d/rc5.d/ | grep postfix

S80postfix

[root@centos6-5vm etc]# file  /etc/rc.d/rc5.d/S80postfix

/etc/rc.d/rc5.d/S80postfix: symbolic link to `../init.d/postfix'

[root@centos6-5vm etc]# chkconfig --level 5 postfix off
[root@centos6-5vm etc]# ls  /etc/rc.d/rc5.d/ | grep postfix

K30postfix

[root@centos6-5vm etc]# file  /etc/rc.d/rc5.d/K30postfix

/etc/rc.d/rc5.d/K30postfix: symbolic link to `../init.d/postfix'


其次是 processname : master

这项条目表明 postfix 服务在启动后的进程叫 master

这就是为什么使用 netstat -an 查看 postfix 服务在启动后监听 TCP 的 25 端口时,对应的 “进程名”为 master;

另外,我们终止 postfix 服务时,不能使用 service master stop ,这样系统无法识别;应该使用 service postfix  stop;

接下来的条目 pidfile 与 config,前者是存储 postfix 服务在运行时的进程标识符(PID)的文件路径;后者是 postfix 的配置文件路径;


粗略来讲,在内核创建 init 进程后,后者按如下流程来进行系统初始化:

(以 CentOS6.5 Linux 为例)


一,内核创建 init 进程 


二,init 读取 /etc/inittab 确定默认运行级别 


三,init 根据 /etc/sysconfig/ 目录的各种配置文件,执行 /etc/rc.d/rc.sysinit 脚本,完成系统初始化 ( init 执行 rc.sysinit 脚本的结果,将相关日志信息输出到 /var/log/boot.log 文件中,需要确认已启动syslog/rsyslog 服务,才能记录信息 )


四,init 根据默认运行级别执行 /etc/rc.d/rcN.d/ 目录下的符号链接,实际执行这些符号链接指向的脚本(位于 /etc/rc.d/init.d/ 目录下),从而启动与停止该运行级别下的服务


五,init 最后执行 /etc/rc.d/rc.local 执行用户指派的特定任务或命令

关于第五点,可以查看 /etc/rc.d/rcN.d/  目录验证,N 的取值可以是 2,3,4,5,表示在运行级别 2,3,4,5 中应该启动与关闭的服务脚本链接:


[root@centos6-5vm /]# pwd
/
[root@centos6-5vm /]# ls -l /etc/rc.d/rc?.d/*local*
lrwxrwxrwx. 1 root root 11 6月  25 16:58 /etc/rc.d/rc2.d/S99local -> ../rc.local
lrwxrwxrwx. 1 root root 11 6月  25 16:58 /etc/rc.d/rc3.d/S99local -> ../rc.local
lrwxrwxrwx. 1 root root 11 6月  25 16:58 /etc/rc.d/rc4.d/S99local -> ../rc.local
lrwxrwxrwx. 1 root root 11 6月  25 16:58 /etc/rc.d/rc5.d/S99local -> ../rc.local

注意通配符 * 在这里的巧妙使用,以上输出表明,运行级别 2,3,4,5 中都有一个优先级为 S99 (即最后启动)的服务脚本符号链接,实际的服务脚本就是 /etc/rc.d/rc.local ,这表明 rc.local 脚本将在所有其它服务都开启后才执行

我们也可以通过重命名 S99local 符号链接,例如改变启动的优先级,来提前执行我们指派给系统的任务。




加载与卸载内核模块相关


内核模块是 linux 内核加载和管理硬件设备驱动程序的其中一种方式;另一种方式为静态内核映像,这些硬件驱动就集成到位于 /boot/vmlinuz-version 的内核映像中,其中 version 是内核版本号,我这个机器上的例子为

/boot/vmliunz-2.6.32-431.el6.i686


有些硬件驱动,例如 IDE 磁盘,SCSI 磁盘,SATA 磁盘等驱动,必须通过 GRUB (引导装载程序),随着内核映像一起,从磁盘上的启动分区( 通常是 /boot/initramfs-* )加载到内存中,否则内核就不能识别磁盘上的其它独立分区,如根分区( / ),也就无法提供基本的文件系统功能;既然无法访问文件系统,也就无法从其子目录,以内核模块的形式来加载其余在系统引导阶段用不上的硬件设备驱动,例如网卡,声卡等驱动;

*****由于 GRUB 在  Linux 内核之前加载到内存,因此它内置了自身实现的磁盘,文件系统驱动来识别计算机上的存储设备及其分区;进一步而言,在  GRUB 自身的磁盘驱动以及文件系统驱动(通常位于 /boot/grub/stage2 )加载到内存前,它使用 BIOS 的磁盘驱动来识别并读写磁盘


整理一下上面的知识点:

/boot  即启动分区,通常为磁盘上的第一个分区,其中包含了:

GRUB 引导加载程序(stage1,stage2,grub.conf 以及其它重要的文件);

Linux 内核映像;

initrd (初始虚拟磁盘,initial ram disk,用于在 Linux 内核的文件系统驱动进驻内存前,识别磁盘上的文件系统)映像;


BIOS 使用自身的磁盘驱动程序,识别并加载 /boot/grub/stage1(准确地讲是识别并加载用户所选启动设备上的0磁道1号扇区,该扇区即 MBR );

GRUB 的 stage1 使用 BIOS 的磁盘驱动程序,识别并加载 /boot/grub/stage2(准确地讲是识别并加载0磁道2号扇区) ,stage2 中包含了 GRUB 自身实现的磁盘驱动程序,此后就用它自己的磁盘驱动识别并加载 /boot 分区中的 Linux 内核映像;

Linux 内核映像中的磁盘驱动程序以及文件系统驱动,可以识别 /boot 分区(以及其它所有磁盘分区),但是在此之前,它需要依靠 initrd 来识别



静态内核映像形式的硬件驱动和内核模块形式的硬件驱动之间的区别在于:通过 modprobe 与 modprobe -r 命令,后者可以“动态”的“按需”加载,卸载;


*****如果要配置作为静态内核映像一部分加载的硬件驱动的行为模式,可以通过 GRUB 或者 LILO 等引导加载程序提供的“内核命令行”来设置引导参数;如下命令可以查看当前的内核引导参数:

[root@centos6-5 ~]# cat /proc/cmdline 
ro root=UUID=0d1c20e2-6fb8-4b37-8ced-987df661f7c8 rd_NO_LUKS  KEYBOARDTYPE=pc KEYTABLE=us rd_NO_MD crashkernel=128M LANG=zh_CN.UTF-8 rd_NO_LVM rd_NO_DM rhgb quiet


*****如果要配置作为内核模块动态加载的硬件驱动行为模式,可以通过编辑 /etc/modprobe.conf 文件来实现,内核在加载相应模块时会读取该文件中的配置参数,来决定该硬件驱动的工作模式;

(但是我发现在 centos6.5 中,该文件默认不存在,只有在基于 RHEL5 系列的发布版中,才有类似文件)


 CentOS 6.5 的内核模块存放目录为

/lib/modules/2.6.32-431.el6.i686/


如前所述,这个目录下存放不需要在系统引导阶段加载的硬件设备驱动程序;

其中,2.6.32-431.el6.i686 为执行命令 uname -r 的结果,取决于你系统的内核版本,这个值可能会有所不同;

每个单独的内核模块,都以 .ko 结尾


wKioL1Qc1YySXgndABBKHrzC6NI123.jpg


参考上面截图,内核模块中有一个是实现类似 iptables 的防火墙日志记录功能,位于目录

/lib/modules/2.6.32-431.el6.i686/kernel/net/netfilter

该目录下的 nf_conntrack.ko 和其家族模块,就是用于记录数据包出入的 IP 地址,端口,状态等信息的模块,在 centos 6.5 中,默认是开启(加载)的;在较低版本的 centos 中,模块的名字可能是以 ip_conntrack 为前缀,需要注意;


nf_conntrack.ko 及其家族模块,会将日志信息输出到基于内存的虚拟文件系统目录下

/proc/net/nf_conntrack

稍后我们将对记录中的每个字段做详细解释;


*****补充知识:与 iptables / netfilter 相关的内核模块,规则表与规则链

我们知道,位于用户态的 iptables 命令行工具,主要用来设置4个表的策略(规则),而相应的内核模块读取这些表中的规则,执行实际的包过滤任务:


filter 表,

/lib/modules/2.6.32-431.el6.i686/kernel/net/ipv4/iptable_filter.ko 

将会根据该表中的策略来过滤数据包


nat 表,

/lib/modules/2.6.32-431.el6.i686/kernel/net/ipv4/iptable_nat.ko

将会根据该表中的策略来路由转发数据包,并且执行 SNAT(源地址转换)与 DNAT(目标地址转换)


mangle 表,

/lib/modules/2.6.32-431.el6.i686/kernel/net/ipv4/iptable_mangle.ko

将会根据该表中的策略来修改数据包


raw 表,

/lib/modules/2.6.32-431.el6.i686/kernel/net/ipv4/iptable_raw.ko

将会根据该表中的策略对状态跟踪机制提供支持


我们用后面介绍的 modinfo 命令,可以查看这4个内核模块的详细信息,如下:


wKiom1QhBhSBCEy7AA1D0oACgjc803.jpg


在处理各种数据包时,根据防火墙规则的不同介入时机,iptables 共涉及5种默认规则链,其应用时间点分别对应如下:

INPUT链:当接收到防火墙本机地址的数据包(入站)时,应用此链中的规则。
OUTPUT链:当防火墙本机向外发送数据包(出站)时,应用此链中的规则。
FORWARD链:当接收到需要通过防火墙发送给其他地址的数据包(转发)时,应用此链中的规则。
PREROUTING链:当数据包需要进入到 iptables 身后的内网时,应用此链中的规则。
POSTROUTING链:当数据包需要经由 iptables 从内网出去时,应用此链中的规则。


INPUT、OUTPUT链更多的应用在“主机防火墙”中,即主要针对运行 iptables 的服务器本机进出数据的安全控制;而FORWARD、PREROUTING、POSTROUTING链更多的应用在“网络防火墙”中,特别是运行 iptables 的服务器作为网关使用时的情况。



*****在 Linux 2.6.14 版内核以后,

对 netfilter 的显式扩展提供支持的内核模块,这些模块统一存放在目录

/lib/modules/2.6.32-431.el6.i686/kernel/net/netfilter

下,这些以 .ko 为后缀的内核模块,是 netfilter 执行显式扩展的匹配任务时,需要用到的模块,例如  xt_string.ko

该目录中的模块可以同时操作基于 IPv4 和 IPv6 网络层协议的数据包,


而在 Linux 2.6.14 版内核以前,只能操作基于 IPv4 数据包的模块,存放在 

/lib/modules/2.6.32-431.el6.i686/kernel/net/ipv4/netfilter  目录下

只能操作基于 IPv6 数据包的模块,存放在

/lib/modules/2.6.32-431.el6.i686/kernel/net/ipv6/netfilter

目录下,当然 Linux 2.6.14 版以后的内核也包括了这2个目录



*****对 iptables 的显式扩展用户接口提供支持的“库模块”,这些模块统一存放在目录 

/lib/xtables 

下,这些以 .so 为后缀的库模块,被 iptables 用来检查用户输入的规则是否正确,并将其写入内存中,供 netfilter 在执行包过滤时的参考依据,例如和前面模块相对应的 libxt_string.so


在上面这个例子中,首先在设置规则时,通过 iptables 命令的 -m 选项,调用 libxt_string.so 来对用户输入的“基于数据包的应用层字串匹配”的显式扩展规则进行语法检查,无误后写入内存,

然后 xt_string.ko 被加载进内核(和执行 modprobe  xt_string.ko 命令的结果一样),

netfilter 根据该条规则调用 xt_string.ko 执行相应的过滤任务。



需要指出,当升级内核时,不能只升级,添加 netfilter 的显式扩展模块,和它相对应的 iptables 库模块也必须添加进来,否则即使 netfilter 可以执行新的数据包过滤功能,你却不能通过 iptables 来指示它如何工作,这一点非常重要

 



*****补充知识:关于 proc 虚拟文件系统


执行如下命令查看 proc 虚拟文件系统的信息:

[root@centos6-5 ~]# mount | grep "proc"
proc on /proc type proc (rw)
none on /proc/sys/fs/binfmt_misc type binfmt_misc (rw)

第一条信息显示,设备文件名为 “proc”,挂载点为 /proc,类型为 proc

简单的讲,所有 /proc 目录下的“文件”,都不存在于实际的磁盘分区上,它是内核构建的虚拟目录,系统重启导致内核重新加载,从而先前在 /proc 中的信息也会丢失;通过向 /proc 目录中的文件读信息,可以获取当前由内核维护的数据,并且是动态更新的,这就是后面我们查看 /proc/net/nf_conntrack 的 IP 记录时,每隔一段时间就变化的原因;

而通过向 /proc 目录中的文件写信息,可以改变内核当前的运行参数;但是这些运行参数将在系统重启后丢失

(原因前面讲过,由于主存储器—内存—为易失性存储器,重新加电导致内核在内存中“重生”,从而由内核维护的 /proc 文件系统丢失)


例如,执行如下命令可以开启内核路由转发的功能,让 linux 主机充当 NAT 路由器,但是系统重启后失效

[root@centos6-5 ~]# echo "1" > /proc/sys/net/ipv4/ip_forward






要查看系统当前已经加载的模块,使用 lsmod 命令,例如:

[root@centos6-5 netfilter]# lsmod | grep "nf_conn"
nf_conntrack_ipv4       7694  2 
nf_defrag_ipv4          1039  1 nf_conntrack_ipv4
nf_conntrack_ipv6       7207  1 
nf_defrag_ipv6          8897  1 nf_conntrack_ipv6
nf_conntrack           65661  3 nf_conntrack_ipv4,nf_conntrack_ipv6,xt_state
ipv6                  261089  49 ip6t_REJECT,nf_conntrack_ipv6,nf_defrag_ipv6


可以查找到 centos6 6.5 系统默认已经加载的 nf_conntrack.ko 家族模块,一共有3个;注意,第一个字段为模块名,完整名应该是以 .ko 结尾;第二个字段为模块大小;

第三个字段为该模块正在被几个其它的模块使用,仅当这个值为0,即没有被任何其它模块使用时,该模块才可以通过命令  modprobe -r [模块名] 进行动态卸载;

第四个字段为占用该模块的其它模块列表;

注意,modprobe [模块名] 用于加载模块;并且临时生效,系统重启后不会自动加载模块;相同道理,通过 modprobe -r 卸载的模块,系统重启后又会自动加载;

因此,要修改成自动加载,需要编辑 /etc/rc.sysinit  ,例如

echo "modprobe ip_vs" >> /etc/rc.sysinit

然后在重启系统时即刻生效;

要修改成自动卸载,将该文件中,对应的命令删除,重启系统时即刻生效;


modinfo [模块名]  ,用于查看指定模块的信息,无论该模块当前是处于加载还是卸载状态,都可以查看:


wKiom1Qc05fzt9uSAAtaQ_iY4yg276.jpg



使用如下命令可以显示最后8条 nf_conntrack 的日志记录:


[root@centos6-5 netfilter]# tail -n 8 /proc/net/nf_conntrack


wKiom1QdHhmQ8T0tAA62wfYbQoA795.jpg





******解压  .tar.gz    压缩包:  tar  -zxvf   $.tar.gz

      将 $ 换成要解压的压缩包名


     打包成  .tar.gz   压缩包: tar  -zcvf   $.tar.gz   [要打包的目录或文件名]

       将 $ 换成打包后的压缩包名


     解压  .tar.bz2   压缩包:  tar  -jxvf   $.tar.bz2

     将 $ 换成要解压的压缩包名


    打包成  .tar.bz2   压缩包: tar  -jcvf   $.tar.bz2   [要打包的目录或文件名]

      将 $ 换成打包后的压缩包名


注意:

一,参数  -v 为显示详细信息

二,参数  -f 必须放在最后面,否则会报错

三,解压 gz 或者 bz2 包时,默认会在当前工作目录下生成解包后的目录

四,对于相同大小的目录或文件,使用 bz2 格式压缩生成的包,比使用 gz 格式压缩生成的包要小,换言之,bz2 压缩格式有较高的压缩比



*****find 搜索命令实战


一,在根目录下查找包含字符串“wireshark”,大小在50~100 MBytes 的属性在 

     一天内发生改变的文件,以 MBytes 统计每个文件的大小并显示:

[root@centos6-5 ~]# find / -name *wireshark* -a -cmin -1440 -a -size +50M -a -size -100M -type f -exec du -m {} \;



二,在  /data  目录下查找所有 MP4 格式的,大小在10~500 MByres 的在五分钟

    内被“看过”的影片,以 MBytes 统计每个影片的大小并显示:

[root@centos6-5 ~]# find /data -name *.mp4 -a -amin -5 -a -size +10M -a -size -500M -type f -exec du -m {} \;



三,在当前目录下查找所有 I 节点为 31531 的硬链接,并将其删除,删除前要求

     用户确认:

[root@centos6-5 ~]# find . -inum 31531 -ok rm {} \;




*****GRUB 加密与使用光盘救援模式恢复硬盘 MBR 中损坏的 GRUB

首先,  /etc/grub.conf  为经常使用的 GRUB 配置文件,但它实际只是符号链接,指向   /boot/grub/grub.conf   这个真正的 GRUB 配置文件:

[root@centos6-5vm ~]# ll /etc/grub.conf 
lrwxrwxrwx. 1 root root 22 6月  25 17:03 /etc/grub.conf -> ../boot/grub/grub.conf
[root@centos6-5vm ~]# file /etc/grub.conf 
/etc/grub.conf: symbolic link to `../boot/grub/grub.conf'
[root@centos6-5vm ~]# file /boot/grub/grub.conf 
/boot/grub/grub.conf: ASCII text

最简单的 GRUB 加密方式,可以使用  grub-md5-crypt  命令:

[root@centos6-5vm 桌面]# grub-md5-crypt
Password: 
Retype password: 
e21e4epx1$iGRjdbg112`1``UhFOGiedwfef


将生成的密文,复制到 GRUB 的配置文件中,注意插入命令的位置,在系统名称(title)后面

root@centos6-5vm ~]# vim /etc/grub.conf

 grub.conf generated by anaconda
#
# Note that you do not have to rerun grub after making changes to this file
# NOTICE:  You have a /boot partition.  This means that
#          all kernel and initrd paths are relative to /boot/, eg.
#          root (hd0,0)
#          kernel /vmlinuz-version ro root=/dev/mapper/vg_centos65vm-lv_root
#          initrd /initrd-[generic-]version.img
#boot=/dev/sda
default=0
timeout=5
splashimage=(hd0,0)/grub/splash.xpm.gz
hiddenmenu
title CentOS (2.6.32-431.el6.i686)
        password --md5 e21e4epx1$iGRjdbg112`1``UhFOGiedwfef
        lock
        root (hd0,0)
        kernel /vmlinuz-2.6.32-431.el6.i686 ro root=/dev/mapper/vg_centos65vm-lv_root rd_LVM_LV=vg_centos65vm/lv_swap rd_NO_LUKS rd_NO_MD crashkernel=128M LANG=zh_CN.UTF-8 rd_LVM_LV=vg_centos65vm/lv_root  KEYBOARDTYPE=pc KEYTABLE=us rd_NO_DM rhgb quiet
        initrd /initramfs-2.6.32-431.el6.i686.img
~

注意在 password 下面一行的 lock ,作用是验证失败后锁定

编辑后保存退出,重新启动,完成对 GRUB 的加密


友情提醒:上面的 GRUB 加密并非无懈可击,可以通过在启动时按任意键进入 GRUB 启动菜单,然后选择一个设置加密的内核,按下 e 键,进入实时编辑 GRUB 启动选项,就可以看到

password --md5 e21e4pex1$iGRjdb112`1``UhFOGiedwfef

上面这一项,与 grub.conf 中的完全一样,此时,我们只需按下 d 键,删除该行,以及删除其后的

lock  这一行,

然后在  kernel / vmlinuz-  这一行的末尾,添加  single  字串,这样就可以进入“单用户模式”,

对于 RedHat 系列及其衍生版(如 CentOS)Linux 而言,默认会以 root 用户进入单用户模式,而且不需要验证 root 用户的口令(密码),最危险的是,还可以任意变更 root 用户密码,修改后,执行命令  init 5  ,即可以新的 root 用户密码,进入多用户模式(带有 X-window 启动,正常联网功能,gnone 或 KDE 桌面环境等)

这意味着,基于物理接触的***者可以很轻易的破解你的 GRUB 与 root 密码双重保险,而且他不会修改到你的 grub.conf 配置文件,因为所有这些操作都是利用了 GRUB 可以实时编辑启动选项的这一安全漏洞;

要避免***者绕过 GRUB 的密码验证流程,一种解决办法是,将

password --md5 及其后面的哈希密文密码,放在 grub.conf 的全局配置段中,具体而言,就是所有 title 的前面,这样,***者无法避开 GRUB 的密码验证流程,如下截图所示:


wKioL1RfAZWzI8DKAAWAURBrQfk189.jpg


wKiom1Re_YfR8SPsAAbEgkXtFhU589.jpg



wKioL1Re_xXBM05aAAZBzY0Jz_Y564.jpg


或者,我们可以在 BIOS 中设置启动密码,这样,BIOS 会验证用户输入的启动密码,如果验证成功,则将对 CPU 的控制权,转交给磁盘 MBR 上的引导代码,从而加载 GRUB ,如果验证失败, BIOS 将中断启动流程并阻止用户访问 GRUB;

更进一步,应该将存储重要业务资料,个人敏感信息的机箱放在带锁的柜子中,避免硬盘被盗取,或者***者通过打开机箱,操作主板上的 BIOS 放电,重置跳线,来清除 BIOS 启动密码


*****上面提到,可以通过实时编辑 GRUB 的启动选项,进入单用户模式;也可以进入紧急模式,方法是在 kernel / vmlinuz-  这一行末尾,添加 emergency 字串,然后按下 b 键启动,以紧急模式启动时,只会挂载根文件系统



对于配备光驱的台式机 PC 或服务器而言,如果 MBR 损坏(例如安装双系统时,GRUB 被后来安装的 windows 覆写),可以将安装盘放入光驱,以救援模式启动,将安装盘上的 GRUB 重新安装到硬盘上来恢复


为了模拟 MBR 损坏的情况,可以使用 dd 命令将硬盘上的 0 磁道 0 柱面前 446个字节的“引导代码”,用零覆盖:

[root@centos6-5vm 桌面]# dd if=/dev/zero of=/dev/sda bs=1 count=446

记录了446+0 的读入
记录了446+0 的写出
446字节(446 B)已复制,0.0162632 秒,27.4 kB/秒

[root@centos6-5vm 桌面]# sync


执行 df 命令,查看分区表中的记录是否正确,因为前面我们只覆写了 MBR 的 512个字节中的前 446个字节,后面 66 个字节的分区表应该是正常的,如果 df 命令不能输出分区信息,说明分区表也丢失,需要用其它的硬盘检测,维修工具来重建分区表:

[root@centos6-5vm 桌面]# df -hT
Filesystem                        Type     Size  Used Avail Use% Mounted on
/dev/mapper/vg_centos65vm-lv_root ext4      35G  7.6G   26G  23% /
tmpfs                             tmpfs    948M  224K  947M   1% /dev/shm
/dev/sda1                         ext4     485M   37M  423M   9% /boot
/dev/sr0                          iso9660  3.6G  3.6G     0 100% /media/CentOS_6.5_Final


由于我们使用虚拟机中的光驱,因此连接宿主(host)机上的 安装光盘 ISO 镜像,然后从光驱启动系统,进行 GRUB 的修复:

[root@centos6-5vm 桌面]# init 6

wKioL1RHP4WikO7RAAUSiD-AaJc309.jpg



应该避免在救援模式中使用中文字符界面,这可能会导致某些选项和信息出现乱码字符;一般而言,救援模式下,不需要网络支持(根据你的需求选择)


wKioL1RHQ2mzHKmXAAp_eHT0-Q0947.jpg



wKiom1RHRRejGi7vAAb8dzRAoeA604.jpg


wKiom1RHScKCSOENAAfLVwJcebw776.jpg


wKiom1RHTl_AMS_1AAjb7dGZJKQ928.jpg



引导加载程序是 BISO 与 操作系统之间的桥梁

用于引导加载 Linux 内核的引导加载程序,可以是 GRUB(GRand Unified Bootloader)或者 LILO(LInux LOader)

正常情况下,当使用光盘或其它介质安装系统时,GRUB 或 LILO 应该已经随系统一同安装到了硬盘上

GRUB 是一个分两阶段执行的引导加载程序:


    stage1   

位于硬盘的 MBR(准确地讲是硬盘的0磁道上的1号扇区,通常,每个磁道有63个扇区,每扇区512字节) ,作为引导代码,占用446字节存储