以下是学习过程记录:
学习环境使用VMware虚拟机,宿主机使用centos6.10,内核源码linux-3.0.1,busybox-1.22.0,dropbear-2020.81。
我新建了5G的磁盘,其实很小就可以。使用fdisk分区1+4G过程略。两个分区分别挂载至宿主机。
mount /dev/sdb1 /mnt/boot;mount /dev/sdb2 /mnt/root
grub-install --root-directory=/mnt /dev/sdb
vim /mnt/boot/grub/grub.conf
default=0
timeout=2
title Mini Linux
root (hd0,0)
kernel /bzImage ro root=/dev/sda2 init=/sbin/init
待会儿我的内核就编译为bzImage非模块化方式。
很多文章都说内核源码放置/usr/src,这只是沿用了系统默认的文件部署形式。其实无所谓的,进入源码根目录。
make allnoconfig(初始化最小配置。)
lscpu;lspci(查看当前系统硬件情况,因为是虚拟机,虚拟的硬件环境一样,参考用。)
make menuconfig是tui界面,会根据内核版本不同而有区别。我总结了几个我认为主要的选项。主要是针对:架构,模块,处理器,pci总线,执行文件,设备驱动(磁盘、键盘、鼠标、/dev、network),fs。
[*] Enable loadable module support --->
[*] Module unloading
Processor type and features --->
[*] Symmetric multi-processing support
[*] Multi-core scheduler support
Bus options (PCI etc.) --->
[*] PCI support
Executable file formats / Emulations --->
[*] Kernel support for ELF binaries
[*] Write ELF core dumps with partial segments
-*- Networking support --->
Networking options --->[*] TCP/IP networking
Device Drivers --->
Generic Driver Options --->
[*] Maintain a devtmpfs filesystem to mount at /dev
[*] Automount devtmpfs at /dev, after the kernel mounted the rootfs
SCSI device support --->
<*> SCSI device support
<*> SCSI disk support
[*] SCSI low-level drivers --->
[*] Fusion MPT device support --->
<*> Fusion MPT ScsiHost drivers for SPI
<*> Fusion MPT ScsiHost drivers for FC
<*> Fusion MPT ScsiHost drivers for SAS
<*> Fusion MPT misc device (ioctl) driver
[*] Network device support --->
[*] Ethernet (1000 Mbit) ---><M> Intel(R) PRO/1000 Gigabit Ethernet support
(网卡选择为<M>稍后编译成模块)
Input device support --->
Keyboards --->
[*] Mice --->
[*] USB support --->
File systems --->
<*> Second extended fs support
<*> Ext3 journalling file system support
<*> The Extended 4 (ext4) filesystem
网卡驱动非模块化方式:
直接编译进内核,不需要后期加载驱动模块。
网卡驱动模块化方式:
modinfo e1000 (查看有无depend项,有的话一并复制)
编译内核:
make -j 4 bzImage:非模块化式编译,不含网卡。编译完成会提示生成位置arch/x86/boot/bzImage
cp arch/x86_64/boot/bzImage /mnt/boot (符号链接x86_64-->x86)
chmod +x /mnt/boot/bzImage
编译网卡驱动:
make M=drivers/net/e1000 (编译单个模块:make M=path/to/dir)
mkdir /mnt/root/lib/modules
cp drivers/net/e1000/e1000.ko /mnt/root/lib/modules
驱动的具体位置需要从源码目录中找到,可以参考宿主机的/lib/modules,
理论上安装位置可以任意指定,加载模块时指定即可。系统原有路径很长,这里就简化处理。
tar -xf busybox-1.22.0.tar.bz2(试过1.35版本编译出错,也许是版本不兼容)
cd busybox-1.22.0
使用静态编译,不依赖动态库文件,把库编译进可执行文件,依赖于glibc-static包
make menuconfig (其中有重要选项,用于设置为静态模式,如下列出)
--- Build Options
[*] Build static binary (no shared libs)
--- Installation Options ("make install" behavior)
(./_install) Destination path for 'make install' (NEW)
make -j 4 && make install
cp -a _install/* /mnt/root
mkdir -p boot root home usr var tmp etc bin sbin lib lib64 mnt media dev proc sys(16个常用目录补全)
另外我写了一个脚本用于移植文件:(其实也可以写得很简洁,我习惯这样写)
#!/bin/bash
#sDestDir="/root/mytest/tmp"
sDestDir="/mnt/root"
sCmdName=""
sFunction=""
case $1 in
"")#install
sFunction="install"
;;
e)#erase
sFunction="remove"
;;
*)
echo "The arguments must be e|none."
exit 2
;;
esac
f_chkInput(){
#read input
read -p "Enter a name of command:" sCmdName
sCmdName=${sCmdName//[[:space:]]}
if [ -z $sCmdName ];then
return 1 #input null
elif [[ $sCmdName == "quit" || $sCmdName == "exit" ]];then
return 2 #input 'quit' or 'exit'
elif (! which $sCmdName &>/dev/null);then
echo "Command not found,or it is a shell builtin."
return 3 #command wrong
#else
fi
echo $sCmdName
}
f_getCmdPath(){
echo $(which $1 | egrep -o '(/[^/]+)+$')
}
f_getDependList(){
echo $(ldd $1 | egrep -o '(/[^/]+)+[[:space:]]')
}
f_InstallOrRemove(){
#Create tmp directory
install -d $sDestDir
#copy files
arrFile=($@)
sNewFilesList=""
iCount=0
for ((i=0;i<${#arrFile[*]};i++));do
sBaseName=${arrFile[$i]##*/}
sDirName=${arrFile[$i]%/*}
sNewDir="${sDestDir}${sDirName}"
if [ $sFunction == "install" ];then
install -d $sNewDir
#if (install ${arrFile[$i]} $sNewDir);then
if ([ -f ${sNewDir}/${sBaseName} ] || cp ${arrFile[$i]} $sNewDir);then
if ((i>0));then
sNewFilesList+="\n"
fi
sNewFilesList+="${sFunction} ${sNewDir}/${sBaseName}"
let iCount++
fi
else
if ([ -f ${sNewDir}/${sBaseName} ] && rm -f $sNewDir/${sBaseName});then
if ((i>0));then
sNewFilesList+="\n"
fi
sNewFilesList+="${sFunction} ${sNewDir}/${sBaseName}"
let iCount++
fi
fi
done
sNewFilesList="-------------------------------------\n"${sNewFilesList}
echo -e $sNewFilesList >> "${sDestDir}/myinstall.log"
echo "$sNewFilesList\n$iCount files done."
}
while true;do
sInputResult=$(f_chkInput)
case $? in
1)#input null
continue;;
2)#input quit
exit 0;;
3)#command wrong
echo $sInputResult
continue;;
esac
sCmdName=$sInputResult
sCmdPath=$(f_getCmdPath $sCmdName)
sDependList=$(f_getDependList $sCmdPath)
declare -a arrFile
arrFile=($sCmdPath $sDependList)
echo -e $(f_InstallOrRemove ${arrFile[*]})
done
使用的时候可以在代码中指定目标目录,也可以给参数“e”,就表示卸载。我是给自己用的,没想那么多,就是用ldd判断依赖关系而已,卸载的时候比较暴力,有些共享的库可能会被删除,不过我不在乎,哪个程序有问题,再移植一下就行了。以后再完善这个脚本。
我使用这个脚本移植了bash过去。
bash myinstall.sh
在提示符下输入bash就可以自动移植完成。
格式:id:runlevel:action:program
::sysinit:/etc/rc.d/rc.sysinit
::respawn:/sbin/getty 9600 tty1
::respawn:/sbin/getty 9600 tty2
::respawn:/sbin/getty 9600 tty3
::ctrlaltdel:/sbin/reboot
::shutdown:/bin/umount -a -r
cd /mnt/root;mkdir etc/rc.d;vim etc/rc.d/rc.sysinit
#!/bin/sh
echo -e "Welcome to \033[33mMini\033[0m Linux"
echo "scan /sys to /dev..."
mdev -s
echo "make dir..."
mkdir var/run dev/pts
echo "mount filesystem..."
mount -a #mount from fstab
mount -o remount,rw /
echo "Load driver ..."
insmod /lib/modules/e1000.ko #(需要在内核源码中编译网卡驱动)
echo "Initializing ethernet card..."
ifconfig eth0 192.168.0.61 up
ifconfig lo 127.0.0.1 up
[ -f /etc/sysconfig/network ] && . /etc/sysconfig/network
[ -z $HOSTNAME -o $HOSTNAME == "(none)" ] && HOSTNAME="localhost"
hostname $HOSTNAME
chmod +x etc/rc.d/rc.sysinit
/dev/sda1 /boot ext4 defaults 0 0
/dev/sda2 / ext4 defaults 0 0
devpts /dev/pts devpts mode=620 0 0
sysfs /sys sysfs defaults 0 0
proc /proc proc defaults 0 0
head -1 /etc/passwd > etc/passwd;head -1 /etc/group > etc/group;head -1 /etc/shadow > etc/shadow(我这是比较懒的做法,把宿主机的root信息复制一份过去)
其中shadow里面密码的加密串很长,minilinux可能不支持,实测,本地登录可以,使用ssh不行。解决方法很简单,chroot或者进入minilinux,更改一下密码就可以了。因为它使用自己支持的格式再生成的密码串,当然没问题。
我虽然下载了源码,但没有编译使用,只是看了一下其中的说明问题,就是要那几个key文件就行了。因为随后要使用我写的脚本向目标位置移植dropbear,dropbearkey,dbclient三个程序,所以我使用yum安装的epel源当中的dropbear。
cd /mnt/root
mkdir etc/dropbear
cd etc/dropbear
dropbearkey -t rsa -s 2048 -f dropbear_rsa_host_key
dropbearkey -t dss -f dropbear_dss_host_key
dropbearkey -t ecdsa -f dropbear_ecdsa_host_key
dropbearkey -t ed25519 -f dropbear_ed25519_host_key
最后一个ed25519它不支持,也就不考虑了,可以不要这个。
新建etc/issue,登录提示文本,内容如下:
kernel \r
新建etc/shells,内容如下:
/bin/sh
/bin/ash
/bin/hush
/bin/bash
/sbin/nologin.
新建etc/nsswitch.conf,用于解析用户名到id,内容如下:
passwd:files
group:files
shadow:files
hosts:files dns
mkdir -p usr/lib64
cp -d /lib64/libnss_file* lib64/
cp -d /usr/lib64/libnss3.so usr/lib64/
cp -d /usr/lib64/libnssutil3.so usr/lib64/
cp -d /usr/lib64/libnss_file* usr/lib64/
新建etc/sysconfig/network,用于指定主机名,内容如下:
HOSTNAME=nxMINI
新建root/.bash_profile,内容如下:
export PS1='[\u@\h \W]\$ ' #(命令行提示符)
export PATH=$PATH:/usr/local/bin:/usr/local/sbin #(dropbear程序所在目录加入环境变量)
新建etc/profile,内容如下:
[ $UID -eq 0 ] && export PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin
启动dropbear:
dropbear -FE
使用ssh登录成功即可。
本文完。