前面我写了如何通过宿主RedHat系统通过精简和调用以及修改的方式,打造一个完全属于自己的微型LInux!
但是,很多人懒啊~~,所以我又写了写脚本,通过分步实现的方式。达到用一个脚本,完全的按照用户想要达到的目的安装一个属于自己的微型Linux。
那么下面我们来看如何实现:
实现过程分析:
1.分区,按照用户所选的盘,将其格式化,分区
2.挂载,按照用户设定的的分区好的盘分别挂载在我们宿主机的一个目录上。方便对微型linux进行编辑。
3.对微型Linux进行写入各项配置信息
4.将微型Linux中我们需要用到的Bash等命令放进去
5.放入内核,和启动必须加载的配置文件
6.对用户的硬盘安装引导程序。
好的~过程已经分析OK了,下面我们动手开始写吧!!!
第一步:实现自动分区!!
我们将问题分开来看,于是成了这样:
写一个脚本,实现将一个硬盘中原有分区信息全部删除,并重新将其分为三个区:
1、提示用户指定要操作的磁盘;如果此硬盘中有分区,显示分区信息,并判断此中分区是否仍然处于挂载状态;
如果是,则显示分区和对应的挂载点;否则,则说明分区没有挂载;
2、提示用户接下来操作会破坏硬盘上的所有数据,并询问用户是否继续进行;形如:Continue(y/N)?
如果用户选择继续,则抹除此硬盘上的所有分区信息(如果是仍处理挂载状态的分区,则需要先卸载);否则退出;
3、将此硬盘分为三个主分区:
第一个主分区,50M,ext3文件系统
第二个主分区,512M,ext3文件系统
第三个主分区,256M,swap文件系统
OK,开始实现:
#!/bin/bash
#: Title: All_Mini_Linux.sh
#: Synopsis:
#: DateTime: 2011-08-04 00:36:35
#: Version: 0.1
#: Author: weiyan
#: Options:
#
read -p "The target disk: " DSK# 提示用户选择即将分区的硬盘
if fdisk -l $DSK | grep "^/dev" &> /dev/null ; then #判断硬盘的分区状态。
fdisk -l $DSK | grep "^/dev"
PARTS=`fdisk -l $DSK | grep "^/dev" | awk '{print $1}'`
for I in $PARTS; do # 使用循环的方式,将硬盘上每一个分区的状态和是否挂载,挂载在哪告诉用户。
if mount | grep "$I" &> /dev/null; then
mount | grep "$I"
else
echo "$I is not mounted."
fi
done
fi
SPART() {# 制作名为SPART的函数,这个函数的功能就是提示用户准备分区,当允许分区则开始分区!
read -p "Warning !!!!! Next you do it will wipe your disk !!!! Continue(y/N)?" CHOICE
case $CHOICE in
y|Y)
for I in $PARTS; do
if mount | grep "$I" &> /dev/null; then
fuser -km $I
umount $I
fi
done
dd if=/dev/zero of=$DSK bs=512 count=1 &> /dev/null # 将用户所选的硬盘的MBR直接擦除。让其成为空盘。
echo '
n
p
1
+50M
n
p
2
+512M
n
p
3
+256M
t
3
82
w' | fdisk $DSK &> /dev/null # 将分区的信息传递给 fdisk,开始分区。
partprobe $DSK
sleep 1 # 分区之后要用sleep命令让系统“沉睡”1秒,这样可以让分区的信息真正的同步进硬盘,而不至于格式化出错。
mke2fs -j ${DSK}1 &> /dev/null# 分别格式化每一个分区并且格式化虚拟分区。
mke2fs -j ${DSK}2 &> /dev/null
mkswap ${DSK}3 &> /dev/null
return 0
;;
n|N)
return 1
;;
*)
return 2
;;
esac
}
SPART # 执行这个 SPART 函数。
[ $? -eq 0 ] && echo "The Disk wipe success !!!!!!!" || echo "Failure"# 判断函数的返回值,如果是0,则提示分区成功。
这样一来,我们就有了一个完整的分好了区,并且格式化了的硬盘了。接下来呢?
将硬盘挂载!
第二步:挂载!
那么将第二步好好的整理一下,发现它其实是不是实现了下面的功能呢?
写一个脚本,实现将上述步骤中创建的分区挂载至某目录:
1、写一个函数,接受两个参数,完成以下功能:
参数1为/boot分区对应的设备,传递至函数之后将其挂载至/mnt/boot;
参数2为/分区对应的设备,传递至函数之后将其挂载至/mnt/sysroot;
说明:上述的挂载点/mnt/boot和/mnt/sysroot如果事先不存在,需要先创建;如果事先存在,且已经被某设备挂载使用,则需要先卸载原来挂载的设备;
2、将第一个脚本中实现的分区1和分区2传递给些函数执行;
那么,目标有了,我们来实现它!
function GUAZAI { # 创建一个名为 GUAZAI 的函数
[ -d /mnt/boot ] || mkdir -p /mnt/boot# 先判断我们要挂载的目录在不在,如果不在,则创建。
umount /mnt/boot &> /dev/null # 当有了目录之后,直接先卸载掉它,不管他之前有没有被挂载。(让我懒一下把-。-)
mount $1 /mnt/boot # 挂载我们指定的参数1的目录,到挂载点。
[ -d /mnt/sysroot ] || mkdir -p /mnt/boot # 同上,判断第二个。
umount /mnt/sysroot &> /dev/null
mount $2 /mnt/sysroot
}
GUAZAI ${DSK}1 ${DSK}2 # 执行这个函数,并传递给它两个需要挂载的分区参数。
OK,挂载也挂载完了,接下来呢?
第三步:写入配置信息!
分析一下,我们要写入的配置信息:
首先要在我们的第二块分区上创建各种各样的文件夹,比如/bin /sbin /usr /root /home /tmp /etc 等等等等。
然后我们要创建/etc/inittab 这个文件
之后创建读取分区信息挂载信息的文件/etc/fstab
再然后呢?创建/etc/rc.d/rc.sysinit文件~
ok~分析得当!开始着手写入吧!
#这里我们使用函数,传递参数,参数只有$1,而$1则是我们的分区2所挂载的目录/mnt/sysroot
function ROOTFS {# 使用函数实现各项功能,方便其他用户或者其他程序的调用,多写成函数,为以后着想哟!
if [ -d $1 ];then
if mount | grep "$1" &> /dev/null ; then # 判断我们的分区2是否正确的挂载了
cd $1
mkdir {boot,proc,sys,dev,home,root,etc/{rc.d,sysconfig,init.d},bin,sbin,lib,usr/{bin,sbin,lib,include},var/{log,run},tmp,mnt,opt,media} -pv &> /dev/null #在这个目录里创建我们所需要用到的,各项文件夹。(麻雀虽小,五脏俱全嘛)
chmod 1777 tmp/
# create inittab
cat >>$1/etc/inittab<< EOF #创建inittab 写入如下的信息
id:3:initdefault:
si::sysinit:/etc/rc.d/rc.sysinit
EOF
# create rc.sysinit #创建rc.sysinit 写入如下的信息
cat >>$1/etc/rc.d/rc.sysinit<< EOF
#!/bin/bash
echo -e "\t\tWelcome to \033[031;1mLittle\033[0m Linux..."
mount -n -o remount,rw /
mount -n -a
/bin/bash
EOF
chmod +x etc/inittab # 分别赋予他们执行的权限(你总不会想看到他们放在那却不能用吧-。-?)
chmod +x etc/rc.d/rc.sysinit
# create fstab # 创建fstab 将我们到时候要挂载的分区信息写入。这里注意,一定是“到时候”要挂载的。
cat >>$1/etc/fstab<< EOF
/dev/sda2 /ext3defaults 0 0
/dev/sda1 /bootext3defaults 0 0
sysfs /sys sysfs defaults 0 0
proc/procprocdefaults 0 0
EOF
else
read -p "Error,the $1 not mount ! Contiune(y|N)?" MOT # 如果发现我们的分区2还没有挂上!就停止!
case $MOT in# 不过这应该是不会没挂上的,否则我们上一步岂不是白做了!?
y|Y)
ROOTFS /mnt/sysroot ;;
*)
echo "Exit......"
return 5
;;
esac
fi
fi
}
ROOTFS /mnt/sysroot # 最后,执行这个函数,传递给他一个/mnt/sysroot这个参数~~OK~
好的!我们完成了前三步!总结一下:
我们先按照用户选择的硬盘,将其分区,分成3块,然后都将其格式化。
之后我们把需要用到的分区挂载到我们设定的目录上去!
然后我们将分区内写入各项配置信息。
接下来,看第二篇啦~完成后面三个步骤!!OK,加油~换个页面,我们继续!
刚才我们已经完成了前三步的工作。我们再次对整个Shell脚本的实现方式进行一次分析:
实现过程分析:
1.分区,按照用户所选的盘,将其格式化,分区
2.挂载,按照用户设定的的分区好的盘分别挂载在我们宿主机的一个目录上。方便对微型linux进行编辑。
3.对微型Linux进行写入各项配置信息
4.将微型Linux中我们需要用到的Bash等命令放进去
5.放入内核,和启动必须加载的配置文件
6.对用户的硬盘安装引导程序。
----------------------------------------------------------------------------------------------------------
好的,刚才那算是帮助大家整理思路,算是“上集回顾”吧~接下来我们继续!将Shell脚本进行到底!
第四步:移植各种各样我们需要的命令进去:
脚本分析:
为了移植命令,我们就要先将我们宿主系统上的命令复制过去。
但是仅仅复制命令是不够的,我们还要将命令所对应的库文件复制过去。
那么,不同的命令有不同的样式,也有不同/相同的库文件。
我们就要辨别到底复制哪些库文件,复制到哪,有没有重复~
最后,我们要知道,不是仅仅复制一个命令就好,我们要循环的让用户选择到底需要什么命令。直到都复制结束~
好的,分析OK,我们按照计划着手去做吧!
function COPYLIB { # 我们依然使用函数,方便以后的调用工作。
#copy command
if which $1 &> /dev/null ;then # 判断用户输入的命令是否真的是个命令,总不能我们输入1,也复制1进去吧~=。=
AA=`which $1 | tail -1 | awk '{print $1}'`
cp "$AA" $2"$AA" # 如果判断成功,则复制~
else
echo "$1 is not exist"
fi
#copy lib # 开始复制命令对应的lib库文件
for LIB in `ldd "$AA" | grep "/lib/" | sed '1,$s@^[[:space:]]/lib@aaa=> /lib@g' | awk -F"=> " '{print $2}' | cut -d" " -f1`;do
LIBPATH=`echo $LIB | sed <a>'s@\(.*\)/[^[:space:]]\{1,\}@\1@g'</a>` # 我们用了一个for循环,来判断我们输入的命令所含的lib,并且将他们对齐,列表
[ -d ${2}$LIBPATH ] || mkdir ${2}$LIBPATH # 判断我们即将复制过去的目录是否存在,万一不存在则创建
[ ! -e $2/$LIB ] && cp -f $LIB ${2}$LIBPATH && echo "$LIB done" # 开始复制~并提示 复制的效果~~
done
}
# 到这里,这个函数就结束了,下面我们准备调用。首先要知道,有两个命令是必须复制的,一个是bash ,一个是 init ,两个都是非常非常重要的命令。
echo "=========================================================="
echo -e "Please input COMMAND with \033[31mbash\033[0m and \033[31minit\033[0m !!!!!"
read -p "COMMAND you want?(Quit for 'q') :" CMD1 # 就是因为太重要,所以我们用上一条语句红色警示用户,必须先复制这两条。
# 然后我们制造一个循环,方便用户反复的加入各种各样的命令。
until [ $CMD1 == 'q' ]; do# 当然,不能总是输入吧,所以我们只需要按 ‘q’
COPYLIB $CMD1 /mnt/sysroot # 执行函数 并且传递我们所输入的命令。
echo -e "Please input COMMAND with \033[31mbash\033[0m and \033[31minit\033[0m !!!!!"
read -p "Which COMMAND you want use ?(Quit for 'q') :" CMD1
done
OK~这样一来,我们的小linux里也有了各种各样我们所输入的命令啦~接下来,就要往里添加内核了!
让我们的linux运行起来!
第五步:弄个内核!让我们的Linux拥有心脏!
在手动打造属于自己的linux的时候,我们已经知道,我们的内核是直接用RedHat的内核文件。
然后再修改initrd这个能在内存中虚拟出一个小linux方便加载根目录系统的文件。
之后,我们将其移植进去就好。
接下来,我们开始做吧~!
function YDFQ {# 依然是函数-。-
TMPDIR=`mktemp -d /tmp/little.XX` # 创建一个临时文件夹,一会儿我们要解压initrd.*.img 用哦~
cd $TMPDIR
zcat /boot/initrd-`uname -r`.img | cpio -id &> /dev/null ## 在临时文件夹中解压并展开我们的initrd文件,准备修改。
sed -i 's@^echo Scanning and configuring dmraid supported devices@#&@g' init
sed -i 's@^echo Scanning logical volumes@#&@g' init
sed -i 's@^lvm vgscan --ignorelockingfailure@#&@g' init
sed -i 's@^echo Activating logical volumes@#&@g' init
sed -i 's@^lvm vgchange -ay --ignorelockingfailure vol0@#&@g' init
sed -i 's@^resume LABEL=SWAP-sda3@#&@g' init# 在init文件中注释掉我们没用的行~
sed -i "s@\(mkrootdev.*\) /.*@\1 sda2@" init# 改变init文件中有用的,比如我们要判断到时候执行哪个盘。
find . | cpio -H newc -o --quiet | gzip -9 > /mnt/boot/initrd.gz# 重新归档并压缩成initrd.gz文件~
cp /boot/vmlinuz-`uname -r` /mnt/boot/vmlinuz # 将我们整理好的文件复制到我们的分区中去!
}
YDFQ /mnt/sysroot# 函数执行的开始-。- 好吧,请原谅我总是将它写在后面
ok~我们小linux的心脏也有了~接下来,就是最后一步了!!!给硬盘一个引导,让他知道自己该如何运行!
第六步:引导文件!
那么,既然需要引导,就又要提到我们伟大的 Grub了~ 它能直接给硬盘安装一个MBR进去~让其拥有boot loader~
这样一来,硬盘在开机启动之后就自己知道自己要做些什么了~~!
当然,我们的系统我们做主,所以里面要加上你自己的东西哟!!
开始动手吧!
## 这里我们要传递四个值到我们的函数中
## $1=我们要安装对哪个硬盘安装bootloader
## $2=我们的主分区,就是内核文件等所在的分区
## $3=内核的名字
## $4=initrd 的名字~
##
function GRUB { ## 好吧,各种各样的函数-。-
if [ `basename $2` == boot ];then ## 判断用户输入的主分区是否是我们需要的主分区,不过这个肯定是了,因为下面我们手动指定了-。-
grub-install --root-directory=/mnt $1 &> /dev/null# 安装grub,到我们的分区去,这样我们就有了bootloader了!
cat >>$2/grub/grub.conf<< EOF # 制定我们自己的开机方式~~
default=0
timeout=10
title Little Linux
root (hd0,0)
kernel /${3} ro root=/dev/sda2 quiet
initrd /${4}
EOF
else
echo "It's not boot !Exit & Please set it again !"
fi
}
GRUB $DSK /mnt/boot vmlinuz initrd.gz # 好吧,函数开始执行了-。-
echo "Congratulation ! Your Mini Linux is install OK !" # 显示庆祝信息!告诉用户我们已经安装好了!
OK~~!!!! 一切搞定~
接下来我们就去测试把~
按照这样的写下来,我们可以说基本实现了一键安装linux,并且是你自己制定的哟!!!!!
~
嗯~
看懂了么?会了么-。-那么,自己做做吧。