396 lines
12 KiB
Bash
396 lines
12 KiB
Bash
#!/bin/bash
|
|
|
|
set -e
|
|
|
|
__usage="
|
|
Usage: build-image [OPTIONS]
|
|
Build raspberrypi image.
|
|
|
|
Options:
|
|
-d, --dir DIR The directory for storing the image and other temporary files, which defaults to be the directory in which the script resides. If the DIR does not exist, it will be created automatically.
|
|
-r, --repo REPO_INFO Required! The URL/path of target repo file or list of repo's baseurls which should be a space separated list.
|
|
-n, --name IMAGE_NAME The raspberrypi image name to be built.
|
|
-s, --spec SPEC The image's specification: headless, xfce, ukui, dde, gnome, devstation or the file path of rpmlist. The default is headless.
|
|
-h, --help Show command help.
|
|
"
|
|
|
|
help()
|
|
{
|
|
echo "$__usage"
|
|
exit $1
|
|
}
|
|
|
|
parseargs()
|
|
{
|
|
if [ "x$#" == "x0" ]; then
|
|
return 1
|
|
fi
|
|
|
|
while [ "x$#" != "x0" ];
|
|
do
|
|
if [ "x$1" == "x-h" -o "x$1" == "x--help" ]; then
|
|
return 1
|
|
elif [ "x$1" == "x" ]; then
|
|
shift
|
|
elif [ "x$1" == "x-r" -o "x$1" == "x--repo" ]; then
|
|
repo_file=`echo $2`
|
|
shift
|
|
shift
|
|
elif [ "x$1" == "x-n" -o "x$1" == "x--name" ]; then
|
|
img_name=`echo $2`
|
|
shift
|
|
shift
|
|
elif [ "x$1" == "x-d" -o "x$1" == "x--dir" ]; then
|
|
workdir=`echo $2`
|
|
shift
|
|
shift
|
|
elif [ "x$1" == "x-s" -o "x$1" == "x--spec" ]; then
|
|
spec_param=`echo $2`
|
|
shift
|
|
shift
|
|
else
|
|
echo `date` - ERROR, UNKNOWN params "$@"
|
|
return 2
|
|
fi
|
|
done
|
|
}
|
|
|
|
ERROR(){
|
|
echo `date` - ERROR, $* | tee -a ${log_dir}/${builddate}.log
|
|
}
|
|
|
|
LOG(){
|
|
echo `date` - INFO, $* | tee -a ${log_dir}/${builddate}.log
|
|
}
|
|
|
|
UMOUNT_ALL(){
|
|
set +e
|
|
if grep -q "${rootfs_dir}/dev " /proc/mounts ; then
|
|
umount -l ${rootfs_dir}/dev
|
|
fi
|
|
if grep -q "${rootfs_dir}/proc " /proc/mounts ; then
|
|
umount -l ${rootfs_dir}/proc
|
|
fi
|
|
if grep -q "${rootfs_dir}/sys " /proc/mounts ; then
|
|
umount -l ${rootfs_dir}/sys
|
|
fi
|
|
set -e
|
|
}
|
|
|
|
LOSETUP_D_IMG(){
|
|
set +e
|
|
if [ -d ${root_mnt} ]; then
|
|
if grep -q "${root_mnt} " /proc/mounts ; then
|
|
umount ${root_mnt}
|
|
fi
|
|
fi
|
|
if [ -d ${boot_mnt} ]; then
|
|
if grep -q "${boot_mnt} " /proc/mounts ; then
|
|
umount ${boot_mnt}
|
|
fi
|
|
fi
|
|
if [ "x$device" != "x" ]; then
|
|
kpartx -d ${device}
|
|
losetup -d ${device}
|
|
device=""
|
|
fi
|
|
if [ -d ${root_mnt} ]; then
|
|
rm -rf ${root_mnt}
|
|
fi
|
|
if [ -d ${boot_mnt} ]; then
|
|
rm -rf ${boot_mnt}
|
|
fi
|
|
set -e
|
|
}
|
|
|
|
INSTALL_PACKAGES(){
|
|
for item in $(cat $1)
|
|
do
|
|
dnf --installroot=${rootfs_dir}/ install -y $item
|
|
if [ $? == 0 ]; then
|
|
LOG install $item.
|
|
else
|
|
ERROR can not install $item.
|
|
fi
|
|
done
|
|
}
|
|
|
|
prepare(){
|
|
if [ ! -d ${tmp_dir} ]; then
|
|
mkdir -p ${tmp_dir}
|
|
else
|
|
rm -rf ${tmp_dir}/*
|
|
fi
|
|
if [ "x$spec_param" == "xheadless" ] || [ "x$spec_param" == "x" ]; then
|
|
:
|
|
elif [ "x$spec_param" == "xxfce" ] || [ "x$spec_param" == "xukui" ] || [ "x$spec_param" == "xdde" ] || [ "x$spec_param" == "xgnome" ] || [ "x$spec_param" == "xdevstation" ]; then
|
|
CONFIG_RPM_LIST=${euler_dir}/rpmlist-${spec_param}
|
|
elif [ -f ${spec_param} ]; then
|
|
cp ${spec_param} ${tmp_dir}/
|
|
spec_file_name=${spec_param##*/}
|
|
CONFIG_RPM_LIST=${tmp_dir}/${spec_file_name}
|
|
else
|
|
echo `date` - ERROR, please check your params in option -s or --spec.
|
|
exit 2
|
|
fi
|
|
if [ "x$repo_file" == "x" ] ; then
|
|
echo `date` - ERROR, \"-r REPO_INFO or --repo REPO_INFO\" missing.
|
|
help 2
|
|
elif [ "x${repo_file:0:4}" == "xhttp" ]; then
|
|
if [ "x${repo_file:0-5}" == "x.repo" ]; then
|
|
wget ${repo_file} -P ${tmp_dir}/
|
|
repo_file_name=${repo_file##*/}
|
|
repo_file=${tmp_dir}/${repo_file_name}
|
|
else
|
|
repo_file_name=tmp.repo
|
|
repo_file_tmp=${tmp_dir}/${repo_file_name}
|
|
index=1
|
|
for baseurl in ${repo_file// / }
|
|
do
|
|
echo [repo${index}] >> ${repo_file_tmp}
|
|
echo name=repo${index} to build raspi image >> ${repo_file_tmp}
|
|
echo baseurl=${baseurl} >> ${repo_file_tmp}
|
|
echo enabled=1 >> ${repo_file_tmp}
|
|
echo gpgcheck=0 >> ${repo_file_tmp}
|
|
echo >> ${repo_file_tmp}
|
|
index=$(($index+1))
|
|
done
|
|
repo_file=${repo_file_tmp}
|
|
fi
|
|
else
|
|
if [ ! -f $repo_file ]; then
|
|
echo `date` - ERROR, repo file $repo_file can not be found.
|
|
exit 2
|
|
else
|
|
cp $repo_file ${tmp_dir}/
|
|
repo_file_name=${repo_file##*/}
|
|
repo_file=${tmp_dir}/${repo_file_name}
|
|
fi
|
|
fi
|
|
|
|
repo_suffix=${repo_file_name%.*}
|
|
if [ "x$img_name" == "x" ]; then
|
|
if [[ "${repo_suffix}" =~ ^${OS_NAME}.* ]]; then
|
|
img_name=${repo_suffix}
|
|
else
|
|
img_name=${OS_NAME}
|
|
fi
|
|
img_name=${img_name}-raspi-aarch64.img
|
|
else
|
|
if [ "x${img_name:0-4}" != "x.img" ]; then
|
|
img_name=${img_name}.img
|
|
fi
|
|
fi
|
|
img_file=${img_dir}/${img_name}
|
|
|
|
if [ ! -d ${log_dir} ]; then
|
|
mkdir -p ${log_dir}
|
|
fi
|
|
LOG "prepare begin..."
|
|
dnf clean all
|
|
dnf makecache
|
|
dnf install -y dnf-plugins-core rsync parted dosfstools grep bash xz kpartx
|
|
|
|
if [ -d ${rootfs_dir} ]; then
|
|
rm -rf ${rootfs_dir}
|
|
fi
|
|
if [ ! -d ${img_dir} ]; then
|
|
mkdir -p ${img_dir}
|
|
fi
|
|
|
|
repo_info_names=`cat ${repo_file} | grep "^\["`
|
|
repo_baseurls=`cat ${repo_file} | grep "^baseurl="`
|
|
index=1
|
|
for repo_name in ${repo_info_names}
|
|
do
|
|
repo_name_list[$index]=${repo_name:1:-1}
|
|
index=$((index+1))
|
|
done
|
|
index=1
|
|
for baseurl in ${repo_baseurls}
|
|
do
|
|
repo_info="${repo_info} --repofrompath ${repo_name_list[$index]}-tmp,${baseurl:8}"
|
|
index=$((index+1))
|
|
done
|
|
set +e
|
|
os_release_name=${OS_NAME}-release
|
|
dnf ${repo_info} --disablerepo="*" --downloaddir=${tmp_dir}/ download ${os_release_name}
|
|
if [ $? != 0 ]; then
|
|
ERROR "Fail to download ${os_release_name}!"
|
|
exit 2
|
|
fi
|
|
os_release_name=`ls -r ${tmp_dir}/${os_release_name}*.rpm 2>/dev/null| head -n 1`
|
|
if [ -z "${os_release_name}" ]; then
|
|
ERROR "${os_release_name} can not be found!"
|
|
exit 2
|
|
fi
|
|
set -e
|
|
LOG "prepare end."
|
|
}
|
|
|
|
make_rootfs(){
|
|
LOG "make rootfs for ${repo_file} begin..."
|
|
if [[ -d ${rootfs_dir} ]]; then
|
|
UMOUNT_ALL
|
|
rm -rf ${rootfs_dir}
|
|
fi
|
|
mkdir -p ${rootfs_dir}/var/lib/rpm
|
|
rpm --root ${rootfs_dir} --initdb
|
|
rpm -ivh --nodeps --root ${rootfs_dir}/ ${os_release_name}
|
|
mkdir -p ${rootfs_dir}/etc/rpm
|
|
chmod a+rX ${rootfs_dir}/etc/rpm
|
|
echo "%_install_langs en_US" > ${rootfs_dir}/etc/rpm/macros.image-language-conf
|
|
if [[ ! -d ${rootfs_dir}/etc/yum.repos.d ]]; then
|
|
mkdir -p ${rootfs_dir}/etc/yum.repos.d
|
|
fi
|
|
cp ${repo_file} ${rootfs_dir}/etc/yum.repos.d/tmp.repo
|
|
dnf --installroot=${rootfs_dir}/ makecache
|
|
set +e
|
|
INSTALL_PACKAGES $CONFIG_RPM_LIST
|
|
cat ${rootfs_dir}/etc/systemd/timesyncd.conf | grep "^NTP=*"
|
|
if [ $? -ne 0 ]; then
|
|
sed -i -e '/^#NTP=/cNTP=0.cn.pool.ntp.org' ${rootfs_dir}/etc/systemd/timesyncd.conf
|
|
sed -i -e 's/#FallbackNTP=/FallbackNTP=1.asia.pool.ntp.org 2.asia.pool.ntp.org /g' ${rootfs_dir}/etc/systemd/timesyncd.conf
|
|
fi
|
|
set -e
|
|
cp ${euler_dir}/hosts ${rootfs_dir}/etc/hosts
|
|
if [ ! -d $rootfs_dir/etc/sysconfig/network-scripts ]; then
|
|
mkdir -p $rootfs_dir/etc/sysconfig/network-scripts
|
|
fi
|
|
cp ${euler_dir}/ifcfg-eth0 $rootfs_dir/etc/sysconfig/network-scripts/ifcfg-eth0
|
|
mkdir -p ${rootfs_dir}/lib/udev/rules.d
|
|
if [ ! -d ${rootfs_dir}/usr/share/licenses/raspi ]; then
|
|
mkdir -p ${rootfs_dir}/usr/share/licenses/raspi
|
|
fi
|
|
cp ${euler_dir}/*.rules ${rootfs_dir}/lib/udev/rules.d/
|
|
cp ${euler_dir}/LICENCE.* ${rootfs_dir}/usr/share/licenses/raspi/
|
|
cp ${euler_dir}/chroot.sh ${rootfs_dir}/chroot.sh
|
|
if [ ! -d ${rootfs_dir}/etc/rc.d/init.d ]; then
|
|
mkdir -p ${rootfs_dir}/etc/rc.d/init.d
|
|
fi
|
|
cp ${euler_dir}/extend-root.sh ${rootfs_dir}/etc/rc.d/init.d/extend-root.sh
|
|
echo net.ipv4.conf.wlan0.rp_filter=0 >> ${rootfs_dir}/etc/sysctl.conf
|
|
chmod +x ${rootfs_dir}/chroot.sh
|
|
mount --bind /dev ${rootfs_dir}/dev
|
|
mount -t proc /proc ${rootfs_dir}/proc
|
|
mount -t sysfs /sys ${rootfs_dir}/sys
|
|
chroot ${rootfs_dir} /bin/bash -c "echo 'Y' | /chroot.sh ${spec_param}"
|
|
UMOUNT_ALL
|
|
rm ${rootfs_dir}/etc/yum.repos.d/tmp.repo
|
|
rm ${rootfs_dir}/chroot.sh
|
|
LOG "make rootfs for ${repo_file} end."
|
|
}
|
|
|
|
make_img(){
|
|
LOG "make ${img_file} begin..."
|
|
device=""
|
|
LOSETUP_D_IMG
|
|
size=`du -sh --block-size=1MiB ${rootfs_dir} | cut -f 1 | xargs`
|
|
size=$(($size+1500))
|
|
losetup -D
|
|
dd if=/dev/zero of=${img_file} bs=1MiB count=$size && sync
|
|
parted ${img_file} mklabel msdos mkpart primary fat32 8192s 593919s
|
|
parted ${img_file} -s set 1 boot
|
|
parted ${img_file} mkpart primary linux-swap 593920s 1593343s
|
|
parted ${img_file} mkpart primary ext4 1593344s 100%
|
|
device=`losetup -f --show -P ${img_file}`
|
|
LOG "after losetup: ${device}"
|
|
trap 'LOSETUP_D_IMG' EXIT
|
|
LOG "image ${img_file} created and mounted as ${device}"
|
|
kpartx -va ${device}
|
|
loopX=${device##*\/}
|
|
partprobe ${device}
|
|
bootp=/dev/mapper/${loopX}p1
|
|
swapp=/dev/mapper/${loopX}p2
|
|
rootp=/dev/mapper/${loopX}p3
|
|
LOG "bootp: " ${bootp} "rootp: " ${rootp}
|
|
mkfs.vfat -n boot ${bootp}
|
|
mkswap ${swapp} --pagesize 4096
|
|
mkfs.ext4 ${rootp}
|
|
mkdir -p ${root_mnt} ${boot_mnt}
|
|
mount -t vfat -o uid=root,gid=root,umask=0000 ${bootp} ${boot_mnt}
|
|
mount -t ext4 ${rootp} ${root_mnt}
|
|
prefix_len=${#loopX}
|
|
let prefix_len=prefix_len+13
|
|
fstab_array=("" "" "" "")
|
|
for line in `blkid | grep /dev/mapper/${loopX}p`
|
|
do
|
|
partuuid=${line#*PARTUUID=\"}
|
|
fstab_array[${line:$prefix_len:1}]=${partuuid%%\"*}
|
|
done
|
|
echo "PARTUUID=${fstab_array[3]} / ext4 defaults,noatime 0 0" > ${rootfs_dir}/etc/fstab
|
|
echo "PARTUUID=${fstab_array[1]} /boot vfat defaults,noatime 0 0" >> ${rootfs_dir}/etc/fstab
|
|
echo "PARTUUID=${fstab_array[2]} swap swap defaults,noatime 0 0" >> ${rootfs_dir}/etc/fstab
|
|
|
|
if [ -d ${rootfs_dir}/boot/grub2 ]; then
|
|
rm -rf ${rootfs_dir}/boot/grub2
|
|
fi
|
|
cp -a ${rootfs_dir}/boot/* ${boot_mnt}/
|
|
cp ${euler_dir}/config.txt ${boot_mnt}/
|
|
echo "console=serial0,115200 console=tty1 root=PARTUUID=${fstab_array[3]} rootfstype=ext4 elevator=deadline rootwait net.ifnames=0" > ${boot_mnt}/cmdline.txt
|
|
|
|
rm -rf ${rootfs_dir}/boot
|
|
rsync -avHAXq ${rootfs_dir}/* ${root_mnt}
|
|
sync
|
|
sleep 10
|
|
LOSETUP_D_IMG
|
|
rm -rf ${rootfs_dir}
|
|
losetup -D
|
|
pushd ${img_dir}
|
|
if [ -f ${img_file} ]; then
|
|
sha256sum $(basename ${img_file}) > ${img_file}.sha256sum
|
|
xz -T 20 -z -c ${img_file} > ${img_file}.xz
|
|
sha256sum $(basename ${img_file}.xz) > ${img_file}.xz.sha256sum
|
|
LOG "made sum files for ${img_file}"
|
|
fi
|
|
popd
|
|
LOG "write ${img_file} done."
|
|
LOG "make ${img_file} end."
|
|
}
|
|
|
|
if [ "$EUID" -ne 0 ]; then
|
|
echo `date` - ERROR, Please run as root!
|
|
exit
|
|
fi
|
|
|
|
cur_dir=$(cd $(dirname $0);pwd)
|
|
workdir=${cur_dir}
|
|
|
|
parseargs "$@" || help $?
|
|
|
|
if [ "x$workdir" == "x" ]; then
|
|
echo `date` - ERROR, \"-d DIR or --dir DIR\" missing.
|
|
help 2
|
|
elif [ ! -d ${workdir} ]; then
|
|
echo `date` - INFO, output dir ${workdir} does not exists.
|
|
mkdir -p ${workdir}
|
|
echo `date` - INFO, output dir: ${workdir} created.
|
|
fi
|
|
|
|
OS_NAME=openEuler
|
|
|
|
workdir=$(cd $workdir; pwd)
|
|
if [ "x${workdir}" == "x/" ]; then
|
|
workdir=/raspi_output
|
|
else
|
|
workdir=${workdir}/raspi_output
|
|
fi
|
|
|
|
tmp_dir=${workdir}/tmp
|
|
log_dir=${workdir}/log
|
|
img_dir=${workdir}/img
|
|
rootfs_dir=${workdir}/rootfs
|
|
root_mnt=${workdir}/root
|
|
boot_mnt=${workdir}/boot
|
|
euler_dir=${cur_dir}/config
|
|
|
|
CONFIG_RPM_LIST=${euler_dir}/rpmlist
|
|
builddate=$(date +%Y%m%d)
|
|
|
|
trap 'UMOUNT_ALL' EXIT
|
|
UMOUNT_ALL
|
|
prepare
|
|
IFS=$'\n'
|
|
make_rootfs
|
|
make_img
|