1/* 2 * Copyright (c) 2021 Huawei Device Co., Ltd. 3 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * you may not use this file except in compliance with the License. 5 * You may obtain a copy of the License at 6 * 7 * http://www.apache.org/licenses/LICENSE-2.0 8 * 9 * Unless required by applicable law or agreed to in writing, software 10 * distributed under the License is distributed on an "AS IS" BASIS, 11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 * See the License for the specific language governing permissions and 13 * limitations under the License. 14 */ 15 16#include "applypatch/partition_record.h" 17#include <cerrno> 18#include <fcntl.h> 19#include <unistd.h> 20#include "fs_manager/mount.h" 21#include "log/log.h" 22#include "securec.h" 23 24namespace Updater { 25PartitionRecord &PartitionRecord::GetInstance() 26{ 27 static PartitionRecord partitionRecord; 28 return partitionRecord; 29} 30bool PartitionRecord::IsPartitionUpdated(const std::string &partitionName) 31{ 32 auto miscBlockDevice = GetMiscPartitionPath(); 33 uint8_t buffer[PARTITION_UPDATER_RECORD_MSG_SIZE]; 34 if (!miscBlockDevice.empty()) { 35 char *realPath = realpath(miscBlockDevice.c_str(), NULL); 36 if (realPath == nullptr) { 37 LOG(ERROR) << "realPath is NULL" << " : " << strerror(errno); 38 return false; 39 } 40 int fd = open(realPath, O_RDONLY | O_EXCL | O_CLOEXEC | O_BINARY); 41 free(realPath); 42 if (fd < 0) { 43 LOG(ERROR) << "PartitionRecord: Open misc to recording partition failed" << " : " << strerror(errno); 44 return false; 45 } 46 if (lseek(fd, PARTITION_RECORD_START, SEEK_CUR) < 0) { 47 LOG(ERROR) << "PartitionRecord: Seek misc to specific offset failed" << " : " << strerror(errno); 48 close(fd); 49 return false; 50 } 51 if (read(fd, buffer, PARTITION_UPDATER_RECORD_MSG_SIZE) != PARTITION_UPDATER_RECORD_MSG_SIZE) { 52 LOG(ERROR) << "PartitionRecord: Read from misc partition failed" << " : " << strerror(errno); 53 close(fd); 54 return false; 55 } 56 for (uint8_t *p = buffer; p < buffer + PARTITION_UPDATER_RECORD_MSG_SIZE; p += sizeof(PartitionRecordInfo)) { 57 PartitionRecordInfo *pri = reinterpret_cast<PartitionRecordInfo*>(p); 58 if (strcmp(pri->partitionName, partitionName.c_str()) == 0) { 59 LOG(DEBUG) << "PartitionRecord: Found " << partitionName << " record in misc partition"; 60 LOG(DEBUG) << "PartitionRecord: update status: " << pri->updated; 61 close(fd); 62 return pri->updated; 63 } 64 } 65 fsync(fd); 66 close(fd); 67 LOG(INFO) << "PartitionRecord: Cannot found " << partitionName << " record in misc partition"; 68 } 69 return false; 70} 71 72bool PartitionRecord::RecordPartitionSetOffset(int fd) 73{ 74 off_t newOffset = 0; 75 if (lseek(fd, PARTITION_RECORD_OFFSET, SEEK_SET) < 0) { 76 LOG(ERROR) << "PartitionRecord: Seek misc to record offset failed: " << strerror(errno); 77 return false; 78 } 79 if (read(fd, &newOffset, sizeof(off_t)) != static_cast<ssize_t>(sizeof(off_t))) { 80 LOG(ERROR) << "PartitionRecord: Read offset failed: " << strerror(errno); 81 return false; 82 } 83 offset_ = newOffset; 84 if (lseek(fd, PARTITION_RECORD_START + offset_, SEEK_SET) < 0) { 85 LOG(ERROR) << "PartitionRecord: Seek misc to specific offset failed: " << strerror(errno); 86 return false; 87 } 88 return true; 89} 90 91bool PartitionRecord::RecordPartitionSetInfo(const std::string &partitionName, bool updated, int fd) 92{ 93 (void)memset_s(&info_, sizeof(info_), 0, sizeof(info_)); 94 if (strncpy_s(info_.partitionName, PARTITION_NAME_LEN, partitionName.c_str(), PARTITION_NAME_LEN - 1) != EOK) { 95 LOG(ERROR) << "PartitionRecord: strncpy_s failed: " << strerror(errno); 96 return false; 97 } 98 info_.updated = updated; 99 if (write(fd, &info_, sizeof(PartitionRecordInfo)) != static_cast<ssize_t>(sizeof(PartitionRecordInfo))) { 100 LOG(ERROR) << "PartitionRecord: write failed: " << strerror(errno); 101 return false; 102 } 103 offset_ += static_cast<off_t>(sizeof(PartitionRecordInfo)); 104 if (lseek(fd, PARTITION_RECORD_OFFSET, SEEK_SET) < 0) { 105 LOG(ERROR) << "PartitionRecord: Seek misc to record offset failed: " << strerror(errno); 106 return false; 107 } 108 if (write(fd, &offset_, sizeof(off_t)) != static_cast<ssize_t>(sizeof(off_t))) { 109 LOG(ERROR) << "PartitionRecord: write misc to record offset failed: " << strerror(errno); 110 return false; 111 } 112 return true; 113} 114 115bool PartitionRecord::RecordPartitionUpdateStatus(const std::string &partitionName, bool updated) 116{ 117 auto miscBlockDevice = GetMiscPartitionPath(); 118 if (!miscBlockDevice.empty()) { 119 char *realPath = realpath(miscBlockDevice.c_str(), NULL); 120 if (realPath == nullptr) { 121 LOG(ERROR) << "realPath is NULL" << " : " << strerror(errno); 122 return false; 123 } 124 int fd = open(realPath, O_RDWR | O_EXCL | O_CLOEXEC | O_BINARY); 125 free(realPath); 126 if (fd < 0) { 127 LOG(ERROR) << "PartitionRecord: Open misc to recording partition failed" << " : " << strerror(errno); 128 return false; 129 } 130 if (!RecordPartitionSetOffset(fd)) { 131 close(fd); 132 return false; 133 } 134 if (offset_ + static_cast<off_t>(sizeof(PartitionRecordInfo)) < PARTITION_UPDATER_RECORD_SIZE) { 135 if (!RecordPartitionSetInfo(partitionName, updated, fd)) { 136 close(fd); 137 return false; 138 } 139 LOG(DEBUG) << "PartitionRecord: offset is " << offset_; 140 } else { 141 LOG(WARNING) << "PartitionRecord: partition record overflow, offset = " << offset_; 142 close(fd); 143 return false; 144 } 145 LOG(DEBUG) << "PartitionRecord: record " << partitionName << " successfully."; 146 fsync(fd); 147 close(fd); 148 } 149 return true; 150} 151 152bool PartitionRecord::ClearRecordPartitionOffset() 153{ 154 auto miscBlockDevice = GetMiscPartitionPath(); 155 if (!miscBlockDevice.empty()) { 156 int fd = open(miscBlockDevice.c_str(), O_RDWR | O_EXCL | O_CLOEXEC | O_BINARY); 157 if (fd < 0) { 158 LOG(ERROR) << "Open misc to recording partition failed" << " : " << strerror(errno); 159 return false; 160 } 161 if (lseek(fd, PARTITION_RECORD_OFFSET, SEEK_SET) < 0) { 162 LOG(ERROR) << "Seek misc to specific offset failed" << " : " << strerror(errno); 163 close(fd); 164 return false; 165 } 166 167 off_t initOffset = 0; 168 if (write(fd, &initOffset, sizeof(off_t)) != static_cast<ssize_t>(sizeof(off_t))) { 169 LOG(ERROR) << "StartUpdater: Write misc initOffset 0 failed" << " : " << strerror(errno); 170 close(fd); 171 return false; 172 } 173 fsync(fd); 174 close(fd); 175 } 176 return true; 177} 178 179std::string PartitionRecord::GetMiscPartitionPath(const std::string &misc) 180{ 181 auto miscBlockDevice = GetBlockDeviceByMountPoint(misc); 182 if (miscBlockDevice.empty()) { 183 LOG(WARNING) << "Can not find misc partition"; 184 } 185 return miscBlockDevice; 186} 187} // namespace Updater 188