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 ${@}
|