Linux系统裁剪笔记

1.什么裁剪?

本篇文章的主要目的是让笔者和读者更深的认识Linux系统的运作方式,大致内容就是把Linux拆开自己一个个组件来组装,然后完成一个微型的Linux系统,从而达到系统缩减,订制特殊系统。

2.原理

大家都知道,操作系统的启动流程是(主要是Linux):POST—>BIOS—>MBR(grub)—kernel-->initrd-->sbin/init,

POST,BIOS都不是我们管的,所以这里我们从MBR开始,Linux的系统引导先主要是用的grub这个软件,grub引导系统了,然后启动内核,内核调用initrd来实现最基本的操作系统,

3.实验 (所有操作均在虚拟机上实现,且定义硬盘时选IDE)

  环境:1).在宿主机上安装一台Redhat5.4,/dev/sda上安装操作系统;

    2).在宿主机上新建一个新硬盘:/dev/hda,且分区为512M的hda1,1G的hda2;

    3).另建立一台测试虚拟机,将原有的硬盘删除,再将硬盘/dev/hda的新增到该测试虚拟机;


1、首先我们得创建一个新的磁盘,来保存我们的grub和内核等关键程序(直接在虚拟机上添加新的磁盘)

分两个区,分别是512M的hda1主盘,和1G的sdb2主盘。

[[email protected] ~]# fdisk -l   查看硬盘分区信息

Disk /dev/sdb: 5368 MB, 5368709120 bytes

255 heads, 63 sectors/track, 652 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: 0x57e43c23


   Device Boot      Start         End      Blocks   Id  System

/dev/hda1               1          63      506016   83  Linux

/dev/hda2              64         195     1060290   83  Linux

/dev/hda3             196         327     1060290   82  Linux swap / Solaris


[[email protected] mnt]# mke2fs -j /dev/hda1 把分区/dev/hda1格式化成ext3文件系统类型

[[email protected] mnt]# mke2fs -j /dev/hda2 把分区/dev/hda2格式化成ext3文件系统类型

[[email protected] ~]# mkdir /mnt/{boot,sysroot} -pv 在当前系统中新建2个目录/mnt/boot /mnt/sysroot/

[[email protected] ~]# ls /mnt

boot lost+found  sysroot

[[email protected] mnt]# mount /dev/hda1 /mnt/boot/ 把分区/dev/hda1挂载到/mnt/boot目录
[[email protected] mnt]# mount /dev/hda2 /mnt/sysroot/ 把分区/dev/hda2挂载到/mnt/sysroot目录
[[email protected] mnt]# mount 查看挂载的分区
...
/dev/hda1 on /mnt/boot type ext3(rw)     已挂载成功
/dev/hda2 on /mnt/sysroot type ext3 (rw)  已挂载成功

[[email protected] mnt]# ls boot/   #验证挂载是否成功 
lost+found
[[email protected] mnt]# ls sysroot/
lost+found


2、启动系统的时候识别硬盘后要有引导程序,系统通过MBR可查找到/dev/sdb中的/mnt

[[email protected] mnt]# grub-install --root-directory=/mnt /dev/sdb 安装grub文件到/mnt目录

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/hda
(hd1)    /dev/sda
(hd2)    /dev/sdb
(hd3)    /dev/sdc

[[email protected] mnt]# ls /mnt/boot/   #grub已成功生成 
grub  lost+found


3、有了引导程序就需要有我们的内核了,没有内核怎么启动啊,但是内核的启动又要依赖initrd,所以我们要建立/mnt/boot/vmlinuz,/mnt/boot/initrd.gz,/mnt/boot/grub/grub.conf

   3.1、 复制内核文件vmlinuz 

[[email protected] mnt]# cp /boot/vmlinuz-2.6.18-164.el5  /mnt/boot/vmlinuz

 

    3.2、 手动展开文件2:initrd文件

方法一:

[[email protected] mnt]# cp /boot/initrd-2.6.18-164.el5.img /root 复制initrd文件到/root目录

[[email protected] mnt]# file /root/initrd-2.6.18-164.el5.img  查看该文件类型为gzip压缩格式
/boot/initrd-2.6.18-164.el5.img: gzip compressed data, from Unix, last modified: Thu Apr 17 11:43:57 2014, max compression
[[email protected] ~]# mv initrd-2.6.18-164.el5.img initrd-2.6.18-164.el5.img.gz  重命名为.gz格式
[[email protected] ~]# gzip -d initrd-2.6.18-164.el5.img.gz  解压该文件gunzip=gzip -d 
[[email protected] ~]# file initrd-2.6.18-164.el5.img  再次查看文件格式变为ASCII类型
initrd-2.6.18-164.el5.img: ASCII cpio archive (SVR4 with no CRC)
[[email protected] ~]# mkdir dirinit  创建一个空目录dirinit

