summaryrefslogtreecommitdiff
path: root/andbackup.sh
blob: 2093832bc52fc9cfbd94801973de952f8e7b414c (plain)
    1 #!/system/xbin/bash
    2 #
    3 # Andbackup performs Android backups and restores.
    4 # Copyright (C) 2016  Aaron Ball <nullspoon@oper.io>
    5 #
    6 # This program is free software: you can redistribute it and/or modify
    7 # it under the terms of the GNU General Public License as published by
    8 # the Free Software Foundation, either version 3 of the License, or
    9 # (at your option) any later version.
   10 #
   11 # This program is distributed in the hope that it will be useful,
   12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
   13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   14 # GNU General Public License for more details.
   15 #
   16 # You should have received a copy of the GNU General Public License
   17 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
   18 #
   19 set -u
   20 
   21 backups=/sdcard/andbackup
   22 
   23 
   24 function backup_app {
   25   local app=${1:-}
   26 
   27   # Make sure app is specified
   28   if [[ -z ${app} ]]; then
   29     echo "Please specify an app to backup."
   30     return 1
   31   fi
   32 
   33   # Make sure app is installed
   34   if [[ $(dumpsys package ${app} | wc -l) -eq 0 ]]; then
   35     echo "Package ${app} appears to not be installed."
   36     return 1
   37   fi
   38 
   39   echo "Backing up ${app}"
   40 
   41   # Stop the application if it is running
   42   am force-stop ${app}
   43 
   44   # Get pertinent metadata
   45   local code=$(dumpsys package ${app} | grep codePath | cut -d'=' -f2 | head -n1)
   46   local data=$(dumpsys package ${app} | grep dataDir  | cut -d'=' -f2 | head -n1)
   47 
   48   # Create backup destination if not exist
   49   [[ ! -d ${backups} ]] && mkdir -p ${backups}
   50   [[ ! -d ${backups}/${app}/data ]] && mkdir -p ${backups}/${app}/data
   51 
   52   # Backup the apk file if it exists
   53   if [[ -f ${code}/base.apk ]]; then
   54     cp ${code}/base.apk ${backups}/${app}/base.apk
   55   else
   56     echo "${app} apk file could not be found. Skipping apk installer backup."
   57   fi
   58 
   59   # Copy the user data
   60   cp -rp ${data}/* ${backups}/${app}/data/
   61   # Delete cache directory if it exists
   62   # This will sometimes significant amounts of space
   63   if [[ -d "${backups}/${app}/data/cache" ]]; then
   64     rm -rf "${backups}/${app}/data/cache"
   65   fi
   66 
   67   # Compress the backup
   68   echo "Compressing userdata for ${app}"
   69   cd ${backups}/${app}/
   70   tar -cf data.tar data
   71   bzip2 -f data.tar
   72   rm -rf data
   73 }
   74 
   75 
   76 # function list_apps {
   77 #   cd ${userdata}
   78 #   for dir in *; do
   79 #     echo ${dir%-*}
   80 #   done
   81 # }
   82 
   83 
   84 function restore_app {
   85   local app=${1:-}
   86 
   87   # Make sure app is specified
   88   if [[ -z ${app} ]]; then
   89     echo "Please specify an app to restore."
   90     return 1
   91   fi
   92 
   93   # Check that backup exists to be restored
   94   if [[ ! -d ${backups}/${app} ]]; then
   95     echo "No backup for ${app} exists."
   96     return 1
   97   fi
   98 
   99   echo "Restoring ${app}"
  100 
  101   # Install app if it is not yet installed
  102   if [[ ! -f "${backups}/${app}/base.apk" ]]; then
  103     echo "Installer for ${app} not found. Only restoring data."
  104   elif [[ $(dumpsys package ${app} | grep -c userId) -eq 0 ]]; then
  105     echo "Installer detected but package ${app} is not installed. Installing"
  106     pm install ${backups}/${app}/base.apk
  107   fi
  108 
  109   # Stop the application if it is running
  110   am force-stop ${app}
  111 
  112   # Get pertinent metadata
  113   local owner=$(dumpsys package ${app} | grep userId | cut -d'=' -f2 | head -n1)
  114   local code=$(dumpsys package ${app} | grep codePath | cut -d'=' -f2 | head -n1)
  115   local data=$(dumpsys package ${app} | grep dataDir  | cut -d'=' -f2 | head -n1)
  116 
  117   # Decompress backup
  118   echo "Decompressing user data for ${app}."
  119   cd ${backups}/${app}/
  120   bunzip2 -c data.tar.bz2 | tar -x
  121 
  122   # Copy the user data in
  123   cp -rp ${backups}/${app}/data/* ${data}/
  124   # Fix data permissions
  125   chown -R ${owner}:${owner} ${data}
  126   # Fix selinux labels
  127   restorecon -R ${data}
  128 
  129   # Cleanup the extracted data so restores don't take too much space
  130   rm -rf ${backups}/${app}/data
  131 }
  132 
  133 
  134 function backup_apps {
  135   local apps=${@}
  136   [[ -z ${apps[@]:-} ]] && echo "At least one app is required." && return 1
  137 
  138   for app in ${apps[@]}; do
  139     backup_app ${app}
  140   done
  141 }
  142 
  143 
  144 function restore_apps {
  145   local apps=${@}
  146   [[ -z ${apps[@]:-} ]] && echo "At least one app is required." && return 1
  147 
  148   for app in ${apps[@]}; do
  149     restore_app ${app}
  150   done
  151 }
  152 
  153 
  154 function list_backup_apps {
  155   local list=${1:-}
  156   [[ -z ${list} ]] && echo "A backup list is required." && return 1
  157 
  158   for app in $(cat ${list}); do
  159     backup_app ${app}
  160   done
  161 }
  162 
  163 
  164 function list_restore_apps {
  165   local list=${1}
  166   [[ -z ${list} ]] && echo "A backup list is required." && return 1
  167 
  168   for app in $(cat ${list}); do
  169     restore_app ${app}
  170   done
  171 }
  172 
  173 
  174 function main {
  175   local cmd=${1:-}
  176   shift
  177 
  178   # Ensure root is running this script
  179   if [[ $(id -u) -gt 0 ]]; then
  180     echo "Script must be run as root (uid 0)."
  181     exit 1
  182   fi
  183 
  184 
  185   if [[ ${cmd} == 'backup' ]]; then
  186     backup_apps ${@}
  187   elif [[ ${cmd} == 'listbackup' ]]; then
  188     list_backup_apps ${@}
  189   elif [[ ${cmd} == 'restore' ]]; then
  190     restore_apps ${@}
  191   elif [[ ${cmd} == 'listrestore' ]]; then
  192     list_restore_apps ${@}
  193   elif [[ ${cmd} == 'ls' || ${cmd} == 'list' ]]; then
  194     list_apps
  195   else
  196     echo "Please specify a command"
  197     echo -e "Available commands are...\n"\
  198             " backup\n"\
  199             " listbackup\n"\
  200             " restore\n"\
  201             " listrestore\n"\
  202             " list\n"
  203     exit 1
  204   fi
  205 }
  206 
  207 main ${@}

Generated by cgit