blob: 7db79048af062c2a3ddf481001dfec74643bf407 [file] [log] [blame]
xunchang388d2532019-04-12 16:22:15 -07001/*
2 * Copyright (C) 2019 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 "install/wipe_data.h"
18
19#include <dirent.h>
20#include <errno.h>
21#include <stdio.h>
22#include <string.h>
23#include <sys/stat.h>
24
25#include <functional>
26#include <memory>
27#include <vector>
28
29#include <android-base/file.h>
30#include <android-base/logging.h>
31#include <android-base/stringprintf.h>
32
33#include "otautil/dirutil.h"
34#include "otautil/logging.h"
35#include "otautil/roots.h"
36#include "recovery_ui/ui.h"
37
38constexpr const char* CACHE_ROOT = "/cache";
39constexpr const char* DATA_ROOT = "/data";
40constexpr const char* METADATA_ROOT = "/metadata";
41
42constexpr const char* CACHE_LOG_DIR = "/cache/recovery";
43
44static struct selabel_handle* sehandle;
45
46void SetWipeDataSehandle(selabel_handle* handle) {
47 sehandle = handle;
48}
49
50struct saved_log_file {
51 std::string name;
52 struct stat sb;
53 std::string data;
54};
55
56static bool EraseVolume(const char* volume, RecoveryUI* ui, bool convert_fbe) {
57 bool is_cache = (strcmp(volume, CACHE_ROOT) == 0);
58 bool is_data = (strcmp(volume, DATA_ROOT) == 0);
59
60 ui->SetBackground(RecoveryUI::ERASING);
61 ui->SetProgressType(RecoveryUI::INDETERMINATE);
62
63 std::vector<saved_log_file> log_files;
64
65 if (is_cache) {
66 // If we're reformatting /cache, we load any past logs
67 // (i.e. "/cache/recovery/last_*") and the current log
68 // ("/cache/recovery/log") into memory, so we can restore them after
69 // the reformat.
70
71 ensure_path_mounted(volume);
72
73 struct dirent* de;
74 std::unique_ptr<DIR, decltype(&closedir)> d(opendir(CACHE_LOG_DIR), closedir);
75 if (d) {
76 while ((de = readdir(d.get())) != nullptr) {
77 if (strncmp(de->d_name, "last_", 5) == 0 || strcmp(de->d_name, "log") == 0) {
78 std::string path = android::base::StringPrintf("%s/%s", CACHE_LOG_DIR, de->d_name);
79
80 struct stat sb;
81 if (stat(path.c_str(), &sb) == 0) {
82 // truncate files to 512kb
83 if (sb.st_size > (1 << 19)) {
84 sb.st_size = 1 << 19;
85 }
86
87 std::string data(sb.st_size, '\0');
88 FILE* f = fopen(path.c_str(), "rbe");
89 fread(&data[0], 1, data.size(), f);
90 fclose(f);
91
92 log_files.emplace_back(saved_log_file{ path, sb, data });
93 }
94 }
95 }
96 } else {
97 if (errno != ENOENT) {
98 PLOG(ERROR) << "Failed to opendir " << CACHE_LOG_DIR;
99 }
100 }
101 }
102
103 ui->Print("Formatting %s...\n", volume);
104
105 ensure_path_unmounted(volume);
106
107 int result;
108 if (is_data && convert_fbe) {
109 constexpr const char* CONVERT_FBE_DIR = "/tmp/convert_fbe";
110 constexpr const char* CONVERT_FBE_FILE = "/tmp/convert_fbe/convert_fbe";
111 // Create convert_fbe breadcrumb file to signal init to convert to file based encryption, not
112 // full disk encryption.
113 if (mkdir(CONVERT_FBE_DIR, 0700) != 0) {
114 PLOG(ERROR) << "Failed to mkdir " << CONVERT_FBE_DIR;
115 return false;
116 }
117 FILE* f = fopen(CONVERT_FBE_FILE, "wbe");
118 if (!f) {
119 PLOG(ERROR) << "Failed to convert to file encryption";
120 return false;
121 }
122 fclose(f);
123 result = format_volume(volume, CONVERT_FBE_DIR);
124 remove(CONVERT_FBE_FILE);
125 rmdir(CONVERT_FBE_DIR);
126 } else {
127 result = format_volume(volume);
128 }
129
130 if (is_cache) {
131 // Re-create the log dir and write back the log entries.
132 if (ensure_path_mounted(CACHE_LOG_DIR) == 0 &&
133 mkdir_recursively(CACHE_LOG_DIR, 0777, false, sehandle) == 0) {
134 for (const auto& log : log_files) {
135 if (!android::base::WriteStringToFile(log.data, log.name, log.sb.st_mode, log.sb.st_uid,
136 log.sb.st_gid)) {
137 PLOG(ERROR) << "Failed to write to " << log.name;
138 }
139 }
140 } else {
141 PLOG(ERROR) << "Failed to mount / create " << CACHE_LOG_DIR;
142 }
143
144 // Any part of the log we'd copied to cache is now gone.
145 // Reset the pointer so we copy from the beginning of the temp
146 // log.
147 reset_tmplog_offset();
148 copy_logs(true /* save_current_log */, true /* has_cache */, sehandle);
149 }
150
151 return (result == 0);
152}
153
154bool WipeCache(RecoveryUI* ui, const std::function<bool()>& confirm_func) {
155 bool has_cache = volume_for_mount_point("/cache") != nullptr;
156 if (!has_cache) {
157 ui->Print("No /cache partition found.\n");
158 return false;
159 }
160
161 if (confirm_func && !confirm_func()) {
162 return false;
163 }
164
165 ui->Print("\n-- Wiping cache...\n");
166 bool success = EraseVolume("/cache", ui, false);
167 ui->Print("Cache wipe %s.\n", success ? "complete" : "failed");
168 return success;
169}
170
171bool WipeData(Device* device, bool convert_fbe) {
172 RecoveryUI* ui = device->GetUI();
173 ui->Print("\n-- Wiping data...\n");
174 bool success = device->PreWipeData();
175 if (success) {
176 success &= EraseVolume(DATA_ROOT, ui, convert_fbe);
177 bool has_cache = volume_for_mount_point("/cache") != nullptr;
178 if (has_cache) {
179 success &= EraseVolume(CACHE_ROOT, ui, false);
180 }
181 if (volume_for_mount_point(METADATA_ROOT) != nullptr) {
182 success &= EraseVolume(METADATA_ROOT, ui, false);
183 }
184 }
185 if (success) {
186 success &= device->PostWipeData();
187 }
188 ui->Print("Data wipe %s.\n", success ? "complete" : "failed");
189 return success;
190}