2 # Copyright 2017-2020 Stan Grishin (stangri@melmac.net)
3 # shellcheck disable=SC2039,SC1091
5 readonly devices_dir
="/usr/share/advanced-reboot/devices/"
8 .
/usr
/share
/libubox
/jshn.sh
10 logger
() { /usr
/bin
/logger
-t advanced-reboot
"$1"; }
11 is_present
() { command -v "$1" >/dev
/null
2>&1; }
14 local p1_mtd
="$1" p2_mtd
="$2"
15 if [ "${p1_mtd:0:3}" = "mtd" ] && [ "${p2_mtd:0:3}" = "mtd" ] && \
16 is_present
'ubiattach' && \
17 is_present
'ubiblock' && \
18 is_present
'mount'; then
25 alt_partition_mount
() {
26 local ubi_dev op_ubi
="$1"
28 ubi_dev
="$(ubiattach -m "$op_ubi")"
29 ubi_dev
="$(echo "$ubi_dev" | sed -n "s
/^UBI device number\s
*\
(\d
*\
),.
*$
/\
1/p
")"
30 if [ -z "$ubi_dev" ]; then
31 ubidetach
-m "$op_ubi"
34 ubiblock
--create "/dev/ubi${ubi_dev}_0" && \
35 mount
-t squashfs
-r "/dev/ubiblock${ubi_dev}_0" /var
/alt_rom
38 alt_partition_unmount
() {
39 local mtdCount i
=0 op_ubi
="$1"
40 mtdCount
="$(ubinfo | grep 'Present UBI devices' | tr ',' '\n' | grep -c 'ubi')"
41 [ -z "$mtdCount" ] && mtdCount
=10
42 [ -d /var
/alt_rom
] && umount
/var
/alt_rom
43 while [ "$i" -le "$mtdCount" ]; do
44 if [ ! -e "/sys/devices/virtual/ubi/ubi${i}/mtd_num" ]; then
47 ubi_mtd
="$(cat /sys/devices/virtual/ubi/ubi${i}/mtd_num)"
48 if [ -n "$ubi_mtd" ] && [ "$ubi_mtd" = "$op_ubi" ]; then
49 ubiblock
--remove /dev
/ubi
${i}_0
50 ubidetach
-m "$op_ubi"
57 get_main_partition_os_info
(){
59 if [ -s "/etc/os-release" ]; then
60 cp_info
="$(. /etc/os-release && echo "$PRETTY_NAME")"
61 if [ "${cp_info//SNAPSHOT}" != "$cp_info" ]; then
62 cp_info
="$(. /etc/os-release && echo "${OPENWRT_RELEASE%%-*}")"
68 get_alt_partition_os_info
(){
69 local op_info op_ubi
="$1"
70 logger
"attempting to mount alternative partition (mtd${op_ubi})"
71 alt_partition_unmount
"$op_ubi"
72 alt_partition_mount
"$op_ubi"
73 if [ -s "/var/alt_rom/etc/os-release" ]; then
74 op_info
="$(. /var/alt_rom/etc/os-release && echo "$PRETTY_NAME")"
75 if [ "${op_info//SNAPSHOT}" != "$op_info" ]; then
76 op_info
="$(. /var/alt_rom/etc/os-release && echo "${OPENWRT_RELEASE%%-*}")"
79 logger
"attempting to unmount alternative partition (mtd${op_ubi})"
80 alt_partition_unmount
"$op_ubi"
85 local boardNames filename i romBoardName
="$1"
86 for filename
in "${devices_dir}"*.json
; do
87 [ "$filename" = "${devices_dir}*.json" ] && return
88 json_load_file
"$filename"
89 json_get_values boardNames
'boardNames'
91 for i
in $boardNames; do
92 if [ "$i" = "$romBoardName" ]; then
100 print_json
() { json_init
; json_add_string
"$1" "$2"; json_dump
; json_cleanup
; }
102 obtain_device_info
(){
103 local romBoardName p zyxelFlagPartition i
104 local vendorName deviceName partition1MTD partition2MTD labelOffset
105 local bootEnv1 bootEnv1Partition1Value bootEnv1Partition2Value
106 local bootEnv2 bootEnv2Partition1Value bootEnv2Partition2Value
107 local p1_label p1_version p2_label p2_version p1_os p2_os
108 local current_partition op_ubi cp_info op_info
110 romBoardName
="$(cat /tmp/sysinfo/board_name)"
111 if [ -z "$romBoardName" ]; then
112 print_json
'error' 'NO_BOARD_NAME'
116 p
="$(find_device_data "$romBoardName")"
117 if [ -z "$p" ] ||
[ ! -s "$p" ]; then
118 print_json
'rom_board_name' "$romBoardName"
123 for i
in vendorName deviceName partition1MTD partition2MTD labelOffset \
124 bootEnv1 bootEnv1Partition1Value bootEnv1Partition2Value \
125 bootEnv2 bootEnv2Partition1Value bootEnv2Partition2Value
; do
130 if [ -n "$labelOffset" ]; then
131 if [ -n "$partition1MTD" ]; then
132 p1_label
="$(dd if="/dev
/${partition1MTD}" bs=1 skip="${labelOffset}" count=64 2>/dev/null)"
133 if [ -n "$p1_label" ]; then
134 p1_version
="$(echo "$p1_label" | sed -n "s
/\
(.
*\
)Linux-\
([0-9.
]\
+\
).
*$
/\
2/p
")"
135 if [ "${p1_label//LEDE}" != "$p1_label" ]; then p1_os
="LEDE"; fi
136 if [ "${p1_label//OpenWrt}" != "$p1_label" ]; then p1_os
="OpenWrt"; fi
137 if [ -n "$vendorName" ] && [ "${p1_label//$vendorName}" != "$p1_label" ]; then
141 if [ -z "$p1_os" ]; then
142 p1_os
="${vendorName:-Unknown}/Unknown"
146 if [ -n "$partition2MTD" ]; then
147 p2_label
="$(dd if="/dev
/${partition2MTD}" bs=1 skip="${labelOffset}" count=64 2>/dev/null)"
148 if [ -n "$p2_label" ]; then
149 p2_version
="$(echo "$p2_label" | sed -n "s
/\
(.
*\
)Linux-\
([0-9.
]\
+\
).
*$
/\
2/p
")"
150 if [ "${p2_label//LEDE}" != "$p2_label" ]; then p2_os
="LEDE"; fi
151 if [ "${p2_label//OpenWrt}" != "$p2_label" ]; then p2_os
="OpenWrt"; fi
152 if [ -n "$vendorName" ] && [ "${p2_label//$vendorName}" != "$p2_label" ]; then
156 if [ -z "$p2_os" ]; then
157 p2_os
="${vendorName:-Unknown}/Unknown"
161 p1_os
="${vendorName}/Unknown (Compressed)"
162 p2_os
="${vendorName}/Unknown (Compressed)"
165 if [ -n "$bootEnv1" ]; then
166 if [ -x "/usr/sbin/fw_printenv" ] && [ -x "/usr/sbin/fw_setenv" ]; then
167 current_partition
="$(/usr/sbin/fw_printenv -n "${bootEnv1}")"
170 for i
in '0:dual_flag' '0:DUAL_FLAG'; do
171 zyxelFlagPartition
="$(find_mtd_part "$i" 2>/dev/null)"
172 [ -n "$zyxelFlagPartition" ] && break
174 if [ -z "$zyxelFlagPartition" ]; then
175 print_json
'error' 'NO_DUAL_FLAG'
176 logger
"Unable to find Dual Boot Environment or Dual Boot Flag Partition."
178 elif [ ! -b "$zyxelFlagPartition" ]; then
179 print_json
'error' 'NO_DUAL_FLAG_BLOCK'
180 logger
"The Dual Boot Flag Partition: $zyxelFlagPartition is not block device."
183 current_partition
="$(dd if="${zyxelFlagPartition}" bs=1 count=1 2>/dev/null | hexdump -n 1 -e '1/1 "%d
"')"
187 if is_alt_mountable
"$partition1MTD" "$partition2MTD"; then
188 if [ "$current_partition" = "$bootEnv1Partition1Value" ]; then
189 op_ubi
=$
(( ${partition2MTD:3:3} + 1 ))
191 op_ubi
=$
(( ${partition1MTD:3:3} + 1 ))
193 cp_info
="$(get_main_partition_os_info $op_ubi)"
194 op_info
="$(get_alt_partition_os_info $op_ubi)"
195 if [ "$current_partition" = "$bootEnv1Partition1Value" ]; then
196 p1_os
="${cp_info:-$p1_os}"
197 p2_os
="${op_info:-$p2_os}"
199 p1_os
="${op_info:-$p1_os}"
200 p2_os
="${cp_info:-$p2_os}"
203 if [ -n "$p1_os" ] && [ -n "$p1_version" ]; then
204 p1_os
="$p1_os (Linux ${p1_version})"
206 if [ -n "$p2_os" ] && [ -n "$p2_version" ]; then
207 p2_os
="$p2_os (Linux ${p2_version})"
211 json_add_int
'current_partition' "$current_partition"
212 json_add_string
'device_name' "$vendorName $deviceName"
213 json_add_array
'partitions'
215 if [ "$bootEnv1Partition1Value" = "$current_partition" ]; then
216 json_add_string
'state' "Current"
218 json_add_string
'state' "Alternative"
220 json_add_string
'os' "$p1_os"
221 json_add_int
'number' "$bootEnv1Partition1Value"
224 if [ "$bootEnv1Partition2Value" = "$current_partition" ]; then
225 json_add_string
'state' "Current"
227 json_add_string
'state' "Alternative"
229 json_add_string
'os' "$p2_os"
230 json_add_int
'number' "$bootEnv1Partition2Value"
233 json_add_string
'rom_board_name' "$romBoardName"
234 json_dump
; json_cleanup
;
237 toggle_boot_partition
(){
238 local zyxelFlagPartition i zyxelBootFlag zyxelNewBootFlag curEnvSetting newEnvSetting
240 local bev1 bev2 bev1p1 bev1p2 bev2p1 bev2p2
241 local vendorName deviceName partition1MTD partition2MTD labelOffset
242 local bootEnv1 bootEnv1Partition1Value bootEnv1Partition2Value
243 local bootEnv2 bootEnv2Partition1Value bootEnv2Partition2Value
245 romBoardName
="$(cat /tmp/sysinfo/board_name)"
246 if [ -z "$romBoardName" ]; then
247 print_json
'error' 'NO_BOARD_NAME'
251 p
="$(find_device_data "$romBoardName")"
252 if [ -z "$p" ] ||
[ ! -s "$p" ]; then
253 print_json
'rom_board_name' "$romBoardName"
258 for i
in vendorName deviceName partition1MTD partition2MTD labelOffset \
259 bootEnv1 bootEnv1Partition1Value bootEnv1Partition2Value \
260 bootEnv2 bootEnv2Partition1Value bootEnv2Partition2Value
; do
268 if [ -n "${bev1}${bev2}" ]; then # Linksys devices
269 if [ -n "$bev1" ]; then
270 curEnvSetting
="$(fw_printenv -n "${bev1}")"
271 if [ -z "$curEnvSetting" ]; then
272 logger
"$(printf "Unable to obtain firmware environment variable
: %s.
" "$bev1")"
274 json_add_string
'error' 'NO_FIRM_ENV'
275 json_add_array
'args'
276 json_add_string
"$bev1"
278 json_add_string
'rom_board_name' "$romBoardName"
279 json_dump
; json_cleanup
;
282 bev1p1
="$bootEnv1Partition1Value"
283 bev1p2
="$bootEnv1Partition2Value"
284 if [ "$curEnvSetting" = "$bev1p1" ]; then
285 newEnvSetting
="$bev1p2"
287 newEnvSetting
="$bev1p1"
289 if ! fw_setenv
"$bev1" "$newEnvSetting"; then
290 logger
"$(printf "Unable to
set firmware environment variable
: %s to
%s.
" "$bev1" "$newEnvSetting")"
292 json_add_string
'error' 'ERR_SET_ENV'
293 json_add_array
'args'
294 json_add_string
"$bev1"
295 json_add_string
"$newEnvSetting"
297 json_add_string
'rom_board_name' "$romBoardName"
298 json_dump
; json_cleanup
;
303 if [ -n "$bev2" ]; then
304 curEnvSetting
="$(fw_printenv -n "${bev2}")"
305 if [ -z "$curEnvSetting" ]; then
306 logger
"$(printf "Unable to obtain firmware environment variable
: %s.
" "$bev2")"
308 json_add_string
'error' 'NO_FIRM_ENV'
309 json_add_array
'args'
310 json_add_string
"$bev2"
312 json_add_string
'rom_board_name' "$romBoardName"
313 json_dump
; json_cleanup
;
316 bev2p1
="$bootEnv2Partition1Value"
317 bev2p2
="$bootEnv2Partition2Value"
318 if [ "$curEnvSetting" = "$bev2p1" ]; then
319 newEnvSetting
="$bev2p2"
321 newEnvSetting
="$bev2p1"
323 if ! fw_setenv
"$bev2" "$newEnvSetting"; then
324 logger
"$(printf "Unable to
set firmware environment variable
: %s to
%s.
" "$bev2" "$newEnvSetting")"
326 json_add_string
'error' 'ERR_SET_ENV'
327 json_add_array
'args'
328 json_add_string
"$bev2"
329 json_add_string
"$newEnvSetting"
331 json_add_string
'rom_board_name' "$romBoardName"
332 json_dump
; json_cleanup
;
338 json_dump
; json_cleanup
;
339 else # NetGear device
340 for i
in '0:dual_flag' '0:DUAL_FLAG'; do
341 zyxelFlagPartition
="$(find_mtd_part "$i" 2>/dev/null)"
342 [ -n "$zyxelFlagPartition" ] && break
344 if [ -z "$zyxelFlagPartition" ]; then
345 print_json
'error' 'NO_DUAL_FLAG'
346 logger
"Unable to find Dual Boot Environment or Dual Boot Flag Partition."
348 elif [ ! -b "$zyxelFlagPartition" ]; then
349 print_json
'error' 'NO_DUAL_FLAG_BLOCK'
350 logger
"The Dual Boot Flag Partition: $zyxelFlagPartition is not block device."
353 zyxelBootFlag
="$(dd if="${zyxelFlagPartition}" bs=1 count=1 2>/dev/null | hexdump -n 1 -e '1/1 "%d
"')"
354 if [ "$zyxelBootFlag" = "1" ]; then
355 zyxelNewBootFlag
="\\xff"
357 zyxelNewBootFlag
="\\x01"
359 if [ -n "$zyxelNewBootFlag" ]; then
360 if ! printf "%b" "$zyxelNewBootFlag" > "$zyxelFlagPartition"; then
361 logger
"$(printf "Unable to
set Dual Boot Flag Partition entry
for partition
: %s.
" "$zyxelFlagPartition")"
363 json_add_string
'error' 'ERR_SET_DUAL_FLAG'
364 json_add_array
'args'
365 json_add_string
"$zyxelFlagPartition"
367 json_add_string
'rom_board_name' "$romBoardName"
368 json_dump
; json_cleanup
;
374 json_dump
; json_cleanup
;
381 json_add_object
"obtain_device_info"
383 json_add_object
"toggle_boot_partition"
392 toggle_boot_partition
)
393 toggle_boot_partition
;;