From 5429442dc35b091367ff7d0744fdfb30bedff258 Mon Sep 17 00:00:00 2001 From: YourFritz Date: Sun, 6 Nov 2016 10:24:51 +0100 Subject: [PATCH] new gui_boot_manager version - Puma6 support added - should be POSIX shell compatible now --- modfs | 1 + modscripts/gui_boot_manager_v0.2 | 0 modscripts/gui_boot_manager_v0.3 | 660 +++++++++++++++++++++++++++++++ 3 files changed, 661 insertions(+) mode change 100755 => 100644 modscripts/gui_boot_manager_v0.2 create mode 100755 modscripts/gui_boot_manager_v0.3 diff --git a/modfs b/modfs index d94b6be..394c60a 100755 --- a/modfs +++ b/modfs @@ -802,6 +802,7 @@ pack_squashfs() popd="$(pwd)" debug "pack_squashfs: using SquashFS version $sq_version" cd "$src" + echo $modfs_version > squashfs-root/etc/.modfs_version sq_mksquashfs squashfs-root "$target" -info -b $blocksize $endian -force-uid 0 -force-gid 0 rc=$? cd "$popd" diff --git a/modscripts/gui_boot_manager_v0.2 b/modscripts/gui_boot_manager_v0.2 old mode 100755 new mode 100644 diff --git a/modscripts/gui_boot_manager_v0.3 b/modscripts/gui_boot_manager_v0.3 new file mode 100755 index 0000000..f08b6ba --- /dev/null +++ b/modscripts/gui_boot_manager_v0.3 @@ -0,0 +1,660 @@ +# MODFS_MODSCRIPT +# SUPPORTS precheck postcheck install language(en,de) +# NAME enable system and branding selection from GUI \(v0.3\) +# DESCRIPTION en +# extent the "restart" page of FRITZ!OS to select system version and branding +# DESCRIPTION de +# Auswahl des zu startenden Systems und des Brandings in der "Neustart"-Seite +# EOH +# +# process parameters +# +language=$1 +rootdir=$2 +mode=$3 +step=$4 +[ ${#4} -eq 0 ] && exit 59 # invalid call +# +# execute the requested step +# +rc=0 +luafile="$rootdir/usr/www/\$TARGET_BRANDING/system/reboot.lua" +binfile="/usr/bin/guibootmanager" +cmdfile="$rootdir$binfile" +find_line() +{ + local line rc=0 + line="$(grep linux_fs_start $(eval echo $luafile))" + [ ${#line} -gt 0 ] && rc=0 || rc=1 + return $rc +} +find_envvar() +{ + local line rc=0 + line="$(grep linux_fs_start /proc/sys/urlader/environment)" + [ ${#line} -gt 0 ] && rc=0 || rc=1 + return $rc +} +install_script() +{ + cat >"$cmdfile" <<"ENDOFSCRIPT" +#! /bin/sh +############################################################################## +# # +# GUI Boot Manager extension for AVM's FRITZ!Box routers with "hot flash" # +# capabilities # +# # +# Copyright (C) 2014-2016 P.Hämmerlein (http://www.yourfritz.de) # +# # +# This program is free software; you can redistribute it and/or # +# modify it under the terms of the GNU General Public License # +# as published by the Free Software Foundation; either version 2 # +# of the License, or (at your option) any later version. # +# # +# This program is distributed in the hope that it will be useful, # +# but WITHOUT ANY WARRANTY; without even the implied warranty of # +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # +# GNU General Public License under # +# http://www.gnu.org/licenses/gpl-2.0.html # +# for more details. # +# # +# "FRITZ!Box" is a registered word mark and "AVM" is a registered # +# word and figurative mark of: # +# AVM Computersysteme Vertriebs GmbH, 10559, Berlin, DE. # +# # +############################################################################## +# # +# pooled variables here for easy changes # +# # +############################################################################## +envpathname="/proc/sys/urlader/environment" +procmtd="/proc/mtd" +mtdprefix="mtd" +mtdblockprefix="/dev/mtdblock" +mmcdevice="mmcblk0" +mmcprefix="/dev/${mmcdevice}p" +pumaparts="/proc/avm_partitions" +kernelname="kernel" +filesystemname="filesystem" +reservedprefix="reserved" +fsvarname="linux_fs_start" +brandingvarname="firmware_version" +wrapper="/wrapper" +statfile="/etc/.modfs_version" +rootfsimage="filesystem_core.squashfs" +versionfilename="etc/version" +defaultspath="etc/default.$CONFIG_PRODUKT" +tmpdirbase="/var/tmp" +altfs="altfs" +altroot="altroot" +############################################################################## +# # +# include FRITZ!Box 6490/6590 detection helpers from AVM # +# # +############################################################################## +. /etc/puma6_helper.sh +############################################################################## +# # +# subfunctions # +# # +############################################################################## +# # +# check, if a list contains an item and return its index (based on 1) # +# $1 - the item to look for (needle) # +# $2 - the haystack # +# # +############################################################################## +index_of_item() +( + i=0 + for item in $2; do + i=$(( i + 1 )) + [ $1 = $item ] && printf $i && return 0 + done + return 1 +) +############################################################################## +# # +# get the count of words in the specified string # +# # +############################################################################## +count_of_items() +( + set -- $* + printf $# +) +############################################################################## +# # +# get branding from environment # +# # +############################################################################## +get_system_branding() +( + sed -n -e "s/^$brandingvarname\t\(.*\)\$/\1/p" $envpathname +) +############################################################################## +# # +# get next system index from environment # +# # +############################################################################## +get_system_switch() +( + sed -n -e "s/^$fsvarname\t\([01]\)/\1/p" $envpathname +) +############################################################################## +# # +# get partition number by name # +# $1 - requested partition name # +# # +############################################################################## +get_partition_by_name() +( + if is_puma6; then + name="$1${2:+_}${2}_ARM" + sed -n -e "s|^${name}=$mmcprefix\([0-9]\{1,2\}\)\$|\1|p" $pumaparts + else + name=$2${2:+-}$1 + sed -n -e "s|$mtdprefix\([0-9]\{1,2\}\): [0-9a-f]\{8\} [0-9a-f]\{8\} \"$name\"|\1|p" $procmtd + fi +) +############################################################################## +# # +# get partition name by number # +# $1 - requested partition number # +# # +############################################################################## +get_partition_by_number() +( + if is_puma6; then + sed -e "/_SIZE=/d" -e "s|_|-|g" $pumaparts | sed -n -e "s|^\([a-z]*\)\(-$reservedprefix\)\?-ARM=$mmcprefix$1|\1\2|p" | sed -e "s|\(.*\)-\(.*\)|\2-\1|" + else + sed -n -e "s|$mtdprefix$1: [0-9a-f]\{8\} [0-9a-f]\{8\} \"\(.*\)\"|\1|p" $procmtd + fi +) +############################################################################## +# # +# build partition groups # +# # +############################################################################## +build_partitions() +( + k1=$(get_partition_by_name $kernelname) + f1=$(get_partition_by_name $filesystemname) + g1=${k1}:${f1} + k2=$(get_partition_by_name $kernelname $reservedprefix) + f2=$(get_partition_by_name $filesystemname $reservedprefix) + g2=${k2}:${f2} + [ $k1 -lt $k2 ] && printf '%s %s' $g1 $g2 || printf '%s %s' $g2 $g1 +) +############################################################################## +# # +# check next system against running # +# # +############################################################################## +is_switched() +( + switched=0 + set -- $(build_partitions) + [ $(get_system_switch) -gt 0 ] && shift + kernel=${1%:*} + kname="$(get_partition_by_number $kernel)" + [ "${kname##$reservedprefix}" = "$kname" ] && switched=1 + return $switched +) +############################################################################## +# # +# extract firmware variables from $versionfilename # +# $1 - system root # +# # +############################################################################## +get_version_values() +( + sed -n -e 's|^export FIRMWARE_\(.*\)=\"\?\([^\"]*\)\"\?$|\1=\"\2\"|p' $1/$versionfilename | sed -e 's| |\ |g' +) +############################################################################## +# # +# get system version # +# $1 - system root # +# # +############################################################################## +get_system_version() +( + eval $(get_version_values $1) + printf '%s%s' $VERSION $SUBVERSION +) +############################################################################## +# # +# get system date # +# $1 - system root # +# # +############################################################################## +get_system_date() +( + eval $(get_version_values $1) + printf '%s' "$DATE" +) +############################################################################## +# # +# switch system selection variable to other value # +# # +############################################################################## +switch_system() +( + printf '%s\t%d\n' $fsvarname $(( ( $(get_system_switch) + 1 ) % 2 )) >$envpathname +) +############################################################################## +# # +# replace branding, if necessary # +# # +############################################################################## +change_branding() +( + [ $1 = $(get_system_branding) ] || printf '%s\t%s' $brandingvarname $1 >$envpathname +) +############################################################################## +# # +# switch next boot time selection to specified system, if action is really # +# needed # +# $1 - 'running' / 'alternative' to switch to the specified system based on # +# the running version # +# # +############################################################################## +switch_system_to() +( + is_switched && ( [ $1 = running ] && switch_system ) || ( [ $1 = alternative ] && switch_system ) + [ -z $2 ] || change_branding $2 +) +############################################################################## +# # +# mount alternative system # +# $1 - source partition index # +# $2 - temporary directory as mount point # +# # +############################################################################## +mount_alternative_system() +( + mkdir -p $2/$altfs 2>/dev/null || return 1 + if is_puma6; then + mount -t squashfs -o ro $mmcprefix$1 $2/$altfs 2>/dev/null || return 1 + printf '%s/%s' $2 $altfs + else + blkid=$(command -v blkid 2>/dev/null) + [ -z $blkid ] && fstype=squashfs + [ -z $fstype ] && fstype=$(blkid $1 | sed -n -e 's|.*TYPE="\(.*\)"|\1|p') + [ -z $fstype ] && fstype=yaffs2 + mount -t $fstype $mtdblockprefix$1 $2/$altfs 2>/dev/null || return 1 + ! [ $fstype = yaffs2 ] && printf '%s/%s' $2 $altfs && return 0 + mkdir -p $2/altroot 2>/dev/null || return 1 + mount -t squashfs -o ro $2/$altfs/$rootfsimage $2/$altroot 2>/dev/null || return 1 + printf '%s/%s' $2 $altroot + fi + return 0 +) +############################################################################## +# # +# dismount the mounted alternative system # +# $1 - mount point # +# # +############################################################################## +dismount_alternative_system() +( + umount $1 2>/dev/null || return 1 + rmdir $1 2>/dev/null + is_puma6 && return 0 + mp=$(sed -n -e "s|[^ ]* \(${1%/*}/[^ ]*\) .*|\1|p" /proc/mounts) + [ -z $mp ] && return 0 + umount $mp 2>/dev/null || return 1 + rmdir $mp 2>/dev/null + return 0 +) +############################################################################## +# # +# get possible brandings from firmware directories # +# $1 - mount point # +# # +############################################################################## +get_brandings() +( + path=${1:-/}${1:+/}$defaultspath + find $path -type d -maxdepth 1 | sed -n -e "s|^$path/\(.*\)|\1|p" | sed -e '/^$/d' -e ':x;$!N;s/\n/ /;tx' +) +############################################################################## +# # +# get name of loop device backing file # +# $1 - loop device number # +# # +############################################################################## +get_loop_device_file() +( + [ -d /sys/block/loop$1/loop ] || return 1 + cat /sys/block/loop$1/loop/backing_file +) +############################################################################## +# # +# get loop device for mount point # +# $1 - mount point # +# # +############################################################################## +get_loop_device() +( + sed -n -e "s|^\(/dev/loop[0-9]\{1,2\}\) $1 .*|\1|p" /proc/mounts +) +############################################################################## +# # +# get image file for loop device mounted SquashFS image # +# $1 - mount point # +# # +############################################################################## +get_image_name() +( + loop=$(get_loop_device $1) + [ -z $loop ] && return 1 + get_loop_device_file ${loop##*[^0-9]} +) +############################################################################## +# # +# cleanup any mounted images and remove the temporary directory # +# # +############################################################################## +cleanup() +( + [ -z $tempdir ] && return + mp=$(sed -n -e "s|[^ ]* \($tempdir/$altroot\) .*|\1|p" /proc/mounts) + [ -z $mp ] || umount $mp 2>/dev/null + mp=$(sed -n -e "s|[^ ]* \($tempdir/$altfs\) .*|\1|p" /proc/mounts) + [ -z $mp ] || umount $mp 2>/dev/null + rm -r "$tempdir" 2>/dev/null +) +############################################################################## +# # +# prepare a temporary directory and a clean exit routine # +# # +############################################################################## +tempdir=$tmpdirbase/$$_$(date +%s) +mkdir -p $tempdir 2>/dev/null +trap cleanup HUP EXIT INT TERM +rc=127 +############################################################################## +# # +# output a SELECT control # +# # +############################################################################## +selectbox() +( + printf '\n' +) +############################################################################## +# # +# create HTML output # +# # +############################################################################## +html_display() +( + switchvalue=$(get_system_switch) + running_kernel=$(get_partition_by_name $kernelname) + alternative_kernel=$(get_partition_by_name $kernelname $reservedprefix) + running_filesystem=$(get_partition_by_name $filesystemname) + alternative_filesystem=$(get_partition_by_name $filesystemname $reservedprefix) + current_branding=$(get_system_branding) + if [ ${#switchvalue} -eq 0 ] || [ ${#running_kernel} -eq 0 ] || [ ${#alternative_kernel} -eq 0 ] || [ ${#running_filesystem} -eq 0 ] || [ ${#alternative_filesystem} -eq 0 ]; then + [ $Language = de ] \ + && printf '

