一、系统启动流程:
1、POST-->BIOS(Boot Sequence)--> BootLoader(MBR)--> Kernel(initrd,initramfs)--> init (/etc/inittab)
第一步首先加电自检,计算机本身不会执行程序,由此它会载入一段程序,它会在开机时自动实现将某个RAM中的程序映射到cpu可以寻址的地址空间中去,并且可以让cpu可以执行其中的指令,而这些指令是完成系统检测的,检测完成之后,当所有的硬件或基本的核心硬件没有问题的话就进行BIOS。根据BIOS中所设定的程序启动流程去找与其对应设备上的MBR,按照引导次序执行(Boot Sequence),根据引导次序逐个查找对应的存储设备上的MBR,若MBR存在,则读取MBR上的BootLoader,BootLoader是一段程序,早期的MBR总共512字节,但它留给BootLoader空间大小是446字节,在BootLoader当中配置了所有引导的操作系统的内核的位置,因此BIOS在载入内存以后,当它实现将控制流程或控制权限转交给BootLoader以后,BootLoader就接收了整个系统的控制权限,而后根据用户的选择,去读取相应操作系统的内核。第三步:将内核装载进内核中合适的位置,解压缩并完成内核初始化,BootLoader会把控制权限转交给内核。第四步:如果内核访问根文件系统的设备需要用到某个驱动程序,而内核中也没有,就需要到根文件中去找这个驱动程序,但这文件系统本身又没有挂载,因此要想访问根文件系统得先找到驱动,要访问驱动得先找到根文件系统,这就出现了一个难题,这时就要借助于initrd,为内核提供访问真正的根文件系统所需要的基本驱动程序。因此initrd是一个辅助性的、过渡性的中间层。它能够实现将kernel与真正的根文件系统连接起来,当连接完成之后它就没有任何意义了。第五步:执行init进程,而init程序本身的配置文件是/etc/inittab(而在红帽6上init不在是传统的init,而是upstart,而upstart的配置文件在/etc/inittab和/etc/init/.*conf下的所有文件
2、(kernel)内核初始化:
硬件探测
装载驱动
挂载根文件系统(rootfs)
启动用户空间中的第一个进程init
3、init所要完成的工作主要取决于/etc/inittab,而 /etc/inittab所要完成的任务有很多:设定默认运行级别;系统初始化脚本(/etc/rc.d/rc.sysinit);运行指定级别的服务脚本:/etc/rc.d/init.d/。连接到:/etc/rc.d/rc#.d(rc0.d--rc6.d),而链接文件比较独特,有的是以K开头的文件,有的是以S开头的文件,这两种文件的后面都跟有一个数字(00-99),而这些数字是运行次序或者说是执行次序。一般来说数字越小,运行级别越高(越先被执行)。而这些链接文件都是通过chkconfig实现的。run运行指定级别的脚本完成之后,设定Ctrl、Alt、Delete三个键的意义,还有设定突然断电时怎么办?电源又恢复的时候怎么办?但这些任务对我们来说并不是最关键的,接下来启动虚拟终端、启动图形终端
4、/etc/rc.d/rc.sysinit:系统初始化,大概执行以下任务:(注意:内核在装载根文件系统时为了避免文件损坏,是以只读方式挂载的)
检测并以读写方式重新挂载根文件系统;设定主机名;检测并挂载/etc/fstab中的其它文件系统;启动swap分区;初始化外围硬件设备的驱动;根据/etc/sysctl.conf设定内核参数;激活udev和selinux;激活LVM和RAID设备;清理过期锁和PID文件;装载键映射;
1、学了那么久的linux了,我们也应该有一个属于自己制作的小linux了,而小linux所要实现的功能有一下几部分:
1)、关机和重启;shutdown -r now 重启;shutdown -h now:关机; halt关机; reboot重启; poweroff关机
2)、主机名;
3)、运行对应服务脚本;
4)、启动终端;
5)、运行用户;
6)、定义单用户级别;
7)、装载网卡驱动,启用网络功能;
8)、提供一个web服务器;
9)、设定内核参数;
这些做完后我们的小linux就算是真正的完成了,但我们发现这个小linux每用到一个命令都要移植,这是比较麻烦的,因为你不仅要移植命令还要移植文件所依赖的库,那接下来我们就做到linux真正的裁剪和定制。
2、我们有一个项目叫busybox,它是一个命令也是一个二进制程序,但是他有很多链接,不到1M大小,一个命令可以模拟几百个命令使用,例如你拿它当ls用,它就是ls等等、、、、我们可以使用一个1M的busybox手动制作一个内核(kernel),因此我们不需要移植太多的模块,只需要移植一些最最基本的就可以了。
下面我们就来制作一个属于自己的小linux
开始之前先把虚拟机安装好,这里我用的是linux-5.8的版本,安装好后,再添加一个盘进来,为了便于区别我安装了一块IDE的盘
1、创建分区(在这里我们创建2个2G的主分区)
partprobe /dev/hda #重读磁盘分区
cat /proc/partitions #查看分区列表
2、创建挂载点,mkdir /mnt/{boot,sysroot}其中hda1挂载在/mnt/boot;hda2挂载在/mnt/sysroot
mkdir /mnt/{boot,sysroot} -pv # 创建挂载点
mke2fs -j /dev/hda1 #格式化
mke2fs -j /dev/hda2
mount /dev/hda1 /mnt/boot #挂载设备
mount /dev/hda2 /mnt/sysroot
mount #查看是否挂载成功
3、切记虽然挂载好了,但挂载点里面没有任何文件,下面我们复制内核
cp /boot/vmlinuz-2.6.18-308.el5 /mnt/boot/vmlinuz
为了便于解压缩,我在这里建一个test目录
mkdir test
cd test
zcat /boot/initrd-2.6.18-308.el5.img | cpio -id
vim init #编辑配置文件
cd lib/ #里面有很多的dm模块,没有用,就删了
rm -f dm-* #删除dm开头的模块文件
find . | cpio -H newc --quit -o | gzip -9 > /mnt/boot/initrd.gz #(先备份出来)
ls -lh /mnt/boot/ #检验
grub-install --root-directory=/mnt /dev/hda #安装grub
ls /mnt/boot #校验一下是否有grub
vim /mnt/boot/grub/grub.conf #编辑配置文件
default=0
timeout=5
title my linux(2.6.18)
root (hd0,0)
kernel /vmlinuz
initrd /initrd.gz
提供真正的根文件系统
cd /mnt/sysroot
mkdir etc/rc.d/init.d bin sbin proc sys dev lib root mnt media var/{log,run,lock/subsys,tmp} usr/{bin,sbin,local} tmp home opt boot -pv #创建所需的根文件系统
vim etc/inittab # 编辑配置文件
id:3:initdefault: #设定默认运行级别
si::sysinit:/etc/rc.d/rc.sysinit #系统初始化脚本
vim etc/rc.d/rc.sysinit #编辑编辑初始化脚本
#!/bin/bash
echo -e "\tWelcome to \033[1;34mMagedu linux\033[0m"
/bin/bash #执行/bin/bash
chmod +x etc/rc.d/rc.sysinit #给配置文件执行权限
复制命令的脚本:在根目录下编辑bincp.sh
vim bincp.sh #复制二进制程序及其依赖的库文件的脚本
#!/bin/bash
#
DEST=/mnt/sysroot
libcp() {
LIBPATH=${1%/*}
[ ! -d $DEST$LIBPATH ] && mkdir -p $DEST$LIBPATH
[ ! -e $DEST${1} ] && cp $1 $DEST$LIBPATH && echo "copy lib $1 finished."
}
bincp() {
CMDPATH=${1%/*}
[ ! -d $DEST$CMDPATH ] && mkdir -p $DEST$CMDPATH
[ ! -e $DEST${1} ] && cp $1 $DEST$CMDPATH
for LIB in `ldd $1 | grep -o "/.*lib\(64\)\{0,1\}/[^[:space:]]\{1,\}"`; do
libcp $LIB
done
}
read -p "Your command: " CMD
until [ $CMD == 'q' ]; do
! which $CMD &> /dev/null && echo "Wrong command" && read -p "Input again:" CMD && continue
COMMAND=` which $CMD | grep -v "^alias" | grep -o "[^[:space:]]\{1,\}"`
bincp $COMMAND
echo "copy $COMMAND finished."
read -p "Continue: " CMD
done
chmod +x bincp.sh #给文件执行权限
复制这些命令:init,bash,ls,touch,mkdir,cat ,mount,umount,vim,vi,chmod,chown,cp,ping,route,reboot,halt,shutdown,hostname,注意每添加一个命令都要复制过来
sync(多同步几次)
验证:
4、新建一个虚拟机,使用我们刚才添加的IDE盘,验证一下看能否启动:
注意:启动小linux完成之后它无法自动完成将根文件系统挂载可读写
而mount –n:挂载时不更新/etc/mtab文件
我们在touch一个文件:
5、现在这个小系统还不能关机,重启,接下来我们就让它可以实现关机,重启的功能:切回到宿主机:给我的小系统提供脚本,来实现系统关机、重启的功能
cd /mnt/sysroot
etc/rc.d/rc.sysdone #脚本,可用于实现微型的Linux系统关机
#!/bin/bash
#
sync
sleep 2
sync
mount | awk '{print $3}' | grep -v -E "\/(dev|proc|sys)?$" | sort -r | while read LINE; do
umount -n -f $LINE
[ $? -eq 0 ] && echo "Unmount $LINE finished." || echo "Can not unmount $LINE."
done
mount | awk '{print $3}' | while read LINE; do
mount -n -o remount,ro $LINE
[ $? -eq 0 ] && echo "Remount $LINE finished." || echo "Can not remount $LINE."
done
exec /sbin/halt -p
chmod +x etc/rc.d/rc.sysdone #给脚本一个执行权限
注意每添加一个命令都要通过bincp.sh脚本复制过去
vim etc/inittab
id:3:initdefault:
si::sysinit:/etc/rc.d/rc.sysinit
l0:0:wait:/etc/rc.d/rc.sysdone #切换到0级别时要执行/etc/rc.d/rc.sysdone
l6:6:wait:/etc/rc.d/rc.reboot #切换到6级别时要执行/etc/rc.d/rc.reboot
vim etc/rc.d/rc.reboot #编辑reboot脚本(重启脚本)
#!/bin/bash
#
sync
sleep 1
sync
exec /sbin/reboot #执行这个脚本
chmod +x etc/rc.d/rc.reboot #给执行权限
vim etc/rc.d/rc.sysdone #关机脚本
#!/bin/bash
#
sync
sleep 2
sync
exec /sbin/halt -p
chmod +x etc/rc.d/rc.sysdone
验证关机与重启功能:
注意:注意如果在此处修改小系统,再回到宿主机,系统可能会崩溃,如果崩溃就用下面的命令修复
cd /mnt/sysroot/
find . | cpio -H newc --quiet -o | gzip > /root/sysroot.gz(把所有的大小打包起来)
cd
umount /mnt/sysroot(若卸不掉就使用fuser -km /dev/hda2)
mke2fs -j /dev/hda2 #重新格式化
mount /dev/hda2 /mnt/sysroot/ #重新挂载
cd /mnt/sysroot
zcat /root/sysroot.gz | cpio -id (展开所有打包的文件)
sync(多执行几次)
6、我们也可以用一个脚本即完成关机又完成重启:
cd /mnt/sysroot/
vim etc/rc.d/init.d/halt
#!/bin/bash
#
case $0 in
*reboot)
COMMAND='/sbin/reboot' ;;
*halt)
COMMAND='/sbin/halt -p' ;;
*)
echo "Only call this script by *reboot OR *halt;" ;;
esac
case $1 in
start) ;;
stop) ;;
*)
echo "Usage:`basename $0` {start|stop}" ;;
esac
exec $COMMAND
chmod +x etc/rc.d/init.d/halt
为halt创建链接:
cd etc/rc.d/
mkdir rc0.d rc6.d #创建两个目录
cd rc0.d/
ln -sv ../init.d/halt S99halt
cd ..
cd rc6.d/
ln -sv ../init.d/halt S99reboot
而rc.reboot rc.sysdone这时已经没用了,那我们就把它删了
rm -rf rc.sysdone rc.reboot
创建rc脚本:把所有S开头的都start,把所有K开头的都stop
vim etc/rc.d/rc
#!/bin/bash
#
RUNLEVEL=$1
for I in /etc/rc.d/rc$RUNLEVEL.d/K*; do
$I stop
done
for I in /etc/rc.d/rc$RUNLEVEL.d/S*; do
$I start
done
chmod +x etc/rc.d/rc
vim etc/inittab
id:3:initdefault:
si::sysinit:/etc/rc.d/rc.sysinit
l0:0:wait:/etc/rc.d/rc 0
l3:3:wait:/etc/rc.d/rc 3 #为3级别创建目录
l6:6:wait:/etc/rc.d/rc 6
cd etc/rc.d/
mkdir rc3.d
vim etc/rc.d/init.d/tserver #脚本,测试SysV服务的定义格式:
#!/bin/bash
#
# chkconfig: 35 66 33 #通过chkconfig控制
# description: test service script
#
. /etc/rc.d/init.d/functions #这个脚本在下面
prog=tserver
lockfile=/var/lock/subsys/$prog
start() {
touch $lockfile
[ $? -eq 0 ] && success "Starting $prog" || failure "Staring $prog"
}
stop() {
rm -f $lockfile
[ $? -eq 0 ] && success "Stopping $prog" || failure "Stopping $prog"
}
status() {
if [ -f $lockfile ]; then
echo "Running..."
else
echo "Stopped..."
fi
}
usage() {
echo "Usage: $prog {start|stop|status|restart}"
}
case $1 in
start)
start ;;
stop)
stop ;;
restart)
stop
start ;;
status)
status ;;
*)
usage
exit 1 ;;
esac
chmod +x init.d/tserver
cd rc3.d #为3级别创建链接文件
ln -sv ../init.d/tserver S66tserver
ln -sv ../init.d/tserver S33tserver
vim etc/inittab #添加终端
1:2345:respawn:/sbin/agetty -n -l /bin/bash 38400 tty1
2:2345:respawn:/sbin/agetty -n -l /bin/bash 38400 tty2
注意每添加一个功能都要在小系统中验证一下
7、要想让根文件系统重新挂载可读写,先编辑etc/fstab配置文件
vim etc/fstab
/dev/hda2 / ext3 defaults 0 0
/dev/hda1 /boot ext3 defaults 0 0
proc /proc proc defaults 0 0
sysfs /sys sysfs defaults 0 0
vim etc/rc.d/rc.sysinit
#!/bin/bash
#
echo -e "\tWelcome to \033[34mMageEdu\033[0m Linux"
echo "Remount rootfs..."
mount -n -o remount,rw /
echo "Set the hostname..."(设定主机名)
[ -f /etc/sysconfig/network ] && . /etc/sysconfig/network #判定文件是否存在
[ -z $HOSTNAME -o "$HOSTNAME" == '(none)' ] && HOSTNAME=localhost #判定主机名是否存在或为空
/bin/hostname $HOSTNAME
echo "Initializing network device..."
/sbin/insmod /lib/modules/mii.ko #cp 模块以后添加进来
/sbin/insmod /lib/modules/pcnet32.ko
mkdir etc/sysconfig
vim etc/sysconfig/network
HOSTNAME=minilinux.magedu.com #添加主机名
vim etc/rc.d/init.d/functions 可用于控制服务脚本的信息显示:
SCREEN=`stty -F /dev/console size 2>/dev/null`
COLUMNS=${SCREEN#* }
[ -z $COLUMNS ] && COLUMNS=80
SPA_COL=$[$COLUMNS-14]
RED='\033[31m'
GREEN='\033[32m'
YELLOW='\033[33m'
BLUE='\033\34m'
NORMAL='\033[0m'
success() {
string=$1
RT_SPA=$[$SPA_COL-${#string}]
echo -n "$string"
for I in `seq 1 $RT_SPA`;do
echo -n " "
done
echo -e "[ ${GREEN}OK${NORMAL} ]"
}
failure() {
string=$1
RT_SPA=$[$SPA_COL-${#string}]
echo -n "$string"
for I in `seq 1 $RT_SPA`;do
echo -n " "
done
echo -e "[ ${RED}FAILED${NORMAL} ]"
}
mkdir lib/modules #创建模块文件
cp /lib/modules/2.6.18-308.el5/kernel/drivers/net/pcnet32.ko/mnt/sysroot /lib/modules
cp /lib/modules/2.6.18-308.el5/kernel/drivers/net/mii.ko /mnt/sysroot/lib/modules/
8、添加IP地址
mkdir -pv etc/sysconfig/network-scripts #先创建目录
vim etc/sysconfig/network-scripts/ifcfg-eth0
DEVICE=eth0
BOOTPROTO=static
IPADDR=192.168.1.150
NETMASK=255.255.255.0
GATEWAY=172.16.0.1
ONBOOT=yes
vim etc/rc.d/init.d/network
#!/bin/bash
#
#chkconfig: 35 09 90
#description: network service
prog=network #定义变量
./etc/rc.d/init.d/functions #调用函数
CONF=/etc/sysconfig/network-scripts/ifcfg-eth0
.$CONF
start() {
ifconfig eth0 $IPADDR/16 up
[ -z $GATEWAY ] && route add default gw $CATEWAY
}
stop() {
ifconfig eth0 down
}
status() {
ifconfig eth0
}
usage() {
echo "$prog:{start|stop|restart|status}"
}
case $1 in
start)
success "Config network eth0" ;;
stop)
success "Stop network card eth0" ;;
restart)
stop
start
success "Restart network card eth0" ;;
status)
status ;;
*)
usage
exit 1 ;;
esac
chmod +x etc/rc.d/init.d/network #执行权限
要想能在级别0,3,6下启动,需要创建链接
cd etc/rc.d/rc0.d/
ln -sv ../init.d/network K90network
cd ../rc6.d/
ln -sv ../init.d/network K90network
cd ../rc3.d/
ln -sv ../init.d/network S09network
用户登陆时显示的信息设置
vim /mnt/sysroot/etc/issue 添加如下内容
My Linux
Kernel \r on an \m #内核版本号
设定内核参数:
vim /mnt/sysroot/etc/sysctl.conf 内容如下:
net.ipv4.ip_forward = 1
编辑/mnt/sysroot/etc/rc.d/rc.sysinit文件 添加以下内容
sysctl -p &> /dev/null #IP地址立即生效
9、添加用户功能
使用不依赖与PAM的login程序
放到/mnt/sysroot/bin/目录下,之后赋予它执行权限
登陆时是使用login程序来验证登陆的,实现用户认证是到特定的文件中去认证的,传统的方式都是
放在/etc/passwd以及/etc/shadow
nsswitch是个框架,它能够完成配置到哪个去找用户的账号及密码;nsswitch就是依靠配置文件来定义的
nsswitch这个框架由库和相对应的配置文件来组成,在配置文件中可直接定义基于哪个库去去找相应的验证文件
例如:在/ect/passwd认证所找的是libnss_file.so这样的库
vim /mnt/sysroot/etc/nsswitch.conf 内容如下:
passwd: files
shadow: files
group: files
hosts: files dns
复制库文件
cp -d /lib/libness_file* /mnt/sysroot/lib/
cp -d /usr/lib/libnss_files.so/mnt/sysroot/usr/lib/
cp -d /usr/lib/libnss3.so /usr/lib/libnssckbi.so /usr/lib/libnssutil3.so /mnt/sysroot/lib/
创建用户
这里直接从本系统上复制一个用户过来
grep -E "^root\> /etc/passwd > /mnt/sysroot/etc/passwd
grep -E "^root\> /etc/shadow > /mnt/sysroot/etc/shadow
grep -E "^root\> /etc/group> /mnt/sysroot/etc/group
修改inittab文件,现在可以改为让输入用户的登陆方式了
vim /mnt/sysroot/etc/inittab 整体内容如下内容如下:
id:3:initdefault:
si::sysinit:/etc/rc.d/rc.sysinit
l0:0:wait:/etc/rc.d/rc 0
l1:1:wait:/etc/rc.d/rc 1
l3:3:wait:/etc/rc.d/rc 3
l6:6:wait:/etc/rc.d/rc 6
1:2345:respawn:/sbin/mingetty tty1
2:2345:respawn:/sbin/mingetty tty2
到这里用户功能的添加就完成了。
补充:
对/mnt/sysroot/etc/rc.d/rc.sysinit配置的整体修改,来实现对界面的进一步美化,代码如下:
#!/bin/bash
#
. /etc/rc.d/init.d/functions
echo -e "\tMy\033[34mMagedu.com\033[0mLinux"
echo "Remount rootfs...."
mount -n -o remount,rw /
[ $? -eq 0 ] && success "Remount rootfs" || failure "Remount rootfs"
mount -a
[ $? -eq 0 ] && success "Mount others filesystem" || failure "Mount others filesystem"
#Set the hostname.....
[ -f /etc/sysconfig/network ] && . /etc/sysconfig/network
[ -z $HOSTNAME -o "$HOSTNAME" == '(none)' ] && HOSTNAME=localhost
/bin/hostname $HOSTNAME
[ $? -eq 0 ] && success "Set the hostname" || failure "Set the hostname"
# Initializing network device....
/sbin/insmod /lib/modules/mii.ko
/sbin/insmod /lib/modules/pcnet32.ko
[ $? -eq 0 ] && success "Initializing network device" || failure "Initialization network device"
ifconfig lo 127.0.0.1/8
[ $? -eq 0 ] && success "Activating loopback network device" || failure "Activating loopback network device"
sysctl -p &> /dev/null
[ $? -eq 0 ] && success "Set kernel parameter" || failure "Set kernel paramenter"
属于自己的小linux就做好了,虽然不是很完善,但是也很好用的,赶快试试吧!
本文出自 “丽的博客” 博客,转载请与作者联系!