blob: 90b8998b0d12ad2c0210705e54079eee9a9f9f2a [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"
Ethan Yonkerf1179622016-08-25 15:32:21 -050035//#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);
Ethan Yonkerf1179622016-08-25 15:32:21 -0500235 int fd = open(v->blk_device, O_WRONLY | O_SYNC);
236 if (fd == -1) {
Tao Baobd82b272016-01-21 13:49:03 -0800237 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 Yonkerf1179622016-08-25 15:32:21 -0500242 lseek(fd, 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) {
Ethan Yonkerf1179622016-08-25 15:32:21 -0500249 ssize_t wrote = TEMP_FAILURE_RETRY(write(fd, start + written, total - written));
Tao Baobd82b272016-01-21 13:49:03 -0800250 if (wrote == -1) {
Ethan Yonkerf1179622016-08-25 15:32:21 -0500251 LOGE("failed to write some bytes: %s\n",
252 strerror(errno));
253 close(fd);
Tao Baobd82b272016-01-21 13:49:03 -0800254 return -1;
255 }
256 written += wrote;
Doug Zongkercc8cd3f2010-09-20 12:16:13 -0700257 }
Tao Baobd82b272016-01-21 13:49:03 -0800258
Ethan Yonkerf1179622016-08-25 15:32:21 -0500259 if (fsync(fd) == -1) {
Tao Baobd82b272016-01-21 13:49:03 -0800260 LOGE("failed to fsync \"%s\": %s\n", v->blk_device, strerror(errno));
Ethan Yonkerf1179622016-08-25 15:32:21 -0500261 close(fd);
Doug Zongkercc8cd3f2010-09-20 12:16:13 -0700262 return -1;
263 }
Ethan Yonkerf1179622016-08-25 15:32:21 -0500264 close(fd);
Doug Zongkercc8cd3f2010-09-20 12:16:13 -0700265 return 0;
266}
Dees_Troy1669f892013-09-04 18:35:08 +0000267
Dees_Troya449a6f2013-04-07 17:50:11 -0500268
269static const char *COMMAND_FILE = "/cache/recovery/command";
270static const int MAX_ARG_LENGTH = 4096;
271static const int MAX_ARGS = 100;
272
273// command line args come from, in decreasing precedence:
274// - the actual command line
275// - the bootloader control block (one per line, after "recovery")
276// - the contents of COMMAND_FILE (one per line)
277void
278get_args(int *argc, char ***argv) {
279 struct bootloader_message boot;
280 memset(&boot, 0, sizeof(boot));
281 get_bootloader_message(&boot); // this may fail, leaving a zeroed structure
282
283 if (boot.command[0] != 0 && boot.command[0] != 255) {
that4e0e3fc2015-04-13 19:52:49 +0200284 LOGI("Boot command: %.*s\n", (int)sizeof(boot.command), boot.command);
Dees_Troya449a6f2013-04-07 17:50:11 -0500285 }
286
287 if (boot.status[0] != 0 && boot.status[0] != 255) {
that4e0e3fc2015-04-13 19:52:49 +0200288 LOGI("Boot status: %.*s\n", (int)sizeof(boot.status), boot.status);
Dees_Troya449a6f2013-04-07 17:50:11 -0500289 }
290
291 // --- if arguments weren't supplied, look in the bootloader control block
292 if (*argc <= 1) {
293 boot.recovery[sizeof(boot.recovery) - 1] = '\0'; // Ensure termination
294 const char *arg = strtok(boot.recovery, "\n");
295 if (arg != NULL && !strcmp(arg, "recovery")) {
296 *argv = (char **) malloc(sizeof(char *) * MAX_ARGS);
297 (*argv)[0] = strdup(arg);
298 for (*argc = 1; *argc < MAX_ARGS; ++*argc) {
299 if ((arg = strtok(NULL, "\n")) == NULL) break;
300 (*argv)[*argc] = strdup(arg);
301 }
302 LOGI("Got arguments from boot message\n");
303 } else if (boot.recovery[0] != 0 && boot.recovery[0] != 255) {
304 LOGE("Bad boot message\n\"%.20s\"\n", boot.recovery);
305 }
306 }
307
308 // --- if that doesn't work, try the command file
309 if (*argc <= 1) {
310 FILE *fp = fopen(COMMAND_FILE, "r");
311 if (fp != NULL) {
that9eadc512015-03-27 00:06:51 +0100312 char *token;
Dees_Troya449a6f2013-04-07 17:50:11 -0500313 char *argv0 = (*argv)[0];
314 *argv = (char **) malloc(sizeof(char *) * MAX_ARGS);
315 (*argv)[0] = argv0; // use the same program name
316
317 char buf[MAX_ARG_LENGTH];
318 for (*argc = 1; *argc < MAX_ARGS; ++*argc) {
319 if (!fgets(buf, sizeof(buf), fp)) break;
that9eadc512015-03-27 00:06:51 +0100320 token = strtok(buf, "\r\n");
321 if (token != NULL) {
322 (*argv)[*argc] = strdup(token); // Strip newline.
323 } else {
324 --*argc;
325 }
Dees_Troya449a6f2013-04-07 17:50:11 -0500326 }
327
328 fflush(fp);
that9eadc512015-03-27 00:06:51 +0100329 if (ferror(fp)) LOGE("Error in %s\n(%s)\n", COMMAND_FILE, strerror(errno));
330 fclose(fp);
Dees_Troya449a6f2013-04-07 17:50:11 -0500331 LOGI("Got arguments from %s\n", COMMAND_FILE);
332 }
333 }
334
335 // --> write the arguments we have back into the bootloader control block
336 // always boot into recovery after this (until finish_recovery() is called)
337 strlcpy(boot.command, "boot-recovery", sizeof(boot.command));
338 strlcpy(boot.recovery, "recovery\n", sizeof(boot.recovery));
339 int i;
340 for (i = 1; i < *argc; ++i) {
341 strlcat(boot.recovery, (*argv)[i], sizeof(boot.recovery));
342 strlcat(boot.recovery, "\n", sizeof(boot.recovery));
343 }
344 set_bootloader_message(&boot);
345}