Die Umschaltung zwischen zwei installierten Systemen ist auf dieser FRITZ!Box nicht verfügbar.

\n' \ + || printf '

Switching between alternative systems is not supported on this device.

\n' + return 1 + else + mp=$(mount_alternative_system $alternative_filesystem $tempdir) + if [ -z $mp ]; then + alternative_version="unknown" + alternative_date="unknown" + alternative_fsdate="unknown" + alternative_brandings="$current_branding" + else + alternative_version=$(get_system_version $mp) + alternative_date=$(get_system_date $mp) + [ -d $wrapper ] \ + && alternative_fsdate=$(stat -c %Y $(get_image_name $mp) 2>/dev/null) \ + || alternative_fsdate=$(stat -c %Y $mp$statfile 2>/dev/null) + alternative_brandings="$current_branding" + if [ -z $alternative_fsdate ]; then + alternative_fsdate="unknown" + else + alternative_fsdate="$(date -d @$alternative_fsdate +'%d.%m.%y %H:%M')" + alternative_brandings="$(get_brandings $mp)" + fi + dismount_alternative_system $mp + fi + running_version=$(get_system_version) + running_date=$(get_system_date) + [ -d $wrapper ] \ + && running_fsdate="$(date -d @$(stat -c %Y $(get_image_name /)) +"%d.%m.%y %H:%M")" \ + || running_fsdate="$(date -d @$(stat -c %Y $statfile) +"%d.%m.%y %H:%M")" + running_brandings="$(get_brandings)" + if is_switched; then + running_checked="" + alternative_checked=" checked=\"checked\"" + show_running=0 + else + running_checked=" checked=\"checked\"" + alternative_checked="" + show_running=1 + fi + [ $(count_of_items "$running_brandings") -gt 1 ] && chg_running_branding=1 || chg_running_branding=0 + [ $(count_of_items "$alternative_brandings") -gt 1 ] && chg_alternative_branding=1 || chg_alternative_branding=0 + [ $alternative_version = unknown ] && chg_alternative_branding=0 + if [ $Language = de ]; then + printf '

