Skip to content
Snippets Groups Projects
Commit e81b411c authored by Thomas Schneider's avatar Thomas Schneider
Browse files

Remodel for kiosk raspi setup

parent 65255327
No related branches found
No related tags found
No related merge requests found
/image.sqfs
/initramfs-virt
/vmlinuz-virt
/apk-cache
apk-cache
root.img
boot.tar
IMAGE=docker.io/library/alpine
TAG=3.18
TAG=3.19
ARCH=arm64
image.sqfs:
podman run --rm --volume $$PWD:/build --workdir /build \
image:
podman run --arch $(ARCH) \
--rm --volume $$PWD:/build --workdir /build \
$(IMAGE):$(TAG) \
./make-image.sh
.PHONY: image.sqfs
./make-image.sh $(ARCH)
.PHONY: image
# Kiosk terminal image builder for Raspberry Pi
This project builds an image for a Raspberry Pi that boots directly into a
browser with a predefined web page. It is a soft fork of
https://git.fsmpi.rwth-aachen.de/thomas/ci-vm-image (which was designed for CI
VM images on amd64).
The system runs from RAM, almost all changes at runtime are ephemeral. The
device can safely be unplugged without shutting down with no real risk of data
loss. As the boot partition is mounted read-write in order to regularly update
the software clock, there is still a minor chance, but in practice it is very
unlikely to corrupt the file system.
On boot, the `kiosk` user is automatically logged in and launches Firefox in
kiosk mode with `/boot/CONFIG/kiosk.html` (see below). Terminal switching is
possible, both `root` and `kiosk` passwords are empty. When Firefox quits, it
will automatically be relaunched, unless `/tmp/noautologin` exists.
:::warning
**Bug**: Firefox will not show (only blank screen) until the first user input,
such as mouse movement or a key press.
:::
## Building
Requirements: Podman and a native arm64 host or a correctly configured
and container-compatible qemu-binfmt setup.
```
% make # for arm64, RPi 3 and later
% make ARCH=arm # for armv7, RPi 2
```
RPi 1 (armv6/armhf) is currently untested and unsupported, but could work. One
would need to pass `--variant` to the `podman` invocation or use a single-arch
image such as `docker.io/arm32v6/alpine`.
The results (`boot.tar`, `root.img`) are placed in the `arm64` or `arm`
directory.
### SELinux
On SELinux-enabled systems (such as Fedora), the container may not have access
to the directories. Either move the whole building directory to an
appropriately labelled place, or customise the scripts to place the in-container
directories elsewhere, or set the type context label of the build directory to
`container_file_t` (e. g., `chcon -R -t container_file_t .`). You may
need to install `container-selinux` manually on Fedora.
## Flashing
1. Partition an SD card with the typical RPi layout:
1. a small-ish (~200MiB should be enough, cf. size of `boot.tar`)
partition at the beginning of MBR type `0x0c` for the boot file system,
2. and a partition of at least 2GiB and type `0x83` for the root file
system.
2. Create a FAT32 file system (e. g., `mkfs.vfat /dev/mmcblk0p1`) on the
first partition.
3. Mount the first partition and extract `boot.tar` to its root. You can
ignore the error that the `boot` symlink cannot be created.
4. Copy `root.img` to the second partition (e. g., `pv -pterbaY root.img
> /dev/mmcblk0p2`)
## Configuration
All configurables are stored in the `CONFIG` directory of the boot partition,
i. e., `/boot/CONFIG/` in the running system.
`swclock`
: Software clock. On boot, system time is set to the time stamp of this file.
Every hour, the time stamp of this file is updated. During normal operation,
time should be updated via NTP.
`interfaces`
: Configuration for [ifupdown-ng](https://github.com/ifupdown-ng/ifupdown-ng).
`hostname`
: System host name.
`kiosk.html`
: Opened on boot, would typically contain a redirect to a web site.
`wpa_supplicant.conf`
: Additional WLAN configuration, required for WPA-EAP (PSK is possible via
`interfaces` alone).
#!/bin/sh
set -e
set -x
exec qemu-system-x86_64 \
-M microvm,x-option-roms=off,pit=off,pic=off,rtc=off,isa-serial=off,pcie=on \
-bios /usr/share/qemu/qboot.rom \
-enable-kvm \
-cpu host \
-m 1536M \
-nodefaults \
-no-user-config \
-nographic \
-device virtio-balloon-device \
-device virtio-rng-device \
-drive id=root,file=image.sqfs,format=raw,if=none \
-device virtio-blk-device,drive=root \
-kernel vmlinuz-virt \
-initrd initramfs-virt \
-append "root=/dev/vda overlaytmpfs console=hvc0 earlyprintk=hvc0" \
-chardev stdio,mux=on,id=stdio \
-device virtio-serial-device \
-device virtconsole,chardev=stdio,name=console.0 \
-mon chardev=stdio,mode=readline \
-netdev user,id=net \
-device virtio-net-device,netdev=net \
-chardev socket,path=qga,server=on,wait=off,id=qga \
-device virtserialport,chardev=qga,name=org.qemu.guest_agent.0 \
-chardev socket,id=virtfs,path=/tmp/virtfs.sock \
-device vhost-user-fs-pci,chardev=virtfs,tag=virtfs,queue-size=1024 \
-object memory-backend-memfd,id=mem,size=1536M,share=on \
-numa node,memdev=mem
#!/bin/sh
# Environment variable from outside
# shellcheck disable=SC2154
if test x"$container" != xpodman; then
echo This script is supposed to be run inside the container. >&2
exit 1
......@@ -7,42 +9,156 @@ fi
set -e
set -x
mkdir -p "$1"
cd "$1"
mkdir -p /image/etc/apk
mkdir -p apk-cache
ln -s "$PWD/apk-cache" /etc/apk/cache
ln -s "$PWD/apk-cache" /image/etc/apk/cache
cp -r /etc/apk/repositories /etc/apk/keys /image/etc/apk
apk add --root /image --update-cache --initdb alpine-base mkinitfs \
qemu-guest-agent git git-lfs gitlab-runner bash buildah
echo 'features="base squashfs virtio"' > /image/etc/mkinitfs/mkinitfs.conf
apk add --root /image linux-virt
apk add --root /image --update-cache --initdb \
alpine-base mkinitfs raspberrypi raspberrypi-utils rng-tools chrony \
kbd-bkeymaps font-terminus \
dosfstools e2fsprogs \
weston weston-backend-drm weston-shell-desktop weston-terminal \
mesa-dri-gallium \
pam-rundir seatd shadow-login agetty \
wpa_supplicant wireless-tools iw iwd \
eudev udev-init-scripts udev-init-scripts-openrc \
firefox-esr font-dejavu font-noto
echo 'features="base ext4 kms mmc usb"' > /image/etc/mkinitfs/mkinitfs.conf
apk add --root /image linux-rpi raspberrypi-bootloader
oldpwd="$PWD"
cd /image/etc/runlevels
for i in devfs dmesg mdev hwdrivers cgroups; do
for i in devfs dmesg cgroups localmount udev udev-trigger udev-settle udev-postmount; do
ln -s /etc/init.d/$i sysinit/$i
done
for i in modules hostname sysctl bootmisc syslog osclock networking; do
for i in bootmisc consolefont hostname klogd loadkmap modules networking rngd seedrng swclock sysctl syslog; do
ln -s /etc/init.d/$i boot/$i
done
ln -s /etc/init.d/killprocs shutdown/killprocs
for i in qemu-guest-agent; do
for i in killprocs mount-ro savecache; do
ln -s /etc/init.d/$i shutdown/$i
done
for i in crond chronyd seatd; do
ln -s /etc/init.d/$i default/$i
done
cd "$oldpwd"
echo hvc0::respawn:/sbin/getty 115200 hvc0 >> /image/etc/inittab
cat <<EOF >/image/etc/network/interfaces
mkdir /image/boot/CONFIG
echo 'swclock_file=/boot/CONFIG/swclock' > /image/etc/conf.d/swclock
touch /image/boot/CONFIG/swclock
cat <<EOF > /image/etc/periodic/hourly/swclock.sh
#!/bin/sh
touch /boot/CONFIG/swclock
EOF
chmod +x /image/etc/periodic/hourly/swclock.sh
ln -s /boot/CONFIG/interfaces /image/etc/network/interfaces
cat <<EOF >/image/boot/CONFIG/interfaces
auto lo
iface lo inet loopback
auto eth0
iface eth0 inet dhcp
#auto wlan0
#iface wlan0
# use dhcp
# use wifi
# wifi-config-path /boot/CONFIG/wpa_supplicant.conf
#auto wlan0
#iface wlan0
# use dhcp
# use wifi
# wifi-ssid Freifunk
#auto wlan0
#iface wlan0
# use dhcp
# use wifi
# wifi-ssid FranzBox1337
# wifi-psk hunter2
EOF
ln -fs /boot/CONFIG/hostname /image/etc/hostname
echo localhost > /image/boot/CONFIG/hostname
cat <<EOF >> /image/etc/fstab
/dev/mmcblk0p1 /boot vfat fmask=0133,dmask=0022 0 2
tmpfs /tmp tmpfs nosuid,nodev 0 0
EOF
cat <<EOF > /image/boot/CONFIG/kiosk.html
<!doctype html>
<meta http-equiv="refresh" content="0; url=https://kiosk.kif.rocks" />
EOF
cat <<EOF > /image/boot/CONFIG/wpa_supplicant.conf
network={
ssid="eduroam"
key_mgmt=WPA_EAP
eap=PWD
identity="u1138@jku-lummerland.edu"
password="hunter2"
}
EOF
chroot /image setup-user -u -g seat kiosk
cat <<EOF > /image/home/kiosk/.profile
if [ \$(tty) = /dev/tty1 -a ! -e /tmp/noautologin ] ; then
exec weston
fi
EOF
cat <<EOF > /image/home/kiosk/kiosk.sh
#!/bin/sh
exec firefox-esr --kiosk /boot/CONFIG/kiosk.html
EOF
chmod +x /image/home/kiosk/kiosk.sh
chown 1000:1000 /image/home/kiosk/kiosk.sh
mkdir /image/home/kiosk/.config
cat <<EOF > /image/home/kiosk/.config/weston.ini
[core]
shell=kiosk
xwayland=false
[keyboard]
keymap_layout=de
[autolaunch]
path=/home/kiosk/kiosk.sh
watch=true
EOF
chown -R 1000:1000 /image/home/kiosk
chroot /image /sbin/setup-keymap de de
echo 'consolefont="ter-128n.psf.gz"' > /image/etc/conf.d/consolefont
sed \
-e '/tty1/c\tty1::respawn:/sbin/agetty --autologin kiosk --noclear tty1' \
-i /image/etc/inittab
echo 'root=/dev/mmcblk0p2 rootfstype=ext4 fsck.repair=yes rootwait overlaytmpfs' > /image/boot/cmdline.txt
echo 'dtoverlay=vc4-kms-v3d' > /image/boot/usercfg.txt
find /image/var/cache/apk -name APKINDEX.\* -delete
rm -f /image/etc/apk/cache
mv /image/boot/vmlinuz-virt /image/boot/initramfs-virt .
apk add squashfs-tools
rm -f image.sqfs
mksquashfs /image/ image.sqfs
rm -f boot.tar
tar -C /image/boot -cf boot.tar .
find /image/boot -mindepth 1 -delete
apk add e2fsprogs
rm -f root.img
truncate -s 2G root.img
mkfs.ext4 -d /image/ root.img
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment