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
24 namespace Updater {
GetInstance()25 PartitionRecord &PartitionRecord::GetInstance()
26 {
27 static PartitionRecord partitionRecord;
28 return partitionRecord;
29 }
IsPartitionUpdated(const std::string & partitionName)30 bool 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
RecordPartitionUpdateStatus(const std::string & partitionName,bool updated)72 bool PartitionRecord::RecordPartitionUpdateStatus(const std::string &partitionName, bool updated)
73 {
74 auto miscBlockDevice = GetMiscPartitionPath();
75 if (!miscBlockDevice.empty()) {
76 char *realPath = realpath(miscBlockDevice.c_str(), NULL);
77 if (realPath == nullptr) {
78 LOG(ERROR) << "realPath is NULL" << " : " << strerror(errno);
79 return false;
80 }
81 int fd = open(realPath, O_RDWR | O_EXCL | O_CLOEXEC | O_BINARY);
82 free(realPath);
83 if (fd < 0) {
84 LOG(ERROR) << "PartitionRecord: Open misc to recording partition failed" << " : " << strerror(errno);
85 return false;
86 }
87 off_t newOffset = 0;
88 UPDATER_CHECK_FILE_OP(lseek(fd, PARTITION_RECORD_OFFSET, SEEK_SET) >= 0,
89 "PartitionRecord: Seek misc to record offset failed", fd, return false);
90 UPDATER_CHECK_FILE_OP(read(fd, &newOffset, sizeof(off_t)) == static_cast<ssize_t>(sizeof(off_t)),
91 "PartitionRecord: Read offset failed", fd, return false);
92
93 offset_ = newOffset;
94 UPDATER_CHECK_FILE_OP(lseek(fd, PARTITION_RECORD_START + offset_, SEEK_SET) >= 0,
95 "PartitionRecord: Seek misc to specific offset failed", fd, return false);
96 if (offset_ + static_cast<off_t>(sizeof(PartitionRecordInfo)) < PARTITION_UPDATER_RECORD_SIZE) {
97 UPDATER_CHECK_FILE_OP(memset_s(&info_, sizeof(info_), 0, sizeof(info_)) == 0,
98 "PartitionRecord: clear partition info failed", fd, return false);
99 UPDATER_CHECK_FILE_OP(!strncpy_s(info_.partitionName, PARTITION_NAME_LEN, partitionName.c_str(),
100 PARTITION_NAME_LEN - 1), "PartitionRecord: strncpy_s failed", fd, return false);
101 info_.updated = updated;
102 UPDATER_CHECK_FILE_OP(write(fd, &info_, sizeof(PartitionRecordInfo)) ==
103 static_cast<ssize_t>(sizeof(PartitionRecordInfo)), "PartitionRecord: write failed", fd, return false);
104 offset_ += static_cast<off_t>(sizeof(PartitionRecordInfo));
105 UPDATER_CHECK_FILE_OP(lseek(fd, PARTITION_RECORD_OFFSET, SEEK_SET) >= 0,
106 "PartitionRecord: Seek misc to record offset failed", fd, return false);
107 UPDATER_CHECK_FILE_OP(write(fd, &offset_, sizeof(off_t)) == static_cast<ssize_t>(sizeof(off_t)),
108 "PartitionRecord: write misc to record offset failed", fd, return false);
109 LOG(DEBUG) << "PartitionRecord: offset is " << offset_;
110 } else {
111 LOG(WARNING) << "PartitionRecord: partition record overflow, offset = " << offset_;
112 close(fd);
113 return false;
114 }
115 LOG(DEBUG) << "PartitionRecord: record " << partitionName << " successfully.";
116 fsync(fd);
117 close(fd);
118 }
119 return true;
120 }
121
ClearRecordPartitionOffset()122 bool PartitionRecord::ClearRecordPartitionOffset()
123 {
124 auto miscBlockDevice = GetMiscPartitionPath();
125 if (!miscBlockDevice.empty()) {
126 int fd = open(miscBlockDevice.c_str(), O_RDWR | O_EXCL | O_CLOEXEC | O_BINARY);
127 if (fd < 0) {
128 LOG(ERROR) << "Open misc to recording partition failed" << " : " << strerror(errno);
129 return false;
130 }
131 if (lseek(fd, PARTITION_RECORD_OFFSET, SEEK_SET) < 0) {
132 LOG(ERROR) << "Seek misc to specific offset failed" << " : " << strerror(errno);
133 close(fd);
134 return false;
135 }
136
137 off_t initOffset = 0;
138 if (write(fd, &initOffset, sizeof(off_t)) != static_cast<ssize_t>(sizeof(off_t))) {
139 LOG(ERROR) << "StartUpdater: Write misc initOffset 0 failed" << " : " << strerror(errno);
140 close(fd);
141 return false;
142 }
143 fsync(fd);
144 close(fd);
145 }
146 return true;
147 }
148
GetMiscPartitionPath(const std::string & misc)149 std::string PartitionRecord::GetMiscPartitionPath(const std::string &misc)
150 {
151 auto miscBlockDevice = GetBlockDeviceByMountPoint(misc);
152 if (miscBlockDevice.empty()) {
153 LOG(WARNING) << "Can not find misc partition";
154 }
155 return miscBlockDevice;
156 }
157 } // namespace Updater
158