写在前面:
1:以下的实现过程都使用VM虚拟机,在这上面实现的。
2:实现打造属于自己的Linux系统,其实用的是将现有的完整的Linux系统精简,然后打包做成不到10M的系统。
3:我所用的Linux系统为Redhat Enterprise Linux 5(内核为 2.6.18)
=======================================================================
首先,我们要知道,一个linux的系统之所以能够启动,需要什么?
1.需要一个boot loader,以确保能够带起硬盘
2.需要一个内核。(废话-。-)
3.需要一个小型的能够加载内核文件系统的程序(initrd)
4.需要一个能够定义如何启动的文件(inittab)
5.需要inittab中供启动的rc.sysinit文件
其实,一个linux能够启动,需要的也就是这么多,那接下来,我们开始一步步着手准备!
-----------------------------------------------------------------------------------------------------------------------------
第一步:准备工作,并创建引导文件!
既然我们需要boot loader能够带起硬盘,那么我们总要先有个硬盘吧?
好,调用虚拟机,给我们的现有的linux额外增加一块新硬盘,这块硬盘可以不用太大,够用就好,比如?嗯……8G,够你用了吧?
点击Add,添加一块新的硬盘,设置大小为8G,其他默认,然后点ok~
进入我们的Linux系统。使用fdisk -l 命令,我们看到了一块完整的未经开垦的硬盘:
Disk /dev/sdc: 8589 MB, 8589934592 bytes 255 heads, 63 sectors/track, 1044 cylinders Units = cylinders of 16065 * 512 = 8225280 bytes Device Boot Start End Blocks Id System
它的名字叫/dev/sdc于是,我们开始给他分区,首先我们要给他分一块主分区,专门放置我们的小系统的内核等重要的文件。
然后我们要分一块稍微大一点的分区,这是我们的应用分区,我们以后所有的各种文件都将放在这个分区里。
使用fdisk /dev/sdc 设置我们硬盘的各个分区之后,确认,于是硬盘成了这个样子:
Disk /dev/sdc: 8589 MB, 8589934592 bytes 255 heads, 63 sectors/track, 1044 cylinders Units = cylinders of 16065 * 512 = 8225280 bytes Device Boot Start End Blocks Id System /dev/sdc1 1 13 104391 83 Linux /dev/sdc2 14 136 987997+ 83 Linux
好的~,我们将其格式化成ext3文件系统,然后分别将两块硬盘挂载在我们新建的两个目录上,1.我们将/dev/sdc1挂载在/mnt/boot中(这就是我们的存放内核等重要文件的分区)
2.我们将/dev/sdc2挂载在/mut/sysroot下(而这个,就是我们日常应用的分区)
好的,接下来。我们就要开始将boot loader,整个磁盘的引导信息写入我们新的硬盘中了。
Linux为我们提供了grub这个好用的写入也是读取更是引导程序。我们只需要使用命令:
[root@station86 ~]# grub-install --root-directory=/mnt /dev/sdc
即可将grub安装在了我们的sdc上,并且默认给他的目录是/mnt。为什么是/mnt而不是/mnt/boot呢?因为 grub安装后,会自动在那个磁盘的根目录下创建/boot目录,所以我们只需要指定它的父目录,即/mnt即可。
于是,我们看看刚才安装的/mnt下有
total 14 drwxr-xr-x 2 root root 1024 Aug 3 07:45 grub drwx------ 2 root root 12288 Aug 3 07:42 lost+found
而进入grub里,则是已经安装在我们这里的文件total 197 -rw-r--r-- 1 root root 60 Aug 3 07:45 device.map -rw-r--r-- 1 root root 7584 Aug 3 07:45 e2fs_stage1_5 -rw-r--r-- 1 root root 7456 Aug 3 07:45 fat_stage1_5 -rw-r--r-- 1 root root 6720 Aug 3 07:45 ffs_stage1_5 -rw-r--r-- 1 root root 6720 Aug 3 07:45 iso9660_stage1_5 -rw-r--r-- 1 root root 8192 Aug 3 07:45 jfs_stage1_5 -rw-r--r-- 1 root root 6880 Aug 3 07:45 minix_stage1_5 -rw-r--r-- 1 root root 9248 Aug 3 07:45 reiserfs_stage1_5 -rw-r--r-- 1 root root 512 Aug 3 07:45 stage1 -rw-r--r-- 1 root root 104988 Aug 3 07:45 stage2 -rw-r--r-- 1 root root 7072 Aug 3 07:45 ufs2_stage1_5 -rw-r--r-- 1 root root 6272 Aug 3 07:45 vstafs_stage1_5 -rw-r--r-- 1 root root 8904 Aug 3 07:45 xfs_stage1_5
----------------------------------------------------------------------------------------------------
第二步 :搞定内核的相关配置。
好的,我们的硬盘已经准备好了,那么内核怎么办呢?这里我们使用Redhat自带的内核
它在/boot目录下,名字叫“vmlinuz-2.6.18-164.el5”。
我们用cp复制命令直接将其复制到我们的主分区下,并命名为一个简单的不带版本号得名字vmlinuz:
[root@station86 grub]# cp /boot/vmlinuz-2.6.18-164.el5 /mnt/boot/vmlinuz
之后,我们的内核有了,但是拿什么来调用它呢?这就需要Redhat中的一个能在内存上加载的驱动根目录文件系统的一个文件了:它就是:lintrd.
它在/root/下静静的放着。每当系统需要启动的时候就会悄悄的执行一下。
用file命令查看它发现他是个gzip文件。
[root@station86 linuxmini]# file initrd-2.6.18-164.el5.img initrd-2.6.18-164.el5.img: gzip compressed data, from Unix, last modified: Wed Jul 20 15:23:58 2011, max compression
好吧,虽然它的确是img格式结尾的,但那不影响我们发现他的伪装,于是我们改名后用gunzip将其解压:[root@station86 linuxmini]# mv initrd-2.6.18-164.el5.img initrd-2.6.18-164.el5.img.gz
解压后的我们再用file命令查看它,发现它又变成了一个cpio文件[root@station86 linuxmini]# gunzip initrd-2.6.18-164.el5.img.gz
cpio文件是一种古老的归档工具,它可以原封不动的将多个文件归档,在制作光盘镜像的时候尤其有用。[root@station86 linuxmini]# file initrd-2.6.18-164.el5.img initrd-2.6.18-164.el5.img: ASCII cpio archive (SVR4 with no CRC)
那么我们使用cpio的命令将它展开:
终于,我们看到了它的真正明面,ll一下:[root@station86 linuxmini]# cpio -id < initrd-2.6.18-164.el5.img
看到了么,这就是一个这样精简的加载在内存里的用来临时充当系统的文件。[root@station86 linuxmini]# ll total 68 drwx------ 2 root root 4096 Aug 3 07:58 bin drwx------ 3 root root 4096 Aug 3 07:58 dev drwx------ 3 root root 4096 Aug 3 07:58 etc -rwx------ 1 root root 2861 Aug 3 07:59 init drwx------ 3 root root 4096 Aug 3 07:58 lib drwx------ 2 root root 4096 Aug 3 07:58 proc lrwxrwxrwx 1 root root 3 Aug 3 07:58 sbin -> bin drwx------ 2 root root 4096 Aug 3 07:58 sys drwx------ 2 root root 4096 Aug 3 07:58 sysroot
我们需要修改一些参数以被我们使用:
用vim打开init这个文件。在最下面找到一行:
这个是最后要引导的硬盘分区目录。mkrootdev -t ext3 -o defaults,ro /dev/vol0/root
我们因为要打造自己的,所以需要改成引导我们自己的
于是:
如果你问,为什么是sda2而不是sdc2,那么我要说的是,因为我们这个系统是最后要移植到其他的机器上的, 那时候,对于那个机子来说,我们这里的sdc2会在那里被识别成sda2,所以我们索性直接将其改为sda2就好。mkrootdev -t ext3 -o defaults,ro sda2
修改完后,我们要将其重新打包:我们将其打包,并直接写成了initrd.gz并放在/mnt/boot下。[root@station86 linuxmini]# find . | cpio -H newc -o --quiet | gzip -9 > /mnt/boot/initrd.gz
好的,我们看一下此时此刻我们创建的主分区到底有哪些东西:
嗯,主分区基本上就这样了。total 5.0M drwxr-xr-x 2 root root 1.0K Aug 3 07:47 grub -rw-r--r-- 1 root root 3.2M Aug 3 08:01 initrd.gz drwx------ 2 root root 12K Aug 3 07:42 lost+found -rw-r--r-- 1 root root 1.8M Aug 3 07:48 vmlinuz
第三步:搞定工作分区,搞定启动流程,搞定各项文件。
进入工作分区/mnt/sysroot/创建那些真正linux中的文件夹:
[root@station86 sysroot]# mkdir {bin,sbin,usr/{bin,sbin},proc,sys,home,root,mnt,media,var,lib,etc,dev,boot,tmp} -pv
我们有各种文件夹之后,就需要考虑系统启动需要的那个主进程init:[root@station86 sysroot]# ls bin dev home lost+found mnt root sys usr boot etc lib media proc sbin tmp var
将这个文件复制到我们的/sbin目录下。[root@station86 sysroot]# cp /sbin/init /mnt/sysroot/sbin/
其实它就是我们的主shell,但是运行它还需要很多链接库文件,它们都在/lib目录下,我们为了能在微型系统上也运行,则需要将它所需要的那些库文件都一一的复制过来。于是:我们使用:ldd命令来查看到底init需要什么库文件:
我们需要将这些库文件一一复制进我们自己的/lib目录里。[root@station86 sysroot]# ldd /sbin/init linux-gate.so.1 => (0x00ccb000) libsepol.so.1 => /lib/libsepol.so.1 (0x0021d000) libselinux.so.1 => /lib/libselinux.so.1 (0x00203000) libc.so.6 => /lib/libc.so.6 (0x004cb000) libdl.so.2 => /lib/libdl.so.2 (0x00613000) /lib/ld-linux.so.2 (0x004a8000)
之后我们有了主进程,还需要我们的bash命令,同理,我们也将/bin/bash复制进我们自己的/bin/目录里。并用ldd命令查看bash需要什么样的库文件,然后一一复制进去。则:[root@station86 sysroot]# cp /lib/libsepol.so.1 /mnt/sysroot/lib/ [root@station86 sysroot]# cp /lib/libselinux.so.1 /mnt/sysroot/lib/ [root@station86 sysroot]# cp /lib/libc.so.6 /mnt/sysroot/lib/ [root@station86 sysroot]# cp /lib/libdl.so.2 /mnt/sysroot/lib/ [root@station86 sysroot]# cp /lib/ld-linux.so.2 /mnt/sysroot/lib/
有了bash,可以说我们已经完全可以进入自己的小系统了。但是系统启动后是先运行sh的,那么我们没有sh怎么办?不复制了,我们直接将sh连接成bash,等于让他启动就直接使用bash。则,我们做一个链接:[root@station86 sysroot]# cp /bin/bash /mnt/sysroot/bin/ [root@station86 sysroot]# ldd /bin/bash linux-gate.so.1 => (0x005ff000) libtermcap.so.2 => /lib/libtermcap.so.2 (0x00642000) libdl.so.2 => /lib/libdl.so.2 (0x00613000) libc.so.6 => /lib/libc.so.6 (0x00110000) /lib/ld-linux.so.2 (0x004a8000) [root@station86 sysroot]# cp /lib/libtermcap.so.2 /mnt/sysroot/lib/
此时,我们ll看一下我们的/bin目录,则已经有了一个链接文件,sh -> bash。这时,我们的小系统可以说已经是可以运行了。[root@station86 bin]# ln -sv bash sh create symbolic link `sh' to `bash' [root@station86 bin]# ll total 732 -rwxr-xr-x 1 root root 735004 Aug 3 08:08 bash lrwxrwxrwx 1 root root 4 Aug 3 08:10 sh -> bash
但是,进去之后我们什么都不能干,只能做一些bash的内部命令,比如……cd...echo.....等等,所以我们还想加入一个ls命令,能够查看目录。
那么这时的你是否会如何往自己的系统内加入一个命令呢?
是的,复制那个/bin或者/sbin下的你要的那个命令到我们自己的/bin或者/sbin下,然后用ldd命令查看运行这个命令需要的基本库文件,然后再将库文件一一复制就好。
那么添加ls命令的过程应该是这样的:
此时的你,可以考虑使用[root@station86 ~]# cp /bin/ls /mnt/sysroot/bin/ [root@station86 ~]# ldd /bin/ls linux-gate.so.1 => (0x00b9f000) librt.so.1 => /lib/librt.so.1 (0x0065b000) libacl.so.1 => /lib/libacl.so.1 (0x00666000) libselinux.so.1 => /lib/libselinux.so.1 (0x00203000) libc.so.6 => /lib/libc.so.6 (0x004cb000) libpthread.so.0 => /lib/libpthread.so.0 (0x00642000) /lib/ld-linux.so.2 (0x004a8000) libattr.so.1 => /lib/libattr.so.1 (0x00265000) libdl.so.2 => /lib/libdl.so.2 (0x00613000) libsepol.so.1 => /lib/libsepol.so.1 (0x0021d000) [root@station86 ~]# cp /lib/librt.so.1 /mnt/sysroot/lib/ [root@station86 ~]# cp /lib/libacl.so.1 /mnt/sysroot/lib/ [root@station86 ~]# cp /lib/libpthread.so.0 /mnt/sysroot/lib/ [root@station86 ~]# cp /lib/libattr.so.1 /mnt/sysroot/lib/
“chroot /mnt/sysroot/ ”这条命令,进入自己的小系统悄悄的看看哟,而且还是可以使用ls命令的哟!
呵呵,那么如何让他能够随开机启动呢?
第四步:搞定开机启动的各项配置:
开机需要读取/etc/inittab所以我们进入我们的小系统手动创建一个inittab文件:
在里面写入:[root@station86 ~]# cd /mnt/sysroot/etc/ [root@station86 etc]# vim inittab
这定义了开机之后以第3中模式(即命令行模式进入系统)id:3:initdefault si::sysinit:/etc/rc.d/rc.sysinit
并启动系统sysinit,而如何启动呢?在/etc/rc.d/rc.sysinit中定义:于是我们又需要手动创建/etc/rc.d/rc.sysinit文件
创建相关目录并创建文件:rc.sysinit
进入文件,写入:这是定义了系统启动后好后,显示的内容,以及启用的shell是什么,我们这里让他直接/bin/bash#!/bin/bash echo -e "====================================" echo -e " \033[31mWelcome to WeiYan's Little Linux\033[0m" echo -e "====================================" /bin/bash
写好这个之后,保存退出,别忘了给它执行权限:
最后,我们就要定义,系统如何启动了。[root@station86 rc.d]# chmod +x rc.sysinit [root@station86 rc.d]# ll total 8 -rwxr-xr-x 1 root root 178 Aug 3 08:24 rc.sysinit
进入/mnt/boot/grub下,找到grub.conf,这个文件定义了开机加电自检之后,系统读取了bootloarder,如何去加载内核等相关信息:
我们修改它:
这句定义了root在哪个磁盘,内核在哪里,内核的root目录在哪,使用什么来启动内核。这些信息。default=0 timeout=10 title WeiYan's Little Linux root (hd0,0) kernel /vmlinuz ro root=/dev/sda2 initrd /initrd.gz
当你定义到这的时候,可以说
你已经大功告成了!接下来,我们就要真正的将这块磁盘予以应用了!
最后一步:实现吧!梦想的少年!
我们新建一个虚拟系统,使用自定义设置,默认workstation 6.
选择另外版本2.6内核的linux。
在自己制定路径,选择核心,选择分配给的内存大小之后。进入选择硬盘的阶段,我们选择,使用一块已有的硬盘:
下一步,选择我们之前挂载在真正linux上的那个硬盘。
好的,点击完成。
接下来,就可以启动我们的小linux了!
经过一系列的内部运行,终于:我们看到了我们自己制作的linux~!
到这里,我们的所有工作都已经做完了,你已经创建出了一个属于自己的,大小不足10M的linux操作系统!!
而且这个系统里还有ls这个外部命令!
ok,今天的讲述就到这里~
欢迎大家讨论指正~共同提高~
谢谢大家~
weiyan
2011.8.2