blob: 449f40e119395b7d87866c2a542fd44a09dfd9b8 [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>
Ethan Yonkerb5236502016-11-19 22:24:59 -060022#include <stdlib.h>
23#include <sys/stat.h>
24#include <unistd.h>
25#include <sys/types.h>
Yabin Cuia58a6db2016-04-06 15:52:18 -070026#include <sys/system_properties.h>
27
28#include <string>
29#include <vector>
30
Ethan Yonkerb5236502016-11-19 22:24:59 -060031/*
Yabin Cuia58a6db2016-04-06 15:52:18 -070032#include <android-base/file.h>
33#include <android-base/stringprintf.h>
34#include <android-base/unique_fd.h>
Ethan Yonkerb5236502016-11-19 22:24:59 -060035*/
36#ifndef EXCLUDE_FS_MGR
Yabin Cuia58a6db2016-04-06 15:52:18 -070037#include <fs_mgr.h>
Ethan Yonkerb5236502016-11-19 22:24:59 -060038#endif
Yabin Cuia58a6db2016-04-06 15:52:18 -070039
Ethan Yonkerb5236502016-11-19 22:24:59 -060040static std::string misc_blkdev;
41
Matt Mower3626bdc2017-01-06 13:45:54 -060042void set_misc_device(std::string name) {
Ethan Yonkerb5236502016-11-19 22:24:59 -060043 misc_blkdev = name;
44}
45
46#ifndef EXCLUDE_FS_MGR
Yabin Cuia58a6db2016-04-06 15:52:18 -070047static struct fstab* read_fstab(std::string* err) {
48 // The fstab path is always "/fstab.${ro.hardware}".
49 std::string fstab_path = "/fstab.";
50 char value[PROP_VALUE_MAX];
51 if (__system_property_get("ro.hardware", value) == 0) {
52 *err = "failed to get ro.hardware";
53 return nullptr;
54 }
55 fstab_path += value;
56 struct fstab* fstab = fs_mgr_read_fstab(fstab_path.c_str());
57 if (fstab == nullptr) {
58 *err = "failed to read " + fstab_path;
59 }
60 return fstab;
61}
Ethan Yonkerb5236502016-11-19 22:24:59 -060062#endif
Yabin Cuia58a6db2016-04-06 15:52:18 -070063
64static std::string get_misc_blk_device(std::string* err) {
Ethan Yonkerb5236502016-11-19 22:24:59 -060065#ifdef EXCLUDE_FS_MGR
66 return misc_blkdev;
67#else
Yabin Cuia58a6db2016-04-06 15:52:18 -070068 struct fstab* fstab = read_fstab(err);
69 if (fstab == nullptr) {
70 return "";
71 }
72 fstab_rec* record = fs_mgr_get_entry_for_mount_point(fstab, "/misc");
73 if (record == nullptr) {
74 *err = "failed to find /misc partition";
75 return "";
76 }
77 return record->blk_device;
Ethan Yonkerb5236502016-11-19 22:24:59 -060078#endif
Yabin Cuia58a6db2016-04-06 15:52:18 -070079}
80
Ethan Yonkerb5236502016-11-19 22:24:59 -060081
Yabin Cui2f272c02016-06-24 18:22:02 -070082// In recovery mode, recovery can get started and try to access the misc
83// device before the kernel has actually created it.
84static bool wait_for_device(const std::string& blk_device, std::string* err) {
85 int tries = 0;
86 int ret;
87 err->clear();
88 do {
89 ++tries;
90 struct stat buf;
91 ret = stat(blk_device.c_str(), &buf);
92 if (ret == -1) {
Ethan Yonkerb5236502016-11-19 22:24:59 -060093 char buffer[2048];
94 sprintf(buffer, "failed to stat %s try %d: %s\n",
95 blk_device.c_str(), tries, strerror(errno));
96 *err += buffer;
97 /*
Yabin Cui2f272c02016-06-24 18:22:02 -070098 *err += android::base::StringPrintf("failed to stat %s try %d: %s\n",
99 blk_device.c_str(), tries, strerror(errno));
Ethan Yonkerb5236502016-11-19 22:24:59 -0600100 */
Yabin Cui2f272c02016-06-24 18:22:02 -0700101 sleep(1);
102 }
103 } while (ret && tries < 10);
104
105 if (ret) {
Ethan Yonkerb5236502016-11-19 22:24:59 -0600106 *err += "failed to stat " + blk_device + "\n";
107 /*
Yabin Cui2f272c02016-06-24 18:22:02 -0700108 *err += android::base::StringPrintf("failed to stat %s\n", blk_device.c_str());
Ethan Yonkerb5236502016-11-19 22:24:59 -0600109 */
Yabin Cui2f272c02016-06-24 18:22:02 -0700110 }
111 return ret == 0;
112}
113
114static bool read_misc_partition(void* p, size_t size, size_t offset, std::string* err) {
115 std::string misc_blk_device = get_misc_blk_device(err);
116 if (misc_blk_device.empty()) {
117 return false;
118 }
119 if (!wait_for_device(misc_blk_device, err)) {
120 return false;
121 }
Ethan Yonkerb5236502016-11-19 22:24:59 -0600122 int fd(open(misc_blk_device.c_str(), O_RDONLY));
123 if (fd < 0) {
124 *err = "failed to open " + misc_blk_device + ": ";
125 *err += strerror(errno);
126 /*
Yabin Cui2f272c02016-06-24 18:22:02 -0700127 *err = android::base::StringPrintf("failed to open %s: %s", misc_blk_device.c_str(),
128 strerror(errno));
Ethan Yonkerb5236502016-11-19 22:24:59 -0600129 */
Yabin Cui2f272c02016-06-24 18:22:02 -0700130 return false;
131 }
Ethan Yonkerb5236502016-11-19 22:24:59 -0600132 if (lseek(fd, static_cast<off_t>(offset), SEEK_SET) != static_cast<off_t>(offset)) {
133 *err = "failed to lseek " + misc_blk_device + ": ";
134 *err += strerror(errno);
135 close(fd);
136 /*
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));
Ethan Yonkerb5236502016-11-19 22:24:59 -0600139 */
Yabin Cui2f272c02016-06-24 18:22:02 -0700140 return false;
141 }
Ethan Yonkerb5236502016-11-19 22:24:59 -0600142 if (read(fd, p, size) != size) {
143 *err = "failed to read " + misc_blk_device + ": ";
144 *err += strerror(errno);
145 close(fd);
146 /*
Yabin Cui2f272c02016-06-24 18:22:02 -0700147 *err = android::base::StringPrintf("failed to read %s: %s", misc_blk_device.c_str(),
148 strerror(errno));
Ethan Yonkerb5236502016-11-19 22:24:59 -0600149 */
Yabin Cui2f272c02016-06-24 18:22:02 -0700150 return false;
151 }
Ethan Yonkerb5236502016-11-19 22:24:59 -0600152 close(fd);
Yabin Cui2f272c02016-06-24 18:22:02 -0700153 return true;
154}
155
156static bool write_misc_partition(const void* p, size_t size, size_t offset, std::string* err) {
Yabin Cuia58a6db2016-04-06 15:52:18 -0700157 std::string misc_blk_device = get_misc_blk_device(err);
158 if (misc_blk_device.empty()) {
Ethan Yonkerb5236502016-11-19 22:24:59 -0600159 *err = "no misc device set";
Yabin Cuia58a6db2016-04-06 15:52:18 -0700160 return false;
161 }
Matt Mower8df31912014-07-09 11:50:05 -0500162 int open_flags = O_WRONLY | O_SYNC;
163 if (offset > 0)
164 open_flags = O_RDWR | O_APPEND | O_SYNC;
165 int fd = (open(misc_blk_device.c_str(), open_flags));
Ethan Yonkerb5236502016-11-19 22:24:59 -0600166 if (fd == -1) {
167 *err = "failed to open " + misc_blk_device + ": ";
168 *err += strerror(errno);
169 /*
Yabin Cuia58a6db2016-04-06 15:52:18 -0700170 *err = android::base::StringPrintf("failed to open %s: %s", misc_blk_device.c_str(),
171 strerror(errno));
Ethan Yonkerb5236502016-11-19 22:24:59 -0600172 */
Yabin Cuia58a6db2016-04-06 15:52:18 -0700173 return false;
174 }
Ethan Yonkerb5236502016-11-19 22:24:59 -0600175 if (lseek(fd, static_cast<off_t>(offset), SEEK_SET) != static_cast<off_t>(offset)) {
176 *err = "failed to lseek " + misc_blk_device + ": ";
177 *err += strerror(errno);
178 close(fd);
179 /*
Yabin Cui6faf0262016-06-09 14:09:39 -0700180 *err = android::base::StringPrintf("failed to lseek %s: %s", misc_blk_device.c_str(),
181 strerror(errno));
Ethan Yonkerb5236502016-11-19 22:24:59 -0600182 */
Yabin Cui6faf0262016-06-09 14:09:39 -0700183 return false;
184 }
Ethan Yonkerb5236502016-11-19 22:24:59 -0600185 if (write(fd, p, size) != size) {
186 *err = "failed to write " + misc_blk_device + ": ";
187 *err += strerror(errno);
188 close(fd);
189 /*
Yabin Cuia58a6db2016-04-06 15:52:18 -0700190 *err = android::base::StringPrintf("failed to write %s: %s", misc_blk_device.c_str(),
191 strerror(errno));
Ethan Yonkerb5236502016-11-19 22:24:59 -0600192 */
Yabin Cuia58a6db2016-04-06 15:52:18 -0700193 return false;
194 }
Yabin Cui6faf0262016-06-09 14:09:39 -0700195
Yabin Cuia58a6db2016-04-06 15:52:18 -0700196 // TODO: O_SYNC and fsync duplicates each other?
Ethan Yonkerb5236502016-11-19 22:24:59 -0600197 if (fsync(fd) == -1) {
198 *err = "failed to fsync " + misc_blk_device + ": ";
199 *err += strerror(errno);
200 close(fd);
201 /*
Yabin Cuia58a6db2016-04-06 15:52:18 -0700202 *err = android::base::StringPrintf("failed to fsync %s: %s", misc_blk_device.c_str(),
203 strerror(errno));
Ethan Yonkerb5236502016-11-19 22:24:59 -0600204 */
Yabin Cuia58a6db2016-04-06 15:52:18 -0700205 return false;
206 }
Ethan Yonkerb5236502016-11-19 22:24:59 -0600207 close(fd);
Yabin Cuia58a6db2016-04-06 15:52:18 -0700208 return true;
209}
210
Yabin Cui2f272c02016-06-24 18:22:02 -0700211bool read_bootloader_message(bootloader_message* boot, std::string* err) {
212 return read_misc_partition(boot, sizeof(*boot), BOOTLOADER_MESSAGE_OFFSET_IN_MISC, err);
213}
214
215bool write_bootloader_message(const bootloader_message& boot, std::string* err) {
Yabin Cui6faf0262016-06-09 14:09:39 -0700216 return write_misc_partition(&boot, sizeof(boot), BOOTLOADER_MESSAGE_OFFSET_IN_MISC, err);
217}
218
Yabin Cuia58a6db2016-04-06 15:52:18 -0700219bool clear_bootloader_message(std::string* err) {
220 bootloader_message boot = {};
221 return write_bootloader_message(boot, err);
222}
223
224bool write_bootloader_message(const std::vector<std::string>& options, std::string* err) {
225 bootloader_message boot = {};
226 strlcpy(boot.command, "boot-recovery", sizeof(boot.command));
227 strlcpy(boot.recovery, "recovery\n", sizeof(boot.recovery));
228 for (const auto& s : options) {
229 strlcat(boot.recovery, s.c_str(), sizeof(boot.recovery));
Ethan Yonkerb5236502016-11-19 22:24:59 -0600230 if (s.substr(s.size() - 1) != "\n") {
Yabin Cuia58a6db2016-04-06 15:52:18 -0700231 strlcat(boot.recovery, "\n", sizeof(boot.recovery));
232 }
233 }
234 return write_bootloader_message(boot, err);
235}
236
Yabin Cui2f272c02016-06-24 18:22:02 -0700237bool read_wipe_package(std::string* package_data, size_t size, std::string* err) {
238 package_data->resize(size);
239 return read_misc_partition(&(*package_data)[0], size, WIPE_PACKAGE_OFFSET_IN_MISC, err);
240}
241
Yabin Cui6faf0262016-06-09 14:09:39 -0700242bool write_wipe_package(const std::string& package_data, std::string* err) {
243 return write_misc_partition(package_data.data(), package_data.size(),
244 WIPE_PACKAGE_OFFSET_IN_MISC, err);
245}
246
Yabin Cuia58a6db2016-04-06 15:52:18 -0700247extern "C" bool write_bootloader_message(const char* options) {
248 std::string err;
Ethan Yonkerb5236502016-11-19 22:24:59 -0600249 bootloader_message boot = {};
250 memcpy(&boot, options, sizeof(boot));
251 return write_bootloader_message(boot, &err);
252}
253
254static const char *COMMAND_FILE = "/cache/recovery/command";
255static const int MAX_ARG_LENGTH = 4096;
256static const int MAX_ARGS = 100;
257
258// command line args come from, in decreasing precedence:
259// - the actual command line
260// - the bootloader control block (one per line, after "recovery")
261// - the contents of COMMAND_FILE (one per line)
262void
263get_args(int *argc, char ***argv) {
264 bootloader_message boot = {};
265 std::string err;
266 if (!read_bootloader_message(&boot, &err)) {
267 printf("%s\n", err.c_str());
268 // If fails, leave a zeroed bootloader_message.
269 memset(&boot, 0, sizeof(boot));
270 }
271 //stage = strndup(boot.stage, sizeof(boot.stage));
272
273 if (boot.command[0] != 0 && boot.command[0] != 255) {
274 printf("Boot command: %.*s\n", (int)sizeof(boot.command), boot.command);
275 }
276
277 if (boot.status[0] != 0 && boot.status[0] != 255) {
278 printf("Boot status: %.*s\n", (int)sizeof(boot.status), boot.status);
279 }
280
281 // --- if arguments weren't supplied, look in the bootloader control block
282 if (*argc <= 1) {
283 boot.recovery[sizeof(boot.recovery) - 1] = '\0'; // Ensure termination
284 const char *arg = strtok(boot.recovery, "\n");
285 if (arg != NULL && !strcmp(arg, "recovery")) {
286 *argv = (char **) malloc(sizeof(char *) * MAX_ARGS);
287 (*argv)[0] = strdup(arg);
288 for (*argc = 1; *argc < MAX_ARGS; ++*argc) {
289 if ((arg = strtok(NULL, "\n")) == NULL) break;
nailyk-fr1021edf2016-12-18 14:32:25 +0100290
291// if the device does not have an own recovery key combo we just want to open TWRP after
292// walking through the factory reset screen - without actually doing a factory reset
293#ifdef IGNORE_MISC_WIPE_DATA
294 if (!strcmp(arg, "--wipe_data")) {
295 (*argv)[*argc] = "";
296 *argc = *argc -1;
297 printf("Bootloader arg \"%s\" ignored because TWRP was compiled with TW_IGNORE_MISC_WIPE_DATA\n", arg);
298 continue;
299 }
300#endif
Ethan Yonkerb5236502016-11-19 22:24:59 -0600301 (*argv)[*argc] = strdup(arg);
302 }
303 printf("Got arguments from boot message\n");
304 } else if (boot.recovery[0] != 0 && boot.recovery[0] != 255) {
305 printf("Bad boot message\n\"%.20s\"\n", boot.recovery);
306 }
307 }
308
309 // --- if that doesn't work, try the command file (if we have /cache).
310 if (*argc <= 1/* && has_cache*/) {
311 FILE *fp = fopen(COMMAND_FILE, "r");
312 if (fp != NULL) {
313 char *token;
314 char *argv0 = (*argv)[0];
315 *argv = (char **) malloc(sizeof(char *) * MAX_ARGS);
316 (*argv)[0] = argv0; // use the same program name
317
318 char buf[MAX_ARG_LENGTH];
319 for (*argc = 1; *argc < MAX_ARGS; ++*argc) {
320 if (!fgets(buf, sizeof(buf), fp)) break;
321 token = strtok(buf, "\r\n");
322 if (token != NULL) {
323 (*argv)[*argc] = strdup(token); // Strip newline.
324 } else {
325 --*argc;
326 }
327 }
328
329 fclose(fp);
330 printf("Got arguments from %s\n", COMMAND_FILE);
331 }
332 }
333
334 // --> write the arguments we have back into the bootloader control block
335 // always boot into recovery after this (until finish_recovery() is called)
336 strlcpy(boot.command, "boot-recovery", sizeof(boot.command));
337 strlcpy(boot.recovery, "recovery\n", sizeof(boot.recovery));
338 int i;
339 for (i = 1; i < *argc; ++i) {
340 strlcat(boot.recovery, (*argv)[i], sizeof(boot.recovery));
341 strlcat(boot.recovery, "\n", sizeof(boot.recovery));
342 }
343 if (!write_bootloader_message(boot, &err)) {
344 printf("%s\n", err.c_str());
345 }
Yabin Cuia58a6db2016-04-06 15:52:18 -0700346}