Folgende Systeme stehen auf dieser FRITZ!Box zur Auswahl bei einem Neustart:


\n' + printf '\n' $fsvarname "$running_checked" + printf '

\n' + printf 'Version %s vom %s (linux_fs_start=%d), das System wurde am %s zuletzt modifiziert

\n' \ + $running_version "$running_date" $(get_system_switch) "$running_fsdate" + printf '\n' $fsvarname "$alternative_checked" + printf '

\n' + if [ $alternative_version = unknown ]; then + printf 'Das System in den alternativen Partitionen kann nicht identifiziert werden, es könnte beschädigt oder nicht vorhanden bzw. gelöscht sein.
\n' + printf 'Eine Umschaltung auf dieses System sollte nur ausgeführt werden, wenn man sich wirklich sehr sicher ist, was man da tut.

\n' + else + printf 'Version %s vom %s (linux_fs_start=%d), das System wurde am %s zuletzt modifiziert

\n' \ + $alternative_version "$alternative_date" $(( ( $(get_system_switch) + 1 ) % 2 )) "$alternative_fsdate" + fi + printf '\n' + if [ $chg_running_branding -eq 1 ]; then + printf '

Das oben ausgewählte System unterstützt mehrere Firmware-Versionen (Brandings), im Moment ist "%s" eingestellt.

