1d9f0492fSopenharmony_ci/*
2d9f0492fSopenharmony_ci * Copyright (c) 2021 Huawei Device Co., Ltd.
3d9f0492fSopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License");
4d9f0492fSopenharmony_ci * you may not use this file except in compliance with the License.
5d9f0492fSopenharmony_ci * You may obtain a copy of the License at
6d9f0492fSopenharmony_ci *
7d9f0492fSopenharmony_ci *     http://www.apache.org/licenses/LICENSE-2.0
8d9f0492fSopenharmony_ci *
9d9f0492fSopenharmony_ci * Unless required by applicable law or agreed to in writing, software
10d9f0492fSopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS,
11d9f0492fSopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12d9f0492fSopenharmony_ci * See the License for the specific language governing permissions and
13d9f0492fSopenharmony_ci * limitations under the License.
14d9f0492fSopenharmony_ci */
15d9f0492fSopenharmony_ci
16d9f0492fSopenharmony_ci#include <cerrno>
17d9f0492fSopenharmony_ci#include <cstdlib>
18d9f0492fSopenharmony_ci#include <cstdio>
19d9f0492fSopenharmony_ci#include <cstdint>
20d9f0492fSopenharmony_ci#include <fcntl.h>
21d9f0492fSopenharmony_ci#include <iostream>
22d9f0492fSopenharmony_ci#include <string>
23d9f0492fSopenharmony_ci#include <sys/stat.h>
24d9f0492fSopenharmony_ci#include <unistd.h>
25d9f0492fSopenharmony_ci
26d9f0492fSopenharmony_ci#include "begetctl.h"
27d9f0492fSopenharmony_ci#include "fs_manager/fs_manager.h"
28d9f0492fSopenharmony_ci#include "shell.h"
29d9f0492fSopenharmony_ci#include "shell_utils.h"
30d9f0492fSopenharmony_ci#include "init_param.h"
31d9f0492fSopenharmony_ci
32d9f0492fSopenharmony_ciconstexpr int MAX_LOGO_SIZE = 1024 * 2038;
33d9f0492fSopenharmony_ciconstexpr int PARTITION_INFO_POS = 1144;
34d9f0492fSopenharmony_ciconstexpr int PARTITION_INFO_MAX_LENGTH = 256;
35d9f0492fSopenharmony_ciconstexpr int BLOCK_SZIE_1 = 512;
36d9f0492fSopenharmony_ciconstexpr uint64_t LOGO_MAGIC = 0XABCABCAB;
37d9f0492fSopenharmony_ci
38d9f0492fSopenharmony_ci#define MISC_DEVICE_NODE "/dev/block/by-name/misc"
39d9f0492fSopenharmony_ci
40d9f0492fSopenharmony_cistatic void ClearLogo(int fd)
41d9f0492fSopenharmony_ci{
42d9f0492fSopenharmony_ci    if (fd < 0) {
43d9f0492fSopenharmony_ci        return;
44d9f0492fSopenharmony_ci    }
45d9f0492fSopenharmony_ci    char buffer[8] = {0}; // logo magic number + logo size is 8
46d9f0492fSopenharmony_ci    int addrOffset = (PARTITION_INFO_POS + PARTITION_INFO_MAX_LENGTH + BLOCK_SZIE_1 - 1) / BLOCK_SZIE_1;
47d9f0492fSopenharmony_ci    if (lseek(fd, addrOffset * BLOCK_SZIE_1, SEEK_SET) < 0) {
48d9f0492fSopenharmony_ci        std::cout << "Failed to clean file\n";
49d9f0492fSopenharmony_ci        return;
50d9f0492fSopenharmony_ci    }
51d9f0492fSopenharmony_ci    if (write(fd, &buffer, sizeof(buffer)) != sizeof(buffer)) {
52d9f0492fSopenharmony_ci        std::cout << "clean misc failed\n";
53d9f0492fSopenharmony_ci        return;
54d9f0492fSopenharmony_ci    }
55d9f0492fSopenharmony_ci}
56d9f0492fSopenharmony_ci
57d9f0492fSopenharmony_cistatic void WriteLogoContent(int fd, const std::string &logoPath, uint32_t size)
58d9f0492fSopenharmony_ci{
59d9f0492fSopenharmony_ci    if (size == 0 || size > MAX_LOGO_SIZE) {
60d9f0492fSopenharmony_ci        BSH_LOGE("logo size is invalid!");
61d9f0492fSopenharmony_ci        return;
62d9f0492fSopenharmony_ci    }
63d9f0492fSopenharmony_ci    FILE *rgbFile = fopen(logoPath.c_str(), "rb");
64d9f0492fSopenharmony_ci    if (rgbFile == nullptr) {
65d9f0492fSopenharmony_ci        std::cout << "cannot find pic file\n";
66d9f0492fSopenharmony_ci        return;
67d9f0492fSopenharmony_ci    }
68d9f0492fSopenharmony_ci    char *buffer = reinterpret_cast<char *>(calloc(1, size));
69d9f0492fSopenharmony_ci    if (buffer == nullptr) {
70d9f0492fSopenharmony_ci        (void)fclose(rgbFile);
71d9f0492fSopenharmony_ci        return;
72d9f0492fSopenharmony_ci    }
73d9f0492fSopenharmony_ci    (void)fread(buffer, 1, size, rgbFile);
74d9f0492fSopenharmony_ci    if (ferror(rgbFile)) {
75d9f0492fSopenharmony_ci        (void)fclose(rgbFile);
76d9f0492fSopenharmony_ci        free(buffer);
77d9f0492fSopenharmony_ci        return;
78d9f0492fSopenharmony_ci    }
79d9f0492fSopenharmony_ci    ssize_t ret = write(fd, buffer, size);
80d9f0492fSopenharmony_ci    if (ret == -1 || ret != size) {
81d9f0492fSopenharmony_ci        (void)fclose(rgbFile);
82d9f0492fSopenharmony_ci        free(buffer);
83d9f0492fSopenharmony_ci        return;
84d9f0492fSopenharmony_ci    }
85d9f0492fSopenharmony_ci    free(buffer);
86d9f0492fSopenharmony_ci    (void)fclose(rgbFile);
87d9f0492fSopenharmony_ci}
88d9f0492fSopenharmony_ci
89d9f0492fSopenharmony_cistatic int WriteLogo(int fd, const std::string &logoPath)
90d9f0492fSopenharmony_ci{
91d9f0492fSopenharmony_ci    int addrOffset = (PARTITION_INFO_POS + PARTITION_INFO_MAX_LENGTH + BLOCK_SZIE_1 - 1) / BLOCK_SZIE_1;
92d9f0492fSopenharmony_ci    if (lseek(fd, addrOffset * BLOCK_SZIE_1, SEEK_SET) < 0) {
93d9f0492fSopenharmony_ci        BSH_LOGI("Failed lseek logoPath %s errno %d ", logoPath.c_str(), errno);
94d9f0492fSopenharmony_ci        return -1;
95d9f0492fSopenharmony_ci    }
96d9f0492fSopenharmony_ci
97d9f0492fSopenharmony_ci    uint32_t magic = 0;
98d9f0492fSopenharmony_ci    if (read(fd, &magic, sizeof(uint32_t)) != sizeof(uint32_t)) {
99d9f0492fSopenharmony_ci        BSH_LOGI("Failed magic logoPath %s errno %d ", logoPath.c_str(), errno);
100d9f0492fSopenharmony_ci        return -1;
101d9f0492fSopenharmony_ci    }
102d9f0492fSopenharmony_ci#ifndef STARTUP_INIT_TEST
103d9f0492fSopenharmony_ci    if (magic == LOGO_MAGIC) {
104d9f0492fSopenharmony_ci        BSH_LOGI("Get matched magic number, logo already written\n");
105d9f0492fSopenharmony_ci        return 0;
106d9f0492fSopenharmony_ci    }
107d9f0492fSopenharmony_ci#endif
108d9f0492fSopenharmony_ci    struct stat st {};
109d9f0492fSopenharmony_ci    magic = LOGO_MAGIC;
110d9f0492fSopenharmony_ci    lseek(fd, addrOffset * BLOCK_SZIE_1, SEEK_SET);
111d9f0492fSopenharmony_ci    if (write(fd, &magic, sizeof(magic)) != sizeof(magic)) {
112d9f0492fSopenharmony_ci        BSH_LOGI("Write magic number failed %d", errno);
113d9f0492fSopenharmony_ci        return -1;
114d9f0492fSopenharmony_ci    }
115d9f0492fSopenharmony_ci
116d9f0492fSopenharmony_ci    if (stat(logoPath.c_str(), &st) < 0) {
117d9f0492fSopenharmony_ci        if (errno == ENOENT) {
118d9f0492fSopenharmony_ci            BSH_LOGI("%s is not exist", logoPath.c_str());
119d9f0492fSopenharmony_ci        } else {
120d9f0492fSopenharmony_ci            BSH_LOGI("Failed to get %s stat", logoPath.c_str());
121d9f0492fSopenharmony_ci        }
122d9f0492fSopenharmony_ci        ClearLogo(fd);
123d9f0492fSopenharmony_ci        return -1;
124d9f0492fSopenharmony_ci    }
125d9f0492fSopenharmony_ci
126d9f0492fSopenharmony_ci    if (st.st_size <= 0 || st.st_size > MAX_LOGO_SIZE) {
127d9f0492fSopenharmony_ci        BSH_LOGE("Invalid logo file with size ");
128d9f0492fSopenharmony_ci        ClearLogo(fd);
129d9f0492fSopenharmony_ci        return -1;
130d9f0492fSopenharmony_ci    }
131d9f0492fSopenharmony_ci
132d9f0492fSopenharmony_ci    uint32_t logoSize =  static_cast<uint32_t>(st.st_size);
133d9f0492fSopenharmony_ci    if (write(fd, &logoSize, sizeof(logoSize)) != sizeof(logoSize)) {
134d9f0492fSopenharmony_ci        BSH_LOGE("Write logo size failed ");
135d9f0492fSopenharmony_ci        ClearLogo(fd);
136d9f0492fSopenharmony_ci        return -1;
137d9f0492fSopenharmony_ci    }
138d9f0492fSopenharmony_ci
139d9f0492fSopenharmony_ci    WriteLogoContent(fd, logoPath, logoSize);
140d9f0492fSopenharmony_ci    return 0;
141d9f0492fSopenharmony_ci}
142d9f0492fSopenharmony_ci
143d9f0492fSopenharmony_cistatic void WriteLogoToMisc(const std::string &logoPath)
144d9f0492fSopenharmony_ci{
145d9f0492fSopenharmony_ci    if (logoPath.empty()) {
146d9f0492fSopenharmony_ci        std::cout << "logo path is empty\n";
147d9f0492fSopenharmony_ci        return;
148d9f0492fSopenharmony_ci    }
149d9f0492fSopenharmony_ci    int fd = open(MISC_DEVICE_NODE, O_RDWR | O_CLOEXEC, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
150d9f0492fSopenharmony_ci    if (fd < 0) {
151d9f0492fSopenharmony_ci        BSH_LOGI("Failed to writeLogoToMisc errno %d ", errno);
152d9f0492fSopenharmony_ci        return;
153d9f0492fSopenharmony_ci    }
154d9f0492fSopenharmony_ci
155d9f0492fSopenharmony_ci    if (WriteLogo(fd, logoPath) < 0) {
156d9f0492fSopenharmony_ci        BSH_LOGI("Failed WriteLogo errno %d ", errno);
157d9f0492fSopenharmony_ci    }
158d9f0492fSopenharmony_ci    close(fd);
159d9f0492fSopenharmony_ci    int addrOffset = (PARTITION_INFO_POS + PARTITION_INFO_MAX_LENGTH + BLOCK_SZIE_1 - 1) / BLOCK_SZIE_1;
160d9f0492fSopenharmony_ci    int fd1 = open(MISC_DEVICE_NODE, O_RDWR | O_CLOEXEC, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
161d9f0492fSopenharmony_ci    if (fd1 < 0) {
162d9f0492fSopenharmony_ci        return;
163d9f0492fSopenharmony_ci    }
164d9f0492fSopenharmony_ci    if (lseek(fd1, addrOffset * BLOCK_SZIE_1, SEEK_SET) < 0) {
165d9f0492fSopenharmony_ci        BSH_LOGI("Failed lseek errno %d ", errno);
166d9f0492fSopenharmony_ci        close(fd1);
167d9f0492fSopenharmony_ci        return;
168d9f0492fSopenharmony_ci    }
169d9f0492fSopenharmony_ci
170d9f0492fSopenharmony_ci    uint32_t magic = 0;
171d9f0492fSopenharmony_ci    uint32_t size = 0;
172d9f0492fSopenharmony_ci    if (read(fd1, &magic, sizeof(uint32_t)) != sizeof(uint32_t)) {
173d9f0492fSopenharmony_ci        BSH_LOGI("Failed read errno %d ", errno);
174d9f0492fSopenharmony_ci        close(fd1);
175d9f0492fSopenharmony_ci        return;
176d9f0492fSopenharmony_ci    }
177d9f0492fSopenharmony_ci    if (read(fd1, &size, sizeof(uint32_t)) != sizeof(uint32_t)) {
178d9f0492fSopenharmony_ci        BSH_LOGI("Failed read migic errno %d ", errno);
179d9f0492fSopenharmony_ci        close(fd1);
180d9f0492fSopenharmony_ci        return;
181d9f0492fSopenharmony_ci    }
182d9f0492fSopenharmony_ci
183d9f0492fSopenharmony_ci    close(fd1);
184d9f0492fSopenharmony_ci}
185d9f0492fSopenharmony_ci
186d9f0492fSopenharmony_cistatic int main_cmd(BShellHandle shell, int argc, char **argv)
187d9f0492fSopenharmony_ci{
188d9f0492fSopenharmony_ci    if (argc >= 2 && strcmp(const_cast<char *>("--write_logo"), argv[0]) == 0) { // 2 min arg
189d9f0492fSopenharmony_ci        WriteLogoToMisc(argv[1]);
190d9f0492fSopenharmony_ci    } else {
191d9f0492fSopenharmony_ci        char *helpArgs[] = {const_cast<char *>("misc_daemon"), nullptr};
192d9f0492fSopenharmony_ci        BShellCmdHelp(shell, 1, helpArgs);
193d9f0492fSopenharmony_ci    }
194d9f0492fSopenharmony_ci    return 0;
195d9f0492fSopenharmony_ci}
196d9f0492fSopenharmony_ci
197d9f0492fSopenharmony_ciMODULE_CONSTRUCTOR(void)
198d9f0492fSopenharmony_ci{
199d9f0492fSopenharmony_ci    const CmdInfo infos[] = {
200d9f0492fSopenharmony_ci        {
201d9f0492fSopenharmony_ci            const_cast<char *>("misc_daemon"), main_cmd, const_cast<char *>("write start logo"),
202d9f0492fSopenharmony_ci            const_cast<char *>("misc_daemon --write_logo xxx.rgb"), const_cast<char *>("misc_daemon --write_logo")
203d9f0492fSopenharmony_ci        }
204d9f0492fSopenharmony_ci    };
205d9f0492fSopenharmony_ci    for (size_t i = 0; i < sizeof(infos) / sizeof(infos[0]); i++) {
206d9f0492fSopenharmony_ci        BShellEnvRegisterCmd(GetShellHandle(), &infos[i]);
207d9f0492fSopenharmony_ci    }
208d9f0492fSopenharmony_ci}
209