LFS系统安装镜像制作

LFS系统安装镜像制作

这篇文章介绍如何将已完成的LFS系统制作成安装镜像的一种方式,关于手动安装的过程可以参考另一篇文章 LFS系统手动安装

概述

简介

将制作好的LFS系统制作成安装镜像的方式:

将整个Linux文件系统打包,解压到安装机器的磁盘分区,然后安装内核和Grub引导程序就行了。
这个过程通常需要在一个宿主环境中进行,所以可以使用一个LiveCD启动机器,然后执行这个操作。
这个LiveCD必须提供必要的分区工具和Grub引导程序。

可以使用Ubuntu提供的方法定制一个简单的LiveCD镜像,将LFS系统封装在镜像内部,LiveCD启动后自动执行一段脚本程序自动安装LFS系统。

制作环境

本次制作过程所使用的环境情况如下:

VMware Workstation 11.1.2

Ubuntu 14.04.5 LTS

在VMware中安装Ubuntu系统作为制作环境,所有操作均在这个Ubuntu系统中进行。

基本流程

  1. 构建一个基本系统,这个系统为LiveCD启动之后的最终系统
  2. 为LiveCD最终系统做一些个性化的定制、压缩成squashfs文件系统格式
  3. 配置ISO镜像、引导程序isolinux、封装所需文件到ISO中
  4. 装载镜像文件测试

LiveCD最终系统制作

创建chroot环境

首先进入Ubuntu系统,打开终端。
为了方便起见以下操作全部在root用户下操作,请先切换到root用户:

su -

定义一个环境变量WORK,指向本次实验的工作目录:

export WORK=/opt/work

debootstrap是一个用来构建基本系统的程序,使用这个命令会自动下载一个系统,
这个系统包括Linux文件系统所要求的基本目录结构,我们基于此系统来制作LiveCD的最终系统。
首先安装debootstrap程序:

apt-get install debootstrap

使用debootstrap下载系统,--arch=amd64指定下载64位,trusty为Ubuntu 14.04代号,
chroot为保存目录,最后跟上镜像源地址,
可以更换为较为快速的下载源

mkdir -pv $WORK/chroot

cd $WORK

debootstrap --arch=amd64 trusty chroot http://mirrors.tuna.tsinghua.edu.cn/ubuntu/

如果想安装基于图形界面的环境,请挂载系统的/dev到chroot环境:

mount --bind /dev $WORK/chroot/dev

复制系统中的网络配置、软件包源到chroot环境,以便切换到chroot后能正常安装软件包

cp /etc/hosts $WORK/chroot/etc/hosts
cp /etc/resolv.conf $WORK/chroot/etc/resolv.conf
cp /etc/apt/sources.list $WORK/chroot/etc/apt/sources.list

导入软件源后还需导入密钥,否则进入chroot环境后无法安装软件。
可以使用apt-key exportall导出本机系统所有密钥到文件中,
进入chroot后再用apt-get add导入这个文件中的密钥。

apt-key exportall > $WORK/chroot/key

准备工作差不多了,现在可以从Ubuntu切到chroot环境中了,使用命令:

chroot $WORK/chroot

现在你已经进入了一个虚拟环境中了,请挂载必须的文件系统,定义环境变量:

mount none -t proc /proc
mount none -t sysfs /sys
mount none -t devpts /dev/pts

export HOME=/root
export LC_ALL=C

导入刚才从主机导出来的密钥文件,成功后就可以将密钥文件删除,然后你就能够使用apt-get命令了:

apt-get add key
rm -f key

更新虚拟环境中的软件包,为后续自定义安装过程做一些准备:

apt-get update
apt-get install --yes dbus
dbus-uuidgen > /var/lib/dbus/machine-id
dpkg-divert --local --rename --add /sbin/initctl

ln -s /bin/true /sbin/initctl

如果你愿意,你也可以在此从软件源更新一下软件包信息:

apt-get --yes upgrade

安装Live System所需要的包:

