blob: fc7a561eb982954c859059def932b9194e512df2 [file] [log] [blame]
Doug Zongkerbc7ffed2014-08-15 14:31:52 -07001/*
2 * Copyright (C) 2014 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include <ctype.h>
18#include <errno.h>
Sami Tolvanen90221202014-12-09 16:39:47 +000019#include <dirent.h>
Doug Zongkerbc7ffed2014-08-15 14:31:52 -070020#include <fcntl.h>
Tao Bao0bbc7642017-03-29 23:57:47 -070021#include <inttypes.h>
Tao Baoba9a42a2015-06-23 23:23:33 -070022#include <linux/fs.h>
Doug Zongkerbc7ffed2014-08-15 14:31:52 -070023#include <pthread.h>
24#include <stdarg.h>
25#include <stdio.h>
26#include <stdlib.h>
27#include <string.h>
Sami Tolvanen90221202014-12-09 16:39:47 +000028#include <sys/stat.h>
Doug Zongkerbc7ffed2014-08-15 14:31:52 -070029#include <sys/types.h>
30#include <sys/wait.h>
31#include <sys/ioctl.h>
32#include <time.h>
33#include <unistd.h>
Sami Tolvanen0a7b4732015-06-25 10:25:36 +010034#include <fec/io.h>
Doug Zongkerbc7ffed2014-08-15 14:31:52 -070035
Tao Baoec8272f2017-03-15 17:39:01 -070036#include <functional>
Tao Baoe6aa3322015-08-05 15:20:27 -070037#include <memory>
38#include <string>
Tianjie Xu8cf5c8f2016-09-08 20:10:11 -070039#include <unordered_map>
Tao Bao0940fe12015-08-27 16:41:21 -070040#include <vector>
Tao Baoe6aa3322015-08-05 15:20:27 -070041
Tao Bao039f2da2016-11-22 16:29:50 -080042#include <android-base/logging.h>
Elliott Hughes4b166f02015-12-04 15:30:20 -080043#include <android-base/parseint.h>
44#include <android-base/strings.h>
Elliott Hughesbcabd092016-03-22 20:19:22 -070045#include <android-base/unique_fd.h>
Tao Bao51412212016-12-28 14:44:05 -080046#include <applypatch/applypatch.h>
47#include <openssl/sha.h>
Tianjie Xua946b9e2017-03-21 16:24:57 -070048#include <private/android_filesystem_config.h>
Tianjie Xu8cf5c8f2016-09-08 20:10:11 -070049#include <ziparchive/zip_archive.h>
Tao Baoe6aa3322015-08-05 15:20:27 -070050
Doug Zongkerbc7ffed2014-08-15 14:31:52 -070051#include "edify/expr.h"
Tianjie Xu16255832016-04-30 11:49:59 -070052#include "error_code.h"
Jed Estep39c1b5e2015-12-15 16:04:53 -080053#include "ota_io.h"
Tao Baoe6aa3322015-08-05 15:20:27 -070054#include "print_sha1.h"
Tao Bao8f237572017-03-26 13:36:49 -070055#include "updater/install.h"
56#include "updater/rangeset.h"
Tao Bao0c7839a2016-10-10 15:48:37 -070057#include "updater/updater.h"
Doug Zongkerbc7ffed2014-08-15 14:31:52 -070058
Sami Tolvanene82fa182015-06-10 15:58:12 +000059// Set this to 0 to interpret 'erase' transfers to mean do a
60// BLKDISCARD ioctl (the normal behavior). Set to 1 to interpret
61// erase to mean fill the region with zeroes.
62#define DEBUG_ERASE 0
63
Tao Bao51412212016-12-28 14:44:05 -080064static constexpr size_t BLOCKSIZE = 4096;
65static constexpr const char* STASH_DIRECTORY_BASE = "/cache/recovery";
66static constexpr mode_t STASH_DIRECTORY_MODE = 0700;
67static constexpr mode_t STASH_FILE_MODE = 0600;
Sami Tolvanen90221202014-12-09 16:39:47 +000068
Tianjie Xu16255832016-04-30 11:49:59 -070069static CauseCode failure_type = kNoCause;
Tianjie Xu7ce287d2016-05-31 09:29:49 -070070static bool is_retry = false;
Tianjie Xu8cf5c8f2016-09-08 20:10:11 -070071static std::unordered_map<std::string, RangeSet> stash_map;
Tianjie Xu7eca97e2016-03-22 18:08:12 -070072
Sami Tolvanen90221202014-12-09 16:39:47 +000073static int read_all(int fd, uint8_t* data, size_t size) {
Doug Zongkerbc7ffed2014-08-15 14:31:52 -070074 size_t so_far = 0;
75 while (so_far < size) {
Jed Estepa7b9a462015-12-15 16:04:53 -080076 ssize_t r = TEMP_FAILURE_RETRY(ota_read(fd, data+so_far, size-so_far));
Elliott Hughes7bad7c42015-04-28 17:24:24 -070077 if (r == -1) {
Tianjie Xu16255832016-04-30 11:49:59 -070078 failure_type = kFreadFailure;
Tao Bao039f2da2016-11-22 16:29:50 -080079 PLOG(ERROR) << "read failed";
Sami Tolvanen90221202014-12-09 16:39:47 +000080 return -1;
Tianjie Xu71e182b2016-08-31 18:06:33 -070081 } else if (r == 0) {
82 failure_type = kFreadFailure;
Tao Bao039f2da2016-11-22 16:29:50 -080083 LOG(ERROR) << "read reached unexpected EOF.";
Tianjie Xu71e182b2016-08-31 18:06:33 -070084 return -1;
Doug Zongkerbc7ffed2014-08-15 14:31:52 -070085 }
Elliott Hughes7bad7c42015-04-28 17:24:24 -070086 so_far += r;
Doug Zongkerbc7ffed2014-08-15 14:31:52 -070087 }
Sami Tolvanen90221202014-12-09 16:39:47 +000088 return 0;
Doug Zongkerbc7ffed2014-08-15 14:31:52 -070089}
90
Tao Bao612336d2015-08-27 16:41:21 -070091static int read_all(int fd, std::vector<uint8_t>& buffer, size_t size) {
92 return read_all(fd, buffer.data(), size);
93}
94
Sami Tolvanen90221202014-12-09 16:39:47 +000095static int write_all(int fd, const uint8_t* data, size_t size) {
Doug Zongkerbc7ffed2014-08-15 14:31:52 -070096 size_t written = 0;
97 while (written < size) {
Jed Estepa7b9a462015-12-15 16:04:53 -080098 ssize_t w = TEMP_FAILURE_RETRY(ota_write(fd, data+written, size-written));
Elliott Hughes7bad7c42015-04-28 17:24:24 -070099 if (w == -1) {
Tianjie Xu16255832016-04-30 11:49:59 -0700100 failure_type = kFwriteFailure;
Tao Bao039f2da2016-11-22 16:29:50 -0800101 PLOG(ERROR) << "write failed";
Sami Tolvanen90221202014-12-09 16:39:47 +0000102 return -1;
Doug Zongkerbc7ffed2014-08-15 14:31:52 -0700103 }
Elliott Hughes7bad7c42015-04-28 17:24:24 -0700104 written += w;
Doug Zongkerbc7ffed2014-08-15 14:31:52 -0700105 }
Sami Tolvanen90221202014-12-09 16:39:47 +0000106
Sami Tolvanen90221202014-12-09 16:39:47 +0000107 return 0;
Doug Zongkerbc7ffed2014-08-15 14:31:52 -0700108}
109
Tao Bao612336d2015-08-27 16:41:21 -0700110static int write_all(int fd, const std::vector<uint8_t>& buffer, size_t size) {
111 return write_all(fd, buffer.data(), size);
112}
113
Tianjie Xu7ce287d2016-05-31 09:29:49 -0700114static bool discard_blocks(int fd, off64_t offset, uint64_t size) {
115 // Don't discard blocks unless the update is a retry run.
116 if (!is_retry) {
117 return true;
118 }
119
120 uint64_t args[2] = {static_cast<uint64_t>(offset), size};
121 int status = ioctl(fd, BLKDISCARD, &args);
122 if (status == -1) {
Tao Bao039f2da2016-11-22 16:29:50 -0800123 PLOG(ERROR) << "BLKDISCARD ioctl failed";
Tianjie Xu7ce287d2016-05-31 09:29:49 -0700124 return false;
125 }
126 return true;
127}
128
Elliott Hughes7bad7c42015-04-28 17:24:24 -0700129static bool check_lseek(int fd, off64_t offset, int whence) {
130 off64_t rc = TEMP_FAILURE_RETRY(lseek64(fd, offset, whence));
131 if (rc == -1) {
Tianjie Xu16255832016-04-30 11:49:59 -0700132 failure_type = kLseekFailure;
Tao Bao039f2da2016-11-22 16:29:50 -0800133 PLOG(ERROR) << "lseek64 failed";
Elliott Hughes7bad7c42015-04-28 17:24:24 -0700134 return false;
Doug Zongkerbc7ffed2014-08-15 14:31:52 -0700135 }
Elliott Hughes7bad7c42015-04-28 17:24:24 -0700136 return true;
Doug Zongkerbc7ffed2014-08-15 14:31:52 -0700137}
138
Tao Bao612336d2015-08-27 16:41:21 -0700139static void allocate(size_t size, std::vector<uint8_t>& buffer) {
Doug Zongkerbc7ffed2014-08-15 14:31:52 -0700140 // if the buffer's big enough, reuse it.
Tao Bao612336d2015-08-27 16:41:21 -0700141 if (size <= buffer.size()) return;
Doug Zongkerbc7ffed2014-08-15 14:31:52 -0700142
Tao Bao612336d2015-08-27 16:41:21 -0700143 buffer.resize(size);
Doug Zongkerbc7ffed2014-08-15 14:31:52 -0700144}
145
Tao Bao60a70af2017-03-26 14:03:52 -0700146/**
147 * RangeSinkWriter reads data from the given FD, and writes them to the destination specified by the
148 * given RangeSet.
149 */
150class RangeSinkWriter {
151 public:
152 RangeSinkWriter(int fd, const RangeSet& tgt)
153 : fd_(fd), tgt_(tgt), next_range_(0), current_range_left_(0) {
154 CHECK_NE(tgt.count, static_cast<size_t>(0));
155 };
Tao Bao0940fe12015-08-27 16:41:21 -0700156
Tao Bao60a70af2017-03-26 14:03:52 -0700157 bool Finished() const {
158 return next_range_ == tgt_.count && current_range_left_ == 0;
Tao Baof7eb7602017-03-27 15:12:48 -0700159 }
160
Tao Bao60a70af2017-03-26 14:03:52 -0700161 size_t Write(const uint8_t* data, size_t size) {
162 if (Finished()) {
163 LOG(ERROR) << "range sink write overrun; can't write " << size << " bytes";
164 return 0;
Tao Baof7eb7602017-03-27 15:12:48 -0700165 }
166
Tao Bao60a70af2017-03-26 14:03:52 -0700167 size_t written = 0;
168 while (size > 0) {
169 // Move to the next range as needed.
170 if (current_range_left_ == 0) {
171 if (next_range_ < tgt_.count) {
172 off64_t offset = static_cast<off64_t>(tgt_.pos[next_range_ * 2]) * BLOCKSIZE;
173 current_range_left_ =
174 (tgt_.pos[next_range_ * 2 + 1] - tgt_.pos[next_range_ * 2]) * BLOCKSIZE;
175 next_range_++;
176 if (!discard_blocks(fd_, offset, current_range_left_)) {
177 break;
178 }
Tao Baof7eb7602017-03-27 15:12:48 -0700179
Tao Bao60a70af2017-03-26 14:03:52 -0700180 if (!check_lseek(fd_, offset, SEEK_SET)) {
181 break;
182 }
183 } else {
184 // We can't write any more; return how many bytes have been written so far.
Tao Baof7eb7602017-03-27 15:12:48 -0700185 break;
186 }
Tao Bao60a70af2017-03-26 14:03:52 -0700187 }
Tao Baof7eb7602017-03-27 15:12:48 -0700188
Tao Bao60a70af2017-03-26 14:03:52 -0700189 size_t write_now = size;
190 if (current_range_left_ < write_now) {
191 write_now = current_range_left_;
192 }
Tao Baof7eb7602017-03-27 15:12:48 -0700193
Tao Bao60a70af2017-03-26 14:03:52 -0700194 if (write_all(fd_, data, write_now) == -1) {
Tao Baof7eb7602017-03-27 15:12:48 -0700195 break;
196 }
Tao Bao60a70af2017-03-26 14:03:52 -0700197
198 data += write_now;
199 size -= write_now;
200
201 current_range_left_ -= write_now;
202 written += write_now;
Doug Zongkerbc7ffed2014-08-15 14:31:52 -0700203 }
Tao Bao60a70af2017-03-26 14:03:52 -0700204
205 return written;
Tao Baof7eb7602017-03-27 15:12:48 -0700206 }
Doug Zongkerbc7ffed2014-08-15 14:31:52 -0700207
Tao Bao60a70af2017-03-26 14:03:52 -0700208 private:
209 // The input data.
210 int fd_;
211 // The destination for the data.
212 const RangeSet& tgt_;
213 // The next range that we should write to.
214 size_t next_range_;
215 // The number of bytes to write before moving to the next range.
216 size_t current_range_left_;
217};
Doug Zongkerbc7ffed2014-08-15 14:31:52 -0700218
Tao Bao60a70af2017-03-26 14:03:52 -0700219/**
220 * All of the data for all the 'new' transfers is contained in one file in the update package,
221 * concatenated together in the order in which transfers.list will need it. We want to stream it out
222 * of the archive (it's compressed) without writing it to a temp file, but we can't write each
223 * section until it's that transfer's turn to go.
224 *
225 * To achieve this, we expand the new data from the archive in a background thread, and block that
226 * threads 'receive uncompressed data' function until the main thread has reached a point where we
227 * want some new data to be written. We signal the background thread with the destination for the
228 * data and block the main thread, waiting for the background thread to complete writing that
229 * section. Then it signals the main thread to wake up and goes back to blocking waiting for a
230 * transfer.
231 *
232 * NewThreadInfo is the struct used to pass information back and forth between the two threads. When
233 * the main thread wants some data written, it sets writer to the destination location and signals
234 * the condition. When the background thread is done writing, it clears writer and signals the
235 * condition again.
236 */
Tao Bao0940fe12015-08-27 16:41:21 -0700237struct NewThreadInfo {
Tao Bao60a70af2017-03-26 14:03:52 -0700238 ZipArchiveHandle za;
239 ZipEntry entry;
Doug Zongkerbc7ffed2014-08-15 14:31:52 -0700240
Tao Bao60a70af2017-03-26 14:03:52 -0700241 RangeSinkWriter* writer;
Doug Zongkerbc7ffed2014-08-15 14:31:52 -0700242
Tao Bao60a70af2017-03-26 14:03:52 -0700243 pthread_mutex_t mu;
244 pthread_cond_t cv;
Tao Bao0940fe12015-08-27 16:41:21 -0700245};
Doug Zongkerbc7ffed2014-08-15 14:31:52 -0700246
Tianjie Xu8cf5c8f2016-09-08 20:10:11 -0700247static bool receive_new_data(const uint8_t* data, size_t size, void* cookie) {
Tao Bao60a70af2017-03-26 14:03:52 -0700248 NewThreadInfo* nti = static_cast<NewThreadInfo*>(cookie);
Doug Zongkerbc7ffed2014-08-15 14:31:52 -0700249
Tao Bao60a70af2017-03-26 14:03:52 -0700250 while (size > 0) {
251 // Wait for nti->writer to be non-null, indicating some of this data is wanted.
252 pthread_mutex_lock(&nti->mu);
253 while (nti->writer == nullptr) {
254 pthread_cond_wait(&nti->cv, &nti->mu);
Doug Zongkerbc7ffed2014-08-15 14:31:52 -0700255 }
Tao Bao60a70af2017-03-26 14:03:52 -0700256 pthread_mutex_unlock(&nti->mu);
Doug Zongkerbc7ffed2014-08-15 14:31:52 -0700257
Tao Bao60a70af2017-03-26 14:03:52 -0700258 // At this point nti->writer is set, and we own it. The main thread is waiting for it to
259 // disappear from nti.
260 size_t written = nti->writer->Write(data, size);
261 data += written;
262 size -= written;
263
264 if (nti->writer->Finished()) {
265 // We have written all the bytes desired by this writer.
266
267 pthread_mutex_lock(&nti->mu);
268 nti->writer = nullptr;
269 pthread_cond_broadcast(&nti->cv);
270 pthread_mutex_unlock(&nti->mu);
271 }
272 }
273
274 return true;
Doug Zongkerbc7ffed2014-08-15 14:31:52 -0700275}
276
277static void* unzip_new_data(void* cookie) {
Mikhail Lappo20791bd2017-03-23 21:30:36 +0100278 NewThreadInfo* nti = static_cast<NewThreadInfo*>(cookie);
Tianjie Xu8cf5c8f2016-09-08 20:10:11 -0700279 ProcessZipEntryContents(nti->za, &nti->entry, receive_new_data, nti);
Tao Bao0940fe12015-08-27 16:41:21 -0700280 return nullptr;
Doug Zongkerbc7ffed2014-08-15 14:31:52 -0700281}
282
Tao Bao612336d2015-08-27 16:41:21 -0700283static int ReadBlocks(const RangeSet& src, std::vector<uint8_t>& buffer, int fd) {
Sami Tolvanen90221202014-12-09 16:39:47 +0000284 size_t p = 0;
Tao Bao612336d2015-08-27 16:41:21 -0700285 uint8_t* data = buffer.data();
Sami Tolvanen90221202014-12-09 16:39:47 +0000286
Tao Bao0940fe12015-08-27 16:41:21 -0700287 for (size_t i = 0; i < src.count; ++i) {
288 if (!check_lseek(fd, (off64_t) src.pos[i * 2] * BLOCKSIZE, SEEK_SET)) {
Sami Tolvanen90221202014-12-09 16:39:47 +0000289 return -1;
290 }
291
Tao Bao0940fe12015-08-27 16:41:21 -0700292 size_t size = (src.pos[i * 2 + 1] - src.pos[i * 2]) * BLOCKSIZE;
Sami Tolvanen90221202014-12-09 16:39:47 +0000293
Tao Bao612336d2015-08-27 16:41:21 -0700294 if (read_all(fd, data + p, size) == -1) {
Sami Tolvanen90221202014-12-09 16:39:47 +0000295 return -1;
296 }
297
298 p += size;
299 }
300
301 return 0;
302}
303
Tao Bao612336d2015-08-27 16:41:21 -0700304static int WriteBlocks(const RangeSet& tgt, const std::vector<uint8_t>& buffer, int fd) {
Tao Bao60a70af2017-03-26 14:03:52 -0700305 size_t written = 0;
306 for (size_t i = 0; i < tgt.count; ++i) {
307 off64_t offset = static_cast<off64_t>(tgt.pos[i * 2]) * BLOCKSIZE;
308 size_t size = (tgt.pos[i * 2 + 1] - tgt.pos[i * 2]) * BLOCKSIZE;
309 if (!discard_blocks(fd, offset, size)) {
310 return -1;
Sami Tolvanen90221202014-12-09 16:39:47 +0000311 }
312
Tao Bao60a70af2017-03-26 14:03:52 -0700313 if (!check_lseek(fd, offset, SEEK_SET)) {
314 return -1;
315 }
316
317 if (write_all(fd, buffer.data() + written, size) == -1) {
318 return -1;
319 }
320
321 written += size;
322 }
323
324 return 0;
Sami Tolvanen90221202014-12-09 16:39:47 +0000325}
326
Tao Baobaad2d42015-12-06 16:56:27 -0800327// Parameters for transfer list command functions
328struct CommandParameters {
329 std::vector<std::string> tokens;
330 size_t cpos;
331 const char* cmdname;
332 const char* cmdline;
333 std::string freestash;
334 std::string stashbase;
335 bool canwrite;
336 int createdstash;
Elliott Hughesbcabd092016-03-22 20:19:22 -0700337 android::base::unique_fd fd;
Tao Baobaad2d42015-12-06 16:56:27 -0800338 bool foundwrites;
339 bool isunresumable;
340 int version;
341 size_t written;
Tianjie Xudd874b12016-05-13 12:13:15 -0700342 size_t stashed;
Tao Baobaad2d42015-12-06 16:56:27 -0800343 NewThreadInfo nti;
344 pthread_t thread;
345 std::vector<uint8_t> buffer;
346 uint8_t* patch_start;
347};
348
Tianjie Xu2cd36ba2017-03-15 23:52:46 +0000349// Print the hash in hex for corrupted source blocks (excluding the stashed blocks which is
350// handled separately).
351static void PrintHashForCorruptedSourceBlocks(const CommandParameters& params,
352 const std::vector<uint8_t>& buffer) {
353 LOG(INFO) << "unexpected contents of source blocks in cmd:\n" << params.cmdline;
Tianjie Xu2cd36ba2017-03-15 23:52:46 +0000354 CHECK(params.tokens[0] == "move" || params.tokens[0] == "bsdiff" ||
355 params.tokens[0] == "imgdiff");
356
357 size_t pos = 0;
358 // Command example:
359 // move <onehash> <tgt_range> <src_blk_count> <src_range> [<loc_range> <stashed_blocks>]
360 // bsdiff <offset> <len> <src_hash> <tgt_hash> <tgt_range> <src_blk_count> <src_range>
361 // [<loc_range> <stashed_blocks>]
362 if (params.tokens[0] == "move") {
363 // src_range for move starts at the 4th position.
364 if (params.tokens.size() < 5) {
365 LOG(ERROR) << "failed to parse source range in cmd:\n" << params.cmdline;
366 return;
367 }
368 pos = 4;
369 } else {
370 // src_range for diff starts at the 7th position.
371 if (params.tokens.size() < 8) {
372 LOG(ERROR) << "failed to parse source range in cmd:\n" << params.cmdline;
373 return;
374 }
375 pos = 7;
376 }
377
378 // Source blocks in stash only, no work to do.
379 if (params.tokens[pos] == "-") {
380 return;
381 }
382
Tao Bao8f237572017-03-26 13:36:49 -0700383 RangeSet src = RangeSet::Parse(params.tokens[pos++]);
Tianjie Xu2cd36ba2017-03-15 23:52:46 +0000384
385 RangeSet locs;
386 // If there's no stashed blocks, content in the buffer is consecutive and has the same
387 // order as the source blocks.
388 if (pos == params.tokens.size()) {
389 locs.count = 1;
390 locs.size = src.size;
391 locs.pos = { 0, src.size };
392 } else {
393 // Otherwise, the next token is the offset of the source blocks in the target range.
394 // Example: for the tokens <4,63946,63947,63948,63979> <4,6,7,8,39> <stashed_blocks>;
395 // We want to print SHA-1 for the data in buffer[6], buffer[8], buffer[9] ... buffer[38];
396 // this corresponds to the 32 src blocks #63946, #63948, #63949 ... #63978.
Tao Bao8f237572017-03-26 13:36:49 -0700397 locs = RangeSet::Parse(params.tokens[pos++]);
Tianjie Xu2cd36ba2017-03-15 23:52:46 +0000398 CHECK_EQ(src.size, locs.size);
399 CHECK_EQ(locs.pos.size() % 2, static_cast<size_t>(0));
400 }
401
402 LOG(INFO) << "printing hash in hex for " << src.size << " source blocks";
403 for (size_t i = 0; i < src.size; i++) {
Tao Bao8f237572017-03-26 13:36:49 -0700404 size_t block_num = src.GetBlockNumber(i);
405 size_t buffer_index = locs.GetBlockNumber(i);
Tianjie Xu2cd36ba2017-03-15 23:52:46 +0000406 CHECK_LE((buffer_index + 1) * BLOCKSIZE, buffer.size());
407
408 uint8_t digest[SHA_DIGEST_LENGTH];
409 SHA1(buffer.data() + buffer_index * BLOCKSIZE, BLOCKSIZE, digest);
410 std::string hexdigest = print_sha1(digest);
411 LOG(INFO) << " block number: " << block_num << ", SHA-1: " << hexdigest;
412 }
413}
414
415// If the calculated hash for the whole stash doesn't match the stash id, print the SHA-1
416// in hex for each block.
417static void PrintHashForCorruptedStashedBlocks(const std::string& id,
418 const std::vector<uint8_t>& buffer,
419 const RangeSet& src) {
420 LOG(INFO) << "printing hash in hex for stash_id: " << id;
421 CHECK_EQ(src.size * BLOCKSIZE, buffer.size());
422
423 for (size_t i = 0; i < src.size; i++) {
Tao Bao8f237572017-03-26 13:36:49 -0700424 size_t block_num = src.GetBlockNumber(i);
Tianjie Xu2cd36ba2017-03-15 23:52:46 +0000425
426 uint8_t digest[SHA_DIGEST_LENGTH];
427 SHA1(buffer.data() + i * BLOCKSIZE, BLOCKSIZE, digest);
428 std::string hexdigest = print_sha1(digest);
429 LOG(INFO) << " block number: " << block_num << ", SHA-1: " << hexdigest;
430 }
431}
432
433// If the stash file doesn't exist, read the source blocks this stash contains and print the
434// SHA-1 for these blocks.
435static void PrintHashForMissingStashedBlocks(const std::string& id, int fd) {
436 if (stash_map.find(id) == stash_map.end()) {
437 LOG(ERROR) << "No stash saved for id: " << id;
438 return;
439 }
440
441 LOG(INFO) << "print hash in hex for source blocks in missing stash: " << id;
442 const RangeSet& src = stash_map[id];
443 std::vector<uint8_t> buffer(src.size * BLOCKSIZE);
444 if (ReadBlocks(src, buffer, fd) == -1) {
445 LOG(ERROR) << "failed to read source blocks for stash: " << id;
446 return;
447 }
448 PrintHashForCorruptedStashedBlocks(id, buffer, src);
449}
450
Tao Bao612336d2015-08-27 16:41:21 -0700451static int VerifyBlocks(const std::string& expected, const std::vector<uint8_t>& buffer,
Tao Bao0940fe12015-08-27 16:41:21 -0700452 const size_t blocks, bool printerror) {
Sen Jiangc48cb5e2016-02-04 16:23:21 +0800453 uint8_t digest[SHA_DIGEST_LENGTH];
Tao Bao612336d2015-08-27 16:41:21 -0700454 const uint8_t* data = buffer.data();
Sami Tolvanen90221202014-12-09 16:39:47 +0000455
Sen Jiangc48cb5e2016-02-04 16:23:21 +0800456 SHA1(data, blocks * BLOCKSIZE, digest);
Sami Tolvanen90221202014-12-09 16:39:47 +0000457
Tao Baoe6aa3322015-08-05 15:20:27 -0700458 std::string hexdigest = print_sha1(digest);
Sami Tolvanen90221202014-12-09 16:39:47 +0000459
Tao Bao0940fe12015-08-27 16:41:21 -0700460 if (hexdigest != expected) {
461 if (printerror) {
Tao Bao039f2da2016-11-22 16:29:50 -0800462 LOG(ERROR) << "failed to verify blocks (expected " << expected << ", read "
463 << hexdigest << ")";
Tao Bao0940fe12015-08-27 16:41:21 -0700464 }
465 return -1;
Sami Tolvanen90221202014-12-09 16:39:47 +0000466 }
467
Tao Bao0940fe12015-08-27 16:41:21 -0700468 return 0;
Sami Tolvanen90221202014-12-09 16:39:47 +0000469}
470
Tao Bao0940fe12015-08-27 16:41:21 -0700471static std::string GetStashFileName(const std::string& base, const std::string& id,
472 const std::string& postfix) {
Tao Baoe6aa3322015-08-05 15:20:27 -0700473 if (base.empty()) {
474 return "";
Sami Tolvanen90221202014-12-09 16:39:47 +0000475 }
476
Tao Baoe6aa3322015-08-05 15:20:27 -0700477 std::string fn(STASH_DIRECTORY_BASE);
478 fn += "/" + base + "/" + id + postfix;
Sami Tolvanen90221202014-12-09 16:39:47 +0000479
480 return fn;
481}
482
Tao Baoec8272f2017-03-15 17:39:01 -0700483// Does a best effort enumeration of stash files. Ignores possible non-file items in the stash
484// directory and continues despite of errors. Calls the 'callback' function for each file.
485static void EnumerateStash(const std::string& dirname,
486 const std::function<void(const std::string&)>& callback) {
487 if (dirname.empty()) return;
Sami Tolvanen90221202014-12-09 16:39:47 +0000488
Tao Baoec8272f2017-03-15 17:39:01 -0700489 std::unique_ptr<DIR, decltype(&closedir)> directory(opendir(dirname.c_str()), closedir);
Sami Tolvanen90221202014-12-09 16:39:47 +0000490
Tao Baoec8272f2017-03-15 17:39:01 -0700491 if (directory == nullptr) {
492 if (errno != ENOENT) {
493 PLOG(ERROR) << "opendir \"" << dirname << "\" failed";
Sami Tolvanen90221202014-12-09 16:39:47 +0000494 }
Tao Bao51412212016-12-28 14:44:05 -0800495 return;
496 }
Tao Baoe6aa3322015-08-05 15:20:27 -0700497
Tao Baoec8272f2017-03-15 17:39:01 -0700498 dirent* item;
499 while ((item = readdir(directory.get())) != nullptr) {
500 if (item->d_type != DT_REG) continue;
501 callback(dirname + "/" + item->d_name);
Tao Bao51412212016-12-28 14:44:05 -0800502 }
Sami Tolvanen90221202014-12-09 16:39:47 +0000503}
504
505// Deletes the stash directory and all files in it. Assumes that it only
506// contains files. There is nothing we can do about unlikely, but possible
507// errors, so they are merely logged.
Tao Baoec8272f2017-03-15 17:39:01 -0700508static void DeleteFile(const std::string& fn) {
509 if (fn.empty()) return;
Sami Tolvanen90221202014-12-09 16:39:47 +0000510
Tao Baoec8272f2017-03-15 17:39:01 -0700511 LOG(INFO) << "deleting " << fn;
Sami Tolvanen90221202014-12-09 16:39:47 +0000512
Tao Baoec8272f2017-03-15 17:39:01 -0700513 if (unlink(fn.c_str()) == -1 && errno != ENOENT) {
514 PLOG(ERROR) << "unlink \"" << fn << "\" failed";
515 }
Sami Tolvanen90221202014-12-09 16:39:47 +0000516}
517
Tao Baoe6aa3322015-08-05 15:20:27 -0700518static void DeleteStash(const std::string& base) {
Tao Baoec8272f2017-03-15 17:39:01 -0700519 if (base.empty()) return;
520
521 LOG(INFO) << "deleting stash " << base;
522
523 std::string dirname = GetStashFileName(base, "", "");
524 EnumerateStash(dirname, DeleteFile);
525
526 if (rmdir(dirname.c_str()) == -1) {
527 if (errno != ENOENT && errno != ENOTDIR) {
528 PLOG(ERROR) << "rmdir \"" << dirname << "\" failed";
Sami Tolvanen90221202014-12-09 16:39:47 +0000529 }
Tao Baoec8272f2017-03-15 17:39:01 -0700530 }
Sami Tolvanen90221202014-12-09 16:39:47 +0000531}
532
Tao Baobcf46492017-03-23 15:28:20 -0700533static int LoadStash(CommandParameters& params, const std::string& id, bool verify, size_t* blocks,
534 std::vector<uint8_t>& buffer, bool printnoent) {
Tianjie Xu7eca97e2016-03-22 18:08:12 -0700535 // In verify mode, if source range_set was saved for the given hash,
536 // check contents in the source blocks first. If the check fails,
537 // search for the stashed files on /cache as usual.
538 if (!params.canwrite) {
539 if (stash_map.find(id) != stash_map.end()) {
540 const RangeSet& src = stash_map[id];
541 allocate(src.size * BLOCKSIZE, buffer);
542
543 if (ReadBlocks(src, buffer, params.fd) == -1) {
Tao Bao039f2da2016-11-22 16:29:50 -0800544 LOG(ERROR) << "failed to read source blocks in stash map.";
Tianjie Xu7eca97e2016-03-22 18:08:12 -0700545 return -1;
546 }
547 if (VerifyBlocks(id, buffer, src.size, true) != 0) {
Tao Bao039f2da2016-11-22 16:29:50 -0800548 LOG(ERROR) << "failed to verify loaded source blocks in stash map.";
Tianjie Xu2cd36ba2017-03-15 23:52:46 +0000549 PrintHashForCorruptedStashedBlocks(id, buffer, src);
Tianjie Xu7eca97e2016-03-22 18:08:12 -0700550 return -1;
551 }
552 return 0;
553 }
554 }
555
Tao Bao0940fe12015-08-27 16:41:21 -0700556 size_t blockcount = 0;
557
Sami Tolvanen90221202014-12-09 16:39:47 +0000558 if (!blocks) {
559 blocks = &blockcount;
560 }
561
Tao Baobcf46492017-03-23 15:28:20 -0700562 std::string fn = GetStashFileName(params.stashbase, id, "");
Sami Tolvanen90221202014-12-09 16:39:47 +0000563
Tao Bao0940fe12015-08-27 16:41:21 -0700564 struct stat sb;
565 int res = stat(fn.c_str(), &sb);
Sami Tolvanen90221202014-12-09 16:39:47 +0000566
567 if (res == -1) {
568 if (errno != ENOENT || printnoent) {
Tao Bao039f2da2016-11-22 16:29:50 -0800569 PLOG(ERROR) << "stat \"" << fn << "\" failed";
Tianjie Xu2cd36ba2017-03-15 23:52:46 +0000570 PrintHashForMissingStashedBlocks(id, params.fd);
Sami Tolvanen90221202014-12-09 16:39:47 +0000571 }
Tao Bao0940fe12015-08-27 16:41:21 -0700572 return -1;
Sami Tolvanen90221202014-12-09 16:39:47 +0000573 }
574
Tao Bao039f2da2016-11-22 16:29:50 -0800575 LOG(INFO) << " loading " << fn;
Sami Tolvanen90221202014-12-09 16:39:47 +0000576
Tao Bao0940fe12015-08-27 16:41:21 -0700577 if ((sb.st_size % BLOCKSIZE) != 0) {
Tao Bao039f2da2016-11-22 16:29:50 -0800578 LOG(ERROR) << fn << " size " << sb.st_size << " not multiple of block size " << BLOCKSIZE;
Tao Bao0940fe12015-08-27 16:41:21 -0700579 return -1;
Sami Tolvanen90221202014-12-09 16:39:47 +0000580 }
581
Elliott Hughesbcabd092016-03-22 20:19:22 -0700582 android::base::unique_fd fd(TEMP_FAILURE_RETRY(ota_open(fn.c_str(), O_RDONLY)));
Sami Tolvanen90221202014-12-09 16:39:47 +0000583 if (fd == -1) {
Tao Bao039f2da2016-11-22 16:29:50 -0800584 PLOG(ERROR) << "open \"" << fn << "\" failed";
Tao Bao0940fe12015-08-27 16:41:21 -0700585 return -1;
Sami Tolvanen90221202014-12-09 16:39:47 +0000586 }
587
Tao Bao612336d2015-08-27 16:41:21 -0700588 allocate(sb.st_size, buffer);
Sami Tolvanen90221202014-12-09 16:39:47 +0000589
Tao Bao612336d2015-08-27 16:41:21 -0700590 if (read_all(fd, buffer, sb.st_size) == -1) {
Tao Bao0940fe12015-08-27 16:41:21 -0700591 return -1;
Sami Tolvanen90221202014-12-09 16:39:47 +0000592 }
593
Tao Bao0940fe12015-08-27 16:41:21 -0700594 *blocks = sb.st_size / BLOCKSIZE;
Sami Tolvanen90221202014-12-09 16:39:47 +0000595
Tao Bao612336d2015-08-27 16:41:21 -0700596 if (verify && VerifyBlocks(id, buffer, *blocks, true) != 0) {
Tao Bao039f2da2016-11-22 16:29:50 -0800597 LOG(ERROR) << "unexpected contents in " << fn;
Tianjie Xu2cd36ba2017-03-15 23:52:46 +0000598 if (stash_map.find(id) == stash_map.end()) {
599 LOG(ERROR) << "failed to find source blocks number for stash " << id
600 << " when executing command: " << params.cmdname;
601 } else {
602 const RangeSet& src = stash_map[id];
603 PrintHashForCorruptedStashedBlocks(id, buffer, src);
604 }
Tao Baoec8272f2017-03-15 17:39:01 -0700605 DeleteFile(fn);
Tao Bao0940fe12015-08-27 16:41:21 -0700606 return -1;
Sami Tolvanen90221202014-12-09 16:39:47 +0000607 }
608
Tao Bao0940fe12015-08-27 16:41:21 -0700609 return 0;
Sami Tolvanen90221202014-12-09 16:39:47 +0000610}
611
Tao Bao612336d2015-08-27 16:41:21 -0700612static int WriteStash(const std::string& base, const std::string& id, int blocks,
Tao Baod2aecd42017-03-23 14:43:44 -0700613 std::vector<uint8_t>& buffer, bool checkspace, bool* exists) {
Tao Bao612336d2015-08-27 16:41:21 -0700614 if (base.empty()) {
Tao Bao0940fe12015-08-27 16:41:21 -0700615 return -1;
Sami Tolvanen90221202014-12-09 16:39:47 +0000616 }
617
618 if (checkspace && CacheSizeCheck(blocks * BLOCKSIZE) != 0) {
Tao Bao039f2da2016-11-22 16:29:50 -0800619 LOG(ERROR) << "not enough space to write stash";
Tao Bao0940fe12015-08-27 16:41:21 -0700620 return -1;
Sami Tolvanen90221202014-12-09 16:39:47 +0000621 }
622
Tao Bao0940fe12015-08-27 16:41:21 -0700623 std::string fn = GetStashFileName(base, id, ".partial");
624 std::string cn = GetStashFileName(base, id, "");
Sami Tolvanen90221202014-12-09 16:39:47 +0000625
Sami Tolvanen43b748f2015-04-17 12:50:31 +0100626 if (exists) {
Tao Bao0940fe12015-08-27 16:41:21 -0700627 struct stat sb;
628 int res = stat(cn.c_str(), &sb);
Sami Tolvanen43b748f2015-04-17 12:50:31 +0100629
630 if (res == 0) {
631 // The file already exists and since the name is the hash of the contents,
632 // it's safe to assume the contents are identical (accidental hash collisions
633 // are unlikely)
Tao Bao039f2da2016-11-22 16:29:50 -0800634 LOG(INFO) << " skipping " << blocks << " existing blocks in " << cn;
Tao Bao0940fe12015-08-27 16:41:21 -0700635 *exists = true;
636 return 0;
Sami Tolvanen43b748f2015-04-17 12:50:31 +0100637 }
638
Tao Bao0940fe12015-08-27 16:41:21 -0700639 *exists = false;
Sami Tolvanen43b748f2015-04-17 12:50:31 +0100640 }
641
Tao Bao039f2da2016-11-22 16:29:50 -0800642 LOG(INFO) << " writing " << blocks << " blocks to " << cn;
Sami Tolvanen90221202014-12-09 16:39:47 +0000643
Tao Bao039f2da2016-11-22 16:29:50 -0800644 android::base::unique_fd fd(
645 TEMP_FAILURE_RETRY(ota_open(fn.c_str(), O_WRONLY | O_CREAT | O_TRUNC, STASH_FILE_MODE)));
Sami Tolvanen90221202014-12-09 16:39:47 +0000646 if (fd == -1) {
Tao Bao039f2da2016-11-22 16:29:50 -0800647 PLOG(ERROR) << "failed to create \"" << fn << "\"";
Tao Bao0940fe12015-08-27 16:41:21 -0700648 return -1;
Sami Tolvanen90221202014-12-09 16:39:47 +0000649 }
650
Tianjie Xua946b9e2017-03-21 16:24:57 -0700651 if (fchown(fd, AID_SYSTEM, AID_SYSTEM) != 0) { // system user
652 PLOG(ERROR) << "failed to chown \"" << fn << "\"";
653 return -1;
654 }
655
Sami Tolvanen90221202014-12-09 16:39:47 +0000656 if (write_all(fd, buffer, blocks * BLOCKSIZE) == -1) {
Tao Bao0940fe12015-08-27 16:41:21 -0700657 return -1;
Sami Tolvanen90221202014-12-09 16:39:47 +0000658 }
659
Jed Estepa7b9a462015-12-15 16:04:53 -0800660 if (ota_fsync(fd) == -1) {
Tianjie Xu16255832016-04-30 11:49:59 -0700661 failure_type = kFsyncFailure;
Tao Bao039f2da2016-11-22 16:29:50 -0800662 PLOG(ERROR) << "fsync \"" << fn << "\" failed";
Tao Bao0940fe12015-08-27 16:41:21 -0700663 return -1;
Sami Tolvanen90221202014-12-09 16:39:47 +0000664 }
665
Tao Baoe6aa3322015-08-05 15:20:27 -0700666 if (rename(fn.c_str(), cn.c_str()) == -1) {
Tao Bao039f2da2016-11-22 16:29:50 -0800667 PLOG(ERROR) << "rename(\"" << fn << "\", \"" << cn << "\") failed";
Tao Bao0940fe12015-08-27 16:41:21 -0700668 return -1;
Sami Tolvanen90221202014-12-09 16:39:47 +0000669 }
670
Tao Bao0940fe12015-08-27 16:41:21 -0700671 std::string dname = GetStashFileName(base, "", "");
Elliott Hughesbcabd092016-03-22 20:19:22 -0700672 android::base::unique_fd dfd(TEMP_FAILURE_RETRY(ota_open(dname.c_str(),
673 O_RDONLY | O_DIRECTORY)));
Tao Baodc392262015-07-31 15:56:44 -0700674 if (dfd == -1) {
Tianjie Xu16255832016-04-30 11:49:59 -0700675 failure_type = kFileOpenFailure;
Tao Bao039f2da2016-11-22 16:29:50 -0800676 PLOG(ERROR) << "failed to open \"" << dname << "\" failed";
Tao Bao0940fe12015-08-27 16:41:21 -0700677 return -1;
Tao Baodc392262015-07-31 15:56:44 -0700678 }
679
Jed Estepa7b9a462015-12-15 16:04:53 -0800680 if (ota_fsync(dfd) == -1) {
Tianjie Xu16255832016-04-30 11:49:59 -0700681 failure_type = kFsyncFailure;
Tao Bao039f2da2016-11-22 16:29:50 -0800682 PLOG(ERROR) << "fsync \"" << dname << "\" failed";
Tao Bao0940fe12015-08-27 16:41:21 -0700683 return -1;
Tao Baodc392262015-07-31 15:56:44 -0700684 }
685
Tao Bao0940fe12015-08-27 16:41:21 -0700686 return 0;
Sami Tolvanen90221202014-12-09 16:39:47 +0000687}
688
689// Creates a directory for storing stash files and checks if the /cache partition
690// hash enough space for the expected amount of blocks we need to store. Returns
691// >0 if we created the directory, zero if it existed already, and <0 of failure.
692
Tao Bao51412212016-12-28 14:44:05 -0800693static int CreateStash(State* state, size_t maxblocks, const std::string& blockdev,
694 std::string& base) {
695 if (blockdev.empty()) {
696 return -1;
697 }
698
699 // Stash directory should be different for each partition to avoid conflicts
700 // when updating multiple partitions at the same time, so we use the hash of
701 // the block device name as the base directory
702 uint8_t digest[SHA_DIGEST_LENGTH];
703 SHA1(reinterpret_cast<const uint8_t*>(blockdev.data()), blockdev.size(), digest);
704 base = print_sha1(digest);
705
706 std::string dirname = GetStashFileName(base, "", "");
707 struct stat sb;
708 int res = stat(dirname.c_str(), &sb);
709 size_t max_stash_size = maxblocks * BLOCKSIZE;
710
711 if (res == -1 && errno != ENOENT) {
712 ErrorAbort(state, kStashCreationFailure, "stat \"%s\" failed: %s\n", dirname.c_str(),
713 strerror(errno));
714 return -1;
715 } else if (res != 0) {
716 LOG(INFO) << "creating stash " << dirname;
717 res = mkdir(dirname.c_str(), STASH_DIRECTORY_MODE);
718
719 if (res != 0) {
720 ErrorAbort(state, kStashCreationFailure, "mkdir \"%s\" failed: %s\n", dirname.c_str(),
721 strerror(errno));
722 return -1;
Sami Tolvanen90221202014-12-09 16:39:47 +0000723 }
724
Tianjie Xua946b9e2017-03-21 16:24:57 -0700725 if (chown(dirname.c_str(), AID_SYSTEM, AID_SYSTEM) != 0) { // system user
726 ErrorAbort(state, kStashCreationFailure, "chown \"%s\" failed: %s\n", dirname.c_str(),
727 strerror(errno));
728 return -1;
729 }
730
Tao Bao51412212016-12-28 14:44:05 -0800731 if (CacheSizeCheck(max_stash_size) != 0) {
732 ErrorAbort(state, kStashCreationFailure, "not enough space for stash (%zu needed)\n",
733 max_stash_size);
734 return -1;
Sami Tolvanen90221202014-12-09 16:39:47 +0000735 }
736
Tao Bao51412212016-12-28 14:44:05 -0800737 return 1; // Created directory
738 }
Sami Tolvanen90221202014-12-09 16:39:47 +0000739
Tao Bao51412212016-12-28 14:44:05 -0800740 LOG(INFO) << "using existing stash " << dirname;
Sami Tolvanen90221202014-12-09 16:39:47 +0000741
Tao Baoec8272f2017-03-15 17:39:01 -0700742 // If the directory already exists, calculate the space already allocated to stash files and check
743 // if there's enough for all required blocks. Delete any partially completed stash files first.
744 EnumerateStash(dirname, [](const std::string& fn) {
745 if (android::base::EndsWith(fn, ".partial")) {
746 DeleteFile(fn);
747 }
748 });
Sami Tolvanen90221202014-12-09 16:39:47 +0000749
Tao Bao51412212016-12-28 14:44:05 -0800750 size_t existing = 0;
Tao Baoec8272f2017-03-15 17:39:01 -0700751 EnumerateStash(dirname, [&existing](const std::string& fn) {
752 if (fn.empty()) return;
753 struct stat sb;
754 if (stat(fn.c_str(), &sb) == -1) {
755 PLOG(ERROR) << "stat \"" << fn << "\" failed";
756 return;
757 }
758 existing += static_cast<size_t>(sb.st_size);
759 });
Sami Tolvanen90221202014-12-09 16:39:47 +0000760
Tao Bao51412212016-12-28 14:44:05 -0800761 if (max_stash_size > existing) {
762 size_t needed = max_stash_size - existing;
763 if (CacheSizeCheck(needed) != 0) {
764 ErrorAbort(state, kStashCreationFailure, "not enough space for stash (%zu more needed)\n",
765 needed);
766 return -1;
Sami Tolvanen90221202014-12-09 16:39:47 +0000767 }
Tao Bao51412212016-12-28 14:44:05 -0800768 }
Sami Tolvanen90221202014-12-09 16:39:47 +0000769
Tao Bao51412212016-12-28 14:44:05 -0800770 return 0; // Using existing directory
Sami Tolvanen90221202014-12-09 16:39:47 +0000771}
772
Tao Baobaad2d42015-12-06 16:56:27 -0800773static int FreeStash(const std::string& base, const std::string& id) {
Tao Baoec8272f2017-03-15 17:39:01 -0700774 if (base.empty() || id.empty()) {
775 return -1;
776 }
Sami Tolvanen90221202014-12-09 16:39:47 +0000777
Tao Baoec8272f2017-03-15 17:39:01 -0700778 DeleteFile(GetStashFileName(base, id, ""));
Sami Tolvanen90221202014-12-09 16:39:47 +0000779
Tao Baoec8272f2017-03-15 17:39:01 -0700780 return 0;
Doug Zongker52ae67d2014-09-08 12:22:09 -0700781}
782
Tao Bao612336d2015-08-27 16:41:21 -0700783static void MoveRange(std::vector<uint8_t>& dest, const RangeSet& locs,
784 const std::vector<uint8_t>& source) {
Doug Zongker52ae67d2014-09-08 12:22:09 -0700785 // source contains packed data, which we want to move to the
Tao Bao612336d2015-08-27 16:41:21 -0700786 // locations given in locs in the dest buffer. source and dest
Doug Zongker52ae67d2014-09-08 12:22:09 -0700787 // may be the same buffer.
788
Tao Bao612336d2015-08-27 16:41:21 -0700789 const uint8_t* from = source.data();
790 uint8_t* to = dest.data();
Tao Bao0940fe12015-08-27 16:41:21 -0700791 size_t start = locs.size;
792 for (int i = locs.count-1; i >= 0; --i) {
793 size_t blocks = locs.pos[i*2+1] - locs.pos[i*2];
Doug Zongker52ae67d2014-09-08 12:22:09 -0700794 start -= blocks;
Tao Bao612336d2015-08-27 16:41:21 -0700795 memmove(to + (locs.pos[i*2] * BLOCKSIZE), from + (start * BLOCKSIZE),
Doug Zongker52ae67d2014-09-08 12:22:09 -0700796 blocks * BLOCKSIZE);
797 }
798}
799
Tao Baod2aecd42017-03-23 14:43:44 -0700800/**
801 * We expect to parse the remainder of the parameter tokens as one of:
802 *
803 * <src_block_count> <src_range>
804 * (loads data from source image only)
805 *
806 * <src_block_count> - <[stash_id:stash_range] ...>
807 * (loads data from stashes only)
808 *
809 * <src_block_count> <src_range> <src_loc> <[stash_id:stash_range] ...>
810 * (loads data from both source image and stashes)
811 *
812 * On return, params.buffer is filled with the loaded source data (rearranged and combined with
813 * stashed data as necessary). buffer may be reallocated if needed to accommodate the source data.
814 * tgt is the target RangeSet for detecting overlaps. Any stashes required are loaded using
815 * LoadStash.
816 */
817static int LoadSourceBlocks(CommandParameters& params, const RangeSet& tgt, size_t* src_blocks,
818 bool* overlap) {
819 CHECK(src_blocks != nullptr);
820 CHECK(overlap != nullptr);
Doug Zongker52ae67d2014-09-08 12:22:09 -0700821
Tao Baod2aecd42017-03-23 14:43:44 -0700822 // <src_block_count>
823 const std::string& token = params.tokens[params.cpos++];
824 if (!android::base::ParseUint(token, src_blocks)) {
825 LOG(ERROR) << "invalid src_block_count \"" << token << "\"";
826 return -1;
827 }
Tao Baobaad2d42015-12-06 16:56:27 -0800828
Tao Baod2aecd42017-03-23 14:43:44 -0700829 allocate(*src_blocks * BLOCKSIZE, params.buffer);
830
831 // "-" or <src_range> [<src_loc>]
832 if (params.tokens[params.cpos] == "-") {
833 // no source ranges, only stashes
834 params.cpos++;
835 } else {
Tao Bao8f237572017-03-26 13:36:49 -0700836 RangeSet src = RangeSet::Parse(params.tokens[params.cpos++]);
837 *overlap = src.Overlaps(tgt);
Tao Baod2aecd42017-03-23 14:43:44 -0700838
839 if (ReadBlocks(src, params.buffer, params.fd) == -1) {
840 return -1;
Tao Baobaad2d42015-12-06 16:56:27 -0800841 }
842
Tao Baod2aecd42017-03-23 14:43:44 -0700843 if (params.cpos >= params.tokens.size()) {
844 // no stashes, only source range
845 return 0;
Tao Baobaad2d42015-12-06 16:56:27 -0800846 }
Doug Zongker52ae67d2014-09-08 12:22:09 -0700847
Tao Bao8f237572017-03-26 13:36:49 -0700848 RangeSet locs = RangeSet::Parse(params.tokens[params.cpos++]);
Tao Baod2aecd42017-03-23 14:43:44 -0700849 MoveRange(params.buffer, locs, params.buffer);
850 }
Doug Zongker52ae67d2014-09-08 12:22:09 -0700851
Tao Baod2aecd42017-03-23 14:43:44 -0700852 // <[stash_id:stash_range]>
853 while (params.cpos < params.tokens.size()) {
854 // Each word is a an index into the stash table, a colon, and then a RangeSet describing where
855 // in the source block that stashed data should go.
856 std::vector<std::string> tokens = android::base::Split(params.tokens[params.cpos++], ":");
857 if (tokens.size() != 2) {
858 LOG(ERROR) << "invalid parameter";
859 return -1;
Doug Zongker52ae67d2014-09-08 12:22:09 -0700860 }
861
Tao Baod2aecd42017-03-23 14:43:44 -0700862 std::vector<uint8_t> stash;
863 if (LoadStash(params, tokens[0], false, nullptr, stash, true) == -1) {
864 // These source blocks will fail verification if used later, but we
865 // will let the caller decide if this is a fatal failure
866 LOG(ERROR) << "failed to load stash " << tokens[0];
867 continue;
Sami Tolvanen90221202014-12-09 16:39:47 +0000868 }
869
Tao Bao8f237572017-03-26 13:36:49 -0700870 RangeSet locs = RangeSet::Parse(tokens[1]);
Tao Baod2aecd42017-03-23 14:43:44 -0700871 MoveRange(params.buffer, locs, stash);
872 }
873
874 return 0;
Sami Tolvanen90221202014-12-09 16:39:47 +0000875}
876
Tao Bao33567772017-03-13 14:57:34 -0700877/**
878 * Do a source/target load for move/bsdiff/imgdiff in version 3.
879 *
880 * We expect to parse the remainder of the parameter tokens as one of:
881 *
882 * <tgt_range> <src_block_count> <src_range>
883 * (loads data from source image only)
884 *
885 * <tgt_range> <src_block_count> - <[stash_id:stash_range] ...>
886 * (loads data from stashes only)
887 *
888 * <tgt_range> <src_block_count> <src_range> <src_loc> <[stash_id:stash_range] ...>
889 * (loads data from both source image and stashes)
890 *
Tao Baod2aecd42017-03-23 14:43:44 -0700891 * 'onehash' tells whether to expect separate source and targe block hashes, or if they are both the
892 * same and only one hash should be expected. params.isunresumable will be set to true if block
Tao Bao33567772017-03-13 14:57:34 -0700893 * verification fails in a way that the update cannot be resumed anymore.
894 *
895 * If the function is unable to load the necessary blocks or their contents don't match the hashes,
896 * the return value is -1 and the command should be aborted.
897 *
898 * If the return value is 1, the command has already been completed according to the contents of the
899 * target blocks, and should not be performed again.
900 *
901 * If the return value is 0, source blocks have expected content and the command can be performed.
902 */
Tao Baod2aecd42017-03-23 14:43:44 -0700903static int LoadSrcTgtVersion3(CommandParameters& params, RangeSet& tgt, size_t* src_blocks,
904 bool onehash, bool* overlap) {
905 CHECK(src_blocks != nullptr);
906 CHECK(overlap != nullptr);
Sami Tolvanen90221202014-12-09 16:39:47 +0000907
Tao Baod2aecd42017-03-23 14:43:44 -0700908 if (params.cpos >= params.tokens.size()) {
909 LOG(ERROR) << "missing source hash";
Tao Bao0940fe12015-08-27 16:41:21 -0700910 return -1;
Tao Baod2aecd42017-03-23 14:43:44 -0700911 }
912
913 std::string srchash = params.tokens[params.cpos++];
914 std::string tgthash;
915
916 if (onehash) {
917 tgthash = srchash;
918 } else {
919 if (params.cpos >= params.tokens.size()) {
920 LOG(ERROR) << "missing target hash";
921 return -1;
922 }
923 tgthash = params.tokens[params.cpos++];
924 }
925
926 // At least it needs to provide three parameters: <tgt_range>, <src_block_count> and
927 // "-"/<src_range>.
928 if (params.cpos + 2 >= params.tokens.size()) {
929 LOG(ERROR) << "invalid parameters";
930 return -1;
931 }
932
933 // <tgt_range>
Tao Bao8f237572017-03-26 13:36:49 -0700934 tgt = RangeSet::Parse(params.tokens[params.cpos++]);
Tao Baod2aecd42017-03-23 14:43:44 -0700935
936 std::vector<uint8_t> tgtbuffer(tgt.size * BLOCKSIZE);
937 if (ReadBlocks(tgt, tgtbuffer, params.fd) == -1) {
938 return -1;
939 }
940
941 // Return now if target blocks already have expected content.
942 if (VerifyBlocks(tgthash, tgtbuffer, tgt.size, false) == 0) {
943 return 1;
944 }
945
946 // Load source blocks.
947 if (LoadSourceBlocks(params, tgt, src_blocks, overlap) == -1) {
948 return -1;
949 }
950
951 if (VerifyBlocks(srchash, params.buffer, *src_blocks, true) == 0) {
952 // If source and target blocks overlap, stash the source blocks so we can
953 // resume from possible write errors. In verify mode, we can skip stashing
954 // because the source blocks won't be overwritten.
955 if (*overlap && params.canwrite) {
956 LOG(INFO) << "stashing " << *src_blocks << " overlapping blocks to " << srchash;
957
958 bool stash_exists = false;
959 if (WriteStash(params.stashbase, srchash, *src_blocks, params.buffer, true,
960 &stash_exists) != 0) {
961 LOG(ERROR) << "failed to stash overlapping source blocks";
962 return -1;
963 }
964
965 params.stashed += *src_blocks;
966 // Can be deleted when the write has completed.
967 if (!stash_exists) {
968 params.freestash = srchash;
969 }
970 }
971
972 // Source blocks have expected content, command can proceed.
973 return 0;
974 }
975
976 if (*overlap && LoadStash(params, srchash, true, nullptr, params.buffer, true) == 0) {
977 // Overlapping source blocks were previously stashed, command can proceed. We are recovering
978 // from an interrupted command, so we don't know if the stash can safely be deleted after this
979 // command.
980 return 0;
981 }
982
983 // Valid source data not available, update cannot be resumed.
984 LOG(ERROR) << "partition has unexpected contents";
985 PrintHashForCorruptedSourceBlocks(params, params.buffer);
986
987 params.isunresumable = true;
988
989 return -1;
Sami Tolvanen90221202014-12-09 16:39:47 +0000990}
991
Tao Bao0940fe12015-08-27 16:41:21 -0700992static int PerformCommandMove(CommandParameters& params) {
Tao Bao33567772017-03-13 14:57:34 -0700993 size_t blocks = 0;
994 bool overlap = false;
995 RangeSet tgt;
Tao Baod2aecd42017-03-23 14:43:44 -0700996 int status = LoadSrcTgtVersion3(params, tgt, &blocks, true, &overlap);
Sami Tolvanen90221202014-12-09 16:39:47 +0000997
Tao Bao33567772017-03-13 14:57:34 -0700998 if (status == -1) {
999 LOG(ERROR) << "failed to read blocks for move";
1000 return -1;
1001 }
Sami Tolvanen90221202014-12-09 16:39:47 +00001002
Tao Bao33567772017-03-13 14:57:34 -07001003 if (status == 0) {
1004 params.foundwrites = true;
1005 } else if (params.foundwrites) {
1006 LOG(WARNING) << "warning: commands executed out of order [" << params.cmdname << "]";
1007 }
Sami Tolvanen90221202014-12-09 16:39:47 +00001008
Tao Bao33567772017-03-13 14:57:34 -07001009 if (params.canwrite) {
Sami Tolvanen90221202014-12-09 16:39:47 +00001010 if (status == 0) {
Tao Bao33567772017-03-13 14:57:34 -07001011 LOG(INFO) << " moving " << blocks << " blocks";
1012
1013 if (WriteBlocks(tgt, params.buffer, params.fd) == -1) {
1014 return -1;
1015 }
1016 } else {
1017 LOG(INFO) << "skipping " << blocks << " already moved blocks";
Sami Tolvanen90221202014-12-09 16:39:47 +00001018 }
Tao Bao33567772017-03-13 14:57:34 -07001019 }
Sami Tolvanen90221202014-12-09 16:39:47 +00001020
Tao Bao33567772017-03-13 14:57:34 -07001021 if (!params.freestash.empty()) {
1022 FreeStash(params.stashbase, params.freestash);
1023 params.freestash.clear();
1024 }
Sami Tolvanen90221202014-12-09 16:39:47 +00001025
Tao Bao33567772017-03-13 14:57:34 -07001026 params.written += tgt.size;
Sami Tolvanen90221202014-12-09 16:39:47 +00001027
Tao Bao33567772017-03-13 14:57:34 -07001028 return 0;
Sami Tolvanen90221202014-12-09 16:39:47 +00001029}
1030
Tao Bao0940fe12015-08-27 16:41:21 -07001031static int PerformCommandStash(CommandParameters& params) {
Tao Baobcf46492017-03-23 15:28:20 -07001032 // <stash_id> <src_range>
1033 if (params.cpos + 1 >= params.tokens.size()) {
1034 LOG(ERROR) << "missing id and/or src range fields in stash command";
1035 return -1;
1036 }
1037
1038 const std::string& id = params.tokens[params.cpos++];
1039 size_t blocks = 0;
1040 if (LoadStash(params, id, true, &blocks, params.buffer, false) == 0) {
1041 // Stash file already exists and has expected contents. Do not read from source again, as the
1042 // source may have been already overwritten during a previous attempt.
1043 return 0;
1044 }
1045
Tao Bao8f237572017-03-26 13:36:49 -07001046 RangeSet src = RangeSet::Parse(params.tokens[params.cpos++]);
Tao Baobcf46492017-03-23 15:28:20 -07001047
1048 allocate(src.size * BLOCKSIZE, params.buffer);
1049 if (ReadBlocks(src, params.buffer, params.fd) == -1) {
1050 return -1;
1051 }
1052 blocks = src.size;
1053 stash_map[id] = src;
1054
1055 if (VerifyBlocks(id, params.buffer, blocks, true) != 0) {
1056 // Source blocks have unexpected contents. If we actually need this data later, this is an
1057 // unrecoverable error. However, the command that uses the data may have already completed
1058 // previously, so the possible failure will occur during source block verification.
1059 LOG(ERROR) << "failed to load source blocks for stash " << id;
1060 return 0;
1061 }
1062
1063 // In verify mode, we don't need to stash any blocks.
1064 if (!params.canwrite) {
1065 return 0;
1066 }
1067
1068 LOG(INFO) << "stashing " << blocks << " blocks to " << id;
1069 params.stashed += blocks;
1070 return WriteStash(params.stashbase, id, blocks, params.buffer, false, nullptr);
Sami Tolvanen90221202014-12-09 16:39:47 +00001071}
1072
Tao Bao0940fe12015-08-27 16:41:21 -07001073static int PerformCommandFree(CommandParameters& params) {
Tao Baobcf46492017-03-23 15:28:20 -07001074 // <stash_id>
1075 if (params.cpos >= params.tokens.size()) {
1076 LOG(ERROR) << "missing stash id in free command";
1077 return -1;
1078 }
Tao Baobaad2d42015-12-06 16:56:27 -08001079
Tao Baobcf46492017-03-23 15:28:20 -07001080 const std::string& id = params.tokens[params.cpos++];
1081 stash_map.erase(id);
Tianjie Xu7eca97e2016-03-22 18:08:12 -07001082
Tao Baobcf46492017-03-23 15:28:20 -07001083 if (params.createdstash || params.canwrite) {
1084 return FreeStash(params.stashbase, id);
1085 }
Tianjie Xu7eca97e2016-03-22 18:08:12 -07001086
Tao Baobcf46492017-03-23 15:28:20 -07001087 return 0;
Sami Tolvanen90221202014-12-09 16:39:47 +00001088}
1089
Tao Bao0940fe12015-08-27 16:41:21 -07001090static int PerformCommandZero(CommandParameters& params) {
Sami Tolvanen90221202014-12-09 16:39:47 +00001091
Tao Baobaad2d42015-12-06 16:56:27 -08001092 if (params.cpos >= params.tokens.size()) {
Tao Bao039f2da2016-11-22 16:29:50 -08001093 LOG(ERROR) << "missing target blocks for zero";
Tao Bao0940fe12015-08-27 16:41:21 -07001094 return -1;
Sami Tolvanen90221202014-12-09 16:39:47 +00001095 }
1096
Tao Bao8f237572017-03-26 13:36:49 -07001097 RangeSet tgt = RangeSet::Parse(params.tokens[params.cpos++]);
Sami Tolvanen90221202014-12-09 16:39:47 +00001098
Tao Bao039f2da2016-11-22 16:29:50 -08001099 LOG(INFO) << " zeroing " << tgt.size << " blocks";
Sami Tolvanen90221202014-12-09 16:39:47 +00001100
Tao Bao612336d2015-08-27 16:41:21 -07001101 allocate(BLOCKSIZE, params.buffer);
1102 memset(params.buffer.data(), 0, BLOCKSIZE);
Sami Tolvanen90221202014-12-09 16:39:47 +00001103
Tao Bao0940fe12015-08-27 16:41:21 -07001104 if (params.canwrite) {
1105 for (size_t i = 0; i < tgt.count; ++i) {
Tianjie Xu7ce287d2016-05-31 09:29:49 -07001106 off64_t offset = static_cast<off64_t>(tgt.pos[i * 2]) * BLOCKSIZE;
1107 size_t size = (tgt.pos[i * 2 + 1] - tgt.pos[i * 2]) * BLOCKSIZE;
1108 if (!discard_blocks(params.fd, offset, size)) {
1109 return -1;
1110 }
1111
1112 if (!check_lseek(params.fd, offset, SEEK_SET)) {
Tao Bao0940fe12015-08-27 16:41:21 -07001113 return -1;
Sami Tolvanen90221202014-12-09 16:39:47 +00001114 }
1115
Tao Bao0940fe12015-08-27 16:41:21 -07001116 for (size_t j = tgt.pos[i * 2]; j < tgt.pos[i * 2 + 1]; ++j) {
1117 if (write_all(params.fd, params.buffer, BLOCKSIZE) == -1) {
1118 return -1;
Sami Tolvanen90221202014-12-09 16:39:47 +00001119 }
1120 }
1121 }
1122 }
1123
Tao Bao0940fe12015-08-27 16:41:21 -07001124 if (params.cmdname[0] == 'z') {
Sami Tolvanene82fa182015-06-10 15:58:12 +00001125 // Update only for the zero command, as the erase command will call
1126 // this if DEBUG_ERASE is defined.
Tao Bao0940fe12015-08-27 16:41:21 -07001127 params.written += tgt.size;
Sami Tolvanen90221202014-12-09 16:39:47 +00001128 }
1129
Tao Bao0940fe12015-08-27 16:41:21 -07001130 return 0;
Sami Tolvanen90221202014-12-09 16:39:47 +00001131}
1132
Tao Bao0940fe12015-08-27 16:41:21 -07001133static int PerformCommandNew(CommandParameters& params) {
Tao Bao60a70af2017-03-26 14:03:52 -07001134 if (params.cpos >= params.tokens.size()) {
1135 LOG(ERROR) << "missing target blocks for new";
1136 return -1;
1137 }
Sami Tolvanen90221202014-12-09 16:39:47 +00001138
Tao Bao8f237572017-03-26 13:36:49 -07001139 RangeSet tgt = RangeSet::Parse(params.tokens[params.cpos++]);
Tao Bao60a70af2017-03-26 14:03:52 -07001140
1141 if (params.canwrite) {
1142 LOG(INFO) << " writing " << tgt.size << " blocks of new data";
1143
1144 RangeSinkWriter writer(params.fd, tgt);
1145 pthread_mutex_lock(&params.nti.mu);
1146 params.nti.writer = &writer;
1147 pthread_cond_broadcast(&params.nti.cv);
1148
1149 while (params.nti.writer != nullptr) {
1150 pthread_cond_wait(&params.nti.cv, &params.nti.mu);
Sami Tolvanen90221202014-12-09 16:39:47 +00001151 }
1152
Tao Bao60a70af2017-03-26 14:03:52 -07001153 pthread_mutex_unlock(&params.nti.mu);
1154 }
Sami Tolvanen90221202014-12-09 16:39:47 +00001155
Tao Bao60a70af2017-03-26 14:03:52 -07001156 params.written += tgt.size;
Sami Tolvanen90221202014-12-09 16:39:47 +00001157
Tao Bao60a70af2017-03-26 14:03:52 -07001158 return 0;
Sami Tolvanen90221202014-12-09 16:39:47 +00001159}
1160
Tao Bao0940fe12015-08-27 16:41:21 -07001161static int PerformCommandDiff(CommandParameters& params) {
Tao Baoc0e1c462017-02-01 10:20:10 -08001162 // <offset> <length>
1163 if (params.cpos + 1 >= params.tokens.size()) {
1164 LOG(ERROR) << "missing patch offset or length for " << params.cmdname;
1165 return -1;
1166 }
Tao Bao0940fe12015-08-27 16:41:21 -07001167
Tao Baoc0e1c462017-02-01 10:20:10 -08001168 size_t offset;
1169 if (!android::base::ParseUint(params.tokens[params.cpos++], &offset)) {
1170 LOG(ERROR) << "invalid patch offset";
1171 return -1;
1172 }
Tao Bao0940fe12015-08-27 16:41:21 -07001173
Tao Baoc0e1c462017-02-01 10:20:10 -08001174 size_t len;
1175 if (!android::base::ParseUint(params.tokens[params.cpos++], &len)) {
1176 LOG(ERROR) << "invalid patch len";
1177 return -1;
1178 }
Tao Bao0940fe12015-08-27 16:41:21 -07001179
Tao Baoc0e1c462017-02-01 10:20:10 -08001180 RangeSet tgt;
1181 size_t blocks = 0;
1182 bool overlap = false;
1183 int status = LoadSrcTgtVersion3(params, tgt, &blocks, false, &overlap);
Tao Bao0940fe12015-08-27 16:41:21 -07001184
Tao Baoc0e1c462017-02-01 10:20:10 -08001185 if (status == -1) {
1186 LOG(ERROR) << "failed to read blocks for diff";
1187 return -1;
1188 }
Sami Tolvanen90221202014-12-09 16:39:47 +00001189
Tao Baoc0e1c462017-02-01 10:20:10 -08001190 if (status == 0) {
1191 params.foundwrites = true;
1192 } else if (params.foundwrites) {
1193 LOG(WARNING) << "warning: commands executed out of order [" << params.cmdname << "]";
1194 }
Sami Tolvanen90221202014-12-09 16:39:47 +00001195
Tao Baoc0e1c462017-02-01 10:20:10 -08001196 if (params.canwrite) {
Sami Tolvanen90221202014-12-09 16:39:47 +00001197 if (status == 0) {
Tao Baoc0e1c462017-02-01 10:20:10 -08001198 LOG(INFO) << "patching " << blocks << " blocks to " << tgt.size;
1199 Value patch_value(
1200 VAL_BLOB, std::string(reinterpret_cast<const char*>(params.patch_start + offset), len));
Sami Tolvanen90221202014-12-09 16:39:47 +00001201
Tao Bao60a70af2017-03-26 14:03:52 -07001202 RangeSinkWriter writer(params.fd, tgt);
Tao Baoc0e1c462017-02-01 10:20:10 -08001203 if (params.cmdname[0] == 'i') { // imgdiff
Tao Bao60a70af2017-03-26 14:03:52 -07001204 if (ApplyImagePatch(params.buffer.data(), blocks * BLOCKSIZE, &patch_value,
1205 std::bind(&RangeSinkWriter::Write, &writer, std::placeholders::_1,
1206 std::placeholders::_2),
1207 nullptr, nullptr) != 0) {
Tao Baoc0e1c462017-02-01 10:20:10 -08001208 LOG(ERROR) << "Failed to apply image patch.";
1209 return -1;
Sami Tolvanen90221202014-12-09 16:39:47 +00001210 }
Tao Baoc0e1c462017-02-01 10:20:10 -08001211 } else {
Tao Bao60a70af2017-03-26 14:03:52 -07001212 if (ApplyBSDiffPatch(params.buffer.data(), blocks * BLOCKSIZE, &patch_value, 0,
1213 std::bind(&RangeSinkWriter::Write, &writer, std::placeholders::_1,
1214 std::placeholders::_2),
1215 nullptr) != 0) {
Tao Baoc0e1c462017-02-01 10:20:10 -08001216 LOG(ERROR) << "Failed to apply bsdiff patch.";
1217 return -1;
1218 }
1219 }
1220
1221 // We expect the output of the patcher to fill the tgt ranges exactly.
Tao Bao60a70af2017-03-26 14:03:52 -07001222 if (!writer.Finished()) {
Tao Baoc0e1c462017-02-01 10:20:10 -08001223 LOG(ERROR) << "range sink underrun?";
1224 }
1225 } else {
1226 LOG(INFO) << "skipping " << blocks << " blocks already patched to " << tgt.size << " ["
1227 << params.cmdline << "]";
Sami Tolvanen90221202014-12-09 16:39:47 +00001228 }
Tao Baoc0e1c462017-02-01 10:20:10 -08001229 }
Sami Tolvanen90221202014-12-09 16:39:47 +00001230
Tao Baoc0e1c462017-02-01 10:20:10 -08001231 if (!params.freestash.empty()) {
1232 FreeStash(params.stashbase, params.freestash);
1233 params.freestash.clear();
1234 }
Sami Tolvanen90221202014-12-09 16:39:47 +00001235
Tao Baoc0e1c462017-02-01 10:20:10 -08001236 params.written += tgt.size;
Sami Tolvanen90221202014-12-09 16:39:47 +00001237
Tao Baoc0e1c462017-02-01 10:20:10 -08001238 return 0;
Sami Tolvanen90221202014-12-09 16:39:47 +00001239}
1240
Tao Bao0940fe12015-08-27 16:41:21 -07001241static int PerformCommandErase(CommandParameters& params) {
Sami Tolvanene82fa182015-06-10 15:58:12 +00001242 if (DEBUG_ERASE) {
1243 return PerformCommandZero(params);
Sami Tolvanen90221202014-12-09 16:39:47 +00001244 }
1245
Tao Bao0940fe12015-08-27 16:41:21 -07001246 struct stat sb;
1247 if (fstat(params.fd, &sb) == -1) {
Tao Bao039f2da2016-11-22 16:29:50 -08001248 PLOG(ERROR) << "failed to fstat device to erase";
Tao Bao0940fe12015-08-27 16:41:21 -07001249 return -1;
Sami Tolvanen90221202014-12-09 16:39:47 +00001250 }
1251
Tao Bao0940fe12015-08-27 16:41:21 -07001252 if (!S_ISBLK(sb.st_mode)) {
Tao Bao039f2da2016-11-22 16:29:50 -08001253 LOG(ERROR) << "not a block device; skipping erase";
Tao Bao0940fe12015-08-27 16:41:21 -07001254 return -1;
Sami Tolvanen90221202014-12-09 16:39:47 +00001255 }
1256
Tao Baobaad2d42015-12-06 16:56:27 -08001257 if (params.cpos >= params.tokens.size()) {
Tao Bao039f2da2016-11-22 16:29:50 -08001258 LOG(ERROR) << "missing target blocks for erase";
Tao Bao0940fe12015-08-27 16:41:21 -07001259 return -1;
Sami Tolvanen90221202014-12-09 16:39:47 +00001260 }
1261
Tao Bao8f237572017-03-26 13:36:49 -07001262 RangeSet tgt = RangeSet::Parse(params.tokens[params.cpos++]);
Sami Tolvanen90221202014-12-09 16:39:47 +00001263
Tao Bao0940fe12015-08-27 16:41:21 -07001264 if (params.canwrite) {
Tao Bao039f2da2016-11-22 16:29:50 -08001265 LOG(INFO) << " erasing " << tgt.size << " blocks";
Sami Tolvanen90221202014-12-09 16:39:47 +00001266
Tao Bao0940fe12015-08-27 16:41:21 -07001267 for (size_t i = 0; i < tgt.count; ++i) {
1268 uint64_t blocks[2];
Sami Tolvanen90221202014-12-09 16:39:47 +00001269 // offset in bytes
Tao Bao0940fe12015-08-27 16:41:21 -07001270 blocks[0] = tgt.pos[i * 2] * (uint64_t) BLOCKSIZE;
Sami Tolvanen90221202014-12-09 16:39:47 +00001271 // length in bytes
Tao Bao0940fe12015-08-27 16:41:21 -07001272 blocks[1] = (tgt.pos[i * 2 + 1] - tgt.pos[i * 2]) * (uint64_t) BLOCKSIZE;
Sami Tolvanen90221202014-12-09 16:39:47 +00001273
Tao Bao0940fe12015-08-27 16:41:21 -07001274 if (ioctl(params.fd, BLKDISCARD, &blocks) == -1) {
Tao Bao039f2da2016-11-22 16:29:50 -08001275 PLOG(ERROR) << "BLKDISCARD ioctl failed";
Tao Bao0940fe12015-08-27 16:41:21 -07001276 return -1;
Sami Tolvanen90221202014-12-09 16:39:47 +00001277 }
1278 }
1279 }
1280
Tao Bao0940fe12015-08-27 16:41:21 -07001281 return 0;
Sami Tolvanen90221202014-12-09 16:39:47 +00001282}
1283
1284// Definitions for transfer list command functions
Tao Bao0940fe12015-08-27 16:41:21 -07001285typedef int (*CommandFunction)(CommandParameters&);
Sami Tolvanen90221202014-12-09 16:39:47 +00001286
Tao Bao612336d2015-08-27 16:41:21 -07001287struct Command {
Sami Tolvanen90221202014-12-09 16:39:47 +00001288 const char* name;
1289 CommandFunction f;
Tao Bao612336d2015-08-27 16:41:21 -07001290};
Sami Tolvanen90221202014-12-09 16:39:47 +00001291
Doug Zongkerbc7ffed2014-08-15 14:31:52 -07001292// args:
1293// - block device (or file) to modify in-place
1294// - transfer list (blob)
1295// - new data stream (filename within package.zip)
1296// - patch stream (filename within package.zip, must be uncompressed)
1297
Tianjie Xuc4447322017-03-06 14:44:59 -08001298static Value* PerformBlockImageUpdate(const char* name, State* state,
1299 const std::vector<std::unique_ptr<Expr>>& argv,
1300 const Command* commands, size_t cmdcount, bool dryrun) {
Tao Bao33567772017-03-13 14:57:34 -07001301 CommandParameters params = {};
1302 params.canwrite = !dryrun;
Sami Tolvanen90221202014-12-09 16:39:47 +00001303
Tao Bao33567772017-03-13 14:57:34 -07001304 LOG(INFO) << "performing " << (dryrun ? "verification" : "update");
1305 if (state->is_retry) {
1306 is_retry = true;
1307 LOG(INFO) << "This update is a retry.";
1308 }
1309 if (argv.size() != 4) {
1310 ErrorAbort(state, kArgsParsingFailure, "block_image_update expects 4 arguments, got %zu",
1311 argv.size());
1312 return StringValue("");
1313 }
1314
1315 std::vector<std::unique_ptr<Value>> args;
1316 if (!ReadValueArgs(state, argv, &args)) {
1317 return nullptr;
1318 }
1319
1320 const Value* blockdev_filename = args[0].get();
1321 const Value* transfer_list_value = args[1].get();
1322 const Value* new_data_fn = args[2].get();
1323 const Value* patch_data_fn = args[3].get();
1324
1325 if (blockdev_filename->type != VAL_STRING) {
1326 ErrorAbort(state, kArgsParsingFailure, "blockdev_filename argument to %s must be string", name);
1327 return StringValue("");
1328 }
1329 if (transfer_list_value->type != VAL_BLOB) {
1330 ErrorAbort(state, kArgsParsingFailure, "transfer_list argument to %s must be blob", name);
1331 return StringValue("");
1332 }
1333 if (new_data_fn->type != VAL_STRING) {
1334 ErrorAbort(state, kArgsParsingFailure, "new_data_fn argument to %s must be string", name);
1335 return StringValue("");
1336 }
1337 if (patch_data_fn->type != VAL_STRING) {
1338 ErrorAbort(state, kArgsParsingFailure, "patch_data_fn argument to %s must be string", name);
1339 return StringValue("");
1340 }
1341
1342 UpdaterInfo* ui = static_cast<UpdaterInfo*>(state->cookie);
1343 if (ui == nullptr) {
1344 return StringValue("");
1345 }
1346
1347 FILE* cmd_pipe = ui->cmd_pipe;
1348 ZipArchiveHandle za = ui->package_zip;
1349
1350 if (cmd_pipe == nullptr || za == nullptr) {
1351 return StringValue("");
1352 }
1353
1354 ZipString path_data(patch_data_fn->data.c_str());
1355 ZipEntry patch_entry;
1356 if (FindEntry(za, path_data, &patch_entry) != 0) {
1357 LOG(ERROR) << name << "(): no file \"" << patch_data_fn->data << "\" in package";
1358 return StringValue("");
1359 }
1360
1361 params.patch_start = ui->package_zip_addr + patch_entry.offset;
1362 ZipString new_data(new_data_fn->data.c_str());
1363 ZipEntry new_entry;
1364 if (FindEntry(za, new_data, &new_entry) != 0) {
1365 LOG(ERROR) << name << "(): no file \"" << new_data_fn->data << "\" in package";
1366 return StringValue("");
1367 }
1368
1369 params.fd.reset(TEMP_FAILURE_RETRY(ota_open(blockdev_filename->data.c_str(), O_RDWR)));
1370 if (params.fd == -1) {
1371 PLOG(ERROR) << "open \"" << blockdev_filename->data << "\" failed";
1372 return StringValue("");
1373 }
1374
1375 if (params.canwrite) {
1376 params.nti.za = za;
1377 params.nti.entry = new_entry;
1378
1379 pthread_mutex_init(&params.nti.mu, nullptr);
1380 pthread_cond_init(&params.nti.cv, nullptr);
1381 pthread_attr_t attr;
1382 pthread_attr_init(&attr);
1383 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
1384
1385 int error = pthread_create(&params.thread, &attr, unzip_new_data, &params.nti);
1386 if (error != 0) {
1387 PLOG(ERROR) << "pthread_create failed";
1388 return StringValue("");
Tianjie Xu7ce287d2016-05-31 09:29:49 -07001389 }
Tao Bao33567772017-03-13 14:57:34 -07001390 }
1391
1392 std::vector<std::string> lines = android::base::Split(transfer_list_value->data, "\n");
1393 if (lines.size() < 2) {
1394 ErrorAbort(state, kArgsParsingFailure, "too few lines in the transfer list [%zd]\n",
1395 lines.size());
1396 return StringValue("");
1397 }
1398
1399 // First line in transfer list is the version number.
1400 if (!android::base::ParseInt(lines[0], &params.version, 3, 4)) {
1401 LOG(ERROR) << "unexpected transfer list version [" << lines[0] << "]";
1402 return StringValue("");
1403 }
1404
1405 LOG(INFO) << "blockimg version is " << params.version;
1406
1407 // Second line in transfer list is the total number of blocks we expect to write.
1408 size_t total_blocks;
1409 if (!android::base::ParseUint(lines[1], &total_blocks)) {
1410 ErrorAbort(state, kArgsParsingFailure, "unexpected block count [%s]\n", lines[1].c_str());
1411 return StringValue("");
1412 }
1413
1414 if (total_blocks == 0) {
1415 return StringValue("t");
1416 }
1417
1418 size_t start = 2;
1419 if (lines.size() < 4) {
1420 ErrorAbort(state, kArgsParsingFailure, "too few lines in the transfer list [%zu]\n",
1421 lines.size());
1422 return StringValue("");
1423 }
1424
1425 // Third line is how many stash entries are needed simultaneously.
1426 LOG(INFO) << "maximum stash entries " << lines[2];
1427
1428 // Fourth line is the maximum number of blocks that will be stashed simultaneously
1429 size_t stash_max_blocks;
1430 if (!android::base::ParseUint(lines[3], &stash_max_blocks)) {
1431 ErrorAbort(state, kArgsParsingFailure, "unexpected maximum stash blocks [%s]\n",
1432 lines[3].c_str());
1433 return StringValue("");
1434 }
1435
1436 int res = CreateStash(state, stash_max_blocks, blockdev_filename->data, params.stashbase);
1437 if (res == -1) {
1438 return StringValue("");
1439 }
1440
1441 params.createdstash = res;
1442
1443 start += 2;
1444
1445 // Build a map of the available commands
1446 std::unordered_map<std::string, const Command*> cmd_map;
1447 for (size_t i = 0; i < cmdcount; ++i) {
1448 if (cmd_map.find(commands[i].name) != cmd_map.end()) {
1449 LOG(ERROR) << "Error: command [" << commands[i].name << "] already exists in the cmd map.";
1450 return StringValue(strdup(""));
1451 }
1452 cmd_map[commands[i].name] = &commands[i];
1453 }
1454
1455 int rc = -1;
1456
1457 // Subsequent lines are all individual transfer commands
1458 for (auto it = lines.cbegin() + start; it != lines.cend(); it++) {
1459 const std::string& line(*it);
1460 if (line.empty()) continue;
1461
1462 params.tokens = android::base::Split(line, " ");
1463 params.cpos = 0;
1464 params.cmdname = params.tokens[params.cpos++].c_str();
1465 params.cmdline = line.c_str();
1466
1467 if (cmd_map.find(params.cmdname) == cmd_map.end()) {
1468 LOG(ERROR) << "unexpected command [" << params.cmdname << "]";
1469 goto pbiudone;
Tianjie Xuc4447322017-03-06 14:44:59 -08001470 }
Doug Zongkerbc7ffed2014-08-15 14:31:52 -07001471
Tao Bao33567772017-03-13 14:57:34 -07001472 const Command* cmd = cmd_map[params.cmdname];
Tianjie Xu5fe280a2016-10-17 18:15:20 -07001473
Tao Bao33567772017-03-13 14:57:34 -07001474 if (cmd->f != nullptr && cmd->f(params) == -1) {
1475 LOG(ERROR) << "failed to execute command [" << line << "]";
1476 goto pbiudone;
Doug Zongkerbc7ffed2014-08-15 14:31:52 -07001477 }
1478
Sami Tolvanen90221202014-12-09 16:39:47 +00001479 if (params.canwrite) {
Tao Bao33567772017-03-13 14:57:34 -07001480 if (ota_fsync(params.fd) == -1) {
Tianjie Xu16255832016-04-30 11:49:59 -07001481 failure_type = kFsyncFailure;
Tao Bao039f2da2016-11-22 16:29:50 -08001482 PLOG(ERROR) << "fsync failed";
Tao Bao33567772017-03-13 14:57:34 -07001483 goto pbiudone;
1484 }
1485 fprintf(cmd_pipe, "set_progress %.4f\n", static_cast<double>(params.written) / total_blocks);
1486 fflush(cmd_pipe);
Sami Tolvanen90221202014-12-09 16:39:47 +00001487 }
Tao Bao33567772017-03-13 14:57:34 -07001488 }
Sami Tolvanen90221202014-12-09 16:39:47 +00001489
Tao Bao33567772017-03-13 14:57:34 -07001490 if (params.canwrite) {
1491 pthread_join(params.thread, nullptr);
1492
1493 LOG(INFO) << "wrote " << params.written << " blocks; expected " << total_blocks;
1494 LOG(INFO) << "stashed " << params.stashed << " blocks";
1495 LOG(INFO) << "max alloc needed was " << params.buffer.size();
1496
1497 const char* partition = strrchr(blockdev_filename->data.c_str(), '/');
1498 if (partition != nullptr && *(partition + 1) != 0) {
1499 fprintf(cmd_pipe, "log bytes_written_%s: %zu\n", partition + 1, params.written * BLOCKSIZE);
1500 fprintf(cmd_pipe, "log bytes_stashed_%s: %zu\n", partition + 1, params.stashed * BLOCKSIZE);
1501 fflush(cmd_pipe);
Sami Tolvanen90221202014-12-09 16:39:47 +00001502 }
Tao Bao33567772017-03-13 14:57:34 -07001503 // Delete stash only after successfully completing the update, as it may contain blocks needed
1504 // to complete the update later.
1505 DeleteStash(params.stashbase);
1506 } else {
1507 LOG(INFO) << "verified partition contents; update may be resumed";
1508 }
Sami Tolvanen90221202014-12-09 16:39:47 +00001509
Tao Bao33567772017-03-13 14:57:34 -07001510 rc = 0;
Tianjie Xu16255832016-04-30 11:49:59 -07001511
Tao Bao33567772017-03-13 14:57:34 -07001512pbiudone:
1513 if (ota_fsync(params.fd) == -1) {
1514 failure_type = kFsyncFailure;
1515 PLOG(ERROR) << "fsync failed";
1516 }
1517 // params.fd will be automatically closed because it's a unique_fd.
1518
1519 // Only delete the stash if the update cannot be resumed, or it's a verification run and we
1520 // created the stash.
1521 if (params.isunresumable || (!params.canwrite && params.createdstash)) {
1522 DeleteStash(params.stashbase);
1523 }
1524
1525 if (failure_type != kNoCause && state->cause_code == kNoCause) {
1526 state->cause_code = failure_type;
1527 }
1528
1529 return StringValue(rc == 0 ? "t" : "");
Sami Tolvanen90221202014-12-09 16:39:47 +00001530}
1531
Tao Bao33567772017-03-13 14:57:34 -07001532/**
1533 * The transfer list is a text file containing commands to transfer data from one place to another
1534 * on the target partition. We parse it and execute the commands in order:
1535 *
1536 * zero [rangeset]
1537 * - Fill the indicated blocks with zeros.
1538 *
1539 * new [rangeset]
1540 * - Fill the blocks with data read from the new_data file.
1541 *
1542 * erase [rangeset]
1543 * - Mark the given blocks as empty.
1544 *
1545 * move <...>
1546 * bsdiff <patchstart> <patchlen> <...>
1547 * imgdiff <patchstart> <patchlen> <...>
1548 * - Read the source blocks, apply a patch (or not in the case of move), write result to target
1549 * blocks. bsdiff or imgdiff specifies the type of patch; move means no patch at all.
1550 *
1551 * See the comments in LoadSrcTgtVersion3() for a description of the <...> format.
1552 *
1553 * stash <stash_id> <src_range>
1554 * - Load the given source range and stash the data in the given slot of the stash table.
1555 *
1556 * free <stash_id>
1557 * - Free the given stash data.
1558 *
1559 * The creator of the transfer list will guarantee that no block is read (ie, used as the source for
1560 * a patch or move) after it has been written.
1561 *
1562 * The creator will guarantee that a given stash is loaded (with a stash command) before it's used
1563 * in a move/bsdiff/imgdiff command.
1564 *
1565 * Within one command the source and target ranges may overlap so in general we need to read the
1566 * entire source into memory before writing anything to the target blocks.
1567 *
1568 * All the patch data is concatenated into one patch_data file in the update package. It must be
1569 * stored uncompressed because we memory-map it in directly from the archive. (Since patches are
1570 * already compressed, we lose very little by not compressing their concatenation.)
1571 *
1572 * Commands that read data from the partition (i.e. move/bsdiff/imgdiff/stash) have one or more
1573 * additional hashes before the range parameters, which are used to check if the command has already
1574 * been completed and verify the integrity of the source data.
1575 */
Tianjie Xuc4447322017-03-06 14:44:59 -08001576Value* BlockImageVerifyFn(const char* name, State* state,
1577 const std::vector<std::unique_ptr<Expr>>& argv) {
Tao Bao0940fe12015-08-27 16:41:21 -07001578 // Commands which are not tested are set to nullptr to skip them completely
Sami Tolvanen90221202014-12-09 16:39:47 +00001579 const Command commands[] = {
1580 { "bsdiff", PerformCommandDiff },
Tao Bao0940fe12015-08-27 16:41:21 -07001581 { "erase", nullptr },
Sami Tolvanen90221202014-12-09 16:39:47 +00001582 { "free", PerformCommandFree },
1583 { "imgdiff", PerformCommandDiff },
1584 { "move", PerformCommandMove },
Tao Bao0940fe12015-08-27 16:41:21 -07001585 { "new", nullptr },
Sami Tolvanen90221202014-12-09 16:39:47 +00001586 { "stash", PerformCommandStash },
Tao Bao0940fe12015-08-27 16:41:21 -07001587 { "zero", nullptr }
Sami Tolvanen90221202014-12-09 16:39:47 +00001588 };
1589
1590 // Perform a dry run without writing to test if an update can proceed
Tianjie Xuc4447322017-03-06 14:44:59 -08001591 return PerformBlockImageUpdate(name, state, argv, commands,
Tao Baoe6aa3322015-08-05 15:20:27 -07001592 sizeof(commands) / sizeof(commands[0]), true);
Sami Tolvanen90221202014-12-09 16:39:47 +00001593}
1594
Tianjie Xuc4447322017-03-06 14:44:59 -08001595Value* BlockImageUpdateFn(const char* name, State* state,
1596 const std::vector<std::unique_ptr<Expr>>& argv) {
Sami Tolvanen90221202014-12-09 16:39:47 +00001597 const Command commands[] = {
1598 { "bsdiff", PerformCommandDiff },
1599 { "erase", PerformCommandErase },
1600 { "free", PerformCommandFree },
1601 { "imgdiff", PerformCommandDiff },
1602 { "move", PerformCommandMove },
1603 { "new", PerformCommandNew },
1604 { "stash", PerformCommandStash },
1605 { "zero", PerformCommandZero }
1606 };
1607
Tianjie Xuc4447322017-03-06 14:44:59 -08001608 return PerformBlockImageUpdate(name, state, argv, commands,
Tao Baoe6aa3322015-08-05 15:20:27 -07001609 sizeof(commands) / sizeof(commands[0]), false);
Doug Zongkerbc7ffed2014-08-15 14:31:52 -07001610}
1611
Tianjie Xuc4447322017-03-06 14:44:59 -08001612Value* RangeSha1Fn(const char* name, State* state, const std::vector<std::unique_ptr<Expr>>& argv) {
1613 if (argv.size() != 2) {
1614 ErrorAbort(state, kArgsParsingFailure, "range_sha1 expects 2 arguments, got %zu",
1615 argv.size());
1616 return StringValue("");
1617 }
1618
Tianjie Xu5fe280a2016-10-17 18:15:20 -07001619 std::vector<std::unique_ptr<Value>> args;
Tianjie Xuc4447322017-03-06 14:44:59 -08001620 if (!ReadValueArgs(state, argv, &args)) {
Tianjie Xu5fe280a2016-10-17 18:15:20 -07001621 return nullptr;
Doug Zongkerbc7ffed2014-08-15 14:31:52 -07001622 }
Tianjie Xu5fe280a2016-10-17 18:15:20 -07001623
1624 const Value* blockdev_filename = args[0].get();
1625 const Value* ranges = args[1].get();
Doug Zongkerbc7ffed2014-08-15 14:31:52 -07001626
1627 if (blockdev_filename->type != VAL_STRING) {
Tianjie Xu16255832016-04-30 11:49:59 -07001628 ErrorAbort(state, kArgsParsingFailure, "blockdev_filename argument to %s must be string",
1629 name);
Tianjie Xuaced5d92016-10-12 10:55:04 -07001630 return StringValue("");
Doug Zongkerbc7ffed2014-08-15 14:31:52 -07001631 }
1632 if (ranges->type != VAL_STRING) {
Tianjie Xu16255832016-04-30 11:49:59 -07001633 ErrorAbort(state, kArgsParsingFailure, "ranges argument to %s must be string", name);
Tianjie Xuaced5d92016-10-12 10:55:04 -07001634 return StringValue("");
Doug Zongkerbc7ffed2014-08-15 14:31:52 -07001635 }
1636
Tianjie Xuaced5d92016-10-12 10:55:04 -07001637 android::base::unique_fd fd(ota_open(blockdev_filename->data.c_str(), O_RDWR));
Elliott Hughesbcabd092016-03-22 20:19:22 -07001638 if (fd == -1) {
Tianjie Xuaced5d92016-10-12 10:55:04 -07001639 ErrorAbort(state, kFileOpenFailure, "open \"%s\" failed: %s",
1640 blockdev_filename->data.c_str(), strerror(errno));
1641 return StringValue("");
Doug Zongkerbc7ffed2014-08-15 14:31:52 -07001642 }
1643
Tao Bao8f237572017-03-26 13:36:49 -07001644 RangeSet rs = RangeSet::Parse(ranges->data);
Doug Zongkerbc7ffed2014-08-15 14:31:52 -07001645
1646 SHA_CTX ctx;
Sen Jiangc48cb5e2016-02-04 16:23:21 +08001647 SHA1_Init(&ctx);
Doug Zongkerbc7ffed2014-08-15 14:31:52 -07001648
Tao Bao612336d2015-08-27 16:41:21 -07001649 std::vector<uint8_t> buffer(BLOCKSIZE);
Tao Bao0940fe12015-08-27 16:41:21 -07001650 for (size_t i = 0; i < rs.count; ++i) {
1651 if (!check_lseek(fd, (off64_t)rs.pos[i*2] * BLOCKSIZE, SEEK_SET)) {
Tianjie Xuaced5d92016-10-12 10:55:04 -07001652 ErrorAbort(state, kLseekFailure, "failed to seek %s: %s",
1653 blockdev_filename->data.c_str(), strerror(errno));
1654 return StringValue("");
Sami Tolvanen90221202014-12-09 16:39:47 +00001655 }
1656
Tao Bao0940fe12015-08-27 16:41:21 -07001657 for (size_t j = rs.pos[i*2]; j < rs.pos[i*2+1]; ++j) {
Sami Tolvanen90221202014-12-09 16:39:47 +00001658 if (read_all(fd, buffer, BLOCKSIZE) == -1) {
Tianjie Xuaced5d92016-10-12 10:55:04 -07001659 ErrorAbort(state, kFreadFailure, "failed to read %s: %s",
1660 blockdev_filename->data.c_str(), strerror(errno));
1661 return StringValue("");
Sami Tolvanen90221202014-12-09 16:39:47 +00001662 }
1663
Sen Jiangc48cb5e2016-02-04 16:23:21 +08001664 SHA1_Update(&ctx, buffer.data(), BLOCKSIZE);
Doug Zongkerbc7ffed2014-08-15 14:31:52 -07001665 }
1666 }
Sen Jiangc48cb5e2016-02-04 16:23:21 +08001667 uint8_t digest[SHA_DIGEST_LENGTH];
1668 SHA1_Final(digest, &ctx);
Doug Zongkerbc7ffed2014-08-15 14:31:52 -07001669
Tianjie Xuaced5d92016-10-12 10:55:04 -07001670 return StringValue(print_sha1(digest));
Doug Zongkerbc7ffed2014-08-15 14:31:52 -07001671}
1672
Tianjie Xu57bed6d2015-12-15 11:47:30 -08001673// This function checks if a device has been remounted R/W prior to an incremental
1674// OTA update. This is an common cause of update abortion. The function reads the
1675// 1st block of each partition and check for mounting time/count. It return string "t"
1676// if executes successfully and an empty string otherwise.
1677
Tianjie Xuc4447322017-03-06 14:44:59 -08001678Value* CheckFirstBlockFn(const char* name, State* state,
1679 const std::vector<std::unique_ptr<Expr>>& argv) {
1680 if (argv.size() != 1) {
1681 ErrorAbort(state, kArgsParsingFailure, "check_first_block expects 1 argument, got %zu",
1682 argv.size());
1683 return StringValue("");
1684 }
1685
Tianjie Xu5fe280a2016-10-17 18:15:20 -07001686 std::vector<std::unique_ptr<Value>> args;
Tianjie Xuc4447322017-03-06 14:44:59 -08001687 if (!ReadValueArgs(state, argv, &args)) {
Tianjie Xu57bed6d2015-12-15 11:47:30 -08001688 return nullptr;
1689 }
Tianjie Xu57bed6d2015-12-15 11:47:30 -08001690
Tianjie Xu5fe280a2016-10-17 18:15:20 -07001691 const Value* arg_filename = args[0].get();
1692
1693 if (arg_filename->type != VAL_STRING) {
Tianjie Xu16255832016-04-30 11:49:59 -07001694 ErrorAbort(state, kArgsParsingFailure, "filename argument to %s must be string", name);
Tianjie Xuaced5d92016-10-12 10:55:04 -07001695 return StringValue("");
Tianjie Xu57bed6d2015-12-15 11:47:30 -08001696 }
1697
Tianjie Xuaced5d92016-10-12 10:55:04 -07001698 android::base::unique_fd fd(ota_open(arg_filename->data.c_str(), O_RDONLY));
Tianjie Xu57bed6d2015-12-15 11:47:30 -08001699 if (fd == -1) {
Tianjie Xuaced5d92016-10-12 10:55:04 -07001700 ErrorAbort(state, kFileOpenFailure, "open \"%s\" failed: %s", arg_filename->data.c_str(),
Tianjie Xu16255832016-04-30 11:49:59 -07001701 strerror(errno));
Tianjie Xuaced5d92016-10-12 10:55:04 -07001702 return StringValue("");
Tianjie Xu57bed6d2015-12-15 11:47:30 -08001703 }
1704
1705 RangeSet blk0 {1 /*count*/, 1/*size*/, std::vector<size_t> {0, 1}/*position*/};
1706 std::vector<uint8_t> block0_buffer(BLOCKSIZE);
1707
1708 if (ReadBlocks(blk0, block0_buffer, fd) == -1) {
Tianjie Xuaced5d92016-10-12 10:55:04 -07001709 ErrorAbort(state, kFreadFailure, "failed to read %s: %s", arg_filename->data.c_str(),
Tianjie Xu30bf4762015-12-15 11:47:30 -08001710 strerror(errno));
Tianjie Xuaced5d92016-10-12 10:55:04 -07001711 return StringValue("");
Tianjie Xu57bed6d2015-12-15 11:47:30 -08001712 }
1713
1714 // https://ext4.wiki.kernel.org/index.php/Ext4_Disk_Layout
1715 // Super block starts from block 0, offset 0x400
1716 // 0x2C: len32 Mount time
1717 // 0x30: len32 Write time
1718 // 0x34: len16 Number of mounts since the last fsck
1719 // 0x38: len16 Magic signature 0xEF53
1720
1721 time_t mount_time = *reinterpret_cast<uint32_t*>(&block0_buffer[0x400+0x2C]);
1722 uint16_t mount_count = *reinterpret_cast<uint16_t*>(&block0_buffer[0x400+0x34]);
1723
1724 if (mount_count > 0) {
Tao Bao0bbc7642017-03-29 23:57:47 -07001725 uiPrintf(state, "Device was remounted R/W %" PRIu16 " times", mount_count);
Tianjie Xu57bed6d2015-12-15 11:47:30 -08001726 uiPrintf(state, "Last remount happened on %s", ctime(&mount_time));
1727 }
1728
Tianjie Xuaced5d92016-10-12 10:55:04 -07001729 return StringValue("t");
Tianjie Xu57bed6d2015-12-15 11:47:30 -08001730}
1731
1732
Tianjie Xuc4447322017-03-06 14:44:59 -08001733Value* BlockImageRecoverFn(const char* name, State* state,
1734 const std::vector<std::unique_ptr<Expr>>& argv) {
1735 if (argv.size() != 2) {
1736 ErrorAbort(state, kArgsParsingFailure, "block_image_recover expects 2 arguments, got %zu",
1737 argv.size());
1738 return StringValue("");
1739 }
1740
Tianjie Xu5fe280a2016-10-17 18:15:20 -07001741 std::vector<std::unique_ptr<Value>> args;
Tianjie Xuc4447322017-03-06 14:44:59 -08001742 if (!ReadValueArgs(state, argv, &args)) {
Tianjie Xu5fe280a2016-10-17 18:15:20 -07001743 return nullptr;
Sami Tolvanen0a7b4732015-06-25 10:25:36 +01001744 }
1745
Tianjie Xu5fe280a2016-10-17 18:15:20 -07001746 const Value* filename = args[0].get();
1747 const Value* ranges = args[1].get();
Sami Tolvanen0a7b4732015-06-25 10:25:36 +01001748
1749 if (filename->type != VAL_STRING) {
Tianjie Xu16255832016-04-30 11:49:59 -07001750 ErrorAbort(state, kArgsParsingFailure, "filename argument to %s must be string", name);
Tianjie Xuaced5d92016-10-12 10:55:04 -07001751 return StringValue("");
Sami Tolvanen0a7b4732015-06-25 10:25:36 +01001752 }
1753 if (ranges->type != VAL_STRING) {
Tianjie Xu16255832016-04-30 11:49:59 -07001754 ErrorAbort(state, kArgsParsingFailure, "ranges argument to %s must be string", name);
Tianjie Xuaced5d92016-10-12 10:55:04 -07001755 return StringValue("");
Sami Tolvanen0a7b4732015-06-25 10:25:36 +01001756 }
1757
Tianjie Xu3b010bc2015-12-09 15:29:45 -08001758 // Output notice to log when recover is attempted
Tao Bao039f2da2016-11-22 16:29:50 -08001759 LOG(INFO) << filename->data << " image corrupted, attempting to recover...";
Tianjie Xu3b010bc2015-12-09 15:29:45 -08001760
Sami Tolvanen0a7b4732015-06-25 10:25:36 +01001761 // When opened with O_RDWR, libfec rewrites corrupted blocks when they are read
Tao Baod2aecd42017-03-23 14:43:44 -07001762 fec::io fh(filename->data, O_RDWR);
Sami Tolvanen0a7b4732015-06-25 10:25:36 +01001763
1764 if (!fh) {
Tianjie Xuaced5d92016-10-12 10:55:04 -07001765 ErrorAbort(state, kLibfecFailure, "fec_open \"%s\" failed: %s", filename->data.c_str(),
Tianjie Xu16255832016-04-30 11:49:59 -07001766 strerror(errno));
Tianjie Xuaced5d92016-10-12 10:55:04 -07001767 return StringValue("");
Sami Tolvanen0a7b4732015-06-25 10:25:36 +01001768 }
1769
1770 if (!fh.has_ecc() || !fh.has_verity()) {
Tianjie Xu16255832016-04-30 11:49:59 -07001771 ErrorAbort(state, kLibfecFailure, "unable to use metadata to correct errors");
Tianjie Xuaced5d92016-10-12 10:55:04 -07001772 return StringValue("");
Sami Tolvanen0a7b4732015-06-25 10:25:36 +01001773 }
1774
1775 fec_status status;
1776
1777 if (!fh.get_status(status)) {
Tianjie Xu16255832016-04-30 11:49:59 -07001778 ErrorAbort(state, kLibfecFailure, "failed to read FEC status");
Tianjie Xuaced5d92016-10-12 10:55:04 -07001779 return StringValue("");
Sami Tolvanen0a7b4732015-06-25 10:25:36 +01001780 }
1781
Tao Bao8f237572017-03-26 13:36:49 -07001782 RangeSet rs = RangeSet::Parse(ranges->data);
Sami Tolvanen0a7b4732015-06-25 10:25:36 +01001783
1784 uint8_t buffer[BLOCKSIZE];
1785
1786 for (size_t i = 0; i < rs.count; ++i) {
1787 for (size_t j = rs.pos[i * 2]; j < rs.pos[i * 2 + 1]; ++j) {
1788 // Stay within the data area, libfec validates and corrects metadata
1789 if (status.data_size <= (uint64_t)j * BLOCKSIZE) {
1790 continue;
1791 }
1792
1793 if (fh.pread(buffer, BLOCKSIZE, (off64_t)j * BLOCKSIZE) != BLOCKSIZE) {
Tianjie Xu16255832016-04-30 11:49:59 -07001794 ErrorAbort(state, kLibfecFailure, "failed to recover %s (block %zu): %s",
Tianjie Xuaced5d92016-10-12 10:55:04 -07001795 filename->data.c_str(), j, strerror(errno));
1796 return StringValue("");
Sami Tolvanen0a7b4732015-06-25 10:25:36 +01001797 }
1798
1799 // If we want to be able to recover from a situation where rewriting a corrected
1800 // block doesn't guarantee the same data will be returned when re-read later, we
1801 // can save a copy of corrected blocks to /cache. Note:
1802 //
1803 // 1. Maximum space required from /cache is the same as the maximum number of
1804 // corrupted blocks we can correct. For RS(255, 253) and a 2 GiB partition,
1805 // this would be ~16 MiB, for example.
1806 //
1807 // 2. To find out if this block was corrupted, call fec_get_status after each
1808 // read and check if the errors field value has increased.
1809 }
1810 }
Tao Bao039f2da2016-11-22 16:29:50 -08001811 LOG(INFO) << "..." << filename->data << " image recovered successfully.";
Tianjie Xuaced5d92016-10-12 10:55:04 -07001812 return StringValue("t");
Sami Tolvanen0a7b4732015-06-25 10:25:36 +01001813}
1814
Doug Zongkerbc7ffed2014-08-15 14:31:52 -07001815void RegisterBlockImageFunctions() {
Sami Tolvanen90221202014-12-09 16:39:47 +00001816 RegisterFunction("block_image_verify", BlockImageVerifyFn);
Doug Zongkerbc7ffed2014-08-15 14:31:52 -07001817 RegisterFunction("block_image_update", BlockImageUpdateFn);
Sami Tolvanen0a7b4732015-06-25 10:25:36 +01001818 RegisterFunction("block_image_recover", BlockImageRecoverFn);
Tianjie Xu57bed6d2015-12-15 11:47:30 -08001819 RegisterFunction("check_first_block", CheckFirstBlockFn);
Doug Zongkerbc7ffed2014-08-15 14:31:52 -07001820 RegisterFunction("range_sha1", RangeSha1Fn);
1821}