|
| 1 | +#!/bin/bash |
| 2 | + |
| 3 | +set -e |
| 4 | + |
| 5 | +# Install dependencies in host system |
| 6 | +apt-get update |
| 7 | +apt-get install -y --no-install-recommends ubuntu-keyring ca-certificates debootstrap git qemu-user-static qemu-utils qemu-system-arm binfmt-support parted kpartx rsync dosfstools xz-utils |
| 8 | + |
| 9 | +# Make sure cross-running ARM ELF executables is enabled |
| 10 | +update-binfmts --enable |
| 11 | + |
| 12 | +rootdir=`pwd` |
| 13 | +basedir=`pwd`/artifacts/elementary-rpi |
| 14 | + |
| 15 | +# Free space on rootfs in MiB |
| 16 | +free_space="500" |
| 17 | + |
| 18 | +export packages="elementary-minimal elementary-desktop elementary-standard" |
| 19 | +export architecture="arm64" |
| 20 | +export codename="focal" |
| 21 | +export channel="daily" |
| 22 | + |
| 23 | +version=6.0 |
| 24 | +YYYYMMDD="$(date +%Y%m%d)" |
| 25 | +imagename=elementaryos-$version-$channel-rpi-$YYYYMMDD |
| 26 | + |
| 27 | +mkdir -p ${basedir} |
| 28 | +cd ${basedir} |
| 29 | + |
| 30 | +# Bootstrap an ubuntu minimal system |
| 31 | +debootstrap --foreign --arch $architecture $codename elementary-$architecture http://ports.ubuntu.com/ubuntu-ports |
| 32 | + |
| 33 | +# Add the QEMU emulator for running ARM executables |
| 34 | +cp /usr/bin/qemu-arm-static elementary-$architecture/usr/bin/ |
| 35 | + |
| 36 | +# Run the second stage of the bootstrap in QEMU |
| 37 | +LANG=C chroot elementary-$architecture /debootstrap/debootstrap --second-stage |
| 38 | + |
| 39 | +# Copy Raspberry Pi specific files |
| 40 | +cp -r ${rootdir}/rpi/rootfs/writable/* elementary-${architecture}/ |
| 41 | + |
| 42 | +# Add the rest of the ubuntu repos |
| 43 | +cat << EOF > elementary-$architecture/etc/apt/sources.list |
| 44 | +deb http://ports.ubuntu.com/ubuntu-ports $codename main restricted universe multiverse |
| 45 | +deb http://ports.ubuntu.com/ubuntu-ports $codename-updates main restricted universe multiverse |
| 46 | +EOF |
| 47 | + |
| 48 | +# Copy in the elementary PPAs/keys/apt config |
| 49 | +for f in ${rootdir}/etc/config/archives/*.list; do cp -- "$f" "elementary-$architecture/etc/apt/sources.list.d/$(basename -- $f)"; done |
| 50 | +for f in ${rootdir}/etc/config/archives/*.key; do cp -- "$f" "elementary-$architecture/etc/apt/trusted.gpg.d/$(basename -- $f).asc"; done |
| 51 | +for f in ${rootdir}/etc/config/archives/*.pref; do cp -- "$f" "elementary-$architecture/etc/apt/preferences.d/$(basename -- $f)"; done |
| 52 | + |
| 53 | +# Set codename/channel in added repos |
| 54 | +sed -i "s/@CHANNEL/$channel/" elementary-$architecture/etc/apt/sources.list.d/*.list* |
| 55 | +sed -i "s/@BASECODENAME/$codename/" elementary-$architecture/etc/apt/sources.list.d/*.list* |
| 56 | + |
| 57 | +# Set codename in added preferences |
| 58 | +sed -i "s/@BASECODENAME/$codename/" elementary-$architecture/etc/apt/preferences.d/*.pref* |
| 59 | + |
| 60 | +echo "elementary" > elementary-$architecture/etc/hostname |
| 61 | + |
| 62 | +cat << EOF > elementary-${architecture}/etc/hosts |
| 63 | +127.0.0.1 elementary localhost |
| 64 | +::1 localhost ip6-localhost ip6-loopback |
| 65 | +fe00::0 ip6-localnet |
| 66 | +ff00::0 ip6-mcastprefix |
| 67 | +ff02::1 ip6-allnodes |
| 68 | +ff02::2 ip6-allrouters |
| 69 | +EOF |
| 70 | + |
| 71 | +# Configure mount points |
| 72 | +cat << EOF > elementary-${architecture}/etc/fstab |
| 73 | +# <file system> <mount point> <type> <options> <dump> <pass> |
| 74 | +proc /proc proc nodev,noexec,nosuid 0 0 |
| 75 | +LABEL=writable / ext4 defaults 0 0 |
| 76 | +LABEL=system-boot /boot/firmware vfat defaults 0 1 |
| 77 | +EOF |
| 78 | + |
| 79 | +export LC_ALL=C |
| 80 | +export DEBIAN_FRONTEND=noninteractive |
| 81 | +# Config to stop flash-kernel trying to detect the hardware in chroot |
| 82 | +export FK_MACHINE=none |
| 83 | + |
| 84 | +mount -t proc proc elementary-$architecture/proc |
| 85 | +mount -o bind /dev/ elementary-$architecture/dev/ |
| 86 | +mount -o bind /dev/pts elementary-$architecture/dev/pts |
| 87 | + |
| 88 | +# Make a third stage that installs all of the metapackages |
| 89 | +cat << EOF > elementary-$architecture/third-stage |
| 90 | +#!/bin/bash |
| 91 | +apt-get update |
| 92 | +apt-get --yes upgrade |
| 93 | +apt-get --yes install $packages |
| 94 | +
|
| 95 | +rm -f /third-stage |
| 96 | +EOF |
| 97 | + |
| 98 | +chmod +x elementary-$architecture/third-stage |
| 99 | +LANG=C chroot elementary-$architecture /third-stage |
| 100 | + |
| 101 | + |
| 102 | +# Install Raspberry Pi specific packages |
| 103 | +cat << EOF > elementary-$architecture/hardware |
| 104 | +#!/bin/bash |
| 105 | +
|
| 106 | +# Make a dummy folder for the boot partition so packages install properly, |
| 107 | +# we'll recreate it on the actual partition later |
| 108 | +mkdir -p /boot/firmware |
| 109 | +
|
| 110 | +apt-get --yes install linux-image-raspi linux-firmware-raspi2 |
| 111 | +
|
| 112 | +rm -rf /boot/firmware |
| 113 | +
|
| 114 | +rm -f hardware |
| 115 | +EOF |
| 116 | + |
| 117 | +chmod +x elementary-$architecture/hardware |
| 118 | +LANG=C chroot elementary-$architecture /hardware |
| 119 | + |
| 120 | +# Copy in any file overrides |
| 121 | +cp -r ${rootdir}/etc/config/includes.chroot/* elementary-$architecture/ |
| 122 | + |
| 123 | +mkdir elementary-$architecture/hooks |
| 124 | +cp ${rootdir}/etc/config/hooks/live/*.chroot elementary-$architecture/hooks |
| 125 | + |
| 126 | +for f in elementary-$architecture/hooks/* |
| 127 | +do |
| 128 | + base=`basename ${f}` |
| 129 | + LANG=C chroot elementary-$architecture "/hooks/${base}" |
| 130 | +done |
| 131 | + |
| 132 | +rm -r "elementary-$architecture/hooks" |
| 133 | + |
| 134 | +# Add a oneshot service to grow the rootfs on first boot |
| 135 | +install -m 755 -o root -g root ${rootdir}/rpi/files/resizerootfs "elementary-$architecture/usr/sbin/resizerootfs" |
| 136 | +install -m 644 -o root -g root ${rootdir}/pinebookpro/files/resizerootfs.service "elementary-$architecture/etc/systemd/system" |
| 137 | +mkdir -p "elementary-$architecture/etc/systemd/system/systemd-remount-fs.service.requires/" |
| 138 | +ln -s /etc/systemd/system/resizerootfs.service "elementary-$architecture/etc/systemd/system/systemd-remount-fs.service.requires/resizerootfs.service" |
| 139 | + |
| 140 | + |
| 141 | +# Support for kernel updates on the Pi 400 |
| 142 | +cat << EOF >> elementary-$architecture/etc/flash-kernel/db |
| 143 | +
|
| 144 | +Machine: Raspberry Pi 400 Rev 1.0 |
| 145 | +Method: pi |
| 146 | +Kernel-Flavors: raspi raspi2 |
| 147 | +DTB-Id: bcm2711-rpi-4-b.dtb |
| 148 | +U-Boot-Script-Name: bootscr.rpi |
| 149 | +Required-Packages: u-boot-tools |
| 150 | +EOF |
| 151 | + |
| 152 | +# Calculate the space to create the image. |
| 153 | +root_size=$(du -s -B1K elementary-$architecture | cut -f1) |
| 154 | +raw_size=$(($((${free_space}*1024))+${root_size})) |
| 155 | + |
| 156 | +# Create the disk and partition it |
| 157 | +echo "Creating image file" |
| 158 | + |
| 159 | +# Sometimes fallocate fails if the filesystem or location doesn't support it, fallback to slower dd in this case |
| 160 | +if ! fallocate -l $(echo ${raw_size}Ki | numfmt --from=iec-i --to=si --format=%.1f) ${basedir}/${imagename}.img |
| 161 | +then |
| 162 | + dd if=/dev/zero of=${basedir}/${imagename}.img bs=1024 count=${raw_size} |
| 163 | +fi |
| 164 | + |
| 165 | +parted ${imagename}.img --script -- mklabel msdos |
| 166 | +parted ${imagename}.img --script -- mkpart primary fat32 0 256 |
| 167 | +parted ${imagename}.img --script -- mkpart primary ext4 256 -1 |
| 168 | + |
| 169 | +# Set the partition variables |
| 170 | +loopdevice=`losetup -f --show ${basedir}/${imagename}.img` |
| 171 | +device=`kpartx -va $loopdevice| sed -E 's/.*(loop[0-9])p.*/\1/g' | head -1` |
| 172 | +device="/dev/mapper/${device}" |
| 173 | +bootp=${device}p1 |
| 174 | +rootp=${device}p2 |
| 175 | + |
| 176 | +# Create file systems |
| 177 | +mkfs.vfat -n system-boot $bootp |
| 178 | +mkfs.ext4 -L writable $rootp |
| 179 | + |
| 180 | +# Create the dirs for the partitions and mount them |
| 181 | +mkdir -p ${basedir}/bootp ${basedir}/root |
| 182 | +mount -t vfat $bootp ${basedir}/bootp |
| 183 | +mount $rootp ${basedir}/root |
| 184 | + |
| 185 | +mkdir -p elementary-$architecture/boot/firmware |
| 186 | +mount -o bind ${basedir}/bootp/ elementary-$architecture/boot/firmware |
| 187 | + |
| 188 | +# Copy Raspberry Pi specific files |
| 189 | +cp -r ${rootdir}/rpi/rootfs/system-boot/* elementary-${architecture}/boot/firmware/ |
| 190 | + |
| 191 | +# Copy kernels and firemware to boot partition |
| 192 | +cat << EOF > elementary-$architecture/hardware |
| 193 | +#!/bin/bash |
| 194 | +
|
| 195 | +cp /boot/vmlinuz /boot/firmware/vmlinuz |
| 196 | +cp /boot/initrd.img /boot/firmware/initrd.img |
| 197 | +
|
| 198 | +# Copy device-tree blobs to fat32 partition |
| 199 | +cp -r /lib/firmware/*-raspi/device-tree/broadcom/* /boot/firmware/ |
| 200 | +cp -r /lib/firmware/*-raspi/device-tree/overlays /boot/firmware/ |
| 201 | +
|
| 202 | +rm -f hardware |
| 203 | +EOF |
| 204 | + |
| 205 | +chmod +x elementary-$architecture/hardware |
| 206 | +LANG=C chroot elementary-$architecture /hardware |
| 207 | + |
| 208 | +# Grab some updated firmware from the Raspberry Pi foundation |
| 209 | +git clone -b '1.20201022' --single-branch --depth 1 https://github.com/raspberrypi/firmware raspi-firmware |
| 210 | +cp raspi-firmware/boot/*.elf ${basedir}/bootp/ |
| 211 | +cp raspi-firmware/boot/*.dat ${basedir}/bootp/ |
| 212 | +cp raspi-firmware/boot/bootcode.bin ${basedir}/bootp/ |
| 213 | + |
| 214 | +umount elementary-$architecture/dev/pts |
| 215 | +umount elementary-$architecture/dev/ |
| 216 | +umount elementary-$architecture/proc |
| 217 | +umount elementary-$architecture/boot/firmware |
| 218 | + |
| 219 | +echo "Rsyncing rootfs into image file" |
| 220 | +rsync -HPavz -q ${basedir}/elementary-$architecture/ ${basedir}/root/ |
| 221 | + |
| 222 | +# Unmount partitions |
| 223 | +umount $bootp |
| 224 | +umount $rootp |
| 225 | +kpartx -dv $loopdevice |
| 226 | +losetup -d $loopdevice |
| 227 | + |
| 228 | +echo "Compressing ${imagename}.img" |
| 229 | +xz -T0 -z ${basedir}/${imagename}.img |
| 230 | + |
| 231 | +cd "${basedir}" |
| 232 | + |
| 233 | +md5sum ${imagename}.img.xz > ${imagename}.md5.txt |
| 234 | +sha256sum ${imagename}.img.xz > ${imagename}.sha256.txt |
| 235 | + |
| 236 | +cd "${rootdir}" |
| 237 | + |
| 238 | +KEY="$1" |
| 239 | +SECRET="$2" |
| 240 | +ENDPOINT="$3" |
| 241 | +BUCKET="$4" |
| 242 | +IMGPATH="${basedir}"/${imagename}.img.xz |
| 243 | +IMGNAME=${channel}-rpi/$(basename "$IMGPATH") |
| 244 | + |
| 245 | +apt-get install -y curl python3 python3-distutils |
| 246 | + |
| 247 | +curl https://bootstrap.pypa.io/get-pip.py -o get-pip.py |
| 248 | +python3 get-pip.py |
| 249 | +pip install boto3 |
| 250 | + |
| 251 | +python3 upload.py "$KEY" "$SECRET" "$ENDPOINT" "$BUCKET" "$IMGPATH" "$IMGNAME" || exit 1 |
| 252 | + |
| 253 | +CHECKSUMPATH="${basedir}"/${imagename}.md5.txt |
| 254 | +CHECKSUMNAME=${channel}-rpi/$(basename "$CHECKSUMPATH") |
| 255 | + |
| 256 | +python3 upload.py "$KEY" "$SECRET" "$ENDPOINT" "$BUCKET" "$CHECKSUMPATH" "$CHECKSUMNAME" || exit 1 |
| 257 | + |
| 258 | +CHECKSUMPATH="${basedir}"/${imagename}.sha256.txt |
| 259 | +CHECKSUMNAME=${channel}-rpi/$(basename "$CHECKSUMPATH") |
| 260 | + |
| 261 | +python3 upload.py "$KEY" "$SECRET" "$ENDPOINT" "$BUCKET" "$CHECKSUMPATH" "$CHECKSUMNAME" || exit 1 |
0 commit comments