写在前面:

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
[root@station86 linuxmini]# gunzip initrd-2.6.18-164.el5.img.gz
解压后的我们再用file命令查看它,发现它又变成了一个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文件是一种古老的归档工具,它可以原封不动的将多个文件归档,在制作光盘镜像的时候尤其有用。

那么我们使用cpio的命令将它展开:

[root@station86 linuxmini]# cpio -id < initrd-2.6.18-164.el5.img
终于,我们看到了它的真正明面,ll一下:

[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
这个是最后要引导的硬盘分区目录。

我们因为要打造自己的,所以需要改成引导我们自己的

于是:

mkrootdev -t ext3 -o defaults,ro sda2
如果你问,为什么是sda2而不是sdc2,那么我要说的是,因为我们这个系统是最后要移植到其他的机器上的, 那时候,对于那个机子来说,我们这里的sdc2会在那里被识别成sda2,所以我们索性直接将其改为sda2就好。
修改完后,我们要将其重新打包:

[root@station86 linuxmini]# find . | cpio -H newc -o --quiet | gzip -9 > /mnt/boot/initrd.gz
我们将其打包,并直接写成了initrd.gz并放在/mnt/boot下。

好的,我们看一下此时此刻我们创建的主分区到底有哪些东西:

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
[root@station86 sysroot]# ls
bin   dev  home  lost+found  mnt   root  sys  usr
boot  etc  lib   media       proc  sbin  tmp  var
我们有各种文件夹之后,就需要考虑系统启动需要的那个主进程init:

[root@station86 sysroot]# cp /sbin/init /mnt/sysroot/sbin/
将这个文件复制到我们的/sbin目录下。

其实它就是我们的主shell,但是运行它还需要很多链接库文件,它们都在/lib目录下,我们为了能在微型系统上也运行,则需要将它所需要的那些库文件都一一的复制过来。于是:我们使用:ldd命令来查看到底init需要什么库文件:

[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)
我们需要将这些库文件一一复制进我们自己的/lib目录里。

[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命令,同理,我们也将/bin/bash复制进我们自己的/bin/目录里。并用ldd命令查看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/
有了bash,可以说我们已经完全可以进入自己的小系统了。但是系统启动后是先运行sh的,那么我们没有sh怎么办?不复制了,我们直接将sh连接成bash,等于让他启动就直接使用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
此时,我们ll看一下我们的/bin目录,则已经有了一个链接文件,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
在里面写入:

id:3:initdefault
si::sysinit:/etc/rc.d/rc.sysinit
这定义了开机之后以第3中模式(即命令行模式进入系统)
并启动系统sysinit,而如何启动呢?在/etc/rc.d/rc.sysinit中定义:

于是我们又需要手动创建/etc/rc.d/rc.sysinit文件

创建相关目录并创建文件:rc.sysinit
进入文件,写入:

#!/bin/bash
echo -e "===================================="
echo -e "  \033[31mWelcome to WeiYan's Little Linux\033[0m"
echo -e "===================================="
/bin/bash
这是定义了系统启动后好后,显示的内容,以及启用的shell是什么,我们这里让他直接/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,如何去加载内核等相关信息:

我们修改它:

default=0
timeout=10
title WeiYan's Little Linux
        root (hd0,0)
        kernel /vmlinuz ro root=/dev/sda2
        initrd /initrd.gz
这句定义了root在哪个磁盘,内核在哪里,内核的root目录在哪,使用什么来启动内核。这些信息。

当你定义到这的时候,可以说
你已经大功告成了!

接下来,我们就要真正的将这块磁盘予以应用了!

最后一步:实现吧!梦想的少年!

我们新建一个虚拟系统,使用自定义设置,默认workstation 6.


选择另外版本2.6内核的linux。


在自己制定路径,选择核心,选择分配给的内存大小之后。进入选择硬盘的阶段,我们选择,使用一块已有的硬盘:


下一步,选择我们之前挂载在真正linux上的那个硬盘。


好的,点击完成。

接下来,就可以启动我们的小linux了!


经过一系列的内部运行,终于:我们看到了我们自己制作的linux~!


到这里,我们的所有工作都已经做完了,你已经创建出了一个属于自己的,大小不足10M的linux操作系统!!

而且这个系统里还有ls这个外部命令!


ok,今天的讲述就到这里~

欢迎大家讨论指正~共同提高~

谢谢大家~

weiyan

2011.8.2








Logo

华为开发者空间,是为全球开发者打造的专属开发空间,汇聚了华为优质开发资源及工具,致力于让每一位开发者拥有一台云主机,基于华为根生态开发、创新。

更多推荐