apt-get install --yes ubuntu-standard casper lupin-casper
apt-get install --yes discover laptop-detect os-prober
apt-get install --yes linux-generic

根据自己的需要安装或卸载一些包,例如安装Vim,删除头文件等等,可选

apt-get install --yes vim
apt-get purge --yes linux-header-3.13.0-96
apt-get autoremove

清理chroot环境

所需软件都安装好了,下面开始清理环境,执行清理痕迹、删除垃圾等操作。
如果你安装过软件包,请确保执行命令:

rm /var/lib/dbus/machine-id

rm /sbin/initctl
dpkg-divert --rename --remove /sbin/initctl

虚拟环境中更新操作可能会导致/boot目录下存有多份linux内核文件、
可以通过以下命令移除旧的linux-kernels包,只保留新的。

ls /boot/vmlinuz-3.13.**-**-generic > list.txt
sum=$(cat list.txt | grep '[^ ]' | wc -l)

if [ $sum -gt 1 ]; then
dpkg -l 'linux-*' | sed '/^ii/!d;/'"$(uname -r | sed "s/\(.*\)-\([^0-9]\+\)/\1/")"'/d;s/^[^ ]* [^ ]* \([^ ]*\).*/\1/;/[0-9]/!d' | xargs sudo apt-get -y purge
fi

rm list.txt

根据自己的需要精简一些文件,比如mirrors源信息,man手册、doc文档等,可选

