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 
32 constexpr int MAX_LOGO_SIZE = 1024 * 2038;
33 constexpr int PARTITION_INFO_POS = 1144;
34 constexpr int PARTITION_INFO_MAX_LENGTH = 256;
35 constexpr int BLOCK_SZIE_1 = 512;
36 constexpr uint64_t LOGO_MAGIC = 0XABCABCAB;
37 
38 #define MISC_DEVICE_NODE "/dev/block/by-name/misc"
39 
ClearLogo(int fd)40 static 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 
WriteLogoContent(int fd,const std::string & logoPath,uint32_t size)57 static 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 
WriteLogo(int fd,const std::string & logoPath)89 static 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 
WriteLogoToMisc(const std::string & logoPath)143 static 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 
main_cmd(BShellHandle shell,int argc,char ** argv)186 static 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 
MODULE_CONSTRUCTOR(void)197 MODULE_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