\n' $current_branding + printf '\n' + selectbox idRunningBranding running_branding "$running_brandings" $current_branding + else + printf '

Das oben ausgewählte System unterstützt nur das Branding "%s", dieses ist im Moment auch eingestellt.

\n' $current_branding + printf '\n' $current_branding + fi + printf '
\n' + printf '\n' + if [ $chg_alternative_branding -eq 1 ]; then + printf '

Das oben ausgewählte System unterstützt mehrere Firmware-Versionen (Brandings), im Moment ist "%s" eingestellt.

\n' $current_branding + printf '\n' + selectbox idAlternativeBranding alternative_branding "$alternative_brandings" $current_branding + else + if [ $alternative_version = unknown ];then + printf '

Da das alternative System nicht identifiziert werden konnte, ist auch keine Information über dort enthaltene Brandings verfügbar.

\n' + printf '\n' $current_branding + else + printf '

Das oben ausgewählte System unterstützt nur das Branding "%s", ' $alternative_brandings + if [ $alternative_brandings = $current_branding ]; then + printf 'dieses ist im Moment auch eingestellt.

\n' + else + printf 'im Moment ist jedoch "%s" eingestellt.\n' $current_branding + printf 'Bei der Umschaltung des zu verwendenden Systems wird daher auch gleichzeitig das Branding auf "%s" geändert.\n' $alternative_brandings + fi + printf '\n' + fi + fi + printf '
\n' + else + printf '