[[email protected] ~]# cd dirinit/  进入dirinit目录

[[email protected] dirinit]# cpio -id < ../initrd-2.6.18-164.el5.img 提取initrd文件中的内容到该目录中
13832 blocks
[[email protected] dirinit]# ls   查看是否提取成功
bin  dev  etc  init  lib  proc  sbin  sys  sysroot
[[email protected] dirinit]# 

*

方法二:(一般用此方法)

[[email protected] ~]# mkdir testiso #创建空目录 
[[email protected] ~]# cd testiso
[[email protected] testiso]# ls
[[email protected] testiso]# zcat /boot/initrd-2.6.18-164.el5.img | cpio -id
13832 blocks
[[email protected] testiso]# ls
bin  dev  etc  init  lib  proc  sbin  sys  sysroot


  3.3、修改INIT文件中的启动分区,再打包成initrd.gz

[[email protected] testiso]# file init  查看init文件类型
init: a /bin/hush script text executable
[[email protected] testiso]# vim init  编辑init文件

#resume /dev/VolGroup00/LogVol01  #禁用swap分区

或#resume LABEL=SWAP-sda9  #禁用swap分区 

mkrootdev -t ext3 -o defaults,ro /dev/hda2    #/dev/hda1为BOOT分区 #红色部分原为:sda5 或                                         /dev/VolGroup00/LogVol00 需改为/dev/hda2根目录分区

[[email protected] testiso]# find . | cpio -H newc --quiet -o | gzip -9 > /mnt/boot/initrd.gz

[[email protected] boot]# ls -lh
total 7.1M
drwxr-xr-x 2 root root 1.0K Nov 21 09:02 grub
-rw-r--r-- 1 root root 2.6M Nov 21 10:13 initrd.gz  #init文件中改为/dev/sda2 
drwx------ 2 root root  12K Nov 21 08:54 lost+found
-rw-r--r-- 1 root root 1.9M Nov 21 09:16 vmlinuz


  3.4、 接下来要配置grub文件,不然系统怎么找到你的硬件,故新建grub.conf文件

[[email protected] boot]# vim /mnt/boot/grub/grub.conf

default=0
timeout=5
title Test Linux 5.4 (Test)
    root (hd0,0)
    kernel /vmlinuz
    initrd /initrd.gz


4、 这样一个简单的操作系统的雏形就做好了,但是OS的操作依赖于shell,所以我们得手动复制bash、bash依赖的库文件,可写程式(附件bincopy.sh)自动复制。

[[email protected] sysroot]# mkdir -pv proc sys dev etc/{rc.d/init.d} lib lib64 bin sbin              var/{log,run,lock/subsys,tmp} usr/{bin,sbin} media mnt tmp opt root home 在该目录下新建proc sys  dev etc/rc.d lib bin sbin boot home var usr/{bin,sbin} root tmp lib64(64位系统)等目录

[[email protected] sysroot]# cp /sbin/init /mnt/sysroot/sbin/
[[email protected] sysroot]# cp /bin/bash /mnt/sysroot/bin/

[[email protected] sysroot]# cp /sbin/init /mnt/sysroot/sbin/
[[email protected] sysroot]# cp /bin/bash /mnt/bin/

 [[email protected] sysroot]# ldd /sbin/init
    libsepol.so.1 => /lib64/libsepol.so.1 (0x0000003941c00000)
    libselinux.so.1 => /lib64/libselinux.so.1 (0x0000003942000000)
    libc.so.6 => /lib64/libc.so.6 (0x0000003940400000)
    libdl.so.2 => /lib64/libdl.so.2 (0x0000003940c00000)

    /lib64/ld-linux-x86-64.so.2 (0x0000003940000000)

[[email protected] sysroot]# cp /lib64/libsepol.so.1 /mnt/sysroot/lib64/ #复制相关库文件
[[email protected] sysroot]# cp /lib64/libselinux.so.1 /mnt/sysroot/lib64/   
[[email protected] sysroot]# cp /lib64/libc.so.6 /mnt/sysroot/lib64/
[[email protected] sysroot]# cp /lib64/libdl.so.2  /mnt/sysroot/lib64/

[[email protected] sysroot]# cp /lib64/ld-linux-x86-64.so.2 /mnt/sysroot/lib64/

[[email protected] sysroot]# ldd /bin/bash

    libtermcap.so.2 => /lib64/libtermcap.so.2 (0x0000003943000000)
    libdl.so.2 => /lib64/libdl.so.2 (0x0000003940c00000)  上面已经复制过,此处无需再复制
    libc.so.6 => /lib64/libc.so.6 (0x0000003940400000)  上面已经复制过,此处无需再复制              /lib64/ld-linux-x86-64.so.2 (0x0000003940000000)   上面已经复制过,此处无需再复制

