Linux系统裁剪之二(Bash脚本编程之十二)

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Linux系统裁剪之二(Bash脚本编程之十二)相关的知识,希望对你有一定的参考价值。

Linux系统裁剪之二(Bash脚本编程之十二) 系统函数库

·Linux系统的启动流程

    1,POST(加电自检)

      计算机本身并不会执行程序,它只是一堆破铜烂铁,但是它可以在开机的时候先去载入一段程序,系统在刚刚启动的时候能够实现将某个ROM芯片中的程序映射到CPU能够寻址的地址空间中去,并且让CPU能够执行其中的指令,这些指令大部分都是用来做系统检测的,当检测完成后,如果系统中所有的基本硬件和核心硬件都没有问题的话,接下来就会根据Bios中设定的系统启动次序(Boot Sequence)去找到对应设备上的MBR。

    2,BIOS(根据Boot Sequence来指定系统的启动次序)

      按照Boot Sequence去挨个逐个的找到我们的对应设备的MBR,如果对应设备的MBR存在的话,那么就读取MBR中的BootLoader。

    3,BootLoader(MBR)

      BootLoader中配置了所要引导的操作系统的内核的位置,BIOS在被载入到内存中之后,就会将系统的控制权限交给BootLoader,此时BootLoader就接收了我们整个操作系统的控制权限,而后根据我们用户的选择去读取相应操作系统的内核。

    4,Kernel

      将内核装载进内存当中合适的位置,解压缩,并完成内核的初始化之后,BootLoader会将整个系统的控制权限转交给内核。

       内核的初始化:

      内核的初始化所要完成的工作有

       ->硬件探测

       ->装载硬件的驱动程序

        驱动程序可能在内核当中,也可能在另一个辅助文件当中,这个辅助文件在红帽5系列的操作系统中叫做initrd,在红帽6系列的操作系统当中叫做initramfs,initrd这个文件中有我们内核所依赖的额外的其他的设备驱动,尤其是根文件系统的驱动。

       ->挂载根文件系统

       ->启动用户空间的第一个进程/sbin/init

      内核想要完称初始化,必须依赖于驱动程序,如果这些所被依赖的驱动程序在内核编译的时候没有被做进内核的话,那么我们就得到文件系统的某个路径下去装载这些驱动程序,但是此时我们的文件系统还没有被挂载,也就无法被访问,更不可能去装载那些内核所依赖的驱动程序了,所以我们才需要initrd这个文件为我们的内核访问我们的文件系统提供所需的基本的驱动程序。 

    5,initrd

      initrd是一个辅助性的过渡性的中间层,可以将kernel和真正的根文件系统连接起来,当连接完成后initrd这个文件就没有意义了。

    6,init

      执行init进程,init进程的配置文件的位置在红帽5系列的操作系统是/etc/inittab,在红帽6系列操作系统上init叫做upstart --> init,upstart的配置文件是/etc/inittab和/etc/init/*.conf,init进程启动起来后所要完成的工作主要取决于inittab这个文件:

       ->设定系统的默认运行级别

        技术分享

      ->执行系统的初始化脚本/etc/rc.d/init.d/rc.sysinit

       技术分享

       这个脚本的具体工作有:

        a,以只读的方式重新挂载根文件系统

        内核在装载真正的根文件系统的时候,为了避免文件系统损坏,会将文件系统以只读的方式进行挂载,rc.sysinit这个脚本的一个很重要的作用就是检测并且以只读的方式重新挂载根文件系统。

        b,设定主机名

        c,检测并挂载/etc/fstab文件中的其它的文件系统

        我们的内核除了要挂载根文件系统之外还要挂载其它的文件系统

        d,激活交换分区

        e,初始化外围硬件设备

        f,根据/etc/sysctl.conf来设定内核的参数

        g,激活udev和selinux

        h,激活LVM和RAID设备

        i,清理过期的锁和PID文件

        j,装载键映射

         键映射指的是键盘上每一个按键的具体功能

      ->运行指定级别的服务脚本

        技术分享

        这些所有的服务脚本全部都在/etc/rc.d/init.d目录下

        技术分享

        不过这些脚本都有自己的链接文件,这些链接文件全部都在/etc/rc.d/rc#.d目录下,#代表不同的运行级别,分别为0-6,rc#.d目录下的链接文件名都是K/S##init.d目录下服务脚本的名字,##两位数字代表的是脚本的运行优先级,数字越小的越容易被执行,这些链接文件全部都可以使用chkconfig命令来生成

        技术分享

      ->运行系统启动的最后一个脚本rc.local

       技术分享

      ->设定Ctrl+Alt+Delete按键的功能

       技术分享

      ->启动虚拟终端

       技术分享

·系统的关机和重启命令

    1,shutdown

    2,halt

    3,reboot

    4,poweroff

    5,init 0->表示系统的运行级别切换到0级别,0级别表示关机

    6,init 6->表示切换到6级别,6级别表示重启

·手动定制一个小型的Linux操作系统

    制作方法:

    1,首先在我们的Vmware虚拟机中添加一个20G大小的IDE磁盘

      技术分享

      如上图所示的硬盘(IDE)

    2,开启虚拟机,在我们的宿主机中找到我们刚刚新添加的磁盘,并将所加磁盘分区、格式化以及挂载

      技术分享

      上图中的/dev/hda就是我们新添加的那块磁盘

      技术分享

      然后我们使用fdisk命令给该磁盘分两个主分区,boot分区大小为500M,根分区大小为1G,分区结果如上图所示

       技术分享

      接下来我们开始格式化以上两个分区,文件系统类型都为ext3格式,格式化结果如上图所示

      技术分享

      最后我们要将格式化好的两个磁盘分区,分别挂载,我们在/mnt目录下面分别新建两个目录,sysroot和boot,sysroot目录当做我们新系统的根分区的挂载点,boot目录当做我们新系统的boot分区的挂载点,如上图所示

    3,在我们的boot分区中安装grub

      技术分享

      安装完成后会自动在我们新建的boot目录下新建一个grub目录,由上图可知我们的/dev/hda被我们的grub识别为hd0

    4,将宿主机的内核复制一份到我们当前的boot分区中,并内核文件名改为vmlinuz

      技术分享

    5,通过宿主机的initrd文件来制作我们小系统的initrd文件

      技术分享

      由于我们的initrd文件是一个cpio格式的归档和gzip格式的压缩文件,所以首先我们得将宿主机的initrd文件在我们的/root目录下加压并解归档,这个时候我们就将initrd文件展开了,展开后我们需要编辑init这个脚本并且在里面将我们的根设备文件改为/dev/hda2,如下图所示:

      技术分享

      之后将之前展开的所有文件重新归档并压缩保存至我们的新系统的boot分区中,如下图所示

      技术分享

      我们制作initrd文件的命令是:

       find . | cpio -H newc --quiet -o | gzip -9 > /media/bootinitrd.gz

       ->newc表示cpio命令归档文件的目录结构,意思是将当前目录下的所有文件以及子目录的路径映射,通通按原有的格式进行保存,并且能够支持多于51200个文件,默认情况下cpio命令进行文件归档的时候所支持的文件个数非常的少,使用newc就可以增加归档文件的数量,所以newc表示的是以新规范的方式来进行归档文件。

       ->--quiet选项表示静默模式,归档文件的时候不想屏幕输出任何信息

      ->-o选项表示创建归档文件并输出,相当于tar命令的-c选项

      至此我们的initrd文件就制作完成了

    6,在我们的小系统的boot分区中的grub目录中手动添加grub的配置文件grub.conf

      技术分享

      其中的UUID为根设备的UUID

    7,在我们小系统的根文件系统中新建一些常用的目录

      技术分享    8,将宿主机的/bin/bash和/sbin/init文件和它们所依赖的库文件分别复制到我们的新系统的根文件系统中的lib目录中

       技术分享

    9,编辑系统的启动服务脚本和init的配置文件inittab

      rc.sysinit系统的启动脚本

      技术分享

      还需要给该脚本加上执行权限

      技术分享

     init的配置文件inittab

      技术分享

    此时我们的最简系统就算是搭建完成了,接下来我们可以将新添加的那块磁盘当做是我们新系统的启动盘来验证我们刚刚搭建的小系统是否可以正常启动

      技术分享

     成功!!!

    此时虽然我们手动搭建的Linux系统成功的启动了,它只是启动了,但是它里面缺少一些我们用来管理系统的一些所必需的命令,这个时候我们可以通过复制宿主机的/bin下的或者/sbin下的命令以及命令所对应的库文件到我们的新系统当中去,但是我们如果手动去一个一个的复制命令的库文件到我们的新系统当中去会非常的麻烦,这个时候我们可以借助脚本来实现这个让人觉得麻烦的过程。

    练习,写一个脚本,要求

    1,脚本实现将/bin或/sbin下的命令以及命令所对应的库文件复制到新系统的bin、sbin以及lib目录中去

    2,脚本可以接收一个参数,这个参数就是命令名(不带绝对路径的命令名)

    脚本内容:

    技术分享

    脚本执行结果:

    技术分享

    这样我们就可以利用脚本来添加我们新系统所需的命令,从而通过这些命令来管理我们的新系统,如下图所示:

    技术分享

     但是我们如此使用脚本的方法一个一个的去手动添加命令来管理我们的新系统也是异常的麻烦的,我们可以借助一个叫做busybox的工具,busybox是一个二进制程序,只有1M左右的大小,这个二进制程序可以用来模仿数百个常用命令的功能。

    不带任何选项的mount命令表示显示当前系统所有被挂载的文件系统:

    技术分享

    /proc/mounts文件中的内容也是当前系统所有被挂载的文件系统:

    技术分享

    我们的所有文件系统,只要是被挂载了,就会被保存到/etc/mtab文件中,而卸载的文件系统会在/etc/mtab文件中被删除:

    技术分享

    

    虽然我们的系统现在可以启动,但是此时我们的根文件系统是只读的,如图所示:

    技术分享

    我们的系统它无法自动将根文件系统重新挂载为可读写的,我们得手动将我们的新系统的根文件系统重新挂载为可读写的,但是此时我们的根文件系统是只读的,我们要重新挂载我们的根文件系统势必会将挂载的信息写入/etc/mtab这个文件,这样就产生了矛盾,这个时候该怎么办呢?

    mount命令有一个-n选项可以在不写入/etc/mtab文件中的情况下挂载我们的文件系统:

    技术分享

    这个时候我们的根文件系统就变成可写的了,如上图所示

    我们可以将使得我们的系统在开机的时候就自动将我们的根文件系统重新挂载为可读写的,只要将对应的命令写入系统的启动脚本rc.sysinit即可

    技术分享

    我们将来还可以定制化安装我们的红帽系列操作系统,并且可以自动化安装操作系统,并且手动定制引导盘。

    到现在我们的这个小型的Linux操作系统就是算是基本上成型了,但是我们还可以给这个操作系统添加一些额外的功能,使它更加趋于一个真正的类似我们RHEL的操作系统:

    1,添加关机和重启功能

      halt命令只可以关闭当前进程,没有办法切断电源,但是-p选项可以切断电源,但是由于halt命令只是bash进程的一个子进程,所以我们在使用halt -p命令时是能够关闭halt子进程,无法关闭掉父进程bash,如果想要将父进程一并关闭的话,得使用exec命令,exec命令可以进行进程的替换,比如说正常情况下,我们的halt进程是我们的bash进程的一个子进程,但是exec命令可以使得halt进程替换掉它的父进程bash进程:

      技术分享

     要想使我们的新系统真正的实现关机,我们得重新在客户机的etc/rc.d目录下添加一个脚本:

      技术分享

      该脚本添加完成之后,我们还得在客户机的inittab文件中定义系统0级别所要做的事情,因为关机就是运行级别0:

      技术分享

      此时我们的客户机的电源就可以被切断了,终于OK了!!!

      如果我们想要使得我们的客户机具有重启的功能,也是一样的道理,先在客户机的etc/rc.d/目录下添加一个名为rc.sysreboot的脚本,然后再在inittab文件里面定义级别6执行rc.sysreboot脚本即可:

      技术分享

      记住凡是在rc.d目录下添加的脚本一定不要忘记添加执行权限!!!

       技术分享    

    但是如果我们想要将我们的客户机设计的更加规范,更加像我们的宿主机那样的话,就得使用类似红帽的那种规范的服务脚本,红帽系列操作系统的服务脚本全都在rc.d/init.d这个目录下,而且这些服务脚本在rc.d/rc#.d(#代表的是系统的运行级别)目录下均有对应的链接文件存在,当我们的系统切换至某一运行级别时,它就会运行rc#.d目录下对应的链接文件,rc#.d目录下的链接文件分为两种,一种K开头的链接文件,一种是S开头的链接文件,K开头的链接文件指向的服务脚本会在切换到当前运行级别时被stop,而S开头的链接文件在切换到当前运行级别时被start,S/K后面的数字代表的是服务脚本的运行优先级,数字越小优先级越高,数字最大为99,故rc#.d目录下的链接文件名为S/K##服务脚本名,这些链接文件全部指向init.d目录下的服务脚本。

    由上可知,我们可以在etc/rc.d/init.d目录下编写一个名为halt的脚本,使用这一个脚本来同时实现关机和重启:

    技术分享

    然后分别在rc0.d和rc6.d目录下常见该脚本的链接文件,来分别控制关机和重启:

     技术分享

     接下来,我们在rc.d目录下编写一个名为rc的脚本,来控制S/K开头的链接文件的所代表的功能:

     技术分享

     接下来在inittab文件中定义好对应级别所要执行的对应目录下的链接文件即可:

     技术分享

      此时我们就可以检测我们的客户机是否可以正常关机和重启。

    

      

    2,在开机时指定主机的主机名

      我们还可以在rc.sysinit脚本中设定我们主机的主机名,首先我们得在客户机的etc目录下创建一个sysconfig目录,并且在该目录下新建一个network文件,我们在该文件中定义我们的主机名:

      技术分享

      接下来我们得在rc.sysinit脚本中定义开机设定主机名的相关内容:

       技术分享

      最后我们来检测这种设定主机名的方法是否可行:

       技术分享

      由上图知,这种设定主机名的方法是可行的。

    3,可以运行系统对应级别的服务脚本

       我们以部署运行级别3的服务脚本为例,首先在我们的客户机上创建etc/rc.d/rc3.d目录,并且在etc/rc.d/init.d目录下编写一个名为testserver的测试服务脚本:

      技术分享

      技术分享

      技术分享

      但是如果我们要想使该脚本成为一个真正意义上的服务脚本,即可以被chkconfig调用的脚本,那么就得在脚本前面加上chkconfig和description两行:

      技术分享

      35表示在3级别和5级别下启动该脚本,66表示该脚本的start优先级,33表示该脚本的stop优先级。

      接下来我们得在inittab文件里面定义级别3执行testserver这个脚本,并且在rc3.d目录中创建该脚本的链接文件,还有一点,既然我们这个脚本是在级别3下启动的,那么在其他级别下就得是stop的:

      技术分享

      技术分享

       红帽系列的操作系统,在开机的时候,如果某一个服务脚本启动成功就会显示为绿色的ok,否则就会显示成为红色的failed,我们也可以使用脚本在我们的客户机中实现对应的功能,在红帽系列的操作系统中的/etc/rc.d/init.d目录下有一个叫做functions的文件,这个文件被称为我们的系统函数库,它里面定义了一堆的函数,通过函数使得我们系统的服务脚本所需要的功能来通过一个函数来实现,我们同样可以在我们的客户机中手动编写一个系统的函数库文件,来实现我们上面所需的功能。

·脚本知识点

    如何应用变量中字符的长度,格式:${#VARNAME}

    我们要想实现ok和failed的功能,就得先实现,无论服务脚本的启动提示字符串有多长,ok和failed总是对齐输出的,我们为了能够测试我们的functions函数的功能,先把它当做一个脚本来写:

    技术分享

    技术分享

    这就是实现我们ok和failed功能的公共函数,我们可以检测一下是否可以实现:

    技术分享

    接下来我们将该公共函数库读进我们的testserver脚本中,就可以实现ok和failed的功能:

    技术分享

    技术分享

    技术分享

    我们可以在客户机中进行检测:

    技术分享

    成功了!!!

       

    4,能够启动虚拟终端

       我们可以使用mingetty命令来帮助我们启动我们的终端,我们系统的正常的启动流程是先启动rc.sysinit脚本中定义的内容,之后再启动对应运行级别下的服务脚本,最后再使用mingetty命令来启动我们的终端,正常情况下,我们不能在rc.sysinit中启动bash,而是在对应运行级别的服务脚本中启动bash,我们可以在inittab文件中来使用mingetty来启动终端,但是当我们在执行mingetty这个程序的时候,它还会另外执行一个叫做login的程序,我们执行了mingetty这个程序之后,它首先会执行一个终端,然后再在这个终端里面再执行一个叫做login的程序,login的作用就是打印登录提示符,使用户可以输入账号密码进行系统的登录,但是我们可以手动在inittab文件中配置我们的loginprog,如果是的loginprog=/bin/bash表示让login打印bash的命令提示符,而不用输入账号和密码来登录系统,此时我们就不需要在rc.sysinit中来启动bash了:

      技术分享

      技术分享

      由上图知,我们的bash还是无法正常启动,并且有报错,证明我们还得完善一些功能。

      由上面的报错可知,我们的终端无法启动/bin/sh这个文件,所以我们得在客户机的/bin目录下创建一个bash的链接文件sh:

       技术分享

      我们在rc.sysinit脚本中使得我们的根文件系统在客户机启动的时候,以读写方式重新挂载,要想实现重新挂载,我们得先创建fstab文件:

      技术分享

      然后在rc.sysinit这个脚本中重新挂载我们客户机的根文件系统:

      技术分享

      我们得让我们的客户机能够使用终端,既然刚才的mingetty不可行,那么我们可以使用agetty这个命令来使得我们的客户机使用终端,agetty模拟的是一个叫做getty的终端,getty是在串行终端上的,我们的设备有两种类型,一种是块设备,一种是字符设备,比如说我们的显示器就是字符设备,因为它是将我们的字符信息一个一个的显示出来的,而且还是串行的,所以说我们的串行设备都得有速率,比如说每秒钟显示多少个字符,我们可以使用stty这个命令来显示我们的终端速率,使用格式:

      stty -F /dev/console(表示控制台或物理终端) speed

      该命令可以显示终端的速率,单位是每秒钟显示多少个字符:

       技术分享

      我们可以使用agetty来帮助我们启动终端,使用格式:

       agetty -n(表示不需要输入用户名) -l 登录程序 终端速率 终端号

       技术分享

        技术分享

    由上图知,我们的系统成功启动终端,并且我们使用Ctrl+Alt+F1/F2会发现有两个终端!!!

    我们只需将inittab文件中的/bin/login改为/bin/bash即可直接登录bash:

     技术分享

      技术分享

    由上图知,我们成功登录bash,代表我们成功登录终端,并且由两个终端!!!

      

    5,能够运行用户

    6,能够使用单用户级别

    7,可以装载网卡驱动、配置IP地址以及启用网络功能

      要想使得我们的客户机能够拥有IP地址,首先得从我们的宿主机的/lib/modules目录下移植两个和网络有关的模块到我们的客户机的lib/modules下去:

      技术分享

      接下来我们得让系统在启动的时候自动装载这两个模块,可以编写rc.sysinit来实现:

      技术分享

      模块装载好之后,我们就得去写网卡的配置文件了:

      技术分享

      最后我们再写一个网络的服务脚本即可:

      技术分享

      技术分享

      技术分享

      同样,我们得给该服务脚本创建链接文件:

       技术分享

      技术分享

    成功!!!

    8,能够提供一个web服务器

      

      

      

本文出自 “菜鸟的技术文档” 博客,请务必保留此出处http://zhubo.blog.51cto.com/11395641/1872436

以上是关于Linux系统裁剪之二(Bash脚本编程之十二)的主要内容,如果未能解决你的问题,请参考以下文章

Linux系统裁剪笔记之二insmod

linux命令:系统裁剪之二 insmod装载模块

Linux C编程之二十二 Linux线程池实现

图像算法之十二:非局部均值滤波及其Matlab实现

Linux系列教程(二十二)——Linux的bash变量

ACM专题