Tiny Core Linux

General TC => Programming & Scripting - Unofficial => Topic started by: CNK on April 30, 2025, 04:00:41 AM

Title: firefox_update.sh - Efficiently Update firefox.tcz
Post by: CNK on April 30, 2025, 04:00:41 AM
This script uses Firefox's update system to update any firefox.tcz extension created using firefox_getLatest.sh to the latest version in its release family. The main advantage is that the download sizes are much smaller (about 10MB unless updating a version many months old) than running firefox_getLatest.sh to download the complete new binary, similar to how tce-update uses Zsync to download just the changes to updated extension files. It also verifies the signature of the downloaded update file without you needing to set up GnuPG to work with "firefox_getLatest.sh -g".

If the firefox.tcz extension is already loaded (but Firefox isn't running) the script automatically adapts the symlinks to any changes and mounts the updated extension so that the new Firefox version is available immediately (the old extension is permanently replaced at next reboot). So you don't have to reboot to use the new version as with firefox_getLatest.sh.

Note that firefox.tcz.dep is not updated if the dependencies for Firefox change in a new version. This must then be edited manually.

Tested on TC15 x86 and x86_64. It should work in any recent version of Tiny Core.

Code: [Select]
#!/bin/ash
# Update existing Firefox extension downloaded with firefox_getLatest.sh.
# Uses partial.mar update files to minimise download size.
# V. 1.0, 2025-04-30. By CNK.
# Firefox update info:
#  https://wiki.mozilla.org/Software_Update:Manually_Installing_a_MAR_file#Steps_for_Linux
#  https://firefox-source-docs.mozilla.org/toolkit/mozapps/update/docs/InAppUpdateProcess.html

. /etc/init.d/tc-functions
useBusybox

if [ "$USER" = root ]
then
   echo " ${YELLOW}This script can't be run by the 'root' user.${NORMAL}"
   exit 1
fi

if [ ! -w /etc/sysconfig/tcedir/optional ]
then
  echo " ${RED}Extension directory is missing or not writable.${NORMAL}"
  exit 1
fi

if [ ! -w /etc/sysconfig/tcedir/optional/firefox.tcz ]
then
  echo " ${YELLOW}Firefox extension missing or unwritable. Try firefox_getLatest.sh instead.${NORMAL}"
  exit 1
fi

if [ -e /etc/sysconfig/tcedir/optional/upgrade/firefox.tcz ]
then
  echo " ${YELLOW}An updated Firefox extension is already set to be installed at next reboot.${NORMAL}"
  exit 1
fi

if killall -q -0 firefox
then
  echo " ${YELLOW}Please close Firefox before running this script.${NORMAL}"
  exit 1
fi

# Check there's enough disk space for upgrade mode or old extension backup
backup=1
tcz_partition="`readlink /etc/sysconfig/tcedir`"
tcz_partition="${tcz_partition#/mnt/}"
tcz_partition=${tcz_partition%%/*}
free=`expr "\`df -m /dev/$tcz_partition\`" : '.*/dev/[a-zA-Z0-9]* *[0-9]* *[0-9]* *\([0-9]*\)'`
required=`du -m /etc/sysconfig/tcedir/optional/firefox.tcz | cut -f 1`
# Allow for max. 10MB size increase
required=`expr $required + 10`
if [ "$free" ]
then
  if [ $free -lt $required ]
  then
    if [ -e /usr/local/tce.installed/firefox ]
    then
      echo -e " ${RED}Not enough free disk space (${required}MB required).\n"\
              "${YELLOW}Please run without the firefox.tcz extension loaded.${NORMAL}"
      exit 1
    fi
    # Can't backup old extenion before upgrading
    backup=0
  fi
else
  echo " ${YELLOW}Caution, unable to determine free disk space remaining.${NORMAL}"
fi

# Download/install script's dependencies
echo " ${BLUE}Loading dependencies${NORMAL}..."
deps="wget squashfs-tools gtk3"
for Z in $deps
do
  Z="${Z#*$'\n'}"
  if [ ! -e /etc/sysconfig/tcedir/optional/$Z ]
  then
    if ! tce-load -w $Z >/dev/null
    then
      echo " ${RED}Dependency $Z download failed${NORMAL}"
      exit 1
    fi
  fi
done

if ! tce-load -i $deps >/dev/null
then
  echo " ${RED}Dependency install failed${NORMAL}"
  exit 1
fi

# Discover system architecture
if [ "`uname -m`" == x86_64 -a -f /lib/ld-linux-x86-64.so.* ]
then
  ffarch=linux-x86_64
else
  ffarch=linux-i686
fi

# Check system language
for lang in ${LANG%.*}
do
case $lang in
C) lang=en-US ;; #English
en_GB*) lang=en-GB ;;
en_ZA*) lang=en-ZA ;;
en*) lang=en-US ;;
es_ES*) lang=es-ES ;; #Spanish
es_MX*) lang=es-MX ;;
es_CL*) lang=es-CL ;;
es_AR*) lang=es-AR ;;
es*) lang=es-ES ;;
fr*) lang=fr ;; #French
de*) lang=de ;; #German
af*) lang=af ;; #Afrikaans
sq*) lang=sq ;; #Albanian
ar*) lang=ar ;; #Arabic
an*) lang=an ;; #Aragonese
hy_AM*) lang=hy-AM ;; #Armenian
ast*) lang=ast ;; #Asturian
as*) lang=as ;; #Assamese
az*) lang=az ;; #Azerbaijani
eu*) lang=eu ;; #Basque
be*) lang=be ;; #Belarusian
bn_BD*) lang=bn-BD ;; #Bengali (Bangladesh)
bn_IN*) lang=bn-IN ;; #Bengali (India)
bs*) lang=bs ;; #Bosnian
br*) lang=br ;; #Breton
bg*) lang=bg ;; #Bulgarian
ca*) lang=ca ;; #Catalan
zh_CN*) lang=zh-CN ;; #Chinese (Simplified)
zh*) lang=zh-TW ;; #Chinese (Traditional)
hr*) lang=hr ;; #Croatian
cs*) lang=cs ;; #Czech
da*) lang=da ;; #Danish
nl*) lang=nl ;; #Dutch
et*) lang=et ;; #Estonian
fi*) lang=fi ;; #Finnish
fy*) lang=fy-NL ;; #Frisian
ff*) lang=ff ;; #Fulah
gd*) lang=gd ;; #Gaelic (Scotland)
gl*) lang=gl ;; #Galician
el*) lang=el ;; #Greek
gu*) lang=gu-IN ;; #Gujarati (India)
he*) lang=he ;; #Hebrew
hi_IN*) lang=hi-IN ;; #Hindi (India)
hu*) lang=hu ;; #Hungarian
is*) lang=is ;; #Icelandic
id*) lang=id ;; #Indonesian
ga_IE*) lang=ga-IE ;; #Irish
it*) lang=it ;; #Italian
ja*) lang=ja ;; #Japanese
kn*) lang=kn ;; #Kannada
kk*) lang=kk ;; #Kazakh
km*) lang=km ;; #Khmer
ko*) lang=ko ;; #Korean
lv*) lang=lv ;; #Latvian
lt*) lang=lt ;; #Lithuanian
mk*) lang=mk ;; #Macedonian
ms*) lang=ms ;; #Malay
ml*) lang=ml ;; #Malayalam
mr*) lang=mr ;; #Marathi
nb_NO*) lang=nb-NO ;; #Norwegian (Bokmal)
nn_NO*) lang=nn-NO ;; #Norwegian (Nynorsk)
or*) lang=or ;; #Oriya
fa*) lang=fa ;; #Persian
pl*) lang=pl ;; #Polish
pt_BR*) lang=pt-BR ;; #Portuguese (Brazilian)
pt_PT*) lang=pt-PT ;; #Portuguese (Portugal)
ro*) lang=ro ;; #Romanian
ru*) lang=ru ;; #Russian
sr*) lang=sr ;; #Serbian
si*) lang=si ;; #Sinhala
sk*) lang=sk ;; #Slovak
sl*) lang=sl ;; #Slovenian
sv_SE*) lang=sv-SE ;; #Swedish
ta*) lang=ta ;; #Tamil
te*) lang=te ;; #Telugu
th*) lang=th ;; #Thai
tr*) lang=tr ;; #Turkish
uk*) lang=uk ;; #Ukrainian
hsb*) lang=hsb ;; #Upper Sorbian
uz*) lang=uz ;; #Uzbek
vi*) lang=vi ;; #Vietnamese
cy*) lang=cy ;; #Welsh
xh*) lang=xh ;; #Xhosa
*) lang=en-US ; echo " ${YELLOW}Language not recognised (check locale bootcode), using defualt${NORMAL}" ;;
esac
done

