-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathbackupMyIPhone.sh
executable file
·228 lines (198 loc) · 9.38 KB
/
backupMyIPhone.sh
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
#! /usr/bin/env nix-shell
#! nix-shell -i bash ./shell.nix
# Nvm: #!/bin/bash
set -e
continuous="$2" # (Optional) Set to 1 to make the backup wait for WiFi. If 1, $inc (aka $1) will be unused.
firstTime="$3" # (Optional) Set to 1 to re-setup device (only for `continuous` mode for now)
dryRun="$4" # (Optional) [Only works when $continuous == 1] Set to 1 to do a dry run (no changes to backup history + it will be verbose with `set -x`)
if [ "$dryRun" == "1" ]; then
set -x
fi
if [ "$continuous" != "1" ] && [ "$EUID" -ne 0 ]
then echo "Please run as root"
exit
fi
waitForBtrbkDaemon()
{
while true; do
echo "Waiting for btrbk daemon to have its port open..."
sleep 3
nc -z localhost 8089
if [ "$?" == "0" ]; then # netcat (nc) returns exit code 0 when port is open/reachable on that host
break
fi
done
}
chownExe()
{
dest="$1"
groupName="$(stat -c %G "$dest")"
if [ "$?" != "0" ]; then
exit
fi
if [ "$groupName" != "iosbackup" ]; then
echo "chowning $dest for correct group"
sudo chown :iosbackup "$dest"
fi
perms="$(stat -c %a "$dest")"
if [ "$?" != "0" ]; then
exit
fi
if [[ $perms != 75* ]]; then
chmod 75${perms: -1} "$dest"
if [ "$?" != "0" ]; then
exit
fi
fi
}
if [ "$continuous" == "1" ]; then
# Grab config
scriptDir="$(dirname "${BASH_SOURCE[0]}")"
source "$scriptDir/config.sh"
mountpoint "$config__drive" || { echo "Error: backup destination drive not mounted. Exiting."; exit 1; }
# The thing is, here, we need the device's ID to know how to reach it beforehand. So you need to provide a command-line argument for which device to connect to (UUID):
deviceToConnectTo="$5" # Leave empty if $firstTime is 1
snapshotBeforeBackup="$6" # 1 to make a snapshot before backing up, then exit without backing up. Leave empty usually.
useUSB="$7" # 1 to backup via USB instead of WiFi. Requires root (will prompt for sudo access). This argument has no effect when running from systemd. Leave empty usually.
nixShellToUseForUSB="$8" # Only works when useUSB == 1. Leave blank to use ./shell_wifi_pair.nix as the nix shell for the libimobiledevice tools like ideviceinfo and idevicebackup2. If not blank, this should be the path to a nix shell file to use for USB backups.
quietUsbmuxd="$9" # Optional. 1 to make usbmuxd not print as much
# Prepare perms
if [ "$EUID" -ne 0 ]; then
echo "Not root, not preparing perms"
if [ "$firstTime" == "1" ]; then
echo "Need to be root for firstTime. Exiting."
exit 1
fi
else
echo "Root, preparing perms and then continuing"
dest='ibackup.sh'
chownExe "$dest"
dest='backupMyIPhone.sh'
chownExe "$dest"
dest='.'
chownExe "$dest"
dest='udidToFolderLookupTable.py'
chownExe "$dest"
#exit
fi
if [ ! -z "$deviceToConnectTo" ]; then
username="$(python3 ./udidToFolderLookupTable.py "$deviceToConnectTo")"
echo "Backing up as user $username"
if [ "$firstTime" == "1" ]; then
sudo ./ibackup.sh "$deviceToConnectTo" "$firstTime" "$dryRun" "$port" "$username" '' "$snapshotBeforeBackup" '' '' "$quietUsbmuxd"
else
#port=$((8089 + $(id -u "$username")))
port=8089
# [nvm, now checking if environment variable is set from the systemd script] Check if sudo is available, i.e. if running as systemd service then we won't have sudo
#if [ -z "$(which sudo)" ]; then
if [ ! -z "$INVOCATION_ID" ]; then
#echo "No sudo found; assuming this is a systemd service and that btrbk daemon is running already."
echo "Assuming this is a systemd service: INVOCATION_ID is $INVOCATION_ID"
# Verify user
moi="$(whoami)"
if [ "$username" != "$moi" ]; then
echo "Expected script's chosen username \"$username\" to equal whoami user \"${moi}\". Exiting."
exit 1
fi
# Wait till the btrbk daemon warms up and binds the address on the port
waitForBtrbkDaemon
trap "trap - SIGTERM && kill -- -$$" SIGINT SIGTERM EXIT # Install signal handlers that, when systemd kills this process, then it will kill children ("the whole process group") too ( https://stackoverflow.com/questions/360201/how-do-i-kill-background-processes-jobs-when-my-shell-script-exits )
# Run it
./ibackup.sh "$deviceToConnectTo" "$firstTime" "$dryRun" "$port" '' '' "$snapshotBeforeBackup" '' '' "$quietUsbmuxd"
else
# Run btrbk "daemon", as sudo so btrfs snapshots work
echo "Starting btrbk daemon..."
sudo -v # Get user's password first, then cache it for the below command ( https://unix.stackexchange.com/questions/479178/how-would-you-put-a-job-which-requires-sudo-to-background ) + "The sudoers policy caches credentials for 5 minutes, unless overridden in sudoers(5). By running sudo with the -v option, a user can update the cached credentials without running a command." ( https://www.sudo.ws/docs/man/1.8.25/sudo.man/ ). So, note that the user must not have changed this to be like 0 minutes or something..... we will assume not..
sudo ./btrbk_daemon.py "" "" "$dryRun" "$port" & # NOTE: this script may fail if port 8089 is in use. We will assume it is an exiting btrbk daemon that is causing that failure...
# Wait till the btrbk daemon warms up and binds the address on the port
waitForBtrbkDaemon
# Run it as a "daemon"
if [ "$useUSB" == "1" ]; then
# Spawn usbmuxd as root for USB access
noStart=0
scriptDir="$(dirname "${BASH_SOURCE[0]}")"
source "$scriptDir/destUsbmuxd.sh" # Sets `dest_usbmuxd` variable
source "$scriptDir/teeWithTimestamps.sh" # Sets `tee_with_timestamps` function
source "$scriptDir/spawnUsbmuxd.sh" # Spawn usbmuxd if noStart == 0
fi
sudo -E su --preserve-environment "$username" -- ./ibackup.sh "$deviceToConnectTo" "$firstTime" "$dryRun" "$port" '' '' "$snapshotBeforeBackup" "$useUSB" "$nixShellToUseForUSB" "$quietUsbmuxd"
fi
fi
else
# First-time run
if [ "$firstTime" != "1" ]; then
echo "Need to be firstTime to have no deviceToConnectTo. Exiting."
exit 1
fi
# First-time setup with sudo
port=""
sudo ./ibackup.sh "$deviceToConnectTo" "$firstTime" "$dryRun" "$port" '' '' "$snapshotBeforeBackup"
fi
exit
fi
# Provide an existing directory in $1 to do an incremental backup:
inc="$1"
dt=$(date '+%Y-%m-%d %I-%M-%S %p')
# Need to warm up sudo
sudo echo 2>&1 | tee -a "$dt.log.txt"
sudo `which usbmuxd` -f 2>&1 | tee -a "$dt.log.txt" &
# Show some syslog output in the background as we go (so you can see why weird errors like this happen: { [...]
# [==================================================] 98% Finished
# [==================================================] 98% Finished
# [==================================================] 98% Finished
# [==================================================] 98% Finished
# [==================================================] 98% Finished
# [==================================================] 98% Finished
# [==================================================] 98% Finished
# [==================================================] 98% Finished
# [==================================================] 98% Finished
# [==================================================] 98% Finished
# [==================================================] 98% Finished
# [==================================================] 98% Finished
# [==================================================] 98% Finished
# [==================================================] 98% Finished
# [================================================= ] 98% Finished
# Receiving files
# [= ] 0% (65.6 KB/2.6 GB)
# Received an error message from device: Input/output error (5)
# [==================================================] 98% Finished2.6 GB)
# ErrorCode 104: Multiple errors uploading files (MBErrorDomain/104)
# Received 466277 files from device.
# Backup Failed (Error Code 104).
# sebastian@MacBookPro:/run/media/sebastian/5F906D2039164F88$ echo $?
# 152
# })
sudo idevicesyslog 2>&1 | tee -a "$inc$dt.log.txt" 1> /dev/null & # https://unix.stackexchange.com/questions/610329/is-it-safe-to-pipe-multiple-commands-output-to-the-same-file-simultaneously-usin : use tee's append option (`-a`)
directory="$dt"
mkdir "$directory"
# Only compatible with iOS 3 and below: idevicebackup backup "$directory" #--udid 00008020-000D29613C61002E
#idevicebackup2 info "$directory" # Show last backup
echo "---------1" 2>&1 | tee -a "$inc$dt.log.txt"
set +e
output=$(sudo `which idevicebackup2` encryption on SuperBewn "$directory" 2>&1 | tee -a "$inc$dt.log.txt") # Provide password and encrypt backups
res=$?
#echo "$res"
hasEnabledAlready=$(echo "$output" | grep -q 'Backup encryption is already enabled')
if [ -z "$hasEnabledAlready" ]; then
# Allow nonzero exit codes to be ok
echo "Backup encryption is already enabled" 2>&1 | tee -a "$inc$dt.log.txt"
:
else
# Error if exit code is nonzero
if [ "$res" != "0" ]; then
echo "$output" 2>&1 | tee -a "$inc$dt.syslog.txt"
exit "$res"
fi
fi
set -e
echo "---------2" 2>&1 | tee -a "$inc$dt.log.txt"
if [ -z "$inc" ]; then
sudo `which idevicebackup2` --interactive backup --full "$directory" 2>&1 | tee -a "$inc$dt.log.txt" # Back up
else
sudo `which idevicebackup2` --interactive backup "$inc" 2>&1 | tee -a "$inc$dt.log.txt" # Back up
fi
sudo pkill idevicesyslog
sleep 8
# Sometimes it doesn't kill gracefully, so kill it completely:
sudo pkill -9 idevicesyslog
sudo pkill usbmuxd