blob: f6c0e934124de805df091a4c6658a4b5a942e9f0 [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
Tao Baobd82b272016-01-21 13:49:03 -080017#include <errno.h>
18#include <fcntl.h>
19#include <inttypes.h>
20#include <stdio.h>
21#include <string.h>
22#include <sys/stat.h>
23#include <sys/types.h>
24#include <unistd.h>
25
Ken Sumrallf35d1ce2013-02-13 12:59:35 -080026#include <fs_mgr.h>
Tao Baobd82b272016-01-21 13:49:03 -080027
Yabin Cui6faf0262016-06-09 14:09:39 -070028#include <android-base/file.h>
29
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -080030#include "bootloader.h"
31#include "common.h"
32#include "mtdutils/mtdutils.h"
33#include "roots.h"
Tao Baobd82b272016-01-21 13:49:03 -080034#include "unique_fd.h"
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -080035
Tao Baobd82b272016-01-21 13:49:03 -080036static int get_bootloader_message_mtd(bootloader_message* out, const Volume* v);
37static int set_bootloader_message_mtd(const bootloader_message* in, const Volume* v);
Yabin Cui6faf0262016-06-09 14:09:39 -070038static bool read_misc_partition(const Volume* v, size_t offset, size_t size, std::string* out);
39static bool write_misc_partition(const Volume* v, size_t offset, const std::string& in);
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -080040
Tao Baobd82b272016-01-21 13:49:03 -080041int get_bootloader_message(bootloader_message* out) {
Doug Zongkercc8cd3f2010-09-20 12:16:13 -070042 Volume* v = volume_for_path("/misc");
Tao Baobd82b272016-01-21 13:49:03 -080043 if (v == nullptr) {
44 LOGE("Cannot load volume /misc!\n");
45 return -1;
Adam Blissb2ceb692011-07-13 15:13:54 -070046 }
Doug Zongkercc8cd3f2010-09-20 12:16:13 -070047 if (strcmp(v->fs_type, "mtd") == 0) {
48 return get_bootloader_message_mtd(out, v);
49 } else if (strcmp(v->fs_type, "emmc") == 0) {
Yabin Cui6faf0262016-06-09 14:09:39 -070050 std::string s;
51 if (!read_misc_partition(v, BOOTLOADER_MESSAGE_OFFSET_IN_MISC, sizeof(bootloader_message),
52 &s)) {
53 return -1;
54 }
55 memcpy(out, s.data(), s.size());
56 return 0;
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -080057 }
Yabin Cui6faf0262016-06-09 14:09:39 -070058 LOGE("Unknown misc partition fs_type \"%s\"\n", v->fs_type);
Doug Zongkercc8cd3f2010-09-20 12:16:13 -070059 return -1;
Doug Zongker04611da2010-08-12 15:35:29 -070060}
61
Yabin Cui6faf0262016-06-09 14:09:39 -070062bool read_wipe_package(size_t size, std::string* out) {
63 Volume* v = volume_for_path("/misc");
64 if (v == nullptr) {
65 LOGE("Cannot load volume /misc!\n");
66 return false;
67 }
68 if (strcmp(v->fs_type, "mtd") == 0) {
69 LOGE("Read wipe package on mtd is not supported.\n");
70 return false;
71 } else if (strcmp(v->fs_type, "emmc") == 0) {
72 return read_misc_partition(v, WIPE_PACKAGE_OFFSET_IN_MISC, size, out);
73 }
74 LOGE("Unknown misc partition fs_type \"%s\"\n", v->fs_type);
75 return false;
76}
77
Tao Baobd82b272016-01-21 13:49:03 -080078int set_bootloader_message(const bootloader_message* in) {
Doug Zongkercc8cd3f2010-09-20 12:16:13 -070079 Volume* v = volume_for_path("/misc");
Tao Baobd82b272016-01-21 13:49:03 -080080 if (v == nullptr) {
81 LOGE("Cannot load volume /misc!\n");
82 return -1;
Adam Blissb2ceb692011-07-13 15:13:54 -070083 }
Doug Zongkercc8cd3f2010-09-20 12:16:13 -070084 if (strcmp(v->fs_type, "mtd") == 0) {
85 return set_bootloader_message_mtd(in, v);
86 } else if (strcmp(v->fs_type, "emmc") == 0) {
Yabin Cui6faf0262016-06-09 14:09:39 -070087 std::string s(reinterpret_cast<const char*>(in), sizeof(*in));
88 bool success = write_misc_partition(v, BOOTLOADER_MESSAGE_OFFSET_IN_MISC, s);
89 return success ? 0 : -1;
Doug Zongker04611da2010-08-12 15:35:29 -070090 }
Yabin Cui6faf0262016-06-09 14:09:39 -070091 LOGE("Unknown misc partition fs_type \"%s\"\n", v->fs_type);
Doug Zongkercc8cd3f2010-09-20 12:16:13 -070092 return -1;
Doug Zongker04611da2010-08-12 15:35:29 -070093}
94
Doug Zongkercc8cd3f2010-09-20 12:16:13 -070095// ------------------------------
96// for misc partitions on MTD
97// ------------------------------
Doug Zongker04611da2010-08-12 15:35:29 -070098
99static const int MISC_PAGES = 3; // number of pages to save
100static const int MISC_COMMAND_PAGE = 1; // bootloader command is this page
101
Tao Baobd82b272016-01-21 13:49:03 -0800102static int get_bootloader_message_mtd(bootloader_message* out,
Doug Zongkercc8cd3f2010-09-20 12:16:13 -0700103 const Volume* v) {
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -0800104 size_t write_size;
Doug Zongkercc8cd3f2010-09-20 12:16:13 -0700105 mtd_scan_partitions();
Tao Baobd82b272016-01-21 13:49:03 -0800106 const MtdPartition* part = mtd_find_partition_by_name(v->blk_device);
107 if (part == nullptr || mtd_partition_info(part, nullptr, nullptr, &write_size)) {
108 LOGE("failed to find \"%s\"\n", v->blk_device);
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -0800109 return -1;
110 }
111
Tao Baobd82b272016-01-21 13:49:03 -0800112 MtdReadContext* read = mtd_read_partition(part);
113 if (read == nullptr) {
114 LOGE("failed to open \"%s\": %s\n", v->blk_device, strerror(errno));
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -0800115 return -1;
116 }
117
118 const ssize_t size = write_size * MISC_PAGES;
119 char data[size];
120 ssize_t r = mtd_read_data(read, data, size);
Tao Baobd82b272016-01-21 13:49:03 -0800121 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 -0800122 mtd_read_close(read);
123 if (r != size) return -1;
124
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -0800125 memcpy(out, &data[write_size * MISC_COMMAND_PAGE], sizeof(*out));
126 return 0;
127}
Tao Baobd82b272016-01-21 13:49:03 -0800128static int set_bootloader_message_mtd(const bootloader_message* in,
Doug Zongkercc8cd3f2010-09-20 12:16:13 -0700129 const Volume* v) {
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -0800130 size_t write_size;
Doug Zongkercc8cd3f2010-09-20 12:16:13 -0700131 mtd_scan_partitions();
Tao Baobd82b272016-01-21 13:49:03 -0800132 const MtdPartition* part = mtd_find_partition_by_name(v->blk_device);
133 if (part == nullptr || mtd_partition_info(part, nullptr, nullptr, &write_size)) {
134 LOGE("failed to find \"%s\"\n", v->blk_device);
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -0800135 return -1;
136 }
137
Tao Baobd82b272016-01-21 13:49:03 -0800138 MtdReadContext* read = mtd_read_partition(part);
139 if (read == nullptr) {
140 LOGE("failed to open \"%s\": %s\n", v->blk_device, strerror(errno));
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -0800141 return -1;
142 }
143
144 ssize_t size = write_size * MISC_PAGES;
145 char data[size];
146 ssize_t r = mtd_read_data(read, data, size);
Tao Baobd82b272016-01-21 13:49:03 -0800147 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 -0800148 mtd_read_close(read);
149 if (r != size) return -1;
150
151 memcpy(&data[write_size * MISC_COMMAND_PAGE], in, sizeof(*in));
152
Tao Baobd82b272016-01-21 13:49:03 -0800153 MtdWriteContext* write = mtd_write_partition(part);
154 if (write == nullptr) {
155 LOGE("failed to open \"%s\": %s\n", v->blk_device, strerror(errno));
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -0800156 return -1;
157 }
158 if (mtd_write_data(write, data, size) != size) {
Tao Baobd82b272016-01-21 13:49:03 -0800159 LOGE("failed to write \"%s\": %s\n", v->blk_device, strerror(errno));
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -0800160 mtd_write_close(write);
161 return -1;
162 }
163 if (mtd_write_close(write)) {
Tao Baobd82b272016-01-21 13:49:03 -0800164 LOGE("failed to finish \"%s\": %s\n", v->blk_device, strerror(errno));
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -0800165 return -1;
166 }
167
168 LOGI("Set boot command \"%s\"\n", in->command[0] != 255 ? in->command : "");
169 return 0;
170}
Doug Zongker04611da2010-08-12 15:35:29 -0700171
Doug Zongkercc8cd3f2010-09-20 12:16:13 -0700172
173// ------------------------------------
174// for misc partitions on block devices
175// ------------------------------------
176
Doug Zongkercfd256a2011-04-22 09:26:44 -0700177static void wait_for_device(const char* fn) {
178 int tries = 0;
179 int ret;
Doug Zongkercfd256a2011-04-22 09:26:44 -0700180 do {
181 ++tries;
Tao Baobd82b272016-01-21 13:49:03 -0800182 struct stat buf;
Doug Zongkercfd256a2011-04-22 09:26:44 -0700183 ret = stat(fn, &buf);
Tao Baobd82b272016-01-21 13:49:03 -0800184 if (ret == -1) {
185 printf("failed to stat \"%s\" try %d: %s\n", fn, tries, strerror(errno));
Doug Zongkercfd256a2011-04-22 09:26:44 -0700186 sleep(1);
187 }
188 } while (ret && tries < 10);
Tao Baobd82b272016-01-21 13:49:03 -0800189
Doug Zongkercfd256a2011-04-22 09:26:44 -0700190 if (ret) {
Tao Baobd82b272016-01-21 13:49:03 -0800191 printf("failed to stat \"%s\"\n", fn);
Doug Zongkercfd256a2011-04-22 09:26:44 -0700192 }
193}
194
Yabin Cui6faf0262016-06-09 14:09:39 -0700195static bool read_misc_partition(const Volume* v, size_t offset, size_t size, std::string* out) {
Ken Sumrallf35d1ce2013-02-13 12:59:35 -0800196 wait_for_device(v->blk_device);
Yabin Cui6faf0262016-06-09 14:09:39 -0700197 unique_fd fd(open(v->blk_device, O_RDONLY));
198 if (fd.get() == -1) {
199 LOGE("Failed to open \"%s\": %s\n", v->blk_device, strerror(errno));
200 return false;
Doug Zongkercc8cd3f2010-09-20 12:16:13 -0700201 }
Yabin Cui6faf0262016-06-09 14:09:39 -0700202 if (lseek(fd.get(), static_cast<off_t>(offset), SEEK_SET) != static_cast<off_t>(offset)) {
203 LOGE("Failed to lseek \"%s\": %s\n", v->blk_device, strerror(errno));
204 return false;
Doug Zongkercc8cd3f2010-09-20 12:16:13 -0700205 }
Yabin Cui6faf0262016-06-09 14:09:39 -0700206 out->resize(size);
207 if (!android::base::ReadFully(fd.get(), &(*out)[0], size)) {
208 LOGE("Failed to read \"%s\": %s\n", v->blk_device, strerror(errno));
209 return false;
Doug Zongkercc8cd3f2010-09-20 12:16:13 -0700210 }
Yabin Cui6faf0262016-06-09 14:09:39 -0700211 return true;
Doug Zongkercc8cd3f2010-09-20 12:16:13 -0700212}
213
Yabin Cui6faf0262016-06-09 14:09:39 -0700214static bool write_misc_partition(const Volume* v, size_t offset, const std::string& in) {
Ken Sumrallf35d1ce2013-02-13 12:59:35 -0800215 wait_for_device(v->blk_device);
Tao Baobd82b272016-01-21 13:49:03 -0800216 unique_fd fd(open(v->blk_device, O_WRONLY | O_SYNC));
217 if (fd.get() == -1) {
Yabin Cui6faf0262016-06-09 14:09:39 -0700218 LOGE("Failed to open \"%s\": %s\n", v->blk_device, strerror(errno));
219 return false;
Doug Zongkercc8cd3f2010-09-20 12:16:13 -0700220 }
Yabin Cui6faf0262016-06-09 14:09:39 -0700221 if (lseek(fd.get(), static_cast<off_t>(offset), SEEK_SET) != static_cast<off_t>(offset)) {
222 LOGE("Failed to lseek \"%s\": %s\n", v->blk_device, strerror(errno));
223 return false;
224 }
225 if (!android::base::WriteFully(fd.get(), in.data(), in.size())) {
226 LOGE("Failed to write \"%s\": %s\n", v->blk_device, strerror(errno));
227 return false;
Doug Zongkercc8cd3f2010-09-20 12:16:13 -0700228 }
Tao Baobd82b272016-01-21 13:49:03 -0800229
230 if (fsync(fd.get()) == -1) {
Yabin Cui6faf0262016-06-09 14:09:39 -0700231 LOGE("Failed to fsync \"%s\": %s\n", v->blk_device, strerror(errno));
232 return false;
Doug Zongkercc8cd3f2010-09-20 12:16:13 -0700233 }
Yabin Cui6faf0262016-06-09 14:09:39 -0700234 return true;
Doug Zongkercc8cd3f2010-09-20 12:16:13 -0700235}