rm -rf /var/lib/apt/lists/mirrors.*
rm -rf /usr/share/man/*
rm -rf /usr/share/doc/*

退出之前清理垃圾:

apt-get clean

rm -rf /tmp/*
rm /etc/resolv.conf

卸载所挂载的文件系统,然后退出虚拟环境:

umount -lf /proc
umount -lf /sys
umount -lf /dev/pts

exit

现在又回到Ubuntu系统中了,如果你之前挂载过系统的/dev目录,现在要卸载掉:

umount $WORK/chroot/dev

CD镜像与配置

安装制作镜像文件所需的程序包

apt-get install syslinux squashfs-tools genisoimage

创建镜像目录结构,最中会压缩image目录中的内容到ISO镜像中

cd $WORK

mkdir -p image/{casper,isolinux,install}

复制内核与initrd文件到镜像目录中:

cp $WORK/chroot/boot/vmlinuz-3.13.**-**-generic $WORK/image/casper/vmlinuz
cp $WORK/chroot/boot/initrd.img-3.13.**-**-generic $WORK/image/casper/initrd.gz

复制Ubuntu系统的isolinux引导程序到镜像目录中:

cp /usr/lib/syslinux/isolinux.bin image/isolinux/
cp /boot/memtest86+.bin image/install/memtest

启动界面

splash.rle图片用来在LiveCD启动的时候显示,splash.jpg图片用来在菜单选择界面当背景显示,
splash.rle文件格式使用如下命令生成:

bmptoppm splash.bmp > splash.ppm

ppmtolss16 '#ffffff=7' < splash.ppm > image/isolinux/splash.rle

cp splash.jpg image/isolinux/

创建boot.msg文件,用来在启动时显示的提示信息,注意第一个字符写入一个特殊字符\x18
用来指示接下来的字符是一个图片文件名。

printf "\x18" > image/isolinux/boot.msg

然后使用追加模式添加如下提示信息,这样splash.rle图片就能显示了:

cat >> image/isolinux/boot.msg << "EOF"
splash.rle

************************************************************************

This is an Ubuntu Remix Live CD.

For the default live system, enter "live". To run memtest86+, enter "memtest"

************************************************************************
EOF

Boot-loader配置文件

LivdCD通过isolinux.bin文件引导启动,然后根据isolinux.cfg配置文件中的内容来加载启动项,
下面创建启动配置文件,关于

cat > image/isolinux/isolinux.cfg << "EOF"
default vesamenu.c32
prompt 0
timeout 100

display boot.msg

menu background splash.jpg
menu title Welcome to Ubuntu LiveCD!
menu color border 0 #ffffffff #00000000
menu color sel 7 #ffffffff #ff000000
menu color title 0 #ffffffff #00000000
menu color tabmsg 0 #ffffffff #00000000
menu color unsel 0 #ffffffff #00000000
menu color hotsel 0 #ff000000 #ffffffff
menu color hotkey 7 #ffffffff #ff000000
menu color scrollbar 0 #ffffffff #00000000

label lfs
  menu label ^Install LFS system
  menu default
  kernel /casper/vmlinuz
  append boot=casper install-lfs initrd=/casper/initrd.gz quiet --
label live
  menu label ^Start Ubuntu Remix LiveCD
  kernel /casper/vmlinuz
  append boot=casper initrd=/casper/initrd.gz quiet --
label check
  menu label ^Check CD for defects
  kernel /casper/vmlinuz
  append boot=casper integrity-check initrd=/casper/initrd.gz quiet --
label memtest
  menu label ^Memory test
  kernel /install/memtest
  append -
label local
  menu label ^Boot from first hard disk
  localboot 0x80
  append -
EOF

上面用到的vesamenu.c32文件,你可以从其它镜像中提取,然后拷贝过来即可

cp vesamenu.c32 image/isolinux/

清单文件

创建清单文件,用来记录系统中所安装的软件信息列表:

chroot chroot dpkg-query -W --showformat='${Package} ${Version}\n' | tee image/casper/filesystem.manifest
cp -v image/casper/filesystem.manifest image/casper/filesystem.manifest-desktop
REMOVE='ubiquity ubiquity-frontend-gtk ubiquity-frontend-kde casper lupin-casper live-initramfs user-setup discover1 xresprobe os-prober libdebian-installer4'
for i in $REMOVE
do
  sed -i "/${i}/d" image/casper/filesystem.manifest-desktop
done

压缩chroot文件系统

压缩chroot系统成squashfs文件系统格式,忽略掉boot目录可以节省一点存储空间:

mksquashfs $WORK/chroot image/casper/filesystem.squashfs -e boot

校验目录大小:

printf $(du -sx --block-size=1 chroot | cut -f1) > image/casper/filesystem.size

diskdefines文件

创建diskdefines文件,定义了一些变量对镜像进行描述

cat > image/README.diskdefines << "EOF"
#define DISKNAME  Ubuntu 14.04 Remix
#define TYPE  binary
#define TYPEbinary  1
#define ARCH  amd64
#define ARCHamd64  1
#define DISKNUM  1
#define DISKNUM1  1
#define TOTALNUM  0
#define TOTALNUM0  1
EOF

额外信息

添加一些记录额外信息的文件和目录,让某些USB设备识别这个镜像

touch image/ubuntu

mkdir image/.disk
cd image/.disk
touch base_installable
echo "full_cd/single" > cd_type
echo "Ubuntu Remix 14.04" > info
echo "http//your-release-notes-url.com" > release_notes_url
cd ../..

封装LFS系统

镜像所需要的文件都已经准备完成,下面来定制一些安装LFS相关的操作。

将现有的LFS文件系统打包成rootfs.tar.gz/boot下的内核文件打包成boot.tar.gz
同时准备一个安装脚本install.sh,下面是一个安装脚本示例:

#!/bin/bash

echo "
**********************************************
*               install start                *
**********************************************
"

PACKAGE=/home/ubuntu/package

# find the disk
DISK=$(fdisk -l 2>/dev/null | grep "^Disk /dev/[shv]d[a-z]" | cut -c6-13 | head -1)
if [ "$DISK" = "" ]; then
  echo "Disk not founded"
  exit 0
else
  echo "Disk is $DISK"
fi

SWAP=$(cat /proc/swaps | grep "$DISK" | awk '{print $1}')
for s in $SWAP; do
  swapoff $s
done

# format disk
echo "format disk $DISK"
dd if=/dev/zero of=$DISK bs=512 count=1 > /dev/null 2>&1

# partition
echo \
"n
p
1

+100M
n
p
2

+2G
n
p
3


w
" | fdisk $DISK > /dev/null 2>&1
sync

BOOT_NUM=1
SWAP_NUM=2
ROOT_NUM=3
DISK_SWAP=${DISK}${SWAP_NUM}
DISK_BOOT=${DISK}${BOOT_NUM}
DISK_ROOT=${DISK}${ROOT_NUM}

# init swap partition
mkswap $DISK_SWAP
# swapon $DISK_SWAP

# init root partition
mkfs -t ext4 $DISK_ROOT > /dev/null 2>&1
mkdir -p /mnt/lfs
mount $DISK_ROOT /mnt/lfs
cd /mnt/lfs
tar zxf $PACKAGE/rootfs.tar.gz
echo "Install Root finished"

# init boot partition
mkfs -t ext4 $DISK_BOOT > /dev/null 2>&1
mkdir -p /mnt/lfs/boot
mount $DISK_BOOT /mnt/lfs/boot
cd /mnt/lfs/boot
tar zxf $PACKAGE/boot.tar.gz
echo "Install Boot finished"

grub-install --root-directory=/mnt/lfs ${DISK}

# init fstab
echo \
"${DISK_ROOT} / ext4 defaults 1 1
${DISK_BOOT} /boot ext4 defaults 1 1
${DISK_SWAP} swap swap pri=1 0 0
proc /proc proc nosuid,noexec,nodev 0 0
sysfs /sys sysfs nosuid,noexec,nodev 0 0
devpts /dev/pts devpts gid=5,mode=620 0 0
tmpfs /run tmpfs defaults 0 0
devtmpfs /dev devtmpfs mode=0755,nosuid 0 0
" > /mnt/lfs/etc/fstab

# init grub.cfg
echo \
"set default=0
set timeout=5
set root=(hd0,${BOOT_NUM})
menuentry \"GNU/Linux, Linux 3.19-lfs-7.7\" {
  linux /vmlinuz-3.19-lfs-7.7 root=${DISK_ROOT} ro
}
" > /mnt/lfs/boot/grub/grub.cfg

# check ip address
check_ip() {
  echo $1 | grep "^\(\(25[0-5]\|2[0-4][0-9]\|1[0-9]\{2\}\|[1-9][0-9]\|[0-9]\)\.\)\{3\}\(25[0-5]\|2[0-4][0-9]\|1[0-9]\{2\}\|[1-9][0-9]\|[0-9]\)$" > /dev/null
  if [ $? -ne 0 ]; then
    return 1
  fi

  ipaddr=$1
  a=$(echo $ipaddr | awk -F'.' '{print $1}')
  b=$(echo $ipaddr | awk -F'.' '{print $2}')
  c=$(echo $ipaddr | awk -F'.' '{print $3}')
  d=$(echo $ipaddr | awk -F'.' '{print $4}')

  for n in $a $b $c $d; do
    if [ $n -gt 255 ] || [ $n -lt 0 ]; then
      return 2
    fi
  done

  return 0
}

# init ip address
NETCARD=$(cat /proc/net/dev | grep "eth" | sed -e "s/^\s*\(eth.*\)\:.*$/\1/")

for NET in $NETCARD; do
  IP=; read -p "Input IP address for $NET: " IP
  check_ip $IP
  while [ $? -ne 0 ]; do
    read -p "Invalid input. ReInput IP address for $NET: " IP
    check_ip $IP
  done

  GATEWAY=; read -p "Input GATEWAY address for $NET: " GATEWAY
  check_ip $GATEWAY
  while [ $? -ne 0 ]; do
    read -p "Invalid input. ReInput GATEWAY address for $NET: " GATEWAY
    check_ip $GATEWAY
  done

  BROADCAST=$(echo "$GATEWAY" | sed -e "s/^\([0-9]\{1,3\}\.[0-9]*\.[0-9]*\)\.[0-9]*$/\1.255/")

  echo \
"ONBOOT=yes
IFACE=$NET
SERVICE=ipv4-static
IP=$IP
GATEWAY=$GATEWAY
PREFIX=24
BROADCAST=$BROADCAST
" > /mnt/lfs/etc/sysconfig/ifconfig.$NET

  mkdir -p /mnt/lfs/etc/sysconfig/network-scripts
  ln -s ../ifconfig.$NET /mnt/lfs/etc/sysconfig/network-scripts/ifcfg-$NET

  echo "Init $NET ip finished"
done

# reset MAC address
rm -f /mnt/lfs/etc/udev/rules.d/70-*

cd /
umount /mnt/lfs/boot
umount /mnt/lfs

echo "
**********************************************
*               install finish               *
**********************************************

The System Will Reboot...
"

sleep 2
reboot

将安装脚本、LFS文件系统、内核文件到复制到镜像目录中:

cd $WORK

mkdir -pv image/packages/package

cp -a ~/install.sh image/packages/
cp -a ~/rootfs.tar.gz image/packages/package/
cp -a ~/boot.tar.gz image/packages/package/

解压image/casper/目录下面的initrd.gz文件,这是一个经过gzip压缩的CPIO格式的归档文件,
解压开来也是一个Linux文件系统,它是Linux系统启动过程中的辅助系统,其根目录下有一个init脚本,
内核启动后会执行这个脚本,来初始化系统运行环境,然后将最终系统挂载到/目录下,
最终系统就运行起来了。

cp -a image/casper/initrd.gz ./
gunzip initrd.gz

mkdir build
cd build

cpio -div < ../initrd
rm -f ../initrd

修改init执行流程中的一个脚本程序,添加上我们自己的初始化过程。
scripts/casper-bottom/ORDER文件记录了脚本的执行顺序,
我们在最后追加自己的脚本:

cat >> scripts/casper-bottom/ORDER << "EOF"
/scripts/casper-bottom/99custom_init
[ -e /conf/param.conf ] && . /conf/param.conf
EOF

下面来创建99custom_init这个文件:

cat > scripts/casper-bottom/99custom_init << "EOF"
#!/bin/sh

RCFILE=/root/cdrom/packages/rc.local

if grep -q install-lfs /proc/cmdline; then
    if [ -f $RCFILE ]; then
        cp -af $RCFILE /root/etc/
    fi
fi
EOF

chmod a+x scripts/casper-bottom/99custom_init

99custom_init所做的工作很简单,仅仅是判断一下用户是否选则的菜单项是否是安装LFS系统,
如果是就把镜像中的rc.local拷贝到/etc下。
LiveCD启动后image目录会被挂载到/root/cdrom

重新压缩initrd.gz文件:

find .|cpio -o -H newc|gzip -9 > ../image/casper/initrd.gz
cd ..

这样做的好处是以后不用解压文件系统了,可以直接修改image/packages下的脚本程序就能修改初始化过程了。

分别创建rc.local.profile文件,在其中添加安装LFS前的初始化操作

cat > image/packages/rc.local << "EOF"
cp -af /cdrom/packages/* /home/ubuntu/
cat /cdrom/packages/.profile >> /home/ubuntu/.profile

exit 0
EOF

chmod a+x image/packages/rc.local
cat > image/packages/.profile << "EOF"
if [ -f ~/install.sh ]; then
    sudo sh ~/install.sh
fi
EOF

packages/.profile里的内容被追加到用户家目录下的.profile中,这样用户一登陆就能够执行了。

生成镜像

计算MD5

pushd image
find . -type f -print0 | xargs -0 md5sum | grep -v "\./md5sum.txt" > md5sum.txt
popd

创建LiveCD镜像

pushd image
mkisofs -r -V "LiveCD-x86_64" -cache-inodes -J -l -b isolinux/isolinux.bin \
    -c isolinux/boot.cat -no-emul-boot -boot-load-size 4 -boot-info-table \
    -o ../LiveCD-x86_64.iso .
popd

至此LiveCD镜像文件制作完毕,使用虚拟机测试一下。

参考文档

LiveCDCustomizationFromScratch

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值