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