# Check the version of Firefox in the current extension
if [ -e /usr/local/tce.installed/firefox ]
then
  ffcurrent_v="`firefox -v`"
else
  # Unpack current extension to determine current version
  rm -r /tmp/ffupdater 2>/dev/null
  echo " ${BLUE}Unpacking old Firefox extension${NORMAL}..."
  unsquashfs -q -d /tmp/ffupdater /etc/sysconfig/tcedir/optional/firefox.tcz || exit 1
  if [ "$ffarch" == "linux-x86_64" ] && [ ! -e /lib64 ]
  then
    sudo ln -s /lib /lib64
  fi
  echo " ${BLUE}Loading Firefox dependencies${NORMAL}..."
  if ! tce-load -i `cat /etc/sysconfig/tcedir/optional/firefox.tcz.dep` >/dev/null
  then
    echo " ${RED}Dependency install failed${NORMAL}"
    rm -r /tmp/ffupdater
    exit 1
  fi
  ffcurrent_v="`/tmp/ffupdater/usr/local/firefox/firefox -v`"
fi
ffcurrent_v="${ffcurrent_v##* }"

# Find release channel in use
altver="`echo -n \"$ffcurrent_v\" | tr -d \".[0-9]\"`"
product=firefox-latest
if [ "$altver" == "esr" ]
then
  product=firefox-esr-latest
