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