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