1 /* 2 * Copyright (C) 2015 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 18 #include <errno.h> 19 #include <fcntl.h> 20 #include <linux/fs.h> 21 #include <sys/ioctl.h> 22 #include <sys/stat.h> 23 #include <sys/types.h> 24 #include <unistd.h> 25 26 #include <arpa/inet.h> 27 #include <stdio.h> 28 #include <stdlib.h> 29 #include <string.h> 30 31 #include <cutils/properties.h> 32 #include <fs_mgr.h> 33 34 #include "bootinfo.h" 35 36 using android::fs_mgr::Fstab; 37 using android::fs_mgr::GetEntryForMountPoint; 38 using android::fs_mgr::ReadDefaultFstab; 39 using android::fs_mgr::ReadFstabFromFile; 40 41 // Open the appropriate fstab file and fallback to /fstab.device if 42 // that's what's being used. 43 static bool open_fstab(Fstab* fstab) 44 { 45 return ReadDefaultFstab(fstab) || ReadFstabFromFile("/fstab.device", fstab); 46 } 47 48 int boot_info_open_partition(const char *name, uint64_t *out_size, int flags) 49 { 50 char *path; 51 int fd; 52 53 // We can't use fs_mgr to look up |name| because fstab doesn't list 54 // every slot partition (it uses the slotselect option to mask the 55 // suffix) and |slot| is expected to be of that form, e.g. boot_a. 56 // 57 // We can however assume that there's an entry for the /misc mount 58 // point and use that to get the device file for the misc 59 // partition. From there we'll assume that a by-name scheme is used 60 // so we can just replace the trailing "misc" by the given |name|, 61 // e.g. 62 // 63 // /dev/block/platform/soc.0/7824900.sdhci/by-name/misc -> 64 // /dev/block/platform/soc.0/7824900.sdhci/by-name/boot_a 65 // 66 // If needed, it's possible to relax this assumption in the future 67 // by trawling /sys/block looking for the appropriate sibling of 68 // misc and then finding an entry in /dev matching the sysfs entry. 69 70 Fstab fstab; 71 if (!open_fstab(&fstab)) { 72 return -1; 73 } 74 auto record = GetEntryForMountPoint(&fstab, "/misc"); 75 if (record == nullptr) { 76 return -1; 77 } 78 if (strcmp(name, "misc") == 0) { 79 path = strdup(record->blk_device.c_str()); 80 } else { 81 size_t trimmed_len, name_len; 82 const char *end_slash = strrchr(record->blk_device.c_str(), '/'); 83 if (end_slash == NULL) { 84 return -1; 85 } 86 trimmed_len = end_slash - record->blk_device.c_str() + 1; 87 name_len = strlen(name); 88 path = static_cast<char *>(calloc(trimmed_len + name_len + 1, 1)); 89 strncpy(path, record->blk_device.c_str(), trimmed_len); 90 strncpy(path + trimmed_len, name, name_len); 91 } 92 93 fd = open(path, flags); 94 free(path); 95 96 // If we successfully opened the device, get size if requested. 97 if (fd != -1 && out_size != NULL) { 98 if (ioctl(fd, BLKGETSIZE64, out_size) != 0) { 99 close(fd); 100 return -1; 101 } 102 } 103 104 return fd; 105 } 106 107 // As per struct bootloader_message_ab which is defined in 108 // boot/1.1/default. 109 // struct bootloader_message_ab { 110 // struct bootloader_message message; 111 // char slot_suffix[32]; 112 // char update_channel[128]; 113 // 114 // // Round up the entire struct to 4096-byte. 115 // char reserved[1888]; 116 // }; 117 // 118 // We can use the 32 bytes in the bootctrl_suffix field provided that they 119 // start with the active slot suffix terminated by NUL. It just so happens 120 // that BrilloBootInfo is laid out this way. 121 #define BOOTINFO_OFFSET 2048 122 123 bool boot_info_load(BrilloBootInfo *out_info) 124 { 125 int fd; 126 127 memset(out_info, '\0', sizeof(BrilloBootInfo)); 128 129 fd = boot_info_open_partition("misc", NULL, O_RDONLY); 130 if (fd == -1) 131 return false; 132 if (lseek(fd, BOOTINFO_OFFSET, SEEK_SET) != BOOTINFO_OFFSET) { 133 close(fd); 134 return false; 135 } 136 ssize_t num_read; 137 do { 138 num_read = read(fd, (void*) out_info, sizeof(BrilloBootInfo)); 139 } while (num_read == -1 && errno == EINTR); 140 close(fd); 141 if (num_read != sizeof(BrilloBootInfo)) 142 return false; 143 return true; 144 } 145 146 bool boot_info_save(BrilloBootInfo *info) 147 { 148 int fd; 149 150 fd = boot_info_open_partition("misc", NULL, O_RDWR); 151 if (fd == -1) 152 return false; 153 if (lseek(fd, BOOTINFO_OFFSET, SEEK_SET) != BOOTINFO_OFFSET) { 154 close(fd); 155 return false; 156 } 157 ssize_t num_written; 158 do { 159 num_written = write(fd, (void*) info, sizeof(BrilloBootInfo)); 160 } while (num_written == -1 && errno == EINTR); 161 close(fd); 162 if (num_written != sizeof(BrilloBootInfo)) 163 return false; 164 return true; 165 } 166 167 bool boot_info_validate(BrilloBootInfo* info) 168 { 169 if (info->magic[0] != 'B' || 170 info->magic[1] != 'C' || 171 info->magic[2] != 'c') 172 return false; 173 if (info->active_slot >= 2) 174 return false; 175 return true; 176 } 177 178 void boot_info_reset(BrilloBootInfo* info) 179 { 180 memset(info, '\0', sizeof(BrilloBootInfo)); 181 info->magic[0] = 'B'; 182 info->magic[1] = 'C'; 183 info->magic[2] = 'c'; 184 } 185