system-image-upgrade: Pass --ignore-time-conflict to gpg
[CyanogenMod/android_bootable_recovery.git] / system-image-upgrader
1 #!/sbin/sh
2 set -e
3
4 if [ ! -e "$1" ]; then
5     echo "Command file doesn't exist: $1"
6     exit 1
7 fi
8 mv $1 $1.applying
9 COMMAND_FILE=$1.applying
10
11 REMOVE_LIST="$COMMAND_FILE"
12
13 echo "Starting image upgrader: $(date)"
14
15 # Functions
16 verify_signature() {
17     # $1 => validation keyring name
18     # $2 => path to validate
19
20     if [ ! -e $2 ]; then
21         echo "File doesn't exist: $2"
22         return 1
23     fi
24
25     # Check against the blacklist
26     if [ -e /tmp/system-image/blacklist/pubring.gpg ]; then
27         export GNUPGHOME=/tmp/system-image/blacklist/
28         if gpg --ignore-time-conflict --verify $2 >/dev/null 2>&1; then
29             echo "File signed by a blacklisted key: $2"
30             return 1
31         fi
32     fi
33
34     # Check against the keyring
35     export GNUPGHOME=/tmp/system-image/$1/
36     if [ ! -e "$GNUPGHOME" ]; then
37         echo "Keyring doesn't exist: $1"
38         return 1
39     fi
40
41     if gpg --ignore-time-conflict --verify $2 >/dev/null 2>&1; then
42         return 0
43     fi
44
45     return 1
46 }
47
48 install_keyring() {
49     # $1 => full path to tarball
50     # $2 => full path to signature
51
52     # Some basic checks
53     if [ ! -e "$1" ] || [ ! -e "$2" ]; then
54         echo "Missing keyring files: $1 => $2"
55         return 1
56     fi
57
58     # Unpacking
59     TMPDIR=$(mktemp -d)
60     cd $TMPDIR
61     cat $1 | unxz | tar xf -
62     if [ ! -e keyring.json ] || [ ! -e keyring.gpg ]; then
63         rm -Rf $TMPDIR
64         echo "Invalid keyring: $1"
65         return 1
66     fi
67
68     # Extract the expiry
69     keyring_expiry=$(grep "^    \"expiry\": " keyring.json | cut -d: -f2 | sed -e "s/[ \",]//g")
70     if [ -n "$keyring_expiry" ] && [ "$keyring_expiry" -lt "$(date +%s)" ]; then
71         rm -Rf $TMPDIR
72         echo "Keyring expired: $1"
73         return 1
74     fi
75
76     # Extract the keyring type
77     keyring_type=$(grep "^    \"type\": " keyring.json | cut -d: -f2 | sed -e "s/[, \"]//g")
78     if [ -z "$keyring_type" ]; then
79         rm -Rf $TMPDIR
80         echo "Missing keyring type: $1"
81         return 1
82     fi
83
84     if [ -e /tmp/system-image/$keyring_type ]; then
85         rm -Rf $TMPDIR
86         echo "Keyring already loaded: $1"
87         return 1
88     fi
89
90     signer="unknown"
91     case "$keyring_type" in
92         archive-master)
93             signer=""
94         ;;
95
96         image-master)
97             signer="archive-master"
98         ;;
99
100         image-signing|blacklist)
101             signer="image-master"
102         ;;
103
104         device-signing)
105             signer="image-signing"
106         ;;
107     esac
108
109     if [ -n "$signer" ] && ! verify_signature $signer $2; then
110         rm -Rf $TMPDIR
111         echo "Invalid signature: $1"
112         return 1
113     fi
114
115     mkdir /tmp/system-image/$keyring_type
116     chmod 700 /tmp/system-image/$keyring_type
117     mv $TMPDIR/keyring.gpg /tmp/system-image/$keyring_type/pubring.gpg
118     chmod 600 /tmp/system-image/$keyring_type/pubring.gpg
119     chown 0:0 /tmp/system-image/$keyring_type/pubring.gpg
120     rm -Rf $TMPDIR
121     return 0
122 }
123
124 # Initialize GPG
125 rm -Rf /tmp/system-image
126 mkdir -p /tmp/system-image
127 if [ -e /etc/system-image/archive-master.tar.xz ]; then
128     echo "Loading keyring: archive-master.tar.xz"
129     install_keyring /etc/system-image/archive-master.tar.xz /etc/system-image/archive-master.tar.xz.asc
130 fi
131
132 # Process the command file
133 FULL_IMAGE=0
134 echo "Processing the command file"
135 while read line
136 do
137     set -- $line
138     case "$1" in
139         format)
140             echo "Formating: $2"
141             case "$2" in
142                 system)
143                     FULL_IMAGE=1
144                     rm -f /data/system.img
145                     dd if=/dev/zero of=/data/system.img seek=500K bs=4096 count=0
146                     mkfs.ext2 -F /data/system.img
147                 ;;
148
149                 data)
150                     for entry in /data/*; do
151                         if [ "$entry" != "/data/system.img" ]; then
152                             rm -Rf $entry
153                         fi
154                     done
155                 ;;
156
157                 *)
158                     echo "Unknown format target: $2"
159                 ;;
160             esac
161         ;;
162
163         load_keyring)
164             if [ ! -e "/cache/recovery/$2" ] || [ ! -e "/cache/recovery/$3" ]; then
165                 echo "Skipping missing file: $2"
166                 continue
167             fi
168             REMOVE_LIST="$REMOVE_LIST /cache/recovery/$2 /cache/recovery/$3"
169
170             echo "Loading keyring: $2"
171             install_keyring /cache/recovery/$2 /cache/recovery/$3
172
173             if [ -e /tmp/system-image/image-master/pubring.gpg ] && \
174                [ ! -e /tmp/system-image/blacklist/pubring.gpg ] && \
175                [ -e /data/system-data/var/lib/system-image/blacklist.tar.xz ] && \
176                [ -e /data/system-data/var/lib/system-image/blacklist.tar.xz.asc ]; then
177                 echo "Loading blacklist keyring"
178                 install_keyring /data/system-data/var/lib/system-image/blacklist.tar.xz /data/system-data/var/lib/system-image/blacklist.tar.xz.asc
179             fi
180         ;;
181
182         mount)
183             case "$2" in
184                 system)
185                     mkdir -p /cache/system
186                     mount -o loop /data/system.img /cache/system/
187                 ;;
188
189                 *)
190                     echo "Unknown mount target: $2"
191                 ;;
192             esac
193         ;;
194
195         unmount)
196             case "$2" in
197                 system)
198                     umount /cache/system
199                     rmdir /cache/system
200                 ;;
201
202                 *)
203                     echo "Unknown mount target: $2"
204                 ;;
205             esac
206         ;;
207
208         update)
209             if [ ! -e "/cache/recovery/$2" ] || [ ! -e "/cache/recovery/$3" ]; then
210                 echo "Skipping missing file: $2"
211                 continue
212             fi
213
214             REMOVE_LIST="$REMOVE_LIST /cache/recovery/$2 /cache/recovery/$3"
215
216             if ! verify_signature device-signing /cache/recovery/$3 && \
217                ! verify_signature image-signing /cache/recovery/$3; then
218                 echo "Invalid signature"
219                 continue
220             fi
221
222             echo "Applying update: $2"
223             cd /cache
224             rm -Rf partitions
225
226             # Start by removing any file listed in "removed"
227             if [ "$FULL_IMAGE" != "1" ]; then
228                 cat recovery/$2 | unxz | tar xf - removed >/dev/null 2>&1 || true
229                 if [ -e removed ]; then
230                     while read file; do
231                         rm -Rf $file
232                     done < removed
233                 fi
234                 rm -f removed
235             fi
236
237             # Unpack everything else on top of the system partition
238             cat recovery/$2 | unxz | tar xf -
239             rm -f removed
240
241             # Process partition images
242             while read line; do
243                 set -- $line
244
245                 part=${1##/}
246                 path=$3
247
248                 if [ -e partitions/${part}.img ] && [ -e $path ]; then
249                     echo "Flashing ${part} at ${path}"
250                     cat partitions/${part}.img > ${path}
251                     rm partitions/${part}.img
252                 fi
253             done < /etc/recovery.fstab
254         ;;
255
256         *)
257             echo "Unknown command: $1"
258         ;;
259     esac
260 done < $COMMAND_FILE
261
262 # Remove the update files
263 for file in $REMOVE_LIST; do
264     rm $file
265 done
266
267 # Create the SWAP image if missing
268 if [ ! -e /data/SWAP.img ]; then
269     echo "Creating SWAP device."
270     dd if=/dev/zero of=/data/SWAP.img bs=4096 count=131072
271     mkswap /data/SWAP.img
272 fi
273
274 # Ensure we have sane permissions
275 chmod 600 /data/system.img
276 chown 0:0 /data/system.img
277 chmod 600 /data/SWAP.img
278 chown 0:0 /data/SWAP.img
279
280 touch /data/.last_update || true
281 sync
282 echo "Done upgrading: $(date)"