Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit c63fa844 authored by Alessandro Astone's avatar Alessandro Astone Committed by Paul Keith
Browse files

backuptool: Support seamless backup and restore to extra partitions

For scripts declaring ADDOND_VERSION=3 automatically mount
vendor, product, system_ext and others (when they're dedicated partitions).

Also expose the get_output_path() function to get the path to where
a file is mounted in case it lives in a dedicated partition.

ab exapmles:
get_output_path "system/product/priv-app/MyApp.apk"  = "/postinstall/product/priv-app/MyApk.apk"
get_output_path "system/app/MySystemApp.apk"         = "/postinstall/system/app/MySystemApp.apk"

a-only examples:
get_output_path "/mnt/system/system/product/priv-app/MyApp.apk" = "/mnt/system/system/product/priv-app/MyApp.apk"

******************************************************************
Instead of cycling all scripts for each stage, run
pre-backup -> backup -> post-backup in quick succession
(and likewise for restore), to ensure backwards compatibility
with scripts that wrongly assumed their environment not to
change between steps.
This is needed because we want to undo any mounting done for V3
scripts when executing V2 scripts. If a V2 script did mounting in
pre-restore and expected things to still be mounted in restore,
we would break their (yes incorrect) assumption.

Change-Id: I73fbad6f45824fed99e4482128769435348588f5
parent 62458730
Loading
Loading
Loading
Loading
+7 −2
Original line number Diff line number Diff line
@@ -34,10 +34,15 @@ restore_file() {
    if [ ! -d "$DIR" ]; then
      mkdir -p "$DIR";
    fi
    copy_file "$C/$DIR/$FILE" "$1";
    copy_file "$C/$DIR/$FILE" $(get_output_path "$1");
    if [ -n "$2" ]; then
      echo "Deleting obsolete file $2"
      rm "$2";
      rm $(get_output_path "$2");
    fi
  fi
}

get_output_path() {
  # In recovery we mounted all partitions in the right place, so we can rely on symlinks
  echo "$1"
}
+87 −9
Original line number Diff line number Diff line
@@ -8,9 +8,20 @@ export SYSDEV="$(readlink -nf "$2")"
export SYSFS="$3"
export V=18.1

export ADDOND_VERSION=3

# Partitions to mount for backup/restore in V3
export all_V3_partitions="vendor product system_ext"

# Scripts in /system/addon.d expect to find backuptool.functions in /tmp
cp -f /tmp/install/bin/backuptool.functions /tmp

get_script_version() {
  version=$(grep "^# ADDOND_VERSION=" $1 | cut -d= -f2)
  [ -z "$version" ] && version=1
  echo $version
}

# Preserve /system/addon.d in /tmp/addon.d
preserve_addon_d() {
  if [ -d $S/addon.d/ ]; then
@@ -43,15 +54,31 @@ fi
return 0
}

# Execute /system/addon.d/*.sh scripts with $1 parameter
run_stage() {
# Execute /system/addon.d/*.sh scripts with each $@ parameter
run_stages() {
if [ -d /tmp/addon.d/ ]; then
  for script in $(find /tmp/addon.d/ -name '*.sh' |sort -n); do
    $script $1
    v=$(get_script_version $script)
    if [ $v -ge 3 ]; then
      mount_extra $all_V3_partitions
    else
      umount_extra $all_V3_partitions
    fi

    for stage in $@; do
      if [ $v -ge 3 ]; then
        $script $stage
      else
        ADDOND_VERSION=2 $script $stage
      fi
    done
  done
fi
}

#####################
### Mount helpers ###
#####################
determine_system_mount() {
  if grep -q -e"^$SYSDEV" /proc/mounts; then
    umount $(grep -e"^$SYSDEV" /proc/mounts | cut -d" " -f2)
@@ -76,26 +103,77 @@ unmount_system() {
  umount $SYSMOUNT
}

get_block_for_mount_point() {
  grep -v "^#" /etc/recovery.fstab | grep " $1 " | tail -n1 | tr -s ' ' | cut -d' ' -f1
}

find_block() {
  local name="$1"
  local fstab_entry=$(get_block_for_mount_point "/$name")
  # P-SAR hacks
  [ -z "$fstab_entry" ] && [ "$name" = "system" ] && fstab_entry=$(get_block_for_mount_point "/")
  [ -z "$fstab_entry" ] && [ "$name" = "system" ] && fstab_entry=$(get_block_for_mount_point "/system_root")

  local dev
  if [ "$DYNAMIC_PARTITIONS" = "true" ]; then
    if [ -n "$fstab_entry" ]; then
      dev="${BLK_PATH}/${fstab_entry}"
    else
      dev="${BLK_PATH}/${name}"
    fi
  else
    if [ -n "$fstab_entry" ]; then
      dev="$fstab_entry"
    else
      dev="${BLK_PATH}/${name}"
    fi
  fi

  if [ -b "$dev" ]; then
    echo "$dev"
  fi
}

determine_system_mount

DYNAMIC_PARTITIONS=$(getprop ro.boot.dynamic_partitions)
BLK_PATH=$(dirname "$SYSDEV")

mount_extra() {
  for partition in $@; do
    mnt_point="/$partition"
    mountpoint "$mnt_point" >/dev/null 2>&1 && break

    blk_dev=$(find_block "$partition")
    if [ -e "$blk_dev" ]; then
      [ "$DYNAMIC_PARTITIONS" = "true" ] && blockdev --setrw "$blk_dev"
      mkdir -p "$mnt_point"
      mount -o rw "$blk_dev" "$mnt_point"
    fi
  done
}

umount_extra() {
  for partition in $@; do
    umount -l "/$partition" 2>/dev/null
  done
}

case "$1" in
  backup)
    mount_system
    if check_prereq; then
      mkdir -p $C
      preserve_addon_d
      run_stage pre-backup
      run_stage backup
      run_stage post-backup
      run_stages pre-backup backup post-backup
    fi
    unmount_system
  ;;
  restore)
    mount_system
    if check_prereq; then
      run_stage pre-restore
      run_stage restore
      run_stage post-restore
      run_stages pre-restore restore post-restore
      umount_extra $all_V3_partitions
      restore_addon_d
      rm -rf $C
      sync
+27 −2
Original line number Diff line number Diff line
@@ -39,10 +39,35 @@ backup_file() {

restore_file() {
  if [ -e "$C/$1" -o -L "$C/$1" ]; then
    move_file "$C/$1" "/postinstall/$1";
    move_file "$C/$1" $(get_output_path "$1");
    if [ -n "$2" ]; then
      echo "Deleting obsolete file $2"
      rm "$2";
      rm $(get_output_path "$2");
    fi
  fi
}

get_output_path() {
  if [ $ADDOND_VERSION -lt 3 ]; then
    echo "/postinstall/$1"
    return
  fi

  file=$(echo "$1" | sed "s|^$S/||")
  if __is_on_mounted_partition "$file"; then
    echo "/postinstall/$file"
  else
    echo "/postinstall/$1"
  fi
}

__is_on_mounted_partition() {
  for p in $all_V3_partitions; do
    mnt_point="/postinstall/$p"
    if echo "$1" | grep -q "^$p/" && [ ! -L "$mnt_point" ] && mountpoint >/dev/null 2>&1 "$mnt_point"; then
      return 0
    fi
  done

  return 1
}
+105 −16
Original line number Diff line number Diff line
@@ -7,26 +7,31 @@ export S=/system
export C=/postinstall/tmp/backupdir
export V=18.1

export ADDOND_VERSION=2
export ADDOND_VERSION=3

# Partitions to mount for backup/restore in V3
export all_V3_partitions="vendor product system_ext odm oem"

# Scripts in /system/addon.d expect to find backuptool.functions in /tmp
mkdir -p /postinstall/tmp/
mountpoint /postinstall/tmp >/dev/null 2>&1 || mount -t tmpfs tmpfs /postinstall/tmp
cp -f /postinstall/system/bin/backuptool_ab.functions /postinstall/tmp/backuptool.functions

get_script_version() {
  version=$(grep "^# ADDOND_VERSION=" $1 | cut -d= -f2)
  [ -z "$version" ] && version=1
  echo $version
}

# Preserve /system/addon.d in /tmp/addon.d
preserve_addon_d() {
  if [ -d /system/addon.d/ ]; then
    mkdir -p /postinstall/tmp/addon.d/
    cp -a /system/addon.d/* /postinstall/tmp/addon.d/

    # Discard any scripts that aren't at least our version level
    # Discard any version 1 script, as it is not compatible with a/b
    for f in /postinstall/tmp/addon.d/*sh; do
      SCRIPT_VERSION=$(grep "^# ADDOND_VERSION=" $f | cut -d= -f2)
      if [ -z "$SCRIPT_VERSION" ]; then
        SCRIPT_VERSION=1
      fi
      if [ $SCRIPT_VERSION -lt $ADDOND_VERSION ]; then
      if [ $(get_script_version $f) = 1 ]; then
        rm $f
      fi
    done
@@ -58,8 +63,8 @@ fi
return 0
}

# Execute /system/addon.d/*.sh scripts with $1 parameter
run_stage() {
# Execute /system/addon.d/*.sh scripts with each $@ parameter
run_stages() {
if [ -d /postinstall/tmp/addon.d/ ]; then
  for script in $(find /postinstall/tmp/addon.d/ -name '*.sh' |sort -n); do
    # we have no /sbin/sh in android, only recovery
@@ -67,9 +72,96 @@ if [ -d /postinstall/tmp/addon.d/ ]; then
    sed -i '0,/#!\/sbin\/sh/{s|#!/sbin/sh|#!/system/bin/sh|}' $script
    # we can't count on /tmp existing on an A/B device, so utilize /postinstall/tmp as tmpfs
    sed -i 's|. /tmp/backuptool.functions|. /postinstall/tmp/backuptool.functions|g' $script
    $script $1

    v=$(get_script_version $script)
    if [ $v -ge 3 ]; then
      mount_extra $all_V3_partitions
    else
      umount_extra $all_V3_partitions
    fi

    for stage in $@; do
      if [ $v -ge 3 ]; then
        $script $stage
      else
        ADDOND_VERSION=2 $script $stage
      fi
    done
  done
fi
}

#####################
### Mount helpers ###
#####################
get_block_for_mount_point() {
  grep -v "^#" /vendor/etc/fstab.$(getprop ro.boot.hardware) | grep " $1 " | tail -n1 | tr -s ' ' | cut -d' ' -f1
}

find_block() {
  local name="$1"
  local fstab_entry=$(get_block_for_mount_point "/$name")
  # P-SAR hacks
  [ -z "$fstab_entry" ] && [ "$name" = "system" ] && fstab_entry=$(get_block_for_mount_point "/")
  [ -z "$fstab_entry" ] && [ "$name" = "system" ] && fstab_entry=$(get_block_for_mount_point "/system_root")

  local dev
  if [ "$DYNAMIC_PARTITIONS" = "true" ]; then
    if [ -n "$fstab_entry" ]; then
      dev="${BLK_PATH}/${fstab_entry}${SLOT_SUFFIX}"
    else
      dev="${BLK_PATH}/${name}${SLOT_SUFFIX}"
    fi
  else
    if [ -n "$fstab_entry" ]; then
      dev="${fstab_entry}${SLOT_SUFFIX}"
    else
      dev="${BLK_PATH}/${name}${SLOT_SUFFIX}"
    fi
  fi

  if [ -b "$dev" ]; then
    echo "$dev"
  fi
}

DYNAMIC_PARTITIONS=$(getprop ro.boot.dynamic_partitions)
if [ "$DYNAMIC_PARTITIONS" = "true" ]; then
    BLK_PATH="/dev/block/mapper"
else
    BLK_PATH=/dev/block/bootdevice/by-name
fi

CURRENTSLOT=$(getprop ro.boot.slot_suffix)
if [ ! -z "$CURRENTSLOT" ]; then
  if [ "$CURRENTSLOT" = "_a" ]; then
    # Opposite slot
    SLOT_SUFFIX="_b"
  else
    SLOT_SUFFIX="_a"
  fi
fi

mount_extra() {
  for partition in $@; do
    mnt_point="/postinstall/$partition"
    mountpoint "$mnt_point" >/dev/null 2>&1 && break

    blk_dev=$(find_block "$partition")
    if [ -n "$blk_dev" ]; then
      [ "$DYNAMIC_PARTITIONS" = "true" ] && blockdev --setrw "$blk_dev"
      mount -o rw "$blk_dev" "$mnt_point"
    fi
  done
}

umount_extra() {
  for partition in $@; do
    # Careful with unmounting. If the update has a partition less than the current system,
    # /postinstall/$partition is a symlink to /system/$partition, which on the active slot
    # is a symlink to /$partition which is a mountpoint we would end up unmounting!
    [ ! -L "/postinstall/$partition" ] && umount -l "/postinstall/$partition" 2>/dev/null
  done
}

case "$1" in
@@ -77,16 +169,13 @@ case "$1" in
    if check_prereq; then
      mkdir -p $C
      preserve_addon_d
      run_stage pre-backup
      run_stage backup
      run_stage post-backup
      run_stages pre-backup backup post-backup
    fi
  ;;
  restore)
    if check_prereq; then
      run_stage pre-restore
      run_stage restore
      run_stage post-restore
      run_stages pre-restore restore post-restore
      umount_extra $all_V3_partitions
      restore_addon_d
      rm -rf $C
      umount /postinstall/tmp