章节导航:

  • 前言

  • Linux系统启动流程

  • 实验前的准备

  • 实验过程

  • 拷贝命令脚本

 

一、前言

我们生活中离不开电脑,时时刻刻在跟操作系统打交道,有时候会被系统中出现的错误搞得头昏脑胀,使用操作系统,不如亲自动手组建一个自己的简单的系统,体验一下制作操作系统的乐趣。在系统的学习了Linux操作系统之后,就有了理论基础,所以,迫不及待的想做一个自己的简单的Linux小系统,有兴趣的同学也可以来动手做一做。

在接下来的文章中,小编会先从Linux系统的启动流程入手,将启动过程一一展示出来,再进行实验指导。

二、Linux系统启动流程

1、加电自检(POSTpower on system test

这些自检的功能是有一个软件程序来实现的,这个软件程序叫做:BIOSBIOS是基本输入输出系统,他是装在一个硬件芯片CMOS之上,加电过程给CMOS通电,BIOS会根据CMOS上的一些配置信息去读取硬件的状态,之后进行硬件设备的初始化。

加电自检主要是检测一下硬件设备是够存在并能够正常运行,如:CPU、内存、硬盘是否存在并能正常运行,CPU风扇是否能够运转散热,以及一些外围的输入输出设备是否存在,但是有些设备存在与否不影响系统的正常启动,如键盘、鼠标。

2、加载MBR

在硬件初始化之后,BIOS会列出一些可以启动的装置顺序,接下来就开始读取第一个可以启动的设备中操作系统的核心文件。我们必须以一个启动管理程序来处理这些核心文件的加载问题,这个启动管理程序为:BootloaderBoot loader是一个程序,他肯定依赖于一个硬件之上,这个硬件就是硬盘,准确的说是第一个可以启动的硬盘的第一个扇区内,就是我们之前读到的MBR(主引导记录)当中。所以,在加电自检之后BIOS会将系统引导到MBR中,找到Boot loader

3Boot loader

Boot Loader就是在操作系统内核运行之前运行的一段小程序。通过这段小程序,可以初始化硬件设备,建立内存空间的映射图,从而将系统的软硬件环境为最终调用操作系统内核做好准备。Boot Loader使用最广的就是Grub了,系统将Linux/boot/grub/grub.conf的配置文件读取到内存中,根据配置文件中的信息找到内核文件和伪根文件,并将伪根文件加载到内存中,模拟出一个根文件系统,再进行加载内核文件。

4、加载系统内核(Kernel),执行系统初始化信息,

Bootloader可以加载kernelinitrd,然后在内存中让initrd解压缩成根目录,然后内核可以在这个虚拟的根文件系统之上加载合适的驱动程序,来加载硬盘等设备,之后释放虚拟的根文件系统,并以只读的方式挂载磁盘上真实的根文件系统,之后就开始正常的启动过程。此时内核程序已经完全接管了BIOS工作,之后的操作都是有内核来完成的

5、启动用户空间第一个执行程序/sbin/init

在内核、硬件及驱动信息加载完毕后,内核会呼叫用户空间的第一个执行程序/sbin/initinti进程主要功能是准备软件运行环境,包括系统的主机名称、网络配置、文件系统格式、服务运行级别等其他服务的启动管理。这些所有的操作都是通过init的配置文件来定义的。

Init的配置文件:

Centos5:由于centos5采用的是Sys init方式,其特点是启动用户空间的服务程序,通常通过脚本运行,有依赖关系的服务将被串行启动,这也就导致了centos5的系统启动过程非常的缓慢,配置文件为:/etc/initab

Centos6:采用Upstart的方式,其特点是守护进程间的通信依赖于D-Bus进行,因此,可基本实现类似并行启动:配置文件:/etc/inittab,/etc/init/*.conf

Centos7采用Systemd方式,其特点是服务只有在第一次被访问到时才会真正启动起来,因此Centos7系统的启动过程非常之快,配置文件是:/usr/lin/system/*

6init程序执行完inittab配置文件后,执行系统初始化脚本rc.sysinit

在定义完运行级别后,Linux系统执行的第一个用户层文件就是rc.sysinit脚本程序,这个脚本为初始化用户空间环境,会执行许多系统初始化任务;在完成系统初始化脚本后,系统还会启动对应级别下设定为要启动的服务,关闭那些设定为要关闭的服务。该步骤是根据inittab配置文件中定义的运行级别,来运行对应运行目录中的服务设定脚本。

在服务启动的最后,会执行最后一个脚本:/etc/rc.d/rc.local,这个脚本是留个用户的,可以将用户想要启动的东西放到这里。

7、执行/bin/login程序,进入登录等待状态

此时就进入了输入usernamepassword时刻了,漫漫开机之路就算到此结束了。

 

附上启动流程图:

三、实验前的准备

我们要制作的是U盘Linux系统,所以要准备一个U盘,不需要太大够用就行。

需要准备的工具:U盘、虚拟机或Centos的主机一台、Centos6系统。

U盘的要求:一般Linux系统不识别NTFS的文件系统,所以要是U盘是NTFS的系统,我们需要将其格式化为FAT32文件系统的格式,这样系统才能识别。

四、实验过程

1、启动虚拟机的VMware USB Arbitration Service服务

我们需要虚拟机能够识别USB接口上的U盘,所以要开启这个服务,如果一斤开启了,可以直接跳过步骤,小编将为大家演示如何开启该服务。

如图所示:

       右击我的电脑,打开管理,进入:

        

在服务中找到VMware USB Arbitration Service项,将服务启动起来,这个时候重新打开虚拟机。

2、将U盘挂载到虚拟机中的系统上

打开虚拟机后,将右下方显示的磁盘标志,找到自己的U盘,选择连接:

 

 

3、  U盘进行分区

我们需要将U盘分为两个分区,一个用来当做boot分区,一个用来当做根分区。使用:fdisk 命令。

在小编的电脑上识别到的U盘为/dev/sdc盘号,所以执行:fdisk/dev/sdc,将/dev/sdc1作为boot分区,分出大小1G;将/dev/sdc2作为根分区,将剩余空间全部分给根分区。

 

 

4、  将分区格式化为ext4文件系统

分好区后并不能直接使用,我们需要将分区格式化后才可以正常使用,使用命令:mkfs.ext4 /dev/sdc1需要将/dev/sdc1/dev/sdc2两个分区进行格式化。

 

5、  创建挂载将要设置为boot分区的目录

该目录必须为boot,这样在生成一些数据的时候才不会乱,因为我们要将分区/dev/sdc1挂载到命名为/boot的目录下,我们需新建目录,为了不和本地系统上的boot目录混淆,小编创建新的目录:mkdir –p  /linshi/boot  

wKioL1nDylHiiHkGAAASoO3soEo040.png

6、  /dev/sdc1挂载到/linshi/boot目录上

执行命令:mount  /dev/sdc1 /linshi/boot

7、  boot分区/dev/sdc1安装grub

执行命令:grub-install  --root-directory=/linshi   /dev/sdc

该命令是用来安装修复grub引导文件的,如果grub目录中的文件损坏了,可以通过该命令进行恢复。因为我们要在U盘的boot目录上安装grub,所以需要指定一个位置,那就是—root-directory=/linshi,对象为/dev/sdc

查看/linshi/boot下的目录树结构:

    查看U盘的MBR表:

 

8、  将本地的boot下的内核文件和伪根文件拷贝到U盘中的boot下,命令如下:

    cp /boot/vmlinuz-2.6.32-696.e16.x86_64  /linshi/boot/

    cp /boot/initramfs-2.6.32-696.e16.x86-64.img  /linshi/boot/

执行过程如图所示:

 

9、  手动编写grub.conf配置文件

Vim /mnt/boot/grub/grub.conf

内容如下:

default=0

timeout=5

hiddenmenu

title Centos-jiake

        root(hd0,0)

        kernel/vmlinuz-2.6.32-696.e16.x86_64 root=UUID=U盘的根分区的UUID selinux=0 init=/bin/bash

        initrd/ initramfs-2.6.32-696.e16.x86-64.img

如图所示:

10、             创建挂载根分区的目录,并挂载U盘的根分区

    mkdir /linshi/sysroot

    mount /dev/sdc2  /linshi/sysroot

如图:

11、             U盘的根分区下创建与本地根下相同的目录

一个一个创建太慢,我们使用一个快捷的方式,先将本地根下的目录名全部存放起来,做成一个列表,然后一次性创建。

ls  / >  /mulu.txt

              mkdir –p `cat mulu.txt`

如图:

 

12、             拷贝网卡驱动

有时候我们需要用用网卡,所以我们将网卡驱动一块拷贝过去,如果不想使用网卡功能,可以不用拷贝这个文件驱动。

使用locate e1000找到网卡驱动的位置,e1000是网卡的驱动程序文件。

如图所示:

13、             通过命令拷贝脚本,将需要使用的命令拷贝到U盘的根分区上

这个脚本是小编自己编写的,如果你不会,不用着急,小编会在后面附上源代码。如果你要使用脚本,记得给脚本加上执行的权限。具提的操作可以看小编的截图:

 

14、             查看我们U盘根分区下的树状结构图

我们拷贝完命令,一定要验证命令是否拷贝成功,并且路径一定要正确。命令原来在什么地方,拷贝过来还要放到对应的目录下。否则会导致命令不可用。 wKioL1nDy6Oh8CeEAABA1gI_27M840.png

 wKiom1nDy9nyEcj5AABVkv7GNkc171.png

 wKioL1nDy6SQYQ5vAABs9RCh1rs206.png

15、             完成命令移植的功能后,将U盘放到独立的机器上启动

要关机将U盘拔下来,这里小编使用电脑作为整机,从U盘启动,所以就不能呈上优质的截图了。一下图片使用手机拍摄。

对于不同的机型,进入本地BIOS的按键也不同,请各位同学自行寻找进入BIOS的按键,进入BIOS需要将U盘设为第一启动项,(为了在BIOSboot启动项显示出U盘,需要先将U盘插入电脑)

找到自己的U盘,使用shift +将U盘移动到第一位:

 wKiom1nDzIzTmEsyAAy_5CGE4r4849.png

完成后按下F10保存退出启动:

 wKioL1nDzFjyCMRlAAUE0zZ0OQo252.png

16、             启动成功!

稍等片刻,我们就能看到成功进入bash的界面了,由于我们自制了一个简单的Linux系统,所以目前只是使用bash进入了一个简单的bash环境,可以执行一些简单的命令,如果想使用init启动进程,需要配置更多的文件,如果有兴趣的同学可以据需深入研究

五、拷贝命令脚本

    #!/bin/bash

    #将用户指定的命令拷贝到对应的根目录下

    copy_comd() {

            com_path=`which $1`

            com_dest=`dirname $com_path`

            [ ! -d $dir$com_dest ] && mkdir -p $dir$com_dest

            ls $dir$com_path  &> /dev/null && { echo "该命令已存在!" ;return 99; }

            cp  $com_path $dir"$com_path"

            echo -e "$com_path  \e[33;5m ====>\e[0m  $dir"$com_path""

    }

  

    #将命令所依赖的库文件拷贝到对应的目录中

    copy_comfile(){

        ldd $(which $1) |grep -oE "/.* " | while read libfile

        do

            local lib_destdir=$dir$(dirname $libfile)

            local lib_destfile=$dir$libfile

            if [ -e $lib_destfile ];then

                continue

            elif [ -d $lib_destdir ];then

                cp  $libfile $lib_destdir

                echo -e "$libfile  \e[33;5m ===> \e[0m $lib_destfile"     

            else

                mkdir -p $lib_destdir &> /dev/null

                cp  $libfile $lib_destdir 

                echo -e "$libfile  \e[33;5m ===> \e[0m $lib_destfile"

            fi

        done

    }    

   #主程序(需要先指定根目录,每个执行步骤都可以quit退出。)

    while true;do

    read -p "Please input the dir("quit" to exit!): " dir

    if [ "$dir" == quit ] ;then 

            exit

    fi

    [ -z $dir ] && { echo -e "\e[31m Please input the dir!\e[0m";continue;}|| break

    done

    ls -d $dir &> /dev/null || mkdir -p $dir

    while true; do

        read -p "Please input the command that you want to copy("quit" to exit! ): " com 

    if [ "$com" == quit ]; then

        exit

    fi

        which "$com" &> /dev/null || { echo "This command is no exited!" ;continue; }

    copy_comd $com

    ret=$?

    [ $ret -eq 99 ] && continue 

    copy_comfile $com

    done

 #(记得给脚本加执行权限哦!)