1 /* 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 17 #include "bootloader.h" 18 #include "common.h" 19 #include "mtdutils/mtdutils.h" 20 #include "roots.h" 21 22 #include <errno.h> 23 #include <stdio.h> 24 #include <string.h> 25 #include <sys/stat.h> 26 #include <unistd.h> 27 28 static int get_bootloader_message_mtd(struct bootloader_message *out, const Volume* v); 29 static int set_bootloader_message_mtd(const struct bootloader_message *in, const Volume* v); 30 static int get_bootloader_message_block(struct bootloader_message *out, const Volume* v); 31 static int set_bootloader_message_block(const struct bootloader_message *in, const Volume* v); 32 33 int get_bootloader_message(struct bootloader_message *out) { 34 Volume* v = volume_for_path("/misc"); 35 if (v == NULL) { 36 LOGE("Cannot load volume /misc!\n"); 37 return -1; 38 } 39 if (strcmp(v->fs_type, "mtd") == 0) { 40 return get_bootloader_message_mtd(out, v); 41 } else if (strcmp(v->fs_type, "emmc") == 0) { 42 return get_bootloader_message_block(out, v); 43 } 44 LOGE("unknown misc partition fs_type \"%s\"\n", v->fs_type); 45 return -1; 46 } 47 48 int set_bootloader_message(const struct bootloader_message *in) { 49 Volume* v = volume_for_path("/misc"); 50 if (v == NULL) { 51 LOGE("Cannot load volume /misc!\n"); 52 return -1; 53 } 54 if (strcmp(v->fs_type, "mtd") == 0) { 55 return set_bootloader_message_mtd(in, v); 56 } else if (strcmp(v->fs_type, "emmc") == 0) { 57 return set_bootloader_message_block(in, v); 58 } 59 LOGE("unknown misc partition fs_type \"%s\"\n", v->fs_type); 60 return -1; 61 } 62 63 // ------------------------------ 64 // for misc partitions on MTD 65 // ------------------------------ 66 67 static const int MISC_PAGES = 3; // number of pages to save 68 static const int MISC_COMMAND_PAGE = 1; // bootloader command is this page 69 70 static int get_bootloader_message_mtd(struct bootloader_message *out, 71 const Volume* v) { 72 size_t write_size; 73 mtd_scan_partitions(); 74 const MtdPartition *part = mtd_find_partition_by_name(v->device); 75 if (part == NULL || mtd_partition_info(part, NULL, NULL, &write_size)) { 76 LOGE("Can't find %s\n", v->device); 77 return -1; 78 } 79 80 MtdReadContext *read = mtd_read_partition(part); 81 if (read == NULL) { 82 LOGE("Can't open %s\n(%s)\n", v->device, strerror(errno)); 83 return -1; 84 } 85 86 const ssize_t size = write_size * MISC_PAGES; 87 char data[size]; 88 ssize_t r = mtd_read_data(read, data, size); 89 if (r != size) LOGE("Can't read %s\n(%s)\n", v->device, strerror(errno)); 90 mtd_read_close(read); 91 if (r != size) return -1; 92 93 memcpy(out, &data[write_size * MISC_COMMAND_PAGE], sizeof(*out)); 94 return 0; 95 } 96 static int set_bootloader_message_mtd(const struct bootloader_message *in, 97 const Volume* v) { 98 size_t write_size; 99 mtd_scan_partitions(); 100 const MtdPartition *part = mtd_find_partition_by_name(v->device); 101 if (part == NULL || mtd_partition_info(part, NULL, NULL, &write_size)) { 102 LOGE("Can't find %s\n", v->device); 103 return -1; 104 } 105 106 MtdReadContext *read = mtd_read_partition(part); 107 if (read == NULL) { 108 LOGE("Can't open %s\n(%s)\n", v->device, strerror(errno)); 109 return -1; 110 } 111 112 ssize_t size = write_size * MISC_PAGES; 113 char data[size]; 114 ssize_t r = mtd_read_data(read, data, size); 115 if (r != size) LOGE("Can't read %s\n(%s)\n", v->device, strerror(errno)); 116 mtd_read_close(read); 117 if (r != size) return -1; 118 119 memcpy(&data[write_size * MISC_COMMAND_PAGE], in, sizeof(*in)); 120 121 MtdWriteContext *write = mtd_write_partition(part); 122 if (write == NULL) { 123 LOGE("Can't open %s\n(%s)\n", v->device, strerror(errno)); 124 return -1; 125 } 126 if (mtd_write_data(write, data, size) != size) { 127 LOGE("Can't write %s\n(%s)\n", v->device, strerror(errno)); 128 mtd_write_close(write); 129 return -1; 130 } 131 if (mtd_write_close(write)) { 132 LOGE("Can't finish %s\n(%s)\n", v->device, strerror(errno)); 133 return -1; 134 } 135 136 LOGI("Set boot command \"%s\"\n", in->command[0] != 255 ? in->command : ""); 137 return 0; 138 } 139 140 141 // ------------------------------------ 142 // for misc partitions on block devices 143 // ------------------------------------ 144 145 static void wait_for_device(const char* fn) { 146 int tries = 0; 147 int ret; 148 struct stat buf; 149 do { 150 ++tries; 151 ret = stat(fn, &buf); 152 if (ret) { 153 printf("stat %s try %d: %s\n", fn, tries, strerror(errno)); 154 sleep(1); 155 } 156 } while (ret && tries < 10); 157 if (ret) { 158 printf("failed to stat %s\n", fn); 159 } 160 } 161 162 static int get_bootloader_message_block(struct bootloader_message *out, 163 const Volume* v) { 164 wait_for_device(v->device); 165 FILE* f = fopen(v->device, "rb"); 166 if (f == NULL) { 167 LOGE("Can't open %s\n(%s)\n", v->device, strerror(errno)); 168 return -1; 169 } 170 struct bootloader_message temp; 171 int count = fread(&temp, sizeof(temp), 1, f); 172 if (count != 1) { 173 LOGE("Failed reading %s\n(%s)\n", v->device, strerror(errno)); 174 return -1; 175 } 176 if (fclose(f) != 0) { 177 LOGE("Failed closing %s\n(%s)\n", v->device, strerror(errno)); 178 return -1; 179 } 180 memcpy(out, &temp, sizeof(temp)); 181 return 0; 182 } 183 184 static int set_bootloader_message_block(const struct bootloader_message *in, 185 const Volume* v) { 186 wait_for_device(v->device); 187 FILE* f = fopen(v->device, "wb"); 188 if (f == NULL) { 189 LOGE("Can't open %s\n(%s)\n", v->device, strerror(errno)); 190 return -1; 191 } 192 int count = fwrite(in, sizeof(*in), 1, f); 193 if (count != 1) { 194 LOGE("Failed writing %s\n(%s)\n", v->device, strerror(errno)); 195 return -1; 196 } 197 if (fclose(f) != 0) { 198 LOGE("Failed closing %s\n(%s)\n", v->device, strerror(errno)); 199 return -1; 200 } 201 return 0; 202 } 203