Linux15 linux启动流程详解及系统制作
目录
Linux启动流程
PC:OS(Linux)
POST(加电自检)-->BIOS(Boot Sequence)-->MBR(bootloader,446)-->Kernel-->initrd(ROOTFS)-->/sbin/init(/etc/inittab)
启动的服务不同:
运行级别:0-6
0:halt # 关机
1:single user mode,直接以管理员身份切入
2: multi user mode,不启用 NFS
3:multi user mode,多用户下的文本模式(text mode)
4:reserved 保留级别
5:multi user mode,graphic mode
6:reboot
内核设计风格:
单内核:Linux(LWP light weight process)
核心:ko(kernel object)
微内核:Windows,Solaries
Redhat SUSE
核心:动态加载 内核模块
内核: /lib/modules/"内核版本号命令的目录"/ # 3.10.0-1160.21.1.el7.x86_64 3.10.0-957.el7.x86_64
Redhat5:ramdisk-->initrd
Redhat6:ramfs-->initramfs
详解启动过程
bootloader(MBR)
# 第一种
LILO:Linux Loader,不能引导1024柱面以后分区的Linux内核,所以不支持大硬盘。在嵌入式系统比较好用
# 第二种
GRUB:Grand Unified Bootloader
Stage1:被装在在MBR
Stage1_5
Stage2:/boot/grub/
grub.conf
default=0 # 设定默认启动的title的编号,从0开始
timeout=5 # 等待用户选择的超时时长,单位是秒
splashimage=(hd0,0)/grub/splash.xpm.gz # grub的背景图片
hiddenmenu # 隐藏菜单
# password redhat
password --md5 # 使用grub-md5-crypt 生成加密密码
title Red Hat Enterprise Linux Server (2.6.18-308.el5) # 内核标题,或操作系统名称,字符串,可自由修改
root (hd0,0) # 内核文件所在的设备;对grub而言,所有类型硬盘一律hd;格式为(hd#,N); hd#, # 表示第几个磁盘;最后的n表示对应磁盘的分区;
kernel /vmlinuz-2.6.18-308.el5 ro root=/dev/vo10/root-rhgb quiet # 内核文件路径,及传给内核的参数 cat /proc/cmdline 查看内核参数
initrd /initrd-2.6.18-308.el5.img # ramdisk文件路径
title Install Red Hat Enterprise Linux 5
root (hd0,0)
kernel /vmlinuz-5 ks=http://192.16.0.1/workstation.cfg ksdevive=eth0 noipv6
initrd /initrd-5
password --md5 $1$FSUEU/$uhUUc8USBK5QAXc.BfW4m.
查看运行级别
runlevel #
N 3 # N表示没有切换过,3表示运行在第三个级别
who -r # 也可以显示运行级别
查看内核版本号
uname -r # 查看内核版本号
grub损坏之后的修复
# 安装grub stage1:
# grub
grub> root (hd0,0)
grub> set (hd0)
# 安装grub第二种方式
# grub-install --root-directory=/path/to/boot's_parent_dir /PATH/TO/DEVICE
grub> find
grub> root (hd#,N)
grub> kernel /PATH/TO/KERNEL_FILE
grub> initrd /PATH/TO/INITRD_FILE
grub> boot
Kernel初始的过程:
1.设备探测
2.驱动初始化(从initrd(initramfs)文件中装载驱模块)
3.以只读挂载根文件系统;
4.装载第一个进程init(PID:1)
/sbin/init: (/etc/inittab)
upstart;ubuntu,d-bus,event-driven
systemd;
# ACTION:
initdefault: 设定默认运行级别
sysinit:系统初始化
wait:等待级别切换至此级别时执行
respawn:一旦程序终止,会重新启动;
id:runlevels:action:process
id:标识符
runlevels:在哪个级别下运行此行
action:在什么情况下执行此行
process:要运行程序;
/etc/rc.d/rc.sysinit完成的任务;
1.激活udev和selinux;
2.根据/etc/sysctl.conf文件,来设定内核参数;
3.设定时钟;
4.装载键盘映射;
5.启用交换分区;
6.设置主机名;
7.根文件系统检测,并以读写方式重新挂载;
8.激活RAID和LVM设备;
9、启用磁盘配额;
10、根据/etc/fstab,检查并挂载其他文件系统;
11、清理过期的锁和PID文件;
id:5:initdefault:
si::sysinit:/etc/rc.d/rc.sysinit
OS初始化
10:0:wait:/etc/rc.d/rc 0
rc0.d/
K*
stop
S*
start
/etc/rc.d/init.d,/etc/init.d
服务类脚本:
start
SysV: /etc/rc/d/init.d
start | stop | restart | status | reload | configtest
# chkconfig命令:管控/etc/init.d下每个服务脚本在各个级别下的启动和关闭状态
能被添加为服务的脚本定义格式:
#!/bin/bash
#
# chkconfig:
# description
# chkconfig: runlevels SS KK
runlevels: -表示, 没有级别默认为S*开头的链接
当chkconfig命令来为此脚本在rc#.d目录创建链接时,runlevels表示默认创建为S*开头的链接,除此之外的级别默认创建为K*开头的链接;S后面的启动优先级为SS所表示的数字;K后面关闭优先次序为KK所表示的数字;
# description: 用于说明此脚本的简单功能; \, 续行
chkconfig --list 显示所有独立守护服务的启动设定;独立守护进程!
chkconfig --list SERVICE_NAME 显示某个服务
chkoconfig --list network
chkconfig --add SERVICE_NAME 添加到chkconfig可以控制的服务列表中
chkconfig --del myservice
chkconfig --level RUNLEVELS SERVICE_NAME {on|off}
如果省略级别指定,默认为2345级别;
chkconfig --level 24 myservice off
#!/bin/bash
#
# chkconfig:2345 77 22
# description: Test Service
#
LOCKFILE=/var/lock/subsys/myservice
status() {
if [ -e $LOCKFILE ];then
echo "Running..."
else
echo "Stopped."
fi
}
usage() {
echo "`basename $0` {start|stop|restart|status}"
}
case $1 in
start)
echo "Starting..."
touch $LOCKFILE ;;
stop)
echo "Stopping..."
rm -f $LOCKFILE &>/dev/null ;;
restart)
echo "Restarting..." ;;
status)
status ;;
*)
usage ;;
esac
文件中没有 # chkconfig # description 这两行,chkconfig -add 无法将此文件添加到服务列表中去
/etc/rc.d/rc.local:系统最后启动的一个服务,准确说,应该执行的一个脚本;
# redhat5上:
/etc/inittab的任务:
1.设定默认运行级别;
2.运行系统初始化脚本;
3.运行指定运行级别对应的目录下的脚本;
4.设定Ctrl+Alt+Del组合键的操作;
5.定义UPS电源在电源故障/恢复时执行的操作;
6.启动虚拟终端(在2345级别);
7.启动图形终端(5级别);
守护进程的类型
独立守护进程
xinetd:超级守护进程,代理人
瞬时守护进程:不需要关联至运行级别
设定内核参数数值的方法:
echo VALUE > /proc/sys/TO/SOMEFILE
sysctl -w kernel.hostname= # 或者 echo "" > /proc/sys/net/ipv4/ip_forward || /proc/sys/vm/drop_caches || /proc/sys/kernel/hostname
能立即生效,但无法永久有效;
永久有效:/etc/sysctl.conf
修改文件完成之后,执行如下命令可立即生效:
sysctl -p
sysctl -a : 显示所有内核参数及其值
内核模块管理:
lsmod # 查看内核装载了哪些模块
modprobe MOD_NAME # 装载某个模块
modprobe -r MOD_NAME #卸载某个模块
modinfo MOD_NAME # 查看模块的具体信息
insmod /path/to module_file # 装载模块
mrmod MODE_NAME # 移除模块
depmod /path/to/modules_dir
内核中的功能除了核心功能之外,在编译时,大多功能都有三种选择:
1.不使用此功能;
2.编译成内核模块;
3.编译进内核;
# 如何手动编译内核:
make gconfig:Gnome 桌面环境使用,需要安装图形开发库组:GNOME Software Development
make kconfig:KDE桌面环境使用,需要安装图形开发库
makemenuconfig
make
make modules_install
make install
screen命令:
screen -ls:显示已经建立的屏幕
screen:直接打开一个新的屏幕
Ctrl+a,松开后按d:拆除屏幕 # 拆除后可以根据screen -r ID 再次进入这个屏幕
screen -r ID:还原回某个屏幕
exit: 退出屏幕
二次编译时清理,清理前,如果有需要,请备份配置文件.config;
make clean # 清理此前编译好的二进制模块
make mrproper # 清理此前编译所残留的操作,
grub-->kernel-->initrd-->ROOTFS(/sbin/init,/bin/bash)
mkinitrd initrd文件路径 内核版本号
mkinitrd /boot/initrd-`uname -r`.img `uname -r`
chroot /mnt/sysroot # 切换到另一个系统
vim etc/rc.d/rc/sysinit
#!/bin/bash
#
echo -e "\tWelcome to \033[31m mini system\033[0m linux."
insmod /lib/modules/mii.ko
insmod /lib/modules/pcnet32.ko
ifconfig ens1 172.16.100.13/16
ifconfig lo 127.0.0.1/8
/bin/bash
:wq
sync
$(parameter#*word) # 从左往右匹配,找到第一个'/',将/及其左边的内容全部去掉
$(parameter##*word) # 从左往右匹配,找到最后一个'/',将/及其左边的内容全部去掉
FILE=/usr/local/src
$(FILE#*/):usr/local/src
$(FILE##*):src
$(parameter%word*) # 从右往左匹配,找到第一个'/',将/及其右边的内容全部去掉
$(parameter%%word*) # 从右往左匹配,找到最后一个'/',将/及其右边的内容全部去掉
$(FILE%*/):/usr/local
$(FILE%%*/)
制作小系统中命令:拷贝每个命令的二进制文件及二进制文件所依赖的库文件
#!/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 && 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
计算机加电之后,系统将ram中的程序映射到CPU可以寻址的某个空间中去,并且CPU执行其中的指令,这些指令完成系统检测,当检测基本硬件或者核心硬件没有问题,进入下一步;
根据BIOS(Boot Sequence)内设定的系统启动流程找对应存储设备上的MBR,如果MBR存在,就会读取MBR中的bootloader(一段程序,MBR留给bootloader的空间是512个字节,但用于bootloader的有446个字节),在bootloader中配置了所要引导的操作系统内核的位置,当BIOS载入内存以后,当他实现将控制流程(控制权限)转交给bootloader以后,bootloader就接受到了整个系统的控制权限,而后根据用户的选择,读取相应操作系统的内核(kernel),将内核装载在内存合适的位置,解压缩,并完成内核初始化以后,bootloader会将控制权限转交给内核;
kernel(initrd(rehl5),initramfs(rehl6)),initrd里面有我们内核所依赖的其他设备驱动,尤其是根文件系统的驱动;
内核初始化的时候需要完成哪些工作:
硬件探测
装载驱动
挂载根文件系统(rootfs)
启动用户空间中的第一个进程init
内核要完成初始化,需要依赖驱动程序,如果这些驱动程序没有被做在内核当中的话,就需要到某个文件按系统的路径下去装载这个驱动程序,而在跟文件系统被挂载之前,就出现了一个难题,如果内核访问根文件系统中的某个设备需要某个驱动程序的话,内核中没有该驱动,它就需要到根文件系统去找这个驱动程序,而这个根文件系统又没挂载,所以要想访问文件系统,得先找到驱动;要想访问驱动,得先找到文件系统,所以出现一个难题。这时就借助于initrd为内核提供访问根文件系统所需要的基本驱动程序,initrd将内核和根文件系统连接起来了,接下来执行init程序(/etc/inittab,RHEL6:upstart)
upstart -->init
/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:运行次序,数字越小,越先被执行
启动虚拟终端
启动图形终端
/etc/rc.d/rc.sysinit:
内核在装载根文件系统时,为了避免根文件系统被损坏,以只读方式挂载根文件系统;
定义主机名;
检测并挂载/etc/fstab中的其他文件系统;
启动swap分区;
初始化外围硬件设备的驱动,包括CPU,内存。 而网卡、显卡等是由init程序驱动
根据/etc/sysctl.conf设定内核参数;
激活udev和selinux;
激活LVM和RAID设备;
清理过期锁和PID文件;
装载键映射;
/etc/inittab
id:3:initdefault:
si:sysinit:/etc/rc.d/rc.sysinit
/etc/rc.d/rc.sysinit
echo
insmod
ifconfig
/bin/bash
/etc/init/*.conf
shutdown # 根据指定得参数关机或重启
halt # 关机
reboot # 重启
poweroff # 关机
init 0 # 关机
init 6 # 重启
1.关机和重启;
2.主机名;
3.运行对应服务脚本;
4.启动终端;
5.运行用户;
6.定义单用户级别;
7.装载网卡驱动,启用网络功能;
8、提供一个web服务器;
busybox:1M
Kernel:
RHEL5,RHEL6
定制安装:
自动化安装
定制引导盘
mount
/dev/hda1 on /mnt/boot type ext3 (rw)
/dev/hda2 on /mnt/sysroot type ext3 (rw)
tree /mnt
cp /boot/vmlinuz-2.6.18-308.el5 /mnt/boot/vmlinuz
cd
mkdir test
cd test/
zcat /boot/initrd-2.6.18-308.el5.img | cpio -id
ls
vim init
cd lib/
rm -f dm-*
cd ..
ls
find . | cpio -H newc --quiet -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=3
title ZhangChang Linux(2.6.18)
root(hd0,0)
kernel /vmlinuz
initrd /initrd.gz
# 提供根文件系统
cd /mnt/sysboot
mkdir -p etc/rc.d/init.d bin sbin proc sys dev lib root mnt media var/{log,run,lock/subsys} usr/{bin,sbin,local} tmp home opt boot
'''
etc/{rc.d/init.d} bin sbin proc sys dev lib是核心的不可以单独分区,mnt media也不可以单独分区但不是核心;home var 可以单独分区;root是管理员的家目录,不可以单独分区;
'''
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[34mZhangChao\033[0m Linux"
/bin/bash
chmod +x etc/rc.d/rc.sysinit
# 移植可执行程序 最核心的有2个 init bash
./bincopy.sh
init
bash
ls
touch
mkdir
rm
mv
cp
cat
mount
umount
vim
chmod
chown
ping
ifconfig
insmod
modprobe
rmmod
route
halt
reboot
shutdown
hostname
sync # 将拷贝的数据同步到磁盘上 可以多sync几下
chroot /mnt/sysroot
创建新的虚拟机,并选择刚刚制作的
touch /tmp/a.txt
# touch:cannot touch '/tmp/a.txt':Tead-only file system
mount -o remount,rw /
can't create lock file /etc/mtab~521:Read-only file system (use -n fila to override)
mount -n -o remount,rw /
warning:can't open /etc/fstab:No such file or directory EXT3 FS on hda2,internal journal
touch /tmp/a.txt
halt # 执行关机命令,只能关掉进程,但是无法切断电源
INIT:Switching to runlevel:0
INIT:Sending processes the TERM signal
INIT: no more processes left in this runlevel
halt -p # 关机并切断电源,因为该命令是在bash中进行的,所以halt是父进程(bash)的子进程,halt只能关掉子进程,对父进程没有影响;可以使用exec,让子进程去替换父进程,而不是作为子进程去运行,这样halt运行结束,bash 也就结束了。
exec halt -p # 表示用exec启动halt命令,并替换bash命令。
INIT:Switching to runlevel:0 # 执行此命令,还需要切换到对应级别下,把halt命令添加到可执行文件。
INIT:Sending processes the TERM signal
INIT: no more processes left in this runlevel
cd /mnt/sysroot
vim etc/rc.d/rc.sysdone
#!/bin/bash
#
sync
sleep 2
sync
exec /sbin/halt -p
sync
chmod +x etc/rc.d/rc.sysdone
./bincp.sh
sync
sleep
cd /mnt/sysroot
vim etc/inittab
id:3:initdefault:
si::sysinit:/etc/rc.d/rc.sysinit
l0:0:wait:/etc/rc.d/rc.sysdone
虚拟机下,开机小系统
能正常运行
init 0 # 小系统能正常关机了
现在系统还不能重启,可以在inittab文件中再编辑reboot
vim etc/inittab
id:3:initdefault:
si::sysinit:/etc/rc.d/rc.sysinit
l0:0:wait:/etc/rc.d/rc.sysdone
l6:6:wait:/etc/rc.d/rc.reboot
vim etc/rc.d/rc.reboot
#!/bin/bash
#
sync
sleep 1
sync
exec /sbin/reboot
mount -n -o remount,rw /
chmod +x etc/rc.d/rc.reboot
init 6 # 测试小系统能不能重启
mount -n # 挂载时不更新/etc/mtab文件;
cat /proc/mounts # 显示系统上挂载的所有文件系统
一个脚本实现小系统的关机和重启
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
cd etc/rc.d
ls init.d/ # halt
mkdir rc0.d rc6.d
cd rc0.d/
ln -sv ../init.d/halt S99halt
ll
lrwxrwxrwx 1 root root 14 Mar 27 13:04 S99halt -> ../init.d/halt
cd rc6.d/
ln -sv ../init.d/halt S99reboot
cd ..
ls
'''
init.d rc0.d rc6.d rc.reboot rc.sysdone rc.sysinit
'''
rm -f rc.reboot rc.sysdone
sync
vim rc
#!/bin/bash
#
RUNLEVEL=$1
for I in /etc/rc.drc$RUNLEVEL.d/K*;do
$I stop
done
for I in /etc/rc.d/rc$RUNLEVEL.d/S*;do
$I start
done
chmod +x rc
vim /etc/inittab
id:3:initdefault:
si::sysinit:/etc/rc.d/rc.sysinit
l0:0:wait:/etc/rc.d/rc 0
l6:6:wait:/etc/rc.d/rc 6
init 6 # 重启
init 0 # 关机
# 在级别3下启动服务
vim etc/inittab
l3:3:wait:/etc/rc.d/rc 3
cd etc/rc.d/
mkdir rc3.d
vim init.d/tserver
#!/bin/bash
#
# chkconfig: 35 66 33
# description: test service script
#
. /etc/rc.d/init.d/functions # 相当于source 或者include引入函数(库)的意思,只不过在shell中这么写而已
prog=tserver
lockfile=/bar/lock/subsys/$prog
start() {
touch $lockfile
[ $? -eq 0 ] && success "Starting $prog" || failure "Starting $prog" # 上面已经将functions文件中的函数已经加载进来,这里可以调到
}
stop() {
rm -f $lockfile
[ $? -eq 0 ] && success "Stopping $prog" || failure "Starting $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
cd rc3.d/
ln -sv ../init.d/tserver S66tserver
cd rc0.d/
ln -sv ../init.d/tserver K33server
vim /etc/inittab
1:2345:respawn:/sbin/mingetty --loginprog=/bin/bash tty1
2:2345:respawn:/sbin/mingetty --loginprog=/bin/bash tty2
vim rc.d/rc.sysinit
删除 /bin/bash
./bincp.sh
mingetty
basename
vim /etc/fstab
/dev/hda2 / ext3 defaults 0 0
/dev/hda1 /boot ext3 defaultss 0 0
/proc /proc proc defaults 0 0
sysfs /sys sysfs defaults 0 0
vim etc/rc.d/rc.sysinit
echo -e "\tWelcome to \033[31m mini system\033[0m linux."
echo "Recount rootfs..."
mount -n -o remount,rw / # 根文件系统重新挂载
# 给小系统添加主机名
vim etc/rc.d/rc.sysinit
mkdir etc/sysconfig
vim etc/sysconfig/network
HOSTNAME=chao.zhang.com
# 在rc.sysinit文件中添加主机名
vim etc/rc.d/rc.sysinit
echo -e "\tWelcome to \033[31m mini system\033[0m linux."
echo "Recount 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
修改开机后不需要用户输入密码
stty -F /dev/console speed # 查看控制台每秒钟输出的字符数
./bincp.sh
agetty
cd /mnt/sysroot
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
l6:6:wait:/etc/rc.d/rc 6
1:2345:respawn:/sbin/agetty -n -l /bin/bash 38400 tty1
2:2345:respawn:/sbin/agetty -n -l /bin/bash 38400 tty2
启动小系统
报错:INIT:No inittab file found # 文件系统因为来回地切换,导致错乱
修复文件系统:可以将 /mnt/sysroot下的文件打包放到其他目录,等到文件系统修复再导回来。
cd /mnt/sysroot/
find . | cpio -H newc --quiet -o | gzip > /root/sysroot.gz
cd
umount /dev/hda2
umount: /mnt/sysroot:device is busy
fuser -km /dev/hda2
umount /dev/hda2
mke2js -j /dev/hda2 # 磁盘分区过后的格式化磁盘
mount /dev/hda2 /mnt/sysroot
cd /mnt/sysroot
zcat /root/sysroot.gz | cpio -id
sync
sync
启动小系统:
报错:INIT:No inittab file found
cd /mnt/sysroot
find . | cpio -H newc --quiet -o | gzip > /root/sysroot.gz
cd
fuser -km /mnt/sysroot
umount /dev/hda2
e2fsck -f /dev/hda2 # 用于检查使用 Linux ext2 档案系统的 partition 是否正常工作
mount /dev/hda2 /mnt/sysroot/
cd /mnt/sysroot
vim etc/inittab # 查看文件内容是否丢失,发现没丢失;如果丢失,继续执行mke2js命令
启动小系统 # 一切正常
红帽系统启动时控制台信息输出OK格式编辑
# A="Starting tserver"
# echo ${#A} # 在一个变量前加井号,表示取字符串的长度;
stty -F /dev/console size # 显示物理终端屏幕的大小
25 80 # 表示25行,80列
stty -F /dev/console size | cut -d' ' -f2
# stty -F /dev/console size | awk '{print $2}'
A=`stty -F /dev/console size`
echo $A
echo ${A#* } # 从左往右找到第一个以空格为分隔符的,把空格左边的全部去掉
echo ${A##* } # 从左往右找到最后一个以空格为分隔符的,把空格左边的全部去掉
/etc/init.d/functions # 定义了一堆函数,文件中函数让公共脚本所需要用到的功能通过函数的方式来实现
如何让系统再启动的时候,服务脚本成功的时候显示为 绿色 [ OK ] 失败的时候显示为红色的 [ failed ] ?
cd /mnt/sysroot
vim etc/rc.d/init.d/functions # 里面只有函数,不需要自己执行,是别的脚本调用执行(载入执行)的,没有任何的主程序,所以不需要 #!/bin/bash
#!/bin/bash
#
SCREEN=`stty -F /dev/console size &> /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} ]"
}
# success "starting tserver"
# failure "starting tserver"
chmod +x etc/rc.d/init.d/functions
修改上面的/etc/rc.d/init.d/tserver 文件
chroot /mnt/sysroot
/etc/rc.d/init.d/tserver/ start
报错:/etc/rc.d/init.d/functions:line 1:stty:command not found
exit
/root/bincp.sh
seq
stty
chroot /mnt/sysroot
报错:stty:/dev/console:No such file or directory
exit
修改/etc/rc.d/init.d/tserver脚本
chroot /mnt/sysroot
/etc/rc.d/init.d/tserver/ start # 正常执行脚本
/etc/rc.d/init.d/tserver/ stop # 正常执行脚本
重新启动小系统
报错:
EXT3-fs error (device hda2):ext3_lookup: unlinked inode 89087 in dir #89071 Aborting journal on device hda2.
/etc/rc.d/rc:line 10:/etc/rc.d/rc3.d/S66tserver:No such file or directory ext3_abort called.
EXT3-fs errot (device hda2):ext3_journal_start_sb:Detected aborted journal Remounting filesystem read-only
cd /mnt/sysroot/
find . | cpio -H newc --quiet -o | gzip > /root/sysroot.2.gz
cd
fuser -km /mnt/sysroot
umount /mnt/sysroot
e2fsck -f /dev/hda2
mke2fs -j /dev/hda2
mount /dev/hda2 /mnt/sysroot
zcat /root/sysroot.2.gz | cpio -id
sync
sync
sync
重新启动小系统 # 一切正常
init 0 # 关机
给小系统添加ip地址
cd /mnt/sysroot
mkdir lib/modules
modinfo pcnet32
cp /lib/modules/3.10.0-1160.21.1.el7.x86_64/kernel/drivers/net/ethernet/amd/pcnet32.ko.xz
/mnt/sysroot/lib/modules/
modinfo mii
cp /lib/modules/3.10.0-1160.21.1.el7.x86_64/kernel/drivers/net/mii.ko.xz /mnt/sysroot/lib/modules/
vim etc/rc.d/rc.sysinit
echo -e "\tWelcome to \033[31m mini system\033[0m linux."
echo "Recount 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
/sbin/insmod /lib/modules/pcnet32.ko
# 自己写一个network的脚本
mkdir -pv etc/sysconfig/network-scripts
vim etc/sysconfig/network-scripts/ifcfg-ens33
DEVICE=ens33
BOOTPROTO=static
IPADDR=172.16.100.5
NETMASK=255.255.0.0
GATEWAY=172.16.0.1
ONBOOT=yes
vim etc/rc.d/init.d/network
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-ens33
. $CONF
NETMASK=16
usage() {
echo "$prog:{start|stop|restart|status}"
}
start() {
ifconfig ens33 $IPADDR/$NETMASK up
[ -z $GATEWAY ] && route add default gw $GATEWAY
return 0
}
stop() {
ifconfig ens33 down
}
status() {
ifconfig ens33
}
case $1 in
start)
start
success "Config network ens33"
;;
stop)
stop
success "Stop network card ens33"
;;
restart)
stop
start
success "Restart network card ens33"
;;
status)
status
return 0
;;
*)
usage
exit 1
;;
esac
chmod +x etc/rc.d/init.d/network
为了能让小系统能在级别3下启动,级别6和级别0下能够关机,需要创建连接
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
chroot /mnt/sysroot
etc/rc.d/init.d/network stop
报错
cd /mnt/sysroot
find . | cpio -H newc --quiet -o | gzip > sysroot.3.gz
cd
fuser -km /dev/hda2
umount /dev/hda2
mke2fs -j /dev/hda2
mount /dev/hda2 /mnt/sysroot
cd /mnt/sysroot
zcat /root/sysroot.3.gz | cpio -id
cd lib/modules/
ls
mii.ko pcnet32.ko
sync
sync
登录终端前屏幕信息
/etc/issue
\r:显示的是uname -r的信息
\m:显示的是uname -m的信息
可以通过mingetty命令查看
cp /etc/issue /mnt/sysroot/etc
vim issue
zhangchao Linux
Kernel \r on an \m
http://www.chaozhang.com
rc.sysinit:挂载/etc/fstab中定义的其它文件系统
除了根文件系统和swap
一个文件系统如果被挂载,一定会出现在/proc/mounts文件中
grep -E -v "\<swap|proc|sysfs\>" /etc/fstab | awk '{print $1}' | while read LINE;do awk '{pirnt $1}' /proc/mounts | grep "^$LINE$"; done
vim etc/rc.d/rc.sysinit
echo -e "\tWelcome to \033[31m mini system\033[0m linux."
echo "Recount rootfs..."
mount -n -o remount,rw / # 根文件系统重新挂载
[ $? -eq 0 ] && success "Remount rootfs" || failure "Mount others filesystem"
mount -a # 挂载etc/fstab中定义的文件系统
[ $? -eq 0 ] && success "Mount others filesystem" || failure "Mount others filesystem"
echo "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...
echo "Initializing network device..."
/sbin/insmod /lib/modules/mii.ko
/sbin/insmod /lib/modules/pcnet32.ko
[ $? -eq 0 ] && success "Initializing network device" || failure "Initializing network device"
ifconfig lo 127.0.0.1/8
[ $? -eq 0 ] && success "Activating loopback network device" || failure "Activating loopback network device"
设定内核参数
/etc/sysctl.conf # 红帽7在/etc/sysctl.d99-sysctl.conf
sysctl -p
/root/bincp.sh
sysctl
vim etc/sysctl.conf
net.ipv4.ip_forward = 1
vim /etc/rc.d/rc.sysinit
#添加如下一行:
sysctl -p &>/dev/null
[ $? -eq 0 ] && success "Set kernel parameter" || failure "Set kernel parameter"
登录时验证用户账号
PAM: Pluggable Authentication Module # 可插入式认证模块,该模块在/etc/pam.d/*
nsswitch: Network Service Switch
通过这个框架我们可以对登录login的认证做切换,比如:Linux使用/etc/passwd找用户,使用/etc/shadow找用户密码,用/etc/group找用户GID
库:libnss_file.so,libnss_nis.so,libnsss_ldap.so
配置文件:/etc/nsswitch.conf # 根据依赖的库,在这个配置文件中配置,去指定的文件中找账号密码
cp -d /lib/libnss_files* /mnt/sysroot/lib/ # -d选项能将文件的链接也拷贝过去
cp -d /usr/lib/libnss_files.so /mnt/sysroot/usr/lib/
cp -d /usr/lib/libnss3.so /usr/lib/libnssckbi.so /usr/lib/libness
cp -d /usr/lib/libnss3.so /usr/lib/libnssckbi.so /usr/lib/libnssutil3.so /mnt/sysroot/lib/
sync
vim /mnt/sysroot/etc/nsswitch.conf
cp /etc/nsswitch.conf /mnt/sysroot/etc
# 保留以下4行
passswd: files
shadow: files
group: files
# hosts: db files nisplus nis dns
hosts: files dns
grep -E "^(root|hadoop)\>" /etc/passwd > /mnt/sysroot/etc/passwd
grep -E "^(root|hadoop)\>" /etc/shadow > /mnt/sysroot/etc/shadow
grep -E "^(root|hadoop)\>" /etc/group > /mnt/sysroot/etc/group
sync
./bincp.sh
mingetty
useradd
passwd
userdel
usermod
groupadd
vim /etc/inittab
# 修改如下两行:
1:2345:respawn:/sbin/mingetty tty1
2:2345:respawn:/sbin/mingetty tty2
# 下载登录的二进制文件
cd /bin
chmod +x login
ldd login
ls /lib
libcrypt.so.1 => /lib/libcrypt.so.1
libm.so.6 => /libm.so.6 (0x007bb000)
libc.so.6 => /lib/libc.so.6 (0x00658000)
/lib/ld-linux.so.2 (0x00639000)
chroot /mnt/sysroot/
login
小系统提示输入用户名和密码:
cd
vim .bash_profile
PS1='[\u@\h \W]\S' # PS1 就是用来定义用户命令提示符信息的,\u表示替换为用户名,\h表示替换为主机名,\W表示替换为工作目录的基名,\w表示替换为工作目录的全名
export PS1
开机密码忘记,进入单用户模式
umount /mnt/sysroot
mke2fs -j /dev/hda2
mount /dev/hda2 /mnt/sysroot/
cd /mnt/sysroot
zcat /root/sysroot.7.gz | cpio -id
chmod -R og=--- root/
vim root/.bash_profile
export PS1='[\u@\h \W]\$' # 表示root用户显示的是#,普通用户显示的是$.
# 提供单用户模式,要修改/etc/inittab,添加1级别
l1:1:wait:/etc/rc.d/rc 1
cd etc/
cd rc.d/
mkdir rc1.d
mkdir rc1.d
cd rc1.d/
ln -sv ../init.d/network K90network
ln -sv ../init.d/tserver K33tserver
vim /etc/init.d/single
#!/bin/bash
#
# chkconfig:
# description:
#
case $1 in
start)
;;
*)
echo "Usage:single start."
;;
esac
exec /sbin/init S # init 0 和init S 都表示切换到级别1
chmod +x rc.d/init.d/single
cd rc.d/rc1.d/
ln -sv ../init.d/single S98single
sync
cd /mnt/sysroot
find . | cpio -H newc --quiet -o | gzip > /root/sysroot.8.gz
cd
sync
开启小系统,进入单用户级别:
按 e 键进入grub,键入1,按b键进入引导;然后进入单用户登录模式;登录后修改密码:passwd;但是没有pam,密码和用户相关的几个文件即使移到/mntsysroot/etc也不能修改密码
当修改完密码后,init 3 进入多用户文本模式(正常使用的模式)
使用busybox制作便携的小系统
内核编译:
busybox
Kernel +ROOTFS
kernel+initrd(ramdisk)
kernel+
busybox-->initrd
kernel + initrd(busybox)-->rootfs(busybox)
kernel
RHEL5.8 + busybox(initrd) + rootfs(busybox)
查看本机硬件设备信息
cat /proc/cpuinfo
lsusb # 查看usb设备的类型和接口信息
lspci # 查看pci总线上的所有设备
hal-device # hal:hardware abstract layer 硬件抽象层,显示设备上的所有硬件信息
编译内核:
1.配置
make menuconfig
make gconfig
make kconfig
make oldconfig
make config
保存为.config
2.make
make modiles_install
make install
模块安装位置:/lib/modules/KERNEL_VERSION/
如何实现部分编译:
1.只编译某子目录下的相关代码:
make dir/
make arch/
make drivers/net/ # 只编译与网卡相关的驱动
2.只编译部分模块
make M=drivers/net
3.只编译某一模块
make drivers/net/pcnet32.ko
4.将编译完成的结果放置于别的目录中
make O=/tmp/kernel
如何编译busybox:
官网下载busybox.tar.bz2二进制包
解压&&cd busybox
make menuconfig
勾选 [*] Build static binary (no shared libs)
exit
准备IDE磁盘:
/dev/hda1:ext3 # 格式化成ext3类型的 挂载到/boot 用于放内核和init、grub文件的
/dev/hda2:ext3 / # 关在到rootfs
cd busybox
make install # 报错
下载Linux内核
解压 && mv busybox /usr/bin
cd /usr/bin/busybox/include/uapi/mtd
cp ./ubi-user.h /root/busybox/include/uapi/mtd # mkdir -p /root/busybox/include/uapi/mtd
make install
在busybox内会生成_install目录及其下文件
cp _install /tmp/busybox/
cd /tmp/busybox
ls
rm linuxrc
mkdir proc sys etc dev lib/modules -pv
mkdir /mnt/sysroot
modinfo ext3
mbcache,jbd2 # ext3模块所依赖的库
cp /lib/modules/3.10.0-1160.21.1.el7.x86_64/kernel/fs/ext4/ext4.ko.xz /tmp/busybox/lib/modules
modinfo mbcache
cp /lib/modules/3.10.0-1160.21.1.el7.x86_64/kernel/fs/mbcache.ko.xz /tmp/busybox/lib/modules
modinfo jbd2
cp /lib/modules/3.10.0-1160.21.1.el7.x86_64/kernel/fs/jbd2/jbd2.ko.xz /tmp/busybox/lib/modules
vim init # 编写init脚本
#!/bin/sh # 没有bash
#
mount -t proc proc /proc
mount -t sysfs sysfs /sys
insmod /lib/modules/jbd.ko
insmod /lib/modules/ext3.ko
mdev -s
mount -t ext3 /dev/hda2 /mnt/sysroot
exec switch_root /mnt/sysroot /sbin/init
echo -e "\tWelcome to \033[34mChaoZhang \033[0m Linux"
# linux有一个udev 可以扫描所有硬件设备,busybox在/sbin目录下也提供了一个mdev用汉语扫描硬件设备
mdev -s
mount -n -o remount,rw /dev/hda2 / # 挂载额外的文件系统
mount -a # 挂载fstab中定义的文件系统
mknod dev/console c 5 1 # 当前在busybox目录中
mknod dev/null c 1 5
mkdir tmp
find . | cpio -H newc --quiet -o | gzip -9 > /mnt/boot/initrd.gz
# 准备内核
cp /boot/vmlinuz-2.6.18-308.el5 /mnt/boot/vmlinuz
# 安装grub
grub-install --root-directory=/mnt /dev/hda
ls /mnt/boot/
grub initrd.gz vmlinuz
vim /mnt/boot/grub/grub.conf
default=0
timeout=3
title ZhangChao Linux(2.6.18)
root(hd0,0)
kernel /vmlinuz ro root=/dev/hda2
initrd /initrd.gz
cp _initall/* /mnt/sysroot/ -a
cd /mnt/sysroot
rm linuxrc
mkdir proc sys dev tmp var/{log,lock,run} lib/modules etc/rc.d/init.d root boot mnt media -pv
vim etc/inittab
::sysinit:/etc/rc.d/rc.sysinit
console::respawn:-/bin/sh
::ctrllaltdel:/sbin/reboot
::shutdown:/bin/umount -a -r
vim etc/fstab
sysfs /sys sysfs defaults 0 0
proc /proc proc defaults 0 0
/dev/hda1 /boot ext3 defaults 0 0
/dev/hda2 / ext3 defaults 1 1
sync
sync
mknod dev/console c 5 1
mknod dev/null c 1 3
vim etc/rc.d/rc.sysinit
#!/bin/bash
#
echo -e " Welcome to \033[34m ChaoZhang \033m[0m Linux "
echo -e "Remounting the root filesystem ......[ \033m[32mOK\033[0m ]"
mount -t proc proc /proc
mount -t sysfs sysfs /sys
mount -o remount,rw /
echo -e "Creating the files of device .......\033m[32mOK\033[0m"
mdev -s
echo -e "Mounting the filesystem .........\033m[32mOK\033[0m"
mount -a
swapon -a
chmod +x etc/rc.d/rc.sysinit
练习
/sysroot下的busybox至另一个目录,以实现与真正的根文件系统分开制作,我们这里选择使用/mnt/temp目录;
mkdir -pv /tmp/busybox
cp -r /mnt/sysroot/* /tmp/busybox
四、制作initrd
cd /tmp/busybox
#1.建立rootfs:
mkdir -pv proc sys etc/init.d tmp dev mnt/sysroot
#2.创建两个必要的设备文件:
mknod dev/console c 5 1
mknod dev/null c 1 5
#3.为initrd 制作init程序,此程序的主要任务是实现rootfs的切换,因此,可以以脚本的方式来实现它;
rm linuxrc
vim init
# 添加以下内容
#!/bin/bash
#
mount -t proc proc /proc
mount -t sysfs sysfs /sys
mdev -s
mount -t ext3 /dev/hda2 /mnt/sysroot
exec switch_root /mnt/sysroot /sbin/init
# 给此脚本执行权限
chmod +x init
# 制作initrd
find . | cpio --quiet -H newc -o | gzip -9 -n > /mnt/boot/initrd.gz
# 五、建立真正的根文件胸痛
cd /mnt/sysroot
# 1.建立rootfs
mkdir -pv proc sys etc/rc.d/init.d tmp dev/pts boot var/log
# 2.创建两个必要的设别文件
mknod dev/console c 5 1
mknod dev/null c 1 3
#3.建立系统初始化脚本文件
vim etc/rc.d/rc.sysinit
# 添加如下内容:
#!/bin/bash
#
echo -e " Welcome to \033[31mToyLinux\033m[0m "
echo -e "Remounting the root filesystem ......[ \033m[32mOK\033[0m ]"
mount -t proc proc /proc
mount -t sysfs sysfs /sys
mount -o remount,rw /
echo -e "Creating the files of device .......\033m[32mOK\033[0m"
mdev -s
echo -e "Mounting the filesystem .........\033m[32mOK\033[0m"
mount -a
swapon -a
echo -e "Starting the log daemon..............\033m[32mOK\033[0m"
syslogd
klogd
echo -e "Configuring loopback interface ......[ \033m[32mOK\033[0m ]"
ifconfig lo 127.0.0.1/24
ifconfig eth0 172.16.100.9/16
# END
而后让此脚本具有执行权限
chmod +x etc/init.d/rc/sysinit
# 4.配置init及其所需要inittab文件
cd /mnt/sysroot
rm -f linuxrc
为init进提供配置文件:
vim etc/inittab
添加如下内容:
::sysinit:/etc/rc.d/rc.sysinit
console::respawn:-/bin/sh
::ctrllaltdel:/sbin/reboot
::shutdown:/bin/umount -a -r
# 5.为系统准备一个"文件系统表"配置文件/etc/fstab
vim etc/fstab
添加如下内容:
sysfs /sys sysfs defaults 0 0
proc /proc proc defaults 0 0
/dev/hda1 /boot ext3 defaults 0 0
/dev/hda2 / ext3 defaults 1 1
# 6. 由于在rc.sysinit文件中启动了日志进程,因此系统在运行中会产生大量日志并将其显示于控制台,这将会经常性的打断正在进行的工作,为了避免这种情况我们这里为日志进程建立配置为你教案,为其指定将日志发送至/var/log/messages文件;
vim etc/syslog.conf
添加如下一行:
*.conf /var/log/messages
六、好了,至此一个简易的基于内存运行的小系统已经构建出来了,我们接下来为此系统创建所需的引导程序
grub-install --root-directory=/mnt /dev/hda
说明:此处的/dev/hda为目标系统所在的那块新磁盘;
接下来为grub建立配置文件:
vim /mnt/boot/grub/grub.conf
添加类似如下内容:
vim /mnt/boot/grub/grub.conf
default=0
timeout=3
color ligth-green/black light-magenta/black
title ZhangChao Linux(2.6.18)
root(hd0,0)
kernel /vmlinuz ro root=/dev/hda2 quiet
initrd /initrd.gz
接下来将此块硬盘接入一个新的主机(这里使用的是虚拟机),启动一下并测试使用。
七、为新构建的ToyLinux启用虚拟控制台
这个可以通过宿主机来实现,也可以直接启动刚构建成功的小Linux进行配置,我们这里采用通过宿主机的方式(重新启动宿主机)
cd /mnt/sysroot
将etc/inittab文件改为如下内容:
::sysinit:/etc/init.d/rc.sysinit
tty1::askfirst:/bin/sh
tty2::askfirst:/bin/sh
tty3::askfirst:/bin/sh
tty4::askfirst:/bin/sh
tty5::askfirst:/bin/sh
tty6::askfirst:/bin/sh
::ctrlaltdel:/sbin/reboot
::shutdown:/bin/umount -a -r
好了,接下来就可以测试六个虚拟控制台的使用了。
八、尽管上述第七步已经实现了虚拟控制台,但其仍是直接进入系统,且系统没有用户账号等安全设施,这将不利于系统的安全性。因此,接下来的这步实现为系统添加用户账号(这里仍然基于宿主机实现)。
1.为了目标主机建立passwd账号文件
cd /mnt/sysroot
vim etc/passwd
添加如下内容:
root:x:0:0::/root:/bin/sh
而后为root用户创建"家"目录:
mkdir root
2.为目标主机创建group账号文件
vim etc/group
添加如下内容:
root:x:0:
3.为目标主机建立shadow影子口令文件,这里采用直接复制宿主机的shadow文件中关于root口令行的行来实现
grep "^root" /etc/shadow > etc/shadow
注:等目标主机启动时,root用户的口令也是宿主机的root用户的口令,您可以在目标主机启动以后再动手更改root用户的口令。
4.将 etc/inittab 文件改为如下内容:
::sysinit:/etc/init.d/rc.sysinit
::respawn:/sbin/getty 9600 tty1
::respawn:/sbin/getty 9600 tty2
::respawn:/sbin/getty 9600 tty3
::respawn:/sbin/getty 9600 tty4
::respawn:/sbin/getty 9600 tty5
::respawn:/sbin/getty 9600 tty6
::shutdown:/bin/umount -a -r
::ctrlaltdel:/sbin/reboot
好了,接下来就可以重新启动目标主机进行验证了。
九、在系统登录时提供banner信息
这个可以通过宿主机来实现,也可以直接在目标主机上进行配置,这里采用直接在目标主机上配置的方式:
vi /etc/issue
添加如下内容:
Welcome to ChaoZhang Linux(http://www.chanzhang.com)...
Kernel \r