blob: 28855e6a279c80bfad38089dc5c5205dc31ee6ae [file] [log] [blame]
Daniel Rosenberg65f99c92018-08-28 01:58:49 -07001/*
2 * Copyright (C) 2018 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#define LOG_TAG "Checkpoint"
18#include "Checkpoint.h"
19
Paul Lawrence1abb2fe2018-09-21 10:49:57 -070020#include <fstream>
Daniel Rosenberg65f99c92018-08-28 01:58:49 -070021#include <list>
Paul Lawrence20400892018-10-03 14:14:52 -070022#include <memory>
Daniel Rosenberg65f99c92018-08-28 01:58:49 -070023#include <string>
Paul Lawrence1abb2fe2018-09-21 10:49:57 -070024#include <vector>
25
26#include <android-base/file.h>
27#include <android-base/logging.h>
28#include <android-base/parseint.h>
Daniel Rosenbergffa1bb02018-12-14 00:20:03 -080029#include <android-base/properties.h>
Paul Lawrence1abb2fe2018-09-21 10:49:57 -070030#include <android-base/unique_fd.h>
Daniel Rosenbergd3992492018-10-02 17:40:44 -070031#include <android/hardware/boot/1.0/IBootControl.h>
Paul Lawrence1abb2fe2018-09-21 10:49:57 -070032#include <cutils/android_reboot.h>
33#include <fcntl.h>
34#include <fs_mgr.h>
35#include <linux/fs.h>
36#include <mntent.h>
37#include <sys/mount.h>
38#include <sys/stat.h>
Daniel Rosenberg65f99c92018-08-28 01:58:49 -070039
Daniel Rosenbergffa1bb02018-12-14 00:20:03 -080040using android::base::SetProperty;
Daniel Rosenberg73680ec2018-10-10 18:52:04 -070041using android::binder::Status;
Daniel Rosenbergd3992492018-10-02 17:40:44 -070042using android::hardware::hidl_string;
43using android::hardware::boot::V1_0::BoolResult;
44using android::hardware::boot::V1_0::IBootControl;
45using android::hardware::boot::V1_0::Slot;
46
Daniel Rosenberg65f99c92018-08-28 01:58:49 -070047namespace android {
48namespace vold {
49
Paul Lawrence1abb2fe2018-09-21 10:49:57 -070050namespace {
51const std::string kMetadataCPFile = "/metadata/vold/checkpoint";
52
53bool setBowState(std::string const& block_device, std::string const& state) {
54 if (block_device.substr(0, 5) != "/dev/") {
55 LOG(ERROR) << "Expected block device, got " << block_device;
56 return false;
57 }
58
59 std::string state_filename = std::string("/sys/") + block_device.substr(5) + "/bow/state";
60 if (!android::base::WriteStringToFile(state, state_filename)) {
61 PLOG(ERROR) << "Failed to write to file " << state_filename;
62 return false;
63 }
64
65 return true;
66}
67
68} // namespace
Daniel Rosenberg65f99c92018-08-28 01:58:49 -070069
Daniel Rosenberg73680ec2018-10-10 18:52:04 -070070Status cp_startCheckpoint(int retry) {
71 if (retry < -1) return Status::fromExceptionCode(EINVAL, "Retry count must be more than -1");
Daniel Rosenberg80d1ca52018-10-09 19:26:57 -070072 std::string content = std::to_string(retry + 1);
Daniel Rosenbergd3992492018-10-02 17:40:44 -070073 if (retry == -1) {
74 sp<IBootControl> module = IBootControl::getService();
75 if (module) {
76 std::string suffix;
77 auto cb = [&suffix](hidl_string s) { suffix = s; };
78 if (module->getSuffix(module->getCurrentSlot(), cb).isOk()) content += " " + suffix;
79 }
80 }
Daniel Rosenberg73680ec2018-10-10 18:52:04 -070081 if (!android::base::WriteStringToFile(content, kMetadataCPFile))
82 return Status::fromExceptionCode(errno, "Failed to write checkpoint file");
83 return Status::ok();
Daniel Rosenberg65f99c92018-08-28 01:58:49 -070084}
85
Daniel Rosenbergffa1bb02018-12-14 00:20:03 -080086namespace {
87
88bool isCheckpointing = false;
89}
90
Daniel Rosenberg73680ec2018-10-10 18:52:04 -070091Status cp_commitChanges() {
Daniel Rosenbergffa1bb02018-12-14 00:20:03 -080092 if (!isCheckpointing) {
93 return Status::ok();
94 }
Paul Lawrence1abb2fe2018-09-21 10:49:57 -070095 // Must take action for list of mounted checkpointed things here
96 // To do this, we walk the list of mounted file systems.
97 // But we also need to get the matching fstab entries to see
98 // the original flags
Daniel Rosenberg73680ec2018-10-10 18:52:04 -070099 std::string err_str;
Paul Lawrence20400892018-10-03 14:14:52 -0700100 auto fstab_default = std::unique_ptr<fstab, decltype(&fs_mgr_free_fstab)>{
101 fs_mgr_read_fstab_default(), fs_mgr_free_fstab};
Daniel Rosenberg73680ec2018-10-10 18:52:04 -0700102 if (!fstab_default) return Status::fromExceptionCode(EINVAL, "Failed to get fstab");
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700103
Paul Lawrence20400892018-10-03 14:14:52 -0700104 auto mounts = std::unique_ptr<fstab, decltype(&fs_mgr_free_fstab)>{
105 fs_mgr_read_fstab("/proc/mounts"), fs_mgr_free_fstab};
Daniel Rosenberg73680ec2018-10-10 18:52:04 -0700106 if (!mounts) return Status::fromExceptionCode(EINVAL, "Failed to get /proc/mounts");
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700107
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700108 // Walk mounted file systems
109 for (int i = 0; i < mounts->num_entries; ++i) {
110 const fstab_rec* mount_rec = &mounts->recs[i];
Paul Lawrence20400892018-10-03 14:14:52 -0700111 const fstab_rec* fstab_rec =
112 fs_mgr_get_entry_for_mount_point(fstab_default.get(), mount_rec->mount_point);
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700113 if (!fstab_rec) continue;
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700114
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700115 if (fs_mgr_is_checkpoint_fs(fstab_rec)) {
116 if (!strcmp(fstab_rec->fs_type, "f2fs")) {
Daniel Rosenberg4b86df12018-11-08 22:18:37 -0800117 if (mount(mount_rec->blk_device, mount_rec->mount_point, "none",
118 MS_REMOUNT | fstab_rec->flags, "checkpoint=enable")) {
119 return Status::fromExceptionCode(EINVAL, "Failed to remount");
120 }
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700121 }
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700122 } else if (fs_mgr_is_checkpoint_blk(fstab_rec)) {
Daniel Rosenberg4b86df12018-11-08 22:18:37 -0800123 if (!setBowState(mount_rec->blk_device, "2"))
124 return Status::fromExceptionCode(EINVAL, "Failed to set bow state");
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700125 }
126 }
Daniel Rosenbergffa1bb02018-12-14 00:20:03 -0800127 SetProperty("vold.checkpoint_committed", "1");
128 isCheckpointing = false;
Daniel Rosenberg4b86df12018-11-08 22:18:37 -0800129 if (!android::base::RemoveFileIfExists(kMetadataCPFile, &err_str))
Daniel Rosenberg73680ec2018-10-10 18:52:04 -0700130 return Status::fromExceptionCode(errno, err_str.c_str());
131 return Status::ok();
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700132}
133
Daniel Rosenberg73680ec2018-10-10 18:52:04 -0700134Status cp_abortChanges() {
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700135 android_reboot(ANDROID_RB_RESTART2, 0, nullptr);
Daniel Rosenberg73680ec2018-10-10 18:52:04 -0700136 return Status::ok();
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700137}
138
Daniel Rosenbergd3992492018-10-02 17:40:44 -0700139bool cp_needsRollback() {
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700140 std::string content;
141 bool ret;
142
143 ret = android::base::ReadFileToString(kMetadataCPFile, &content);
Daniel Rosenbergd3992492018-10-02 17:40:44 -0700144 if (ret) {
145 if (content == "0") return true;
146 if (content.substr(0, 3) == "-1 ") {
147 std::string oldSuffix = content.substr(3);
148 sp<IBootControl> module = IBootControl::getService();
149 std::string newSuffix;
150
151 if (module) {
152 auto cb = [&newSuffix](hidl_string s) { newSuffix = s; };
153 module->getSuffix(module->getCurrentSlot(), cb);
154 if (oldSuffix == newSuffix) return true;
155 }
156 }
157 }
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700158 return false;
159}
160
Daniel Rosenberg80d1ca52018-10-09 19:26:57 -0700161bool cp_needsCheckpoint() {
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700162 bool ret;
163 std::string content;
Daniel Rosenbergd3992492018-10-02 17:40:44 -0700164 sp<IBootControl> module = IBootControl::getService();
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700165
Daniel Rosenbergffa1bb02018-12-14 00:20:03 -0800166 if (module && module->isSlotMarkedSuccessful(module->getCurrentSlot()) == BoolResult::FALSE) {
167 isCheckpointing = true;
Daniel Rosenbergd3992492018-10-02 17:40:44 -0700168 return true;
Daniel Rosenbergffa1bb02018-12-14 00:20:03 -0800169 }
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700170 ret = android::base::ReadFileToString(kMetadataCPFile, &content);
Daniel Rosenbergffa1bb02018-12-14 00:20:03 -0800171 if (ret) {
172 ret = content != "0";
173 isCheckpointing = ret;
174 return ret;
175 }
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700176 return false;
177}
178
Daniel Rosenberg73680ec2018-10-10 18:52:04 -0700179Status cp_prepareCheckpoint() {
Paul Lawrence20400892018-10-03 14:14:52 -0700180 auto fstab_default = std::unique_ptr<fstab, decltype(&fs_mgr_free_fstab)>{
181 fs_mgr_read_fstab_default(), fs_mgr_free_fstab};
Daniel Rosenberg73680ec2018-10-10 18:52:04 -0700182 if (!fstab_default) return Status::fromExceptionCode(EINVAL, "Failed to get fstab");
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700183
Paul Lawrence20400892018-10-03 14:14:52 -0700184 auto mounts = std::unique_ptr<fstab, decltype(&fs_mgr_free_fstab)>{
185 fs_mgr_read_fstab("/proc/mounts"), fs_mgr_free_fstab};
Daniel Rosenberg73680ec2018-10-10 18:52:04 -0700186 if (!mounts) return Status::fromExceptionCode(EINVAL, "Failed to get /proc/mounts");
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700187
188 for (int i = 0; i < mounts->num_entries; ++i) {
189 const fstab_rec* mount_rec = &mounts->recs[i];
Paul Lawrence20400892018-10-03 14:14:52 -0700190 const fstab_rec* fstab_rec =
191 fs_mgr_get_entry_for_mount_point(fstab_default.get(), mount_rec->mount_point);
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700192 if (!fstab_rec) continue;
193
194 if (fs_mgr_is_checkpoint_blk(fstab_rec)) {
195 android::base::unique_fd fd(
196 TEMP_FAILURE_RETRY(open(mount_rec->mount_point, O_RDONLY | O_CLOEXEC)));
197 if (!fd) {
198 PLOG(ERROR) << "Failed to open mount point" << mount_rec->mount_point;
199 continue;
200 }
201
202 struct fstrim_range range = {};
203 range.len = ULLONG_MAX;
204 if (ioctl(fd, FITRIM, &range)) {
205 PLOG(ERROR) << "Failed to trim " << mount_rec->mount_point;
206 continue;
207 }
208
209 setBowState(mount_rec->blk_device, "1");
210 }
211 }
Daniel Rosenberg73680ec2018-10-10 18:52:04 -0700212 return Status::ok();
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700213}
214
215namespace {
216const int kBlockSize = 4096;
217const int kSectorSize = 512;
218
219typedef uint64_t sector_t;
220
221struct log_entry {
222 sector_t source;
223 sector_t dest;
224 uint32_t size;
225 uint32_t checksum;
226} __attribute__((packed));
227
228struct log_sector {
229 uint32_t magic;
230 uint32_t count;
231 uint32_t sequence;
232 struct log_entry entries[];
233} __attribute__((packed));
234
235// MAGIC is BOW in ascii
236const int kMagic = 0x00574f42;
237
238void crc32(const void* data, size_t n_bytes, uint32_t* crc) {
239 static uint32_t table[0x100] = {
240 0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, 0x706AF48F, 0xE963A535,
241 0x9E6495A3, 0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988, 0x09B64C2B, 0x7EB17CBD,
242 0xE7B82D07, 0x90BF1D91, 0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE, 0x1ADAD47D,
243 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7, 0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC,
244 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5, 0x3B6E20C8, 0x4C69105E, 0xD56041E4,
245 0xA2677172, 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B, 0x35B5A8FA, 0x42B2986C,
246 0xDBBBC9D6, 0xACBCF940, 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59, 0x26D930AC,
247 0x51DE003A, 0xC8D75180, 0xBFD06116, 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F,
248 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924, 0x2F6F7C87, 0x58684C11, 0xC1611DAB,
249 0xB6662D3D,
250
251 0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F, 0x9FBFE4A5,
252 0xE8B8D433, 0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, 0x7F6A0DBB, 0x086D3D2D,
253 0x91646C97, 0xE6635C01, 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E, 0x6C0695ED,
254 0x1B01A57B, 0x8208F4C1, 0xF50FC457, 0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C,
255 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65, 0x4DB26158, 0x3AB551CE, 0xA3BC0074,
256 0xD4BB30E2, 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB, 0x4369E96A, 0x346ED9FC,
257 0xAD678846, 0xDA60B8D0, 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9, 0x5005713C,
258 0x270241AA, 0xBE0B1010, 0xC90C2086, 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F,
259 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17, 0x2EB40D81, 0xB7BD5C3B,
260 0xC0BA6CAD,
261
262 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A, 0xEAD54739, 0x9DD277AF, 0x04DB2615,
263 0x73DC1683, 0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8, 0xE40ECF0B, 0x9309FF9D,
264 0x0A00AE27, 0x7D079EB1, 0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE, 0xF762575D,
265 0x806567CB, 0x196C3671, 0x6E6B06E7, 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC,
266 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5, 0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4,
267 0x4FDFF252, 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B, 0xD80D2BDA, 0xAF0A1B4C,
268 0x36034AF6, 0x41047A60, 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79, 0xCB61B38C,
269 0xBC66831A, 0x256FD2A0, 0x5268E236, 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F,
270 0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B,
271 0x5BDEAE1D,
272
273 0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, 0x9C0906A9, 0xEB0E363F, 0x72076785,
274 0x05005713, 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38, 0x92D28E9B, 0xE5D5BE0D,
275 0x7CDCEFB7, 0x0BDBDF21, 0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E, 0x81BE16CD,
276 0xF6B9265B, 0x6FB077E1, 0x18B74777, 0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C,
277 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45, 0xA00AE278, 0xD70DD2EE, 0x4E048354,
278 0x3903B3C2, 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB, 0xAED16A4A, 0xD9D65ADC,
279 0x40DF0B66, 0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9, 0xBDBDF21C,
280 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF,
281 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94, 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B,
282 0x2D02EF8D};
283
284 for (size_t i = 0; i < n_bytes; ++i) {
285 *crc ^= ((uint8_t*)data)[i];
286 *crc = table[(uint8_t)*crc] ^ *crc >> 8;
287 }
288}
289
290} // namespace
291
Daniel Rosenberg73680ec2018-10-10 18:52:04 -0700292Status cp_restoreCheckpoint(const std::string& blockDevice) {
293 LOG(INFO) << "Restoring checkpoint on " << blockDevice;
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700294 std::fstream device(blockDevice, std::ios::binary | std::ios::in | std::ios::out);
295 if (!device) {
296 PLOG(ERROR) << "Cannot open " << blockDevice;
Daniel Rosenberg73680ec2018-10-10 18:52:04 -0700297 return Status::fromExceptionCode(errno, ("Cannot open " + blockDevice).c_str());
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700298 }
Greg Kaiser41066642018-12-18 12:22:29 -0800299 alignas(alignof(log_sector)) char ls_buffer[kBlockSize];
300 device.read(ls_buffer, kBlockSize);
301 log_sector& ls = *reinterpret_cast<log_sector*>(ls_buffer);
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700302 if (ls.magic != kMagic) {
303 LOG(ERROR) << "No magic";
Daniel Rosenberg73680ec2018-10-10 18:52:04 -0700304 return Status::fromExceptionCode(EINVAL, "No magic");
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700305 }
306
307 LOG(INFO) << "Restoring " << ls.sequence << " log sectors";
308
309 for (int sequence = ls.sequence; sequence >= 0; sequence--) {
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700310 device.seekg(0);
Greg Kaiser41066642018-12-18 12:22:29 -0800311 device.read(ls_buffer, kBlockSize);
312 ls = *reinterpret_cast<log_sector*>(ls_buffer);
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700313 if (ls.magic != kMagic) {
314 LOG(ERROR) << "No magic!";
Daniel Rosenberg73680ec2018-10-10 18:52:04 -0700315 return Status::fromExceptionCode(EINVAL, "No magic");
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700316 }
317
318 if ((int)ls.sequence != sequence) {
319 LOG(ERROR) << "Expecting log sector " << sequence << " but got " << ls.sequence;
Daniel Rosenberg73680ec2018-10-10 18:52:04 -0700320 return Status::fromExceptionCode(
321 EINVAL, ("Expecting log sector " + std::to_string(sequence) + " but got " +
322 std::to_string(ls.sequence))
323 .c_str());
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700324 }
325
326 LOG(INFO) << "Restoring from log sector " << ls.sequence;
327
328 for (log_entry* le = &ls.entries[ls.count - 1]; le >= ls.entries; --le) {
329 LOG(INFO) << "Restoring " << le->size << " bytes from sector " << le->dest << " to "
330 << le->source << " with checksum " << std::hex << le->checksum;
331 std::vector<char> buffer(le->size);
332 device.seekg(le->dest * kSectorSize);
333 device.read(&buffer[0], le->size);
334
335 uint32_t checksum = le->source / (kBlockSize / kSectorSize);
336 for (size_t i = 0; i < le->size; i += kBlockSize) {
337 crc32(&buffer[i], kBlockSize, &checksum);
338 }
339
340 if (le->checksum && checksum != le->checksum) {
341 LOG(ERROR) << "Checksums don't match " << std::hex << checksum;
Daniel Rosenberg73680ec2018-10-10 18:52:04 -0700342 return Status::fromExceptionCode(EINVAL, "Checksums don't match");
Paul Lawrence1abb2fe2018-09-21 10:49:57 -0700343 }
344
345 device.seekg(le->source * kSectorSize);
346 device.write(&buffer[0], le->size);
347 }
348 }
349
Daniel Rosenberg73680ec2018-10-10 18:52:04 -0700350 return Status::ok();
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700351}
352
Daniel Rosenberg73680ec2018-10-10 18:52:04 -0700353Status cp_markBootAttempt() {
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700354 std::string oldContent, newContent;
355 int retry = 0;
Daniel Rosenberg73680ec2018-10-10 18:52:04 -0700356 struct stat st;
357 int result = stat(kMetadataCPFile.c_str(), &st);
358
359 // If the file doesn't exist, we aren't managing a checkpoint retry counter
360 if (result != 0) return Status::ok();
361 if (!android::base::ReadFileToString(kMetadataCPFile, &oldContent)) {
362 PLOG(ERROR) << "Failed to read checkpoint file";
363 return Status::fromExceptionCode(errno, "Failed to read checkpoint file");
364 }
Daniel Rosenbergd3992492018-10-02 17:40:44 -0700365 std::string retryContent = oldContent.substr(0, oldContent.find_first_of(" "));
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700366
Daniel Rosenberg73680ec2018-10-10 18:52:04 -0700367 if (!android::base::ParseInt(retryContent, &retry))
368 return Status::fromExceptionCode(EINVAL, "Could not parse retry count");
369 if (retry > 0) {
370 retry--;
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700371
Daniel Rosenberg73680ec2018-10-10 18:52:04 -0700372 newContent = std::to_string(retry);
373 if (!android::base::WriteStringToFile(newContent, kMetadataCPFile))
374 return Status::fromExceptionCode(errno, "Could not write checkpoint file");
375 }
376 return Status::ok();
Daniel Rosenberg65f99c92018-08-28 01:58:49 -0700377}
378
379} // namespace vold
380} // namespace android