else
  if [ "$altver" == "b" ]
  then
    product=firefox-beta-latest
    altver="b[0-9]*"
  fi
fi

# Find the latest version
addressX='http://download.mozilla.org/?os=linux&product='
MOZURL="$(/usr/local/bin/wget -q --max-redirect 0 -S --spider "$addressX$product" 2>&1 | grep 'Location:')"
ffnew_v=$(expr "$MOZURL" : ".*releases/\([0-9]*\.[0-9.]*$altver\)/") #"
if [ -z "$ffnew_v" ]
then
  echo " ${RED}Failed to determine latest version (check network connection).${NORMAL}"
  rm -r /tmp/ffupdater 2>/dev/null
  exit 1
fi

echo " ${GREEN}Latest version ${WHITE}is ${CYAN}$ffnew_v${NORMAL}"

if [ "$ffcurrent_v" == "$ffnew_v" ]
then
  echo " ${YELLOW}$product ${CYAN}$ffnew_v${YELLOW} is already the currently installed version.${NORMAL}"
  echo " ${GREEN}No update required.${NORMAL}"
  rm -r /tmp/ffupdater 2>/dev/null
  exit
fi

echo " ${BLUE}Updating $product from ${CYAN}$ffcurrent_v ${BLUE}to ${CYAN}$ffnew_v${NORMAL}..."

# Need to unpack the extension now if this was skipped before
if [ -e /usr/local/tce.installed/firefox ]
then
  rm -r /tmp/ffupdater 2>/dev/null
  echo " ${BLUE}Unpacking old Firefox extension${NORMAL}..."
  unsquashfs -q -d /tmp/ffupdater /etc/sysconfig/tcedir/optional/firefox.tcz || exit 1
fi

# Update extension files
mkdir -p /tmp/ffupdates
cd /tmp/ffupdates
# Check that last update download wasn't for another Firefox build
if [ -L update.mar ]
then
  mar="`readlink update.mar`"
  if [ "$mar" != "firefox-${ffcurrent_v}-${ffnew_v}-$lang.partial.mar" ] && [ "$mar" != "firefox-${ffnew_v}-$lang.complete.mar" ]
  then
    rm firefox-*.mar
  fi
fi
# Download update
if ! /usr/local/bin/wget -c -O "firefox-${ffcurrent_v}-${ffnew_v}-$lang.partial.mar" \
     "http://download.cdn.mozilla.net/pub/firefox/releases/$ffnew_v/update/$ffarch/$lang/firefox-${ffcurrent_v}-${ffnew_v}.partial.mar"