The following systems are available to be booted on this device next time:


\n' + printf '\n' $fsvarname "$running_checked" + printf '

\n' + printf 'version %s - originally built on %s (linux_fs_start=%d), this system was last modified on %s

\n' \ + $running_version "$running_date" $(get_system_switch) "$running_fsdate" + printf '\n' $fsvarname "$alternative_checked" + printf '

\n' + if [ $alternative_version = unknown ]; then + printf 'Unable to identify the installed system in the alternative partitions, it could have been damaged or was missing/deleted.
\n' + printf 'Switching to this system may prevent your device from starting correctly - you should be really sure, what you are doing in this case.

\n' + else + printf 'version %s - originally built on %s (linux_fs_start=%d), this system was last modified on %s

\n' \ + $alternative_version "$alternative_date" $(( ( $(get_system_switch) + 1 ) % 2 )) "$alternative_fsdate" + fi + printf '\n' + if [ $chg_running_branding -eq 1 ]; then + printf '

The system selected above supports different provider/OEM names (aka "brandings"), currently the value "%s" is set.

\n' $current_branding + printf '\n' + selectbox idRunningBranding running_branding "$running_brandings" $current_branding + else + printf '

The system selected above supports only a single provider/OEM name "%s", it is already the current value.

\n' $current_branding + printf '\n' $current_branding + fi + printf '
\n' + printf '\n' + if [ $chg_alternative_branding -eq 1 ]; then + printf '

The system selected above supports different provider/OEM names (aka "brandings"), currently the value "%s" is set.

\n' $current_branding + printf '\n' + selectbox idAlternativeBranding alternative_branding "$alternative_brandings" $current_branding + else + if [ $alternative_version = unknown ];then + printf '

Due to problems identifying the installed alternative system, there is no possibility to change the provider/OEM name for this one.

\n' + printf '\n' $current_branding + else + printf '

The system selected above supports only a single provider/OEM name "%s", ' $alternative_brandings + if [ $alternative_brandings = $current_branding ]; then + printf 'this value is already the current.

\n' + else + printf 'but currently "%s" is in use.\n' $current_branding + printf 'Switching the system to the alternative partitions will also set the provider/OEM name to "%s" without further questions.\n' $alternative_brandings + fi + printf '\n' + fi + fi + printf '
\n' + fi + printf '\n' + return 0 + fi +) +############################################################################## +# # +# check parameters and call requested function # +# # +############################################################################## +case $1 in + (html_display) + html_display + rc=$? + ;; + (switch_to) + switch_system_to $2 $3 + rc=$? + ;; +esac +exit $rc +ENDOFSCRIPT + chown root:root "$cmdfile" + chmod 755 "$cmdfile" +} +case $step in + precheck) + find_line + rc=$? + if [ $rc -eq 0 ]; then + case "$language" in + de) + echo "Die Modifikation wurde bereit angewendet." 1>&2 + ;; + *) + echo "The startup file was already modified." 1>&2 + ;; + esac + rc=1 + else + find_envvar + rc=$? + if [ $rc -ne 0 ]; then + case "$language" in + de) + echo "Dieses Gerät unterstützt keine 'dual boot'-Möglichkeit." 1>&2 + ;; + *) + echo "This device doesn't support booting the system software an alternative partition set." 1>&2 + ;; + esac + rc=1 + else + rc=0 + fi + fi + ;; + postcheck) + find_line + rc=$? + if [ $rc -eq 1 ]; then + case "$language" in + de) + echo "Die Modifikation war nicht erfolgreich." 1>&2 + ;; + *) + echo "The startup file seems to be unmodified." 1>&2 + ;; + esac + rc=1 + fi + ;; + install) + for TARGET_BRANDING in $TARGET_BRANDINGS; do + file="$(eval echo $luafile)" + sed -i "$file" -e " +/^local savecookie/a\\ +if box.post.linux_fs_start then\\ +local linux_fs_start = box.post.linux_fs_start\\ +local branding = box.post[linux_fs_start..\"_branding\"]\\ +os.execute(\"$binfile switch_to \"..linux_fs_start..\" \"..branding)\\ +end +/^
\\ +\\ + +" + done + install_script + rc=0 + ;; + *) + rc=59 + ;; +esac +exit $rc