1#!/bin/sh
2
3kgetopt ()
4{
5    _cmdline="$(cat /proc/cmdline)"
6    _optname="$1"
7    _optval="$2"
8    for _opt in $_cmdline
9    do
10        case "$_opt" in
11            "${_optname}"=*)
12                _optval="${_opt##"${_optname}"=}"
13                ;;
14            *)
15                ;;
16        esac
17    done
18    [ -n "$_optval" ] && echo "$_optval"
19}
20
21fslist="proc sys dev run"
22rodir=/mnt/rofs
23mmcdev="/dev/mmcblk0"
24rwfsdev="/dev/disk/by-partlabel/rwfs"
25
26cd /
27
28# We want to make all the directories in $fslist, not one directory named by
29# concatonating the names with spaces
30#
31# shellcheck disable=SC2086
32mkdir -p $fslist
33
34mount dev dev -tdevtmpfs
35mount sys sys -tsysfs
36mount proc proc -tproc
37mount tmpfs run -t tmpfs -o mode=755,nodev
38
39# Wait up to 5s for the mmc device to appear. Continue even if the count is
40# exceeded. A failure will be caught later like in the mount command.
41count=0
42while [ $count -lt 5 ]; do
43    if [ -e "${mmcdev}" ]; then
44        break
45    fi
46    sleep 1
47    count=$((count + 1))
48done
49
50# Move the secondary GPT to the end of the device if needed. Look for the GPT
51# header signature "EFI PART" located 512 bytes from the end of the device.
52if ! tail -c 512 "${mmcdev}" | hexdump -C -n 8 | grep -q "EFI PART"; then
53    sgdisk -e "${mmcdev}"
54    partprobe
55fi
56
57# There eMMC GPT labels for the rootfs are rofs-a and rofs-b, and the label for
58# the read-write partition is rwfs. Run udev to make the partition labels show
59# up. Mounting by label allows for partition numbers to change if needed.
60udevd --daemon
61udevadm trigger --type=devices --action=add
62udevadm settle --timeout=10
63# The real udevd will be started a bit later by systemd-udevd.service
64# so kill the one we started above now that we have the needed
65# devices loaded
66udevadm control --exit
67
68mkdir -p $rodir
69if ! mount /dev/disk/by-partlabel/"$(kgetopt root=PARTLABEL)" $rodir -t ext4 -o ro; then
70    /bin/sh
71fi
72
73# Determine if a factory reset has been requested
74mkdir -p /var/lock
75resetval=$(fw_printenv -n rwreset 2>/dev/null)
76if gpiopresent=$(gpiofind factory-reset-toggle) ; then
77    # gpiopresent contains both the gpiochip and line number as
78    # separate words, and gpioget needs to see them as such.
79    # shellcheck disable=SC2086
80    gpioval=$(gpioget $gpiopresent)
81else
82    gpioval=""
83fi
84# Prevent unnecessary resets on first boot
85if [ -n "$gpioval" ] && [ -z "$resetval" ]; then
86    fw_setenv rwreset "$gpioval"
87    resetval=$gpioval
88fi
89if [ "$resetval" = "true" ] || [ -n "$gpioval" ] && [ "$resetval" != "$gpioval" ]; then
90    echo "Factory reset requested."
91    if ! mkfs.ext4 -F "${rwfsdev}"; then
92        echo "Reformat for factory reset failed."
93        /bin/sh
94    else
95        # gpioval will be an empty string if factory-reset-toggle was not found
96        fw_setenv rwreset "$gpioval"
97        echo "rwfs has been formatted."
98    fi
99fi
100
101fsck.ext4 -p "${rwfsdev}"
102if ! mount "${rwfsdev}" $rodir/var -t ext4 -o rw; then
103    /bin/sh
104fi
105
106rm -rf $rodir/var/persist/etc-work/
107mkdir -p $rodir/var/persist/etc $rodir/var/persist/etc-work $rodir/var/persist/home/root
108mount overlay $rodir/etc -t overlay -o lowerdir=$rodir/etc,upperdir=$rodir/var/persist/etc,workdir=$rodir/var/persist/etc-work
109
110init="$(kgetopt init /sbin/init)"
111
112for f in $fslist; do
113    mount --move "$f" "$rodir/$f"
114done
115
116exec switch_root $rodir "$init"
117