then
 if ! /usr/local/bin/wget -c -O "firefox-${ffnew_v}-$lang.complete.mar" \
      "http://download.cdn.mozilla.net/pub/firefox/releases/$ffnew_v/update/$ffarch/$lang/firefox-${ffnew_v}.complete.mar"
  then
    echo " ${RED}Couldn't download update file."
    echo " ${YELLOW}Try firefox_getLatest.sh instead.${NORMAL}"
    cd /tmp
    rm -r ffupdater
    exit 1
  fi
fi
# Symlink to downloaded file
[ -e update.mar ] || ln -s firefox-*"${ffnew_v}-$lang".*.mar update.mar

# Save pre-update file list:
find /tmp/ffupdater > /tmp/ffpre-update.list

cd /tmp/ffupdater/usr/local/firefox
echo " ${BLUE}Applying update${NORMAL}..."
LD_LIBRARY_PATH=/tmp/ffupdater/usr/local/firefox ./updater /tmp/ffupdates /tmp/ffupdater/usr/local/firefox /tmp/ffupdater/usr/local/firefox
if [ "`cat /tmp/ffupdates/update.status`" != "succeeded" ]
then
  echo " ${RED}Firefox updater failed${NORMAL}"
  echo "${RED}Updater log:${NORMAL}"
  cat /tmp/ffupdates/update.log
  cd /tmp
  rm -r ffupdater ffpre-update.list
  exit 1
fi
rm -r /tmp/ffupdates

# Check if extension is installed
if [ -e /usr/local/tce.installed/firefox ]
then
  installdir=/etc/sysconfig/tcedir/optional/upgrade
  mkdir -p $installdir || exit 1
  reloadExt=1
else
  installdir=/etc/sysconfig/tcedir/optional
  reloadExt=0
fi

# Rebuild extension
echo " ${BLUE}Rebuilding Firefox extension${NORMAL}..."
cd $installdir
if [ -f "firefox.tcz" ]
then
  # Backup old extension in case mksquashfs fails, if there's enough disk space
  [ $backup -gt 0 ] && mv firefox.tcz firefox.tcz.old || rm -f firefox.tcz
fi
if ! mksquashfs /tmp/ffupdater/ firefox.tcz -all-root -quiet
then
  " ${RED}Rebuilding extension failed${NORMAL}"
  rm -rf firefox.tcz /tmp/ffupdater /tmp/ffpre-update.list
  [ $backup -gt 0 ] && mv firefox.tcz.old firefox.tcz
  exit 1
fi
md5sum firefox.tcz > firefox.tcz.md5.txt
[ $reloadExt -gt 0 ] && cp ../firefox.tcz.dep ./
echo " ${GREEN}Firefox extension updated.${NORMAL}"

# Remount extension
if [ $reloadExt -gt 0 ]
then
  # Save post-update file list:
  find /tmp/ffupdater > /tmp/ffpost-update.list
  # Rebuild symlinks to any changed/added filenames
  if ! busybox diff -U 0 /tmp/ffpre-update.list /tmp/ffpost-update.list > /tmp/ffdiff.list
  then
    grep '/tmp/ffupdater' /tmp/ffdiff.list | while read FILE
    do
      MODE="${FILE%%/*}"
      FILE="${FILE#?/tmp/ffupdater}"
      if [ "$MODE" == "+" ]
      then
        if [ -d "/tmp/ffupdater$FILE" ]
        then
          # Make new directory
          sudo mkdir "$FILE"
        else
          # Make new symlink
          sudo ln -s "/tmp/tcloop/firefox$FILE" "$FILE"
        fi
      else
        # Remove old directory/symlink
        sudo rm -rf "$FILE"
      fi
    done
  fi
  echo " ${BLUE}Mounting updated extension...${NORMAL}"
  sudo umount /tmp/tcloop/firefox
  if sudo mount $installdir/firefox.tcz /tmp/tcloop/firefox
  then
    echo " ${GREEN}Firefox $ffnew_v is now ready to use.${NORMAL}"
  fi
fi

rm -rf firefox.tcz.old /tmp/ffupdater /tmp/ffpre-update.list /tmp/ffpost-update.list /tmp/ffdiff.list