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