1#!/bin/bash
2
3# Get the mtd device number (mtdX)
4function findmtd() {
5    m="$(grep -xl "$1" /sys/class/mtd/*/name)"
6    m="${m%/name}"
7    m="${m##*/}"
8    echo "${m}"
9}
10
11# Get the ubi device number (ubiX_Y)
12function findubi() {
13    u="$(grep -xl "$1" /sys/class/ubi/ubi?/subsystem/ubi*/name)"
14    u="${u%/name}"
15    u="${u##*/}"
16    echo "${u}"
17}
18
19# Get the mount information
20function is_mounted() {
21    grep -q "$1" /proc/mounts
22    return $?
23}
24
25# Attach the pnor mtd device to ubi.
26function attach_ubi() {
27    pnormtd="$(findmtd pnor)"
28    pnor="${pnormtd#mtd}"
29    pnordev="/dev/mtd${pnor}"
30
31    if [ -d "/sys/class/ubi/ubi${pnor}" ]; then
32        # Already attached
33        return 0
34    fi
35
36    ubiattach /dev/ubi_ctrl -m "${pnor}" -d "${pnor}"
37    rc=$?
38    if [ ${rc} -ne 0 ]; then
39        # Check the pnor mtd device is formatted as ubi by reading the first 3 byes,
40        # which should be the ascii chars 'UBI'
41        magic="$(hexdump -C -n 3 "${pnordev}")"
42        if [[ "${magic}" =~ "UBI" ]]; then
43            # Device already formatted as ubi, ubiattach failed for some other reason
44            return ${rc}
45        else
46            # Format device as ubi
47            echo "Starting ubiformat ${pnordev}"
48            ubiformat "${pnordev}" -y -q
49            # Retry the ubiattach
50            ubiattach /dev/ubi_ctrl -m "${pnor}" -d "${pnor}"
51        fi
52    fi
53}
54
55function mount_squashfs() {
56    pnormtd="$(findmtd pnor)"
57    ubidev="/dev/ubi${pnormtd#mtd}"
58    mountdir="/media/${name}"
59    vol="$(findubi "${name}")"
60    img="/tmp/images/${version}/pnor.xz.squashfs"
61    # shellcheck disable=SC2012 # ls provides the size in human-readable form
62    filesize="$(ls -sh "$img" | awk -F " " '{print $1}')"
63
64    if is_mounted "${name}"; then
65        echo "${name} is already mounted."
66        return 0
67    fi
68
69    if [ -n "${vol}" ]; then
70        ubirmvol "${ubidev}" -N "${name}"
71    fi
72
73    if [ ! -d "${mountdir}" ]; then
74        mkdir "${mountdir}"
75    fi
76
77    # Set size of read-only partition equal to pnor.xz.squashfs
78    ubimkvol "${ubidev}" -N "${name}" -s "${filesize}"KiB --type=static
79    if ! vol="$(findubi "${name}")"; then
80        echo "Unable to create RO volume!"
81        return 1
82    fi
83
84    ubidevid="${vol#ubi}"
85    if ! ubiupdatevol "/dev/ubi${ubidevid}" "${img}"; then
86        echo "Unable to update RO volume!"
87        return 1
88    fi
89
90    if ! ubiblock --create "/dev/ubi${ubidevid}"; then
91        echo "Unable to create UBI block for RO volume!"
92        return 1
93    fi
94
95    if ! mount -t squashfs -o ro "/dev/ubiblock${ubidevid}" "${mountdir}"; then
96        echo "Unable to mount RO volume!"
97        return 1
98    fi
99}
100
101function mount_ubi() {
102    pnormtd="$(findmtd pnor)"
103    pnor="${pnormtd#mtd}"
104    ubidev="/dev/ubi${pnor}"
105    pnordev="/dev/mtd${pnor}"
106
107    if [[ "${name}" == "pnor-patch" ]]; then
108        if [[ "$(fw_printenv fieldmode 2>/dev/null)" == "fieldmode=true" ]]; then
109            return 0
110        fi
111        if [[ ! "$(hexdump -C -n 3 "${pnordev}")" =~ "UBI" ]]; then
112            return 0
113        fi
114        mountdir="/usr/local/share/pnor"
115    else
116        mountdir="/media/${name}"
117    fi
118
119    if [[ "${name}" == "pnor-prsv" ]]; then
120        size="2MiB"
121    else
122        size="16MiB"
123    fi
124
125    if [ ! -d "${mountdir}" ]; then
126        mkdir -p "${mountdir}"
127    fi
128
129    vol="$(findubi "${name}")"
130    if [ -z "${vol}" ]; then
131        ubimkvol "${ubidev}" -N "${name}" -s "${size}"
132    fi
133
134    if ! is_mounted "${name}"; then
135        mountdev="ubi${pnor}:${name}"
136        mount -t ubifs "${mountdev}" "${mountdir}"
137    fi
138}
139
140function umount_ubi() {
141    pnormtd="$(findmtd pnor)"
142    pnor="${pnormtd#mtd}"
143    ubidev="/dev/ubi${pnor}"
144    mountdir="/media/${name}"
145
146    if is_mounted "${name}"; then
147        umount "${mountdir}"
148    fi
149
150    vol="$(findubi "${name}")"
151    id="${vol##*_}"
152    if [ -n "${id}" ]; then
153        ubirmvol "${ubidev}" -n "${id}"
154    fi
155
156    if [ -d "${mountdir}" ]; then
157        rm -r "${mountdir}"
158    fi
159}
160
161function remount_ubi() {
162    pnormtd="$(findmtd pnor)"
163    pnor="${pnormtd#mtd}"
164    pnordev="/dev/mtd${pnor}"
165
166    # Re-Attach the pnor mtd device to ubi
167    if [[ $(hexdump -C -n 3 "${pnordev}") =~ "UBI" ]]; then
168        ubiattach /dev/ubi_ctrl -m "${pnor}" -d "${pnor}"
169    else
170        # Device not formatted as ubi.
171        return 0
172    fi
173
174    # Get information on all ubi volumes
175    ubinfo=$(ubinfo -d "${pnor}")
176    presentVolumes=${ubinfo##*:}
177    IFS=', ' read -r -a array <<< "$presentVolumes"
178    for element in "${array[@]}";
179    do
180        elementProperties=$(ubinfo -d "$pnor" -n "$element")
181        # Get ubi volume name by getting rid of additional properties
182        name=${elementProperties#*Name:}
183        name="${name%Character*}"
184        name="$(echo -e "${name}" | tr -d '[:space:]')"
185
186        if [[ ${name} == pnor-prsv ]] || [[ ${name} == pnor-rw* ]] || [[ ${name} == pnor-ro* ]]; then
187            mountdir="/media/${name}"
188            if [ ! -d "${mountdir}" ]; then
189                mkdir -p "${mountdir}"
190            fi
191
192            if [[ ${name} == pnor-ro* ]]
193            then
194                ubiblock --create "/dev/ubi${pnor}_${element}"
195                mount -t squashfs -o ro "/dev/ubiblock${pnor}_${element}" "${mountdir}"
196            else
197                mount -t ubifs "ubi${pnor}:${name}" "${mountdir}"
198            fi
199        fi
200    done
201}
202
203function ubi_cleanup() {
204    # When ubi_cleanup is run, it expects one or no active version.
205    activeVersion=$(busctl --list --no-pager tree \
206            org.open_power.Software.Host.Updater | \
207        grep /xyz/openbmc_project/software/ | tail -c 9)
208
209    if [[ -z "$activeVersion" ]]; then
210        vols=$(ubinfo -a | grep -e "pnor-ro-" -e "pnor-rw-" | cut -c 14-)
211        mapfile -t array <<< "${vols}"
212    else
213        vols=$(ubinfo -a | grep -e "pnor-ro-" -e "pnor-rw-" | \
214            grep -v "$activeVersion" | cut -c 14-)
215        mapfile -t array <<< "${vols}"
216    fi
217
218    for (( index=0; index<${#array[@]}; index++ )); do
219        name=${array[index]}
220        umount_ubi
221    done
222}
223
224case "$1" in
225    ubiattach)
226        attach_ubi
227        ;;
228    squashfsmount)
229        name="$2"
230        version="$3"
231        mount_squashfs
232        ;;
233    ubimount)
234        name="$2"
235        mount_ubi
236        ;;
237    ubiumount)
238        name="$2"
239        umount_ubi
240        ;;
241    ubiremount)
242        remount_ubi
243        ;;
244    ubicleanup)
245        ubi_cleanup
246        ;;
247    *)
248        echo "Invalid argument"
249        exit 1
250        ;;
251esac
252rc=$?
253if [ ${rc} -ne 0 ]; then
254    echo "$0: error ${rc}"
255    exit ${rc}
256fi
257