blob: fbb31e060152e397b3888dd1ba6f5c5cdeef0e95 [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_Troy1669f892013-09-04 18:35:08 +000017/*
Ken Sumrallf35d1ce2013-02-13 12:59:35 -080018#include <fs_mgr.h>
Dees_Troy1669f892013-09-04 18:35:08 +000019*/
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -080020#include "bootloader.h"
21#include "common.h"
Dees_Troy51a0e822012-09-05 15:24:24 -040022extern "C" {
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -080023#include "mtdutils/mtdutils.h"
Dees_Troy51a0e822012-09-05 15:24:24 -040024}
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -080025#include "roots.h"
26
27#include <errno.h>
28#include <stdio.h>
29#include <string.h>
Doug Zongkercfd256a2011-04-22 09:26:44 -070030#include <sys/stat.h>
31#include <unistd.h>
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -080032
Dees_Troy1669f892013-09-04 18:35:08 +000033static char device_type = 'e'; // e for emmc or m for mtd, default is emmc
34static char device_name[256];
35
36/*
Doug Zongkercc8cd3f2010-09-20 12:16:13 -070037static int get_bootloader_message_mtd(struct bootloader_message *out, const Volume* v);
38static int set_bootloader_message_mtd(const struct bootloader_message *in, const Volume* v);
39static int get_bootloader_message_block(struct bootloader_message *out, const Volume* v);
40static int set_bootloader_message_block(const struct bootloader_message *in, const Volume* v);
Dees_Troy1669f892013-09-04 18:35:08 +000041*/
Doug Zongkercc8cd3f2010-09-20 12:16:13 -070042int get_bootloader_message(struct bootloader_message *out) {
Dees_Troy1669f892013-09-04 18:35:08 +000043 //volume_for_path("/misc");
44 if (device_name[0] == 0) {
Adam Blissb2ceb692011-07-13 15:13:54 -070045 LOGE("Cannot load volume /misc!\n");
46 return -1;
47 }
Dees_Troy1669f892013-09-04 18:35:08 +000048 if (device_type == 'm') {
49 return get_bootloader_message_mtd_name(out);
50 } else if (device_type == 'e') {
51 return get_bootloader_message_block_name(out);
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -080052 }
Dees_Troy1669f892013-09-04 18:35:08 +000053 LOGE("unknown misc partition fs_type \"%c\"\n", device_type);
Doug Zongkercc8cd3f2010-09-20 12:16:13 -070054 return -1;
Doug Zongker04611da2010-08-12 15:35:29 -070055}
56
Doug Zongkercc8cd3f2010-09-20 12:16:13 -070057int set_bootloader_message(const struct bootloader_message *in) {
Dees_Troy1669f892013-09-04 18:35:08 +000058 //volume_for_path("/misc");
59 if (device_name[0] == 0) {
Adam Blissb2ceb692011-07-13 15:13:54 -070060 LOGE("Cannot load volume /misc!\n");
61 return -1;
62 }
Dees_Troy1669f892013-09-04 18:35:08 +000063 if (device_type == 'm') {
64 return set_bootloader_message_mtd_name(in, device_name);
65 } else if (device_type == 'e') {
66 return set_bootloader_message_block_name(in, device_name);
Doug Zongker04611da2010-08-12 15:35:29 -070067 }
Dees_Troy1669f892013-09-04 18:35:08 +000068 LOGE("unknown misc partition type \"%c\"\n", device_type);
Doug Zongkercc8cd3f2010-09-20 12:16:13 -070069 return -1;
Doug Zongker04611da2010-08-12 15:35:29 -070070}
71
Doug Zongkercc8cd3f2010-09-20 12:16:13 -070072// ------------------------------
73// for misc partitions on MTD
74// ------------------------------
Doug Zongker04611da2010-08-12 15:35:29 -070075
76static const int MISC_PAGES = 3; // number of pages to save
77static const int MISC_COMMAND_PAGE = 1; // bootloader command is this page
Dees_Troy1669f892013-09-04 18:35:08 +000078/*
Doug Zongkercc8cd3f2010-09-20 12:16:13 -070079static int get_bootloader_message_mtd(struct bootloader_message *out,
80 const Volume* v) {
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -080081 size_t write_size;
Doug Zongkercc8cd3f2010-09-20 12:16:13 -070082 mtd_scan_partitions();
Ken Sumrallf35d1ce2013-02-13 12:59:35 -080083 const MtdPartition *part = mtd_find_partition_by_name(v->blk_device);
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -080084 if (part == NULL || mtd_partition_info(part, NULL, NULL, &write_size)) {
Ken Sumrallf35d1ce2013-02-13 12:59:35 -080085 LOGE("Can't find %s\n", v->blk_device);
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -080086 return -1;
87 }
88
89 MtdReadContext *read = mtd_read_partition(part);
90 if (read == NULL) {
Ken Sumrallf35d1ce2013-02-13 12:59:35 -080091 LOGE("Can't open %s\n(%s)\n", v->blk_device, strerror(errno));
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -080092 return -1;
93 }
94
95 const ssize_t size = write_size * MISC_PAGES;
96 char data[size];
97 ssize_t r = mtd_read_data(read, data, size);
Ken Sumrallf35d1ce2013-02-13 12:59:35 -080098 if (r != size) LOGE("Can't read %s\n(%s)\n", v->blk_device, strerror(errno));
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -080099 mtd_read_close(read);
100 if (r != size) return -1;
101
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -0800102 memcpy(out, &data[write_size * MISC_COMMAND_PAGE], sizeof(*out));
103 return 0;
104}
Doug Zongkercc8cd3f2010-09-20 12:16:13 -0700105static int set_bootloader_message_mtd(const struct bootloader_message *in,
106 const Volume* v) {
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -0800107 size_t write_size;
Doug Zongkercc8cd3f2010-09-20 12:16:13 -0700108 mtd_scan_partitions();
Ken Sumrallf35d1ce2013-02-13 12:59:35 -0800109 const MtdPartition *part = mtd_find_partition_by_name(v->blk_device);
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -0800110 if (part == NULL || mtd_partition_info(part, NULL, NULL, &write_size)) {
Ken Sumrallf35d1ce2013-02-13 12:59:35 -0800111 LOGE("Can't find %s\n", v->blk_device);
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -0800112 return -1;
113 }
114
115 MtdReadContext *read = mtd_read_partition(part);
116 if (read == NULL) {
Ken Sumrallf35d1ce2013-02-13 12:59:35 -0800117 LOGE("Can't open %s\n(%s)\n", v->blk_device, strerror(errno));
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -0800118 return -1;
119 }
120
121 ssize_t size = write_size * MISC_PAGES;
122 char data[size];
123 ssize_t r = mtd_read_data(read, data, size);
Ken Sumrallf35d1ce2013-02-13 12:59:35 -0800124 if (r != size) LOGE("Can't read %s\n(%s)\n", v->blk_device, strerror(errno));
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -0800125 mtd_read_close(read);
126 if (r != size) return -1;
127
128 memcpy(&data[write_size * MISC_COMMAND_PAGE], in, sizeof(*in));
129
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -0800130 MtdWriteContext *write = mtd_write_partition(part);
131 if (write == NULL) {
Ken Sumrallf35d1ce2013-02-13 12:59:35 -0800132 LOGE("Can't open %s\n(%s)\n", v->blk_device, strerror(errno));
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -0800133 return -1;
134 }
135 if (mtd_write_data(write, data, size) != size) {
Ken Sumrallf35d1ce2013-02-13 12:59:35 -0800136 LOGE("Can't write %s\n(%s)\n", v->blk_device, strerror(errno));
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -0800137 mtd_write_close(write);
138 return -1;
139 }
140 if (mtd_write_close(write)) {
Ken Sumrallf35d1ce2013-02-13 12:59:35 -0800141 LOGE("Can't finish %s\n(%s)\n", v->blk_device, strerror(errno));
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -0800142 return -1;
143 }
144
145 LOGI("Set boot command \"%s\"\n", in->command[0] != 255 ? in->command : "");
146 return 0;
147}
Dees_Troy1669f892013-09-04 18:35:08 +0000148*/
Doug Zongker04611da2010-08-12 15:35:29 -0700149
Dees_Troy1669f892013-09-04 18:35:08 +0000150void set_device_type(char new_type) {
151 device_type = new_type;
152}
153
154void set_device_name(const char* new_name) {
155 if (strlen(new_name) >= sizeof(device_name)) {
156 LOGE("New device name of '%s' is too large for bootloader.cpp\n", new_name);
157 } else {
158 strcpy(device_name, new_name);
159 }
160}
161
162int get_bootloader_message_mtd_name(struct bootloader_message *out) {
163 size_t write_size;
164 mtd_scan_partitions();
165 const MtdPartition *part = mtd_find_partition_by_name(device_name);
166 if (part == NULL || mtd_partition_info(part, NULL, NULL, &write_size)) {
167 LOGE("Can't find %s\n", device_name);
168 return -1;
169 }
170
171 MtdReadContext *read = mtd_read_partition(part);
172 if (read == NULL) {
173 LOGE("Can't open %s\n(%s)\n", device_name, strerror(errno));
174 return -1;
175 }
176
177 const ssize_t size = write_size * MISC_PAGES;
178 char data[size];
179 ssize_t r = mtd_read_data(read, data, size);
180 if (r != size) LOGE("Can't read %s\n(%s)\n", device_name, strerror(errno));
181 mtd_read_close(read);
182 if (r != size) return -1;
183
184 memcpy(out, &data[write_size * MISC_COMMAND_PAGE], sizeof(*out));
185 return 0;
186}
Doug Zongker04611da2010-08-12 15:35:29 -0700187
Dees_Troy2673cec2013-04-02 20:22:16 +0000188int set_bootloader_message_mtd_name(const struct bootloader_message *in,
189 const char* mtd_name) {
190 size_t write_size;
191 mtd_scan_partitions();
192 const MtdPartition *part = mtd_find_partition_by_name(mtd_name);
193 if (part == NULL || mtd_partition_info(part, NULL, NULL, &write_size)) {
194 printf("Can't find %s\n", mtd_name);
195 return -1;
196 }
197
198 MtdReadContext *read = mtd_read_partition(part);
199 if (read == NULL) {
200 printf("Can't open %s\n(%s)\n", mtd_name, strerror(errno));
201 return -1;
202 }
203
204 ssize_t size = write_size * MISC_PAGES;
205 char data[size];
206 ssize_t r = mtd_read_data(read, data, size);
207 if (r != size) printf("Can't read %s\n(%s)\n", mtd_name, strerror(errno));
208 mtd_read_close(read);
209 if (r != size) return -1;
210
211 memcpy(&data[write_size * MISC_COMMAND_PAGE], in, sizeof(*in));
212
213 MtdWriteContext *write = mtd_write_partition(part);
214 if (write == NULL) {
215 printf("Can't open %s\n(%s)\n", mtd_name, strerror(errno));
216 return -1;
217 }
218 if (mtd_write_data(write, data, size) != size) {
219 printf("Can't write %s\n(%s)\n", mtd_name, strerror(errno));
220 mtd_write_close(write);
221 return -1;
222 }
223 if (mtd_write_close(write)) {
224 printf("Can't finish %s\n(%s)\n", mtd_name, strerror(errno));
225 return -1;
226 }
227
228 printf("Set boot command \"%s\"\n", in->command[0] != 255 ? in->command : "");
229 return 0;
230}
Doug Zongkercc8cd3f2010-09-20 12:16:13 -0700231
232// ------------------------------------
233// for misc partitions on block devices
234// ------------------------------------
235
Doug Zongkercfd256a2011-04-22 09:26:44 -0700236static void wait_for_device(const char* fn) {
237 int tries = 0;
238 int ret;
239 struct stat buf;
240 do {
241 ++tries;
242 ret = stat(fn, &buf);
243 if (ret) {
244 printf("stat %s try %d: %s\n", fn, tries, strerror(errno));
245 sleep(1);
246 }
247 } while (ret && tries < 10);
248 if (ret) {
249 printf("failed to stat %s\n", fn);
250 }
251}
Dees_Troy1669f892013-09-04 18:35:08 +0000252/*
Doug Zongkercc8cd3f2010-09-20 12:16:13 -0700253static int get_bootloader_message_block(struct bootloader_message *out,
254 const Volume* v) {
Ken Sumrallf35d1ce2013-02-13 12:59:35 -0800255 wait_for_device(v->blk_device);
256 FILE* f = fopen(v->blk_device, "rb");
Doug Zongkercc8cd3f2010-09-20 12:16:13 -0700257 if (f == NULL) {
Ken Sumrallf35d1ce2013-02-13 12:59:35 -0800258 LOGE("Can't open %s\n(%s)\n", v->blk_device, strerror(errno));
Doug Zongkercc8cd3f2010-09-20 12:16:13 -0700259 return -1;
260 }
261 struct bootloader_message temp;
262 int count = fread(&temp, sizeof(temp), 1, f);
263 if (count != 1) {
Ken Sumrallf35d1ce2013-02-13 12:59:35 -0800264 LOGE("Failed reading %s\n(%s)\n", v->blk_device, strerror(errno));
Doug Zongkercc8cd3f2010-09-20 12:16:13 -0700265 return -1;
266 }
267 if (fclose(f) != 0) {
Ken Sumrallf35d1ce2013-02-13 12:59:35 -0800268 LOGE("Failed closing %s\n(%s)\n", v->blk_device, strerror(errno));
Doug Zongkercc8cd3f2010-09-20 12:16:13 -0700269 return -1;
270 }
271 memcpy(out, &temp, sizeof(temp));
272 return 0;
273}
274
275static int set_bootloader_message_block(const struct bootloader_message *in,
276 const Volume* v) {
Ken Sumrallf35d1ce2013-02-13 12:59:35 -0800277 wait_for_device(v->blk_device);
278 FILE* f = fopen(v->blk_device, "wb");
Doug Zongkercc8cd3f2010-09-20 12:16:13 -0700279 if (f == NULL) {
Ken Sumrallf35d1ce2013-02-13 12:59:35 -0800280 LOGE("Can't open %s\n(%s)\n", v->blk_device, strerror(errno));
Doug Zongkercc8cd3f2010-09-20 12:16:13 -0700281 return -1;
282 }
283 int count = fwrite(in, sizeof(*in), 1, f);
284 if (count != 1) {
Ken Sumrallf35d1ce2013-02-13 12:59:35 -0800285 LOGE("Failed writing %s\n(%s)\n", v->blk_device, strerror(errno));
Doug Zongkercc8cd3f2010-09-20 12:16:13 -0700286 return -1;
287 }
288 if (fclose(f) != 0) {
Ken Sumrallf35d1ce2013-02-13 12:59:35 -0800289 LOGE("Failed closing %s\n(%s)\n", v->blk_device, strerror(errno));
Doug Zongkercc8cd3f2010-09-20 12:16:13 -0700290 return -1;
291 }
292 return 0;
293}
Dees_Troy1669f892013-09-04 18:35:08 +0000294*/
295
296int get_bootloader_message_block_name(struct bootloader_message *out) {
297 wait_for_device(device_name);
298 FILE* f = fopen(device_name, "rb");
299 if (f == NULL) {
300 LOGE("Can't open %s\n(%s)\n", device_name, strerror(errno));
301 return -1;
302 }
303 struct bootloader_message temp;
304 int count = fread(&temp, sizeof(temp), 1, f);
305 if (count != 1) {
306 LOGE("Failed reading %s\n(%s)\n", device_name, strerror(errno));
307 return -1;
308 }
309 if (fclose(f) != 0) {
310 LOGE("Failed closing %s\n(%s)\n", device_name, strerror(errno));
311 return -1;
312 }
313 memcpy(out, &temp, sizeof(temp));
314 return 0;
315}
Dees_Troy2673cec2013-04-02 20:22:16 +0000316
317int set_bootloader_message_block_name(const struct bootloader_message *in,
318 const char* block_name) {
319 wait_for_device(block_name);
320 FILE* f = fopen(block_name, "wb");
321 if (f == NULL) {
322 printf("Can't open %s\n(%s)\n", block_name, strerror(errno));
323 return -1;
324 }
325 int count = fwrite(in, sizeof(*in), 1, f);
326 if (count != 1) {
327 printf("Failed writing %s\n(%s)\n", block_name, strerror(errno));
328 return -1;
329 }
330 if (fclose(f) != 0) {
331 printf("Failed closing %s\n(%s)\n", block_name, strerror(errno));
332 return -1;
333 }
334 return 0;
335}
Dees_Troya449a6f2013-04-07 17:50:11 -0500336
337static const char *COMMAND_FILE = "/cache/recovery/command";
338static const int MAX_ARG_LENGTH = 4096;
339static const int MAX_ARGS = 100;
340
341// command line args come from, in decreasing precedence:
342// - the actual command line
343// - the bootloader control block (one per line, after "recovery")
344// - the contents of COMMAND_FILE (one per line)
345void
346get_args(int *argc, char ***argv) {
347 struct bootloader_message boot;
348 memset(&boot, 0, sizeof(boot));
349 get_bootloader_message(&boot); // this may fail, leaving a zeroed structure
350
351 if (boot.command[0] != 0 && boot.command[0] != 255) {
352 LOGI("Boot command: %.*s\n", sizeof(boot.command), boot.command);
353 }
354
355 if (boot.status[0] != 0 && boot.status[0] != 255) {
356 LOGI("Boot status: %.*s\n", sizeof(boot.status), boot.status);
357 }
358
359 // --- if arguments weren't supplied, look in the bootloader control block
360 if (*argc <= 1) {
361 boot.recovery[sizeof(boot.recovery) - 1] = '\0'; // Ensure termination
362 const char *arg = strtok(boot.recovery, "\n");
363 if (arg != NULL && !strcmp(arg, "recovery")) {
364 *argv = (char **) malloc(sizeof(char *) * MAX_ARGS);
365 (*argv)[0] = strdup(arg);
366 for (*argc = 1; *argc < MAX_ARGS; ++*argc) {
367 if ((arg = strtok(NULL, "\n")) == NULL) break;
368 (*argv)[*argc] = strdup(arg);
369 }
370 LOGI("Got arguments from boot message\n");
371 } else if (boot.recovery[0] != 0 && boot.recovery[0] != 255) {
372 LOGE("Bad boot message\n\"%.20s\"\n", boot.recovery);
373 }
374 }
375
376 // --- if that doesn't work, try the command file
377 if (*argc <= 1) {
378 FILE *fp = fopen(COMMAND_FILE, "r");
379 if (fp != NULL) {
380 char *argv0 = (*argv)[0];
381 *argv = (char **) malloc(sizeof(char *) * MAX_ARGS);
382 (*argv)[0] = argv0; // use the same program name
383
384 char buf[MAX_ARG_LENGTH];
385 for (*argc = 1; *argc < MAX_ARGS; ++*argc) {
386 if (!fgets(buf, sizeof(buf), fp)) break;
387 (*argv)[*argc] = strdup(strtok(buf, "\r\n")); // Strip newline.
388 }
389
390 fflush(fp);
391 if (ferror(fp)) LOGE("Error in %s\n(%s)\n", COMMAND_FILE, strerror(errno));
392 fclose(fp);
393 LOGI("Got arguments from %s\n", COMMAND_FILE);
394 }
395 }
396
397 // --> write the arguments we have back into the bootloader control block
398 // always boot into recovery after this (until finish_recovery() is called)
399 strlcpy(boot.command, "boot-recovery", sizeof(boot.command));
400 strlcpy(boot.recovery, "recovery\n", sizeof(boot.recovery));
401 int i;
402 for (i = 1; i < *argc; ++i) {
403 strlcat(boot.recovery, (*argv)[i], sizeof(boot.recovery));
404 strlcat(boot.recovery, "\n", sizeof(boot.recovery));
405 }
406 set_bootloader_message(&boot);
407}