blob: 13bc39167e50c3454187756d575d2bdc8a2f4a5c [file] [log] [blame]
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -08001/*
2 * Copyright (C) 2008 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
Dees_Troy51a0e822012-09-05 15:24:24 -040017extern "C" {
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -080018#include "mtdutils/mtdutils.h"
Dees_Troy51a0e822012-09-05 15:24:24 -040019}
Ethan Yonker34ae4832016-08-24 15:32:18 -050020
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -080021#include <errno.h>
Tao Baobd82b272016-01-21 13:49:03 -080022#include <fcntl.h>
23#include <inttypes.h>
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -080024#include <stdio.h>
25#include <string.h>
Doug Zongkercfd256a2011-04-22 09:26:44 -070026#include <sys/stat.h>
Tao Baobd82b272016-01-21 13:49:03 -080027#include <sys/types.h>
Doug Zongkercfd256a2011-04-22 09:26:44 -070028#include <unistd.h>
Ethan Yonkerc798c9c2015-10-09 11:15:26 -050029#include <stdlib.h>
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -080030
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -080031#include "bootloader.h"
32#include "common.h"
33#include "mtdutils/mtdutils.h"
Ethan Yonker34ae4832016-08-24 15:32:18 -050034//#include "roots.h"
Tao Baobd82b272016-01-21 13:49:03 -080035#include "unique_fd.h"
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -080036
that4e0e3fc2015-04-13 19:52:49 +020037// fake Volume struct that allows us to use the AOSP code easily
38struct Volume
39{
40 char fs_type[8];
41 char blk_device[256];
42};
Dees_Troy1669f892013-09-04 18:35:08 +000043
that4e0e3fc2015-04-13 19:52:49 +020044static Volume misc;
45
46void set_misc_device(const char* type, const char* name) {
47 strlcpy(misc.fs_type, type, sizeof(misc.fs_type));
48 if (strlen(name) >= sizeof(misc.blk_device)) {
49 LOGE("New device name of '%s' is too large for bootloader.cpp\n", name);
50 } else {
51 strcpy(misc.blk_device, name);
52 }
53}
54
Tao Baobd82b272016-01-21 13:49:03 -080055static int get_bootloader_message_mtd(bootloader_message* out, const Volume* v);
56static int set_bootloader_message_mtd(const bootloader_message* in, const Volume* v);
57static int get_bootloader_message_block(bootloader_message* out, const Volume* v);
58static int set_bootloader_message_block(const bootloader_message* in, const Volume* v);
that4e0e3fc2015-04-13 19:52:49 +020059
Tao Baobd82b272016-01-21 13:49:03 -080060int get_bootloader_message(bootloader_message* out) {
that4e0e3fc2015-04-13 19:52:49 +020061#if 0
62 Volume* v = volume_for_path("/misc");
Tao Baobd82b272016-01-21 13:49:03 -080063 if (v == nullptr) {
64 LOGE("Cannot load volume /misc!\n");
65 return -1;
Adam Blissb2ceb692011-07-13 15:13:54 -070066 }
that4e0e3fc2015-04-13 19:52:49 +020067#else
68 Volume* v = &misc;
69 if (v->fs_type[0] == 0) {
70 LOGI("Not using /misc, not defined in fstab.\n");
71 return -1;
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -080072 }
that4e0e3fc2015-04-13 19:52:49 +020073#endif
74 if (strcmp(v->fs_type, "mtd") == 0) {
75 return get_bootloader_message_mtd(out, v);
76 } else if (strcmp(v->fs_type, "emmc") == 0) {
77 return get_bootloader_message_block(out, v);
78 }
79 LOGE("unknown misc partition fs_type \"%s\"\n", v->fs_type);
Doug Zongkercc8cd3f2010-09-20 12:16:13 -070080 return -1;
Doug Zongker04611da2010-08-12 15:35:29 -070081}
82
Tao Baobd82b272016-01-21 13:49:03 -080083int set_bootloader_message(const bootloader_message* in) {
that4e0e3fc2015-04-13 19:52:49 +020084#if 0
85 Volume* v = volume_for_path("/misc");
Tao Baobd82b272016-01-21 13:49:03 -080086 if (v == nullptr) {
87 LOGE("Cannot load volume /misc!\n");
88 return -1;
Adam Blissb2ceb692011-07-13 15:13:54 -070089 }
that4e0e3fc2015-04-13 19:52:49 +020090#else
91 Volume* v = &misc;
92 if (v->fs_type[0] == 0) {
93 LOGI("Not using /misc, not defined in fstab.\n");
94 return -1;
Doug Zongker04611da2010-08-12 15:35:29 -070095 }
that4e0e3fc2015-04-13 19:52:49 +020096#endif
97 if (strcmp(v->fs_type, "mtd") == 0) {
98 return set_bootloader_message_mtd(in, v);
99 } else if (strcmp(v->fs_type, "emmc") == 0) {
100 return set_bootloader_message_block(in, v);
101 }
102 LOGE("unknown misc partition fs_type \"%s\"\n", v->fs_type);
Doug Zongkercc8cd3f2010-09-20 12:16:13 -0700103 return -1;
Doug Zongker04611da2010-08-12 15:35:29 -0700104}
105
Doug Zongkercc8cd3f2010-09-20 12:16:13 -0700106// ------------------------------
107// for misc partitions on MTD
108// ------------------------------
Doug Zongker04611da2010-08-12 15:35:29 -0700109
110static const int MISC_PAGES = 3; // number of pages to save
111static const int MISC_COMMAND_PAGE = 1; // bootloader command is this page
that4e0e3fc2015-04-13 19:52:49 +0200112
Tao Baobd82b272016-01-21 13:49:03 -0800113static int get_bootloader_message_mtd(bootloader_message* out,
Doug Zongkercc8cd3f2010-09-20 12:16:13 -0700114 const Volume* v) {
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -0800115 size_t write_size;
Doug Zongkercc8cd3f2010-09-20 12:16:13 -0700116 mtd_scan_partitions();
Tao Baobd82b272016-01-21 13:49:03 -0800117 const MtdPartition* part = mtd_find_partition_by_name(v->blk_device);
118 if (part == nullptr || mtd_partition_info(part, nullptr, nullptr, &write_size)) {
119 LOGE("failed to find \"%s\"\n", v->blk_device);
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -0800120 return -1;
121 }
122
Tao Baobd82b272016-01-21 13:49:03 -0800123 MtdReadContext* read = mtd_read_partition(part);
124 if (read == nullptr) {
125 LOGE("failed to open \"%s\": %s\n", v->blk_device, strerror(errno));
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -0800126 return -1;
127 }
128
129 const ssize_t size = write_size * MISC_PAGES;
130 char data[size];
131 ssize_t r = mtd_read_data(read, data, size);
Tao Baobd82b272016-01-21 13:49:03 -0800132 if (r != size) LOGE("failed to read \"%s\": %s\n", v->blk_device, strerror(errno));
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -0800133 mtd_read_close(read);
134 if (r != size) return -1;
135
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -0800136 memcpy(out, &data[write_size * MISC_COMMAND_PAGE], sizeof(*out));
137 return 0;
138}
Tao Baobd82b272016-01-21 13:49:03 -0800139static int set_bootloader_message_mtd(const bootloader_message* in,
Doug Zongkercc8cd3f2010-09-20 12:16:13 -0700140 const Volume* v) {
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -0800141 size_t write_size;
Doug Zongkercc8cd3f2010-09-20 12:16:13 -0700142 mtd_scan_partitions();
Tao Baobd82b272016-01-21 13:49:03 -0800143 const MtdPartition* part = mtd_find_partition_by_name(v->blk_device);
144 if (part == nullptr || mtd_partition_info(part, nullptr, nullptr, &write_size)) {
145 LOGE("failed to find \"%s\"\n", v->blk_device);
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -0800146 return -1;
147 }
148
Tao Baobd82b272016-01-21 13:49:03 -0800149 MtdReadContext* read = mtd_read_partition(part);
150 if (read == nullptr) {
151 LOGE("failed to open \"%s\": %s\n", v->blk_device, strerror(errno));
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -0800152 return -1;
153 }
154
155 ssize_t size = write_size * MISC_PAGES;
156 char data[size];
157 ssize_t r = mtd_read_data(read, data, size);
Tao Baobd82b272016-01-21 13:49:03 -0800158 if (r != size) LOGE("failed to read \"%s\": %s\n", v->blk_device, strerror(errno));
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -0800159 mtd_read_close(read);
160 if (r != size) return -1;
161
162 memcpy(&data[write_size * MISC_COMMAND_PAGE], in, sizeof(*in));
163
Tao Baobd82b272016-01-21 13:49:03 -0800164 MtdWriteContext* write = mtd_write_partition(part);
165 if (write == nullptr) {
166 LOGE("failed to open \"%s\": %s\n", v->blk_device, strerror(errno));
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -0800167 return -1;
168 }
169 if (mtd_write_data(write, data, size) != size) {
Tao Baobd82b272016-01-21 13:49:03 -0800170 LOGE("failed to write \"%s\": %s\n", v->blk_device, strerror(errno));
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -0800171 mtd_write_close(write);
172 return -1;
173 }
174 if (mtd_write_close(write)) {
Tao Baobd82b272016-01-21 13:49:03 -0800175 LOGE("failed to finish \"%s\": %s\n", v->blk_device, strerror(errno));
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -0800176 return -1;
177 }
178
179 LOGI("Set boot command \"%s\"\n", in->command[0] != 255 ? in->command : "");
180 return 0;
181}
Doug Zongker04611da2010-08-12 15:35:29 -0700182
Doug Zongkercc8cd3f2010-09-20 12:16:13 -0700183
184// ------------------------------------
185// for misc partitions on block devices
186// ------------------------------------
187
Doug Zongkercfd256a2011-04-22 09:26:44 -0700188static void wait_for_device(const char* fn) {
189 int tries = 0;
190 int ret;
Doug Zongkercfd256a2011-04-22 09:26:44 -0700191 do {
192 ++tries;
Tao Baobd82b272016-01-21 13:49:03 -0800193 struct stat buf;
Doug Zongkercfd256a2011-04-22 09:26:44 -0700194 ret = stat(fn, &buf);
Tao Baobd82b272016-01-21 13:49:03 -0800195 if (ret == -1) {
196 printf("failed to stat \"%s\" try %d: %s\n", fn, tries, strerror(errno));
Doug Zongkercfd256a2011-04-22 09:26:44 -0700197 sleep(1);
198 }
199 } while (ret && tries < 10);
Tao Baobd82b272016-01-21 13:49:03 -0800200
Doug Zongkercfd256a2011-04-22 09:26:44 -0700201 if (ret) {
Tao Baobd82b272016-01-21 13:49:03 -0800202 printf("failed to stat \"%s\"\n", fn);
Doug Zongkercfd256a2011-04-22 09:26:44 -0700203 }
204}
that4e0e3fc2015-04-13 19:52:49 +0200205
Tao Baobd82b272016-01-21 13:49:03 -0800206static int get_bootloader_message_block(bootloader_message* out,
Doug Zongkercc8cd3f2010-09-20 12:16:13 -0700207 const Volume* v) {
Ken Sumrallf35d1ce2013-02-13 12:59:35 -0800208 wait_for_device(v->blk_device);
209 FILE* f = fopen(v->blk_device, "rb");
Tao Baobd82b272016-01-21 13:49:03 -0800210 if (f == nullptr) {
211 LOGE("failed to open \"%s\": %s\n", v->blk_device, strerror(errno));
Doug Zongkercc8cd3f2010-09-20 12:16:13 -0700212 return -1;
213 }
Matt Mowerfb60a942014-07-08 22:25:38 -0500214#ifdef BOARD_RECOVERY_BLDRMSG_OFFSET
215 fseek(f, BOARD_RECOVERY_BLDRMSG_OFFSET, SEEK_SET);
216#endif
Tao Baobd82b272016-01-21 13:49:03 -0800217 bootloader_message temp;
Ethan Yonker34ae4832016-08-24 15:32:18 -0500218
Doug Zongkercc8cd3f2010-09-20 12:16:13 -0700219 int count = fread(&temp, sizeof(temp), 1, f);
220 if (count != 1) {
Tao Baobd82b272016-01-21 13:49:03 -0800221 LOGE("failed to read \"%s\": %s\n", v->blk_device, strerror(errno));
Doug Zongkercc8cd3f2010-09-20 12:16:13 -0700222 return -1;
223 }
224 if (fclose(f) != 0) {
Tao Baobd82b272016-01-21 13:49:03 -0800225 LOGE("failed to close \"%s\": %s\n", v->blk_device, strerror(errno));
Doug Zongkercc8cd3f2010-09-20 12:16:13 -0700226 return -1;
227 }
228 memcpy(out, &temp, sizeof(temp));
229 return 0;
230}
231
Tao Baobd82b272016-01-21 13:49:03 -0800232static int set_bootloader_message_block(const bootloader_message* in,
Doug Zongkercc8cd3f2010-09-20 12:16:13 -0700233 const Volume* v) {
Ken Sumrallf35d1ce2013-02-13 12:59:35 -0800234 wait_for_device(v->blk_device);
Tao Baobd82b272016-01-21 13:49:03 -0800235 unique_fd fd(open(v->blk_device, O_WRONLY | O_SYNC));
236 if (fd.get() == -1) {
237 LOGE("failed to open \"%s\": %s\n", v->blk_device, strerror(errno));
Doug Zongkercc8cd3f2010-09-20 12:16:13 -0700238 return -1;
239 }
Tao Baobd82b272016-01-21 13:49:03 -0800240
Matt Mowerfb60a942014-07-08 22:25:38 -0500241#ifdef BOARD_RECOVERY_BLDRMSG_OFFSET
Ethan Yonker34ae4832016-08-24 15:32:18 -0500242 lseek(fd.get(), BOARD_RECOVERY_BLDRMSG_OFFSET, SEEK_SET);
Matt Mowerfb60a942014-07-08 22:25:38 -0500243#endif
Ethan Yonker34ae4832016-08-24 15:32:18 -0500244
Tao Baobd82b272016-01-21 13:49:03 -0800245 size_t written = 0;
246 const uint8_t* start = reinterpret_cast<const uint8_t*>(in);
247 size_t total = sizeof(*in);
248 while (written < total) {
249 ssize_t wrote = TEMP_FAILURE_RETRY(write(fd.get(), start + written, total - written));
250 if (wrote == -1) {
251 LOGE("failed to write %" PRId64 " bytes: %s\n",
252 static_cast<off64_t>(written), strerror(errno));
253 return -1;
254 }
255 written += wrote;
Doug Zongkercc8cd3f2010-09-20 12:16:13 -0700256 }
Tao Baobd82b272016-01-21 13:49:03 -0800257
258 if (fsync(fd.get()) == -1) {
259 LOGE("failed to fsync \"%s\": %s\n", v->blk_device, strerror(errno));
Doug Zongkercc8cd3f2010-09-20 12:16:13 -0700260 return -1;
261 }
262 return 0;
263}
Dees_Troy1669f892013-09-04 18:35:08 +0000264
Dees_Troya449a6f2013-04-07 17:50:11 -0500265
266static const char *COMMAND_FILE = "/cache/recovery/command";
267static const int MAX_ARG_LENGTH = 4096;
268static const int MAX_ARGS = 100;
269
270// command line args come from, in decreasing precedence:
271// - the actual command line
272// - the bootloader control block (one per line, after "recovery")
273// - the contents of COMMAND_FILE (one per line)
274void
275get_args(int *argc, char ***argv) {
276 struct bootloader_message boot;
277 memset(&boot, 0, sizeof(boot));
278 get_bootloader_message(&boot); // this may fail, leaving a zeroed structure
279
280 if (boot.command[0] != 0 && boot.command[0] != 255) {
that4e0e3fc2015-04-13 19:52:49 +0200281 LOGI("Boot command: %.*s\n", (int)sizeof(boot.command), boot.command);
Dees_Troya449a6f2013-04-07 17:50:11 -0500282 }
283
284 if (boot.status[0] != 0 && boot.status[0] != 255) {
that4e0e3fc2015-04-13 19:52:49 +0200285 LOGI("Boot status: %.*s\n", (int)sizeof(boot.status), boot.status);
Dees_Troya449a6f2013-04-07 17:50:11 -0500286 }
287
288 // --- if arguments weren't supplied, look in the bootloader control block
289 if (*argc <= 1) {
290 boot.recovery[sizeof(boot.recovery) - 1] = '\0'; // Ensure termination
291 const char *arg = strtok(boot.recovery, "\n");
292 if (arg != NULL && !strcmp(arg, "recovery")) {
293 *argv = (char **) malloc(sizeof(char *) * MAX_ARGS);
294 (*argv)[0] = strdup(arg);
295 for (*argc = 1; *argc < MAX_ARGS; ++*argc) {
296 if ((arg = strtok(NULL, "\n")) == NULL) break;
297 (*argv)[*argc] = strdup(arg);
298 }
299 LOGI("Got arguments from boot message\n");
300 } else if (boot.recovery[0] != 0 && boot.recovery[0] != 255) {
301 LOGE("Bad boot message\n\"%.20s\"\n", boot.recovery);
302 }
303 }
304
305 // --- if that doesn't work, try the command file
306 if (*argc <= 1) {
307 FILE *fp = fopen(COMMAND_FILE, "r");
308 if (fp != NULL) {
that9eadc512015-03-27 00:06:51 +0100309 char *token;
Dees_Troya449a6f2013-04-07 17:50:11 -0500310 char *argv0 = (*argv)[0];
311 *argv = (char **) malloc(sizeof(char *) * MAX_ARGS);
312 (*argv)[0] = argv0; // use the same program name
313
314 char buf[MAX_ARG_LENGTH];
315 for (*argc = 1; *argc < MAX_ARGS; ++*argc) {
316 if (!fgets(buf, sizeof(buf), fp)) break;
that9eadc512015-03-27 00:06:51 +0100317 token = strtok(buf, "\r\n");
318 if (token != NULL) {
319 (*argv)[*argc] = strdup(token); // Strip newline.
320 } else {
321 --*argc;
322 }
Dees_Troya449a6f2013-04-07 17:50:11 -0500323 }
324
325 fflush(fp);
that9eadc512015-03-27 00:06:51 +0100326 if (ferror(fp)) LOGE("Error in %s\n(%s)\n", COMMAND_FILE, strerror(errno));
327 fclose(fp);
Dees_Troya449a6f2013-04-07 17:50:11 -0500328 LOGI("Got arguments from %s\n", COMMAND_FILE);
329 }
330 }
331
332 // --> write the arguments we have back into the bootloader control block
333 // always boot into recovery after this (until finish_recovery() is called)
334 strlcpy(boot.command, "boot-recovery", sizeof(boot.command));
335 strlcpy(boot.recovery, "recovery\n", sizeof(boot.recovery));
336 int i;
337 for (i = 1; i < *argc; ++i) {
338 strlcat(boot.recovery, (*argv)[i], sizeof(boot.recovery));
339 strlcat(boot.recovery, "\n", sizeof(boot.recovery));
340 }
341 set_bootloader_message(&boot);
342}