[[email protected] sysroot]# cp /lib64/libtermcap.so.2 /mnt/sysroot/lib64/

[[email protected] sysroot]# chroot /mnt/sysroot/   #切换根目录
bash-3.2# pwd
/

bash-4.1# ls

bash: ls: command not found

bash-4.1# exit

exit

[[email protected] sysroot]# sync  把数据同步到硬盘

[[email protected] sysroot]# cd /mnt/sysroot/

[[email protected] sysroot]# pwd

/mnt/sysroot

[[email protected] sysroot]# ls

bin  boot  dev  etc  home  lib lib64  lost+found  proc  root  sbin  sys  tmp usr var


5、 好了!系统到这里就差不多了,不过我们还得修修,大家可以看到,我们的init=/bin/bash,这时候就会有同学问了,有没搞错,Linux系统化初始化不都是调用/sbin/init的么,你怎么调用了/bin/bash,没错,其实这里指向什么就调什么,那我们现在重新让他指向/etc/rc.d/rc.sysinit。

[[email protected] sysroot]# vim etc/inittab 编辑inittab并保存
[[email protected] sysroot]# cat etc/inittab
id:3:initdefault:
si::sysinit:/etc/rc.d/rc.sysinit


[[email protected] sysroot]# vim etc/rc.d/rc.sysinit 编辑rc.sysinit并保存

[[email protected] sysroot]# cat etc/rc.d/rc.sysinit
#!/bin/bash
#
echo -e "\t Welcome to \033[32mDongen CentOS6.5\033[0m Linux"
/bin/bash

[[email protected] sysroot]# chmod +x etc/rc.d/rc.sysinit

[[email protected] sysroot]# sync  把数据同步到硬盘

[[email protected] sysroot]# sync  把数据同步到硬盘

[[email protected] sysroot]# sync  把数据同步到硬盘

[[email protected] sysroot]# sync  把数据同步到硬盘

[[email protected] sysroot]# sync  把数据同步到硬盘  多执行几次sync,以免没有同步成功

3.6.如下图,执行成功了

linux命令:系统裁剪之一grub引导 复制库文件脚本 % #截取目录的部分

好了,整个系统安装完成了!



附1:自动复制相关库文件 

* FILE=/usr/local/src

TEST=${FILE#*/}:$TEST结果为usr/local/src, 以/为关键字,删除从左边数第一个/及关键字/左边的所有字符串。 

DEST=${FILE##*/}:$DEST结果为src,以/为关键字,删除最后一个关键字/及关键字/左边的所有字符串。


DOTEST=${FILE%/*}:$DOTEST结果为/usr/local,以/为关键字,删除从右边数第一个/及关键字/右边的所有字符串。

DODEST=${FILE%%/*}:$DODEST结果为空,以/为关键字,删除从右边数最后一个/及关键字/右边的所有字符串。

[[email protected] ~]# vim cpbin.sh

#!/bin/bash

# bincopy.sh

DEST=/mnt/sysroot

libcp() {     #该函数接收一个库文件路径

 LIBPATH=${1%/*} #红色部分将/lib/libc.so.6切割成/lib/   %:表示从右边数删除第一个/及其右边的字符串。

[ ! -d $DEST$LIBPATH ] && mkdir -p $DEST$LIBPATH #路径是否存在

 [ ! -e $DEST${1} ] && cp $1 $DEST$LIBPATH && echo "copy lib $1 finished."#库文件是否存在 

}

 

bincp() {      #该函数接收一个命令对应的地址,如:/bin/ls 

 CMDPATH=${1%/*} #红色部分将/bin/ls切割成/bin/ 

  [ ! -d $DEST$CMDPATH ] && mkdir -p $DEST$CMDPATH

  [ ! -e $DEST${1} ] && cp $1 $DEST$CMDPATH

 

  for LIB in  `ldd $1 | grep -o "/.*lib\(64\)\{0,1\}/[^[:space:]]\{1,\}"`; do

    libcp $LIB   # /.*lib绿色为:/开始,中间任意字符,接着lib 

  done        # \(64\)\{0,1\}红色为:64出现0或1次 
}            # [^[:space:]]\{1,\}绿色为:空格开关且至少出现一次


read -p "Your command: " CMD

until [ $CMD == 'q' ]; do

 ! which $CMD &> /dev/null && echo "Wrong command" && read -p "Input again:" CMD && continue

 COMMAND=`which $CMD |grep -v "^alias" |grep -o "[^[:space:]]\{1,\}"`#以alias开头的行不显示

 bincp $COMMAND

 echo"copy $COMMAND finished."

 read -p"Continue: " CMD

done