blob: 9fad7ff44dc781ae227dce07a6b099b30bbe153e [file] [log] [blame]
Yabin Cuia58a6db2016-04-06 15:52:18 -07001/*
2 * Copyright (C) 2016 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
Yabin Cui2f272c02016-06-24 18:22:02 -070017#include <bootloader_message/bootloader_message.h>
18
Yabin Cuia58a6db2016-04-06 15:52:18 -070019#include <errno.h>
20#include <fcntl.h>
21#include <string.h>
Yabin Cuia58a6db2016-04-06 15:52:18 -070022
23#include <string>
Tao Bao35e0f6d2019-05-16 14:42:42 -070024#include <string_view>
Yabin Cuia58a6db2016-04-06 15:52:18 -070025#include <vector>
26
27#include <android-base/file.h>
28#include <android-base/stringprintf.h>
29#include <android-base/unique_fd.h>
Tom Cherry772c93c2018-12-04 09:37:39 -080030#include <fstab/fstab.h>
Yabin Cui8b309f62016-06-24 18:22:02 -070031
Tom Cherry72a114a2019-01-30 15:59:53 -080032using android::fs_mgr::Fstab;
33using android::fs_mgr::ReadDefaultFstab;
34
Tao Bao35e0f6d2019-05-16 14:42:42 -070035static std::string g_misc_device_for_test;
36
37// Exposed for test purpose.
38void SetMiscBlockDeviceForTest(std::string_view misc_device) {
39 g_misc_device_for_test = misc_device;
40}
Yabin Cuia58a6db2016-04-06 15:52:18 -070041
Ethan Yonker8373cfe2017-09-08 06:50:54 -050042#ifdef USE_OLD_BOOTLOADER_MESSAGE
43#include <sys/system_properties.h>
Ethan Yonkerb5236502016-11-19 22:24:59 -060044
Yabin Cuia58a6db2016-04-06 15:52:18 -070045static struct fstab* read_fstab(std::string* err) {
46 // The fstab path is always "/fstab.${ro.hardware}".
47 std::string fstab_path = "/fstab.";
48 char value[PROP_VALUE_MAX];
49 if (__system_property_get("ro.hardware", value) == 0) {
50 *err = "failed to get ro.hardware";
51 return nullptr;
52 }
53 fstab_path += value;
54 struct fstab* fstab = fs_mgr_read_fstab(fstab_path.c_str());
55 if (fstab == nullptr) {
56 *err = "failed to read " + fstab_path;
57 }
58 return fstab;
59}
Ethan Yonkerb5236502016-11-19 22:24:59 -060060#endif
Yabin Cuia58a6db2016-04-06 15:52:18 -070061
62static std::string get_misc_blk_device(std::string* err) {
bigbiff26d5d5f2020-03-23 09:56:16 -040063<<<<<<< HEAD
Ethan Yonker8373cfe2017-09-08 06:50:54 -050064#ifdef USE_OLD_BOOTLOADER_MESSAGE
Yabin Cuia58a6db2016-04-06 15:52:18 -070065 struct fstab* fstab = read_fstab(err);
Ethan Yonker8373cfe2017-09-08 06:50:54 -050066#else
Bowgo Tsai4508f232017-03-27 17:47:21 +000067 std::unique_ptr<fstab, decltype(&fs_mgr_free_fstab)> fstab(fs_mgr_read_fstab_default(),
68 fs_mgr_free_fstab);
Ethan Yonker8373cfe2017-09-08 06:50:54 -050069#endif
Bowgo Tsaid13b6cf2017-03-10 16:00:40 +080070 if (!fstab) {
71 *err = "failed to read default fstab";
Yabin Cuia58a6db2016-04-06 15:52:18 -070072 return "";
73 }
Ethan Yonker8373cfe2017-09-08 06:50:54 -050074#ifdef USE_OLD_BOOTLOADER_MESSAGE
Yabin Cuia58a6db2016-04-06 15:52:18 -070075 fstab_rec* record = fs_mgr_get_entry_for_mount_point(fstab, "/misc");
Ethan Yonker8373cfe2017-09-08 06:50:54 -050076#else
Bowgo Tsaid13b6cf2017-03-10 16:00:40 +080077 fstab_rec* record = fs_mgr_get_entry_for_mount_point(fstab.get(), "/misc");
Ethan Yonker8373cfe2017-09-08 06:50:54 -050078#endif
Yabin Cuia58a6db2016-04-06 15:52:18 -070079 if (record == nullptr) {
80 *err = "failed to find /misc partition";
81 return "";
bigbiff26d5d5f2020-03-23 09:56:16 -040082=======
Tao Bao35e0f6d2019-05-16 14:42:42 -070083 if (!g_misc_device_for_test.empty()) {
84 return g_misc_device_for_test;
Yabin Cuia58a6db2016-04-06 15:52:18 -070085 }
Tom Cherry772c93c2018-12-04 09:37:39 -080086 Fstab fstab;
87 if (!ReadDefaultFstab(&fstab)) {
Yabin Cui8b309f62016-06-24 18:22:02 -070088 *err = "failed to read default fstab";
89 return "";
90 }
Tom Cherry772c93c2018-12-04 09:37:39 -080091 for (const auto& entry : fstab) {
92 if (entry.mount_point == "/misc") {
93 return entry.blk_device;
94 }
bigbiff26d5d5f2020-03-23 09:56:16 -040095>>>>>>> android-10.0.0_r25
Yabin Cui8b309f62016-06-24 18:22:02 -070096 }
Tom Cherry772c93c2018-12-04 09:37:39 -080097
98 *err = "failed to find /misc partition";
99 return "";
Yabin Cuia58a6db2016-04-06 15:52:18 -0700100}
101
Yabin Cui2f272c02016-06-24 18:22:02 -0700102// In recovery mode, recovery can get started and try to access the misc
103// device before the kernel has actually created it.
104static bool wait_for_device(const std::string& blk_device, std::string* err) {
105 int tries = 0;
106 int ret;
107 err->clear();
108 do {
109 ++tries;
110 struct stat buf;
111 ret = stat(blk_device.c_str(), &buf);
112 if (ret == -1) {
113 *err += android::base::StringPrintf("failed to stat %s try %d: %s\n",
114 blk_device.c_str(), tries, strerror(errno));
115 sleep(1);
116 }
117 } while (ret && tries < 10);
118
119 if (ret) {
120 *err += android::base::StringPrintf("failed to stat %s\n", blk_device.c_str());
121 }
122 return ret == 0;
123}
124
Tao Baobedf5fc2016-11-18 12:01:26 -0800125static bool read_misc_partition(void* p, size_t size, const std::string& misc_blk_device,
126 size_t offset, std::string* err) {
Yabin Cui2f272c02016-06-24 18:22:02 -0700127 if (!wait_for_device(misc_blk_device, err)) {
128 return false;
129 }
Yabin Cui0d5b8592016-07-06 11:47:23 -0700130 android::base::unique_fd fd(open(misc_blk_device.c_str(), O_RDONLY));
Tao Baobedf5fc2016-11-18 12:01:26 -0800131 if (fd == -1) {
Yabin Cui2f272c02016-06-24 18:22:02 -0700132 *err = android::base::StringPrintf("failed to open %s: %s", misc_blk_device.c_str(),
133 strerror(errno));
134 return false;
135 }
Ethan Yonkerb5236502016-11-19 22:24:59 -0600136 if (lseek(fd, static_cast<off_t>(offset), SEEK_SET) != static_cast<off_t>(offset)) {
Yabin Cui2f272c02016-06-24 18:22:02 -0700137 *err = android::base::StringPrintf("failed to lseek %s: %s", misc_blk_device.c_str(),
138 strerror(errno));
139 return false;
140 }
Tao Baobedf5fc2016-11-18 12:01:26 -0800141 if (!android::base::ReadFully(fd, p, size)) {
Yabin Cui2f272c02016-06-24 18:22:02 -0700142 *err = android::base::StringPrintf("failed to read %s: %s", misc_blk_device.c_str(),
143 strerror(errno));
144 return false;
145 }
146 return true;
147}
148
Tao Baobedf5fc2016-11-18 12:01:26 -0800149static bool write_misc_partition(const void* p, size_t size, const std::string& misc_blk_device,
150 size_t offset, std::string* err) {
151 android::base::unique_fd fd(open(misc_blk_device.c_str(), O_WRONLY));
Ethan Yonkerb5236502016-11-19 22:24:59 -0600152 if (fd == -1) {
Yabin Cuia58a6db2016-04-06 15:52:18 -0700153 *err = android::base::StringPrintf("failed to open %s: %s", misc_blk_device.c_str(),
154 strerror(errno));
155 return false;
156 }
Ethan Yonkerb5236502016-11-19 22:24:59 -0600157 if (lseek(fd, static_cast<off_t>(offset), SEEK_SET) != static_cast<off_t>(offset)) {
Yabin Cui6faf0262016-06-09 14:09:39 -0700158 *err = android::base::StringPrintf("failed to lseek %s: %s", misc_blk_device.c_str(),
159 strerror(errno));
160 return false;
161 }
Tao Baobedf5fc2016-11-18 12:01:26 -0800162 if (!android::base::WriteFully(fd, p, size)) {
Yabin Cuia58a6db2016-04-06 15:52:18 -0700163 *err = android::base::StringPrintf("failed to write %s: %s", misc_blk_device.c_str(),
164 strerror(errno));
165 return false;
166 }
Ethan Yonkerb5236502016-11-19 22:24:59 -0600167 if (fsync(fd) == -1) {
Yabin Cuia58a6db2016-04-06 15:52:18 -0700168 *err = android::base::StringPrintf("failed to fsync %s: %s", misc_blk_device.c_str(),
169 strerror(errno));
170 return false;
171 }
172 return true;
173}
174
Alex Deymofb00d822016-11-08 15:46:07 -0800175std::string get_bootloader_message_blk_device(std::string* err) {
176 std::string misc_blk_device = get_misc_blk_device(err);
177 if (misc_blk_device.empty()) return "";
178 if (!wait_for_device(misc_blk_device, err)) return "";
179 return misc_blk_device;
180}
181
Tao Baobedf5fc2016-11-18 12:01:26 -0800182bool read_bootloader_message_from(bootloader_message* boot, const std::string& misc_blk_device,
183 std::string* err) {
184 return read_misc_partition(boot, sizeof(*boot), misc_blk_device,
185 BOOTLOADER_MESSAGE_OFFSET_IN_MISC, err);
186}
187
Yabin Cui2f272c02016-06-24 18:22:02 -0700188bool read_bootloader_message(bootloader_message* boot, std::string* err) {
Tao Baobedf5fc2016-11-18 12:01:26 -0800189 std::string misc_blk_device = get_misc_blk_device(err);
190 if (misc_blk_device.empty()) {
191 return false;
192 }
193 return read_bootloader_message_from(boot, misc_blk_device, err);
194}
195
196bool write_bootloader_message_to(const bootloader_message& boot, const std::string& misc_blk_device,
197 std::string* err) {
198 return write_misc_partition(&boot, sizeof(boot), misc_blk_device,
199 BOOTLOADER_MESSAGE_OFFSET_IN_MISC, err);
Yabin Cui2f272c02016-06-24 18:22:02 -0700200}
201
202bool write_bootloader_message(const bootloader_message& boot, std::string* err) {
Tao Baobedf5fc2016-11-18 12:01:26 -0800203 std::string misc_blk_device = get_misc_blk_device(err);
204 if (misc_blk_device.empty()) {
205 return false;
206 }
207 return write_bootloader_message_to(boot, misc_blk_device, err);
Yabin Cui6faf0262016-06-09 14:09:39 -0700208}
209
Yabin Cuia58a6db2016-04-06 15:52:18 -0700210bool clear_bootloader_message(std::string* err) {
211 bootloader_message boot = {};
212 return write_bootloader_message(boot, err);
213}
214
215bool write_bootloader_message(const std::vector<std::string>& options, std::string* err) {
216 bootloader_message boot = {};
Tianjie Xua88cc542017-10-25 13:16:54 -0700217 update_bootloader_message_in_struct(&boot, options);
218
Yabin Cuia58a6db2016-04-06 15:52:18 -0700219 return write_bootloader_message(boot, err);
220}
221
Tao Bao2292db82016-12-13 21:53:31 -0800222bool update_bootloader_message(const std::vector<std::string>& options, std::string* err) {
223 bootloader_message boot;
224 if (!read_bootloader_message(&boot, err)) {
225 return false;
226 }
Tianjie Xua88cc542017-10-25 13:16:54 -0700227 update_bootloader_message_in_struct(&boot, options);
Tao Bao2292db82016-12-13 21:53:31 -0800228
Tianjie Xua88cc542017-10-25 13:16:54 -0700229 return write_bootloader_message(boot, err);
230}
Tao Bao2292db82016-12-13 21:53:31 -0800231
Tianjie Xua88cc542017-10-25 13:16:54 -0700232bool update_bootloader_message_in_struct(bootloader_message* boot,
233 const std::vector<std::string>& options) {
234 if (!boot) return false;
235 // Replace the command & recovery fields.
236 memset(boot->command, 0, sizeof(boot->command));
237 memset(boot->recovery, 0, sizeof(boot->recovery));
238
239 strlcpy(boot->command, "boot-recovery", sizeof(boot->command));
240 strlcpy(boot->recovery, "recovery\n", sizeof(boot->recovery));
Tao Bao2292db82016-12-13 21:53:31 -0800241 for (const auto& s : options) {
Tianjie Xua88cc542017-10-25 13:16:54 -0700242 strlcat(boot->recovery, s.c_str(), sizeof(boot->recovery));
Tao Bao2292db82016-12-13 21:53:31 -0800243 if (s.back() != '\n') {
Tianjie Xua88cc542017-10-25 13:16:54 -0700244 strlcat(boot->recovery, "\n", sizeof(boot->recovery));
Tao Bao2292db82016-12-13 21:53:31 -0800245 }
246 }
Tianjie Xua88cc542017-10-25 13:16:54 -0700247 return true;
Tao Bao2292db82016-12-13 21:53:31 -0800248}
249
Vineela Tummalapallicba7fa82016-10-28 19:44:40 -0700250bool write_reboot_bootloader(std::string* err) {
251 bootloader_message boot;
252 if (!read_bootloader_message(&boot, err)) {
253 return false;
254 }
255 if (boot.command[0] != '\0') {
256 *err = "Bootloader command pending.";
257 return false;
258 }
259 strlcpy(boot.command, "bootonce-bootloader", sizeof(boot.command));
260 return write_bootloader_message(boot, err);
261}
262
Yabin Cui2f272c02016-06-24 18:22:02 -0700263bool read_wipe_package(std::string* package_data, size_t size, std::string* err) {
Tao Baobedf5fc2016-11-18 12:01:26 -0800264 std::string misc_blk_device = get_misc_blk_device(err);
265 if (misc_blk_device.empty()) {
266 return false;
267 }
Yabin Cui2f272c02016-06-24 18:22:02 -0700268 package_data->resize(size);
Tao Baobedf5fc2016-11-18 12:01:26 -0800269 return read_misc_partition(&(*package_data)[0], size, misc_blk_device,
270 WIPE_PACKAGE_OFFSET_IN_MISC, err);
Yabin Cui2f272c02016-06-24 18:22:02 -0700271}
272
Yabin Cui6faf0262016-06-09 14:09:39 -0700273bool write_wipe_package(const std::string& package_data, std::string* err) {
Tao Baobedf5fc2016-11-18 12:01:26 -0800274 std::string misc_blk_device = get_misc_blk_device(err);
275 if (misc_blk_device.empty()) {
276 return false;
277 }
278 return write_misc_partition(package_data.data(), package_data.size(), misc_blk_device,
Yabin Cui6faf0262016-06-09 14:09:39 -0700279 WIPE_PACKAGE_OFFSET_IN_MISC, err);
280}
281
Tao Bao35e0f6d2019-05-16 14:42:42 -0700282static bool OffsetAndSizeInVendorSpace(size_t offset, size_t size) {
283 auto total_size = WIPE_PACKAGE_OFFSET_IN_MISC - VENDOR_SPACE_OFFSET_IN_MISC;
284 return size <= total_size && offset <= total_size - size;
285}
286
287bool ReadMiscPartitionVendorSpace(void* data, size_t size, size_t offset, std::string* err) {
288 if (!OffsetAndSizeInVendorSpace(offset, size)) {
289 *err = android::base::StringPrintf("Out of bound read (offset %zu size %zu)", offset, size);
290 return false;
291 }
292 auto misc_blk_device = get_misc_blk_device(err);
293 if (misc_blk_device.empty()) {
294 return false;
295 }
296 return read_misc_partition(data, size, misc_blk_device, VENDOR_SPACE_OFFSET_IN_MISC + offset,
297 err);
298}
299
300bool WriteMiscPartitionVendorSpace(const void* data, size_t size, size_t offset, std::string* err) {
301 if (!OffsetAndSizeInVendorSpace(offset, size)) {
302 *err = android::base::StringPrintf("Out of bound write (offset %zu size %zu)", offset, size);
303 return false;
304 }
305 auto misc_blk_device = get_misc_blk_device(err);
306 if (misc_blk_device.empty()) {
307 return false;
308 }
309 return write_misc_partition(data, size, misc_blk_device, VENDOR_SPACE_OFFSET_IN_MISC + offset,
310 err);
311}
312
Vineela Tummalapallicba7fa82016-10-28 19:44:40 -0700313extern "C" bool write_reboot_bootloader(void) {
314 std::string err;
315 return write_reboot_bootloader(&err);
316}
317
Yabin Cuia58a6db2016-04-06 15:52:18 -0700318extern "C" bool write_bootloader_message(const char* options) {
319 std::string err;
Yabin Cui8b309f62016-06-24 18:22:02 -0700320 return write_bootloader_message({options}, &err);
Yabin Cuia58a6db2016-04-06 15:52:18 -0700321}