1/* 2 * Copyright (c) 2020 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#include <gtest/gtest.h> 16#include <cerrno> 17#include <cstdio> 18#include <cstdlib> 19#include <dirent.h> 20#include <string> 21#include <sys/stat.h> 22#include <sys/types.h> 23 24#include "cJSON.h" 25#include "init_cmds.h" 26#include "init_jobs_internal.h" 27#include "init_log.h" 28#include "init_service_manager.h" 29#include "param_stub.h" 30#include "securec.h" 31 32using namespace std; 33using namespace testing::ext; 34 35namespace OHOS { 36std::vector<std::string> g_supportedCmds; 37const std::string ROOT_DIR = "/storage/data/"; 38const std::string TEST_DRI = ROOT_DIR + "StartInitTestDir"; 39const std::string TEST_FILE = TEST_DRI + "/test.txt"; 40const std::string TEST_CFG_ILLEGAL = TEST_DRI + "/illegal.cfg"; 41const std::string TEST_PROC_MOUNTS = "/proc/mounts"; 42#ifndef USE_EMMC_STORAGE 43const uid_t TEST_FILE_UID = 999; 44const gid_t TEST_FILE_GID = 999; 45const mode_t TEST_FILE_MODE = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH; 46#endif 47 48// init.cfg related 49const std::string CFG_FILE = "/etc/init.cfg"; 50const std::string SERVICE_ARR_NAME_IN_JSON = "services"; 51const std::string JOBS_ARR_NAME_IN_JSON = "jobs"; 52const std::string CMDS_ARR_NAME_IN_JSON = "cmds"; 53const uid_t CFG_FILE_UID = 0; 54const gid_t CFG_FILE_GID = 0; 55const mode_t CFG_FILE_MODE = S_IRUSR; 56const int JOBS_IN_FILE_COUNT = 3; // pre-init, init, post-init 57const int MAX_SERVICES_COUNT_IN_FILE = 100; 58const int MAX_CAPS_CNT_FOR_ONE_SERVICE = 100; 59const unsigned int MAX_JSON_FILE_LEN = 102400; // max init.cfg size 100KB 60const int TEST_MAX_PATH_ARGS_CNT = 20; // max path and args count 61const int TEST_MAX_ONE_ARG_LEN = 64; // max length of one param/path 62const int CAT_BUF_SIZE = 512; // standard Cat buffer size from vfs_shell_cmd 63 64// job test related 65const std::string PRE_INIT_DIR = ROOT_DIR + "preInitDir/"; 66const std::string INIT_DIR = PRE_INIT_DIR + "initDir"; 67const std::string POST_INIT_DIR = INIT_DIR + "postInitDir"; 68 69using TestCmdLine = struct { 70 char name[MAX_CMD_NAME_LEN + 1]; 71 char cmdContent[MAX_CMD_CONTENT_LEN + 1]; 72}; 73 74class StartupInitUTest : public testing::Test { 75public: 76 static void SetUpTestCase() 77 { 78 g_supportedCmds.push_back(std::string("start ")); 79 g_supportedCmds.push_back(std::string("mkdir ")); 80 g_supportedCmds.push_back(std::string("chmod ")); 81 g_supportedCmds.push_back(std::string("chown ")); 82 g_supportedCmds.push_back(std::string("mount ")); 83 g_supportedCmds.push_back(std::string("loadcfg ")); 84 const mode_t mode = 0755; 85 if (mkdir(TEST_DRI.c_str(), mode) != 0) { 86 if (errno != EEXIST) { 87 return; 88 } 89 } 90 91 FILE *testFile = fopen(TEST_FILE.c_str(), "w+"); 92 if (testFile == nullptr) { 93 return; 94 } 95 96 std::string writeContent = "This is a test file for startup subsystem init module."; 97 if (fwrite(writeContent.c_str(), writeContent.length(), 1, testFile) != 1) { 98 (void)fclose(testFile); 99 return; 100 } 101 (void)fclose(testFile); 102 103#ifndef USE_EMMC_STORAGE // emmc storage does not support chmod/chown 104 105 if (chmod(TEST_FILE.c_str(), TEST_FILE_MODE) != 0) { 106 return; 107 } 108 109 if (chown(TEST_FILE.c_str(), TEST_FILE_UID, TEST_FILE_GID) != 0) { 110 return; 111 } 112#endif // USE_EMMC_STORAGE 113 PrepareInitUnitTestEnv(); 114 } 115 116 static void TearDownTestCase() 117 { 118 if (remove(TEST_FILE.c_str()) != 0) { 119 return; 120 } 121 if (remove(TEST_DRI.c_str()) != 0) { 122 return; 123 } 124 } 125 void SetUp() 126 { 127 EnableInitLog(INIT_FATAL); 128 } 129 void TearDown() {} 130}; 131 132void ParseCmdLine(const char *content, TestCmdLine *resCmd) 133{ 134 if (content == nullptr || resCmd == nullptr) { 135 return; 136 } 137 138 const struct CmdTable *cmd = GetCmdByName(content); 139 if (cmd == nullptr) { 140 (void)memset_s(resCmd, sizeof(TestCmdLine), 0, sizeof(TestCmdLine)); 141 return; 142 } 143 if (strlen(content) <= (strlen(cmd->name) + 1)) { 144 (void)memset_s(resCmd, sizeof(TestCmdLine), 0, sizeof(TestCmdLine)); 145 return; 146 } 147 int ret1 = strcpy_s(resCmd->name, MAX_CMD_NAME_LEN, cmd->name); 148 int ret2 = strcpy_s(resCmd->cmdContent, MAX_CMD_CONTENT_LEN, content + strlen(cmd->name)); 149 if (ret1 || ret2) { 150 (void)memset_s(resCmd, sizeof(TestCmdLine), 0, sizeof(TestCmdLine)); 151 return; 152 } 153} 154 155void DoCmd(const TestCmdLine *resCmd) 156{ 157 if (resCmd == nullptr) { 158 return; 159 } 160 int cmdIndex = 0; 161 (void)GetMatchCmd(resCmd->name, &cmdIndex); 162 DoCmdByIndex(cmdIndex, resCmd->cmdContent, nullptr); 163} 164 165/* 166 * @tc.name: cmdFuncParseCmdTest_001 167 * @tc.desc: parse function, nullptr test 168 * @tc.type: FUNC 169 */ 170HWTEST_F(StartupInitUTest, cmdFuncParseCmdTest_001, TestSize.Level0) 171{ 172 // do not crash 173 ParseCmdLine(nullptr, nullptr); 174}; 175 176/* 177 * @tc.name: cmdFuncParseCmdTest_002 178 * @tc.desc: parse function, invalid strings test 179 * @tc.type: FUNC 180 */ 181HWTEST_F(StartupInitUTest, cmdFuncParseCmdTest_002, TestSize.Level0) 182{ 183 TestCmdLine curCmdLine; 184 (void)memset_s(&curCmdLine, sizeof(curCmdLine), 0, sizeof(curCmdLine)); 185 186 ParseCmdLine(nullptr, &curCmdLine); 187 EXPECT_EQ(0, strlen(curCmdLine.name)); 188 EXPECT_EQ(0, strlen(curCmdLine.cmdContent)); 189 190 ParseCmdLine("", &curCmdLine); 191 EXPECT_EQ(0, strlen(curCmdLine.name)); 192 EXPECT_EQ(0, strlen(curCmdLine.cmdContent)); 193 194 ParseCmdLine("xxxxxxxx", &curCmdLine); 195 EXPECT_EQ(0, strlen(curCmdLine.name)); 196 EXPECT_EQ(0, strlen(curCmdLine.cmdContent)); 197 198 ParseCmdLine("asdnkawdqw4145a45sdqw_-+\\\\sdqwdasd", &curCmdLine); 199 EXPECT_EQ(0, strlen(curCmdLine.name)); 200 EXPECT_EQ(0, strlen(curCmdLine.cmdContent)); 201} 202 203/* 204 * @tc.name: cmdFuncParseCmdTest_003 205 * @tc.desc: parse function, cmd content empty test 206 * @tc.type: FUNC 207 */ 208HWTEST_F(StartupInitUTest, cmdFuncParseCmdTest_003, TestSize.Level0) 209{ 210 TestCmdLine curCmdLine; 211 (void)memset_s(&curCmdLine, sizeof(curCmdLine), 0, sizeof(curCmdLine)); 212 213 for (size_t i = 0; i < g_supportedCmds.size(); ++i) { 214 ParseCmdLine(g_supportedCmds[i].c_str(), &curCmdLine); 215 EXPECT_EQ(0, strlen(curCmdLine.name)); 216 EXPECT_EQ(0, strlen(curCmdLine.cmdContent)); 217 } 218} 219 220/* 221 * @tc.name: cmdFuncParseCmdTest_004 222 * @tc.desc: parse function, cmd content too long test 223 * @tc.type: FUNC 224 */ 225HWTEST_F(StartupInitUTest, cmdFuncParseCmdTest_004, TestSize.Level0) 226{ 227 TestCmdLine curCmdLine; 228 (void)memset_s(&curCmdLine, sizeof(curCmdLine), 0, sizeof(curCmdLine)); 229 230 char toLongContent[MAX_CMD_CONTENT_LEN + 10]; 231 int ret = memset_s(toLongContent, MAX_CMD_CONTENT_LEN + 10, 'x', MAX_CMD_CONTENT_LEN + 9); 232 EXPECT_EQ(0, ret); 233 234 toLongContent[MAX_CMD_CONTENT_LEN + 9] = '\0'; 235 for (size_t i = 0; i < g_supportedCmds.size(); ++i) { 236 size_t curCmdLen = g_supportedCmds[i].length(); 237 char *curCmd = (char *)malloc(curCmdLen + MAX_CMD_CONTENT_LEN + 10); 238 if (curCmd == nullptr) { 239 break; 240 } 241 errno_t ret = memcpy_s(curCmd, curCmdLen + MAX_CMD_CONTENT_LEN + 10, \ 242 g_supportedCmds[i].c_str(), curCmdLen); 243 errno_t ret2 = memcpy_s(curCmd + curCmdLen, MAX_CMD_CONTENT_LEN + 10, \ 244 toLongContent, strlen(toLongContent)); 245 if (ret != EOK || ret2 != EOK) { 246 free(curCmd); 247 curCmd = nullptr; 248 break; 249 } 250 curCmd[curCmdLen + MAX_CMD_CONTENT_LEN + 9] = '\0'; 251 252 ParseCmdLine(curCmd, &curCmdLine); 253 EXPECT_EQ(0, strlen(curCmdLine.name)); 254 EXPECT_EQ(0, strlen(curCmdLine.cmdContent)); 255 free(curCmd); 256 curCmd = nullptr; 257 } 258} 259 260/* 261 * @tc.name: cmdFuncParseCmdTest_005 262 * @tc.desc: parse function, parse success test 263 * @tc.type: FUNC 264 */ 265HWTEST_F(StartupInitUTest, cmdFuncParseCmdTest_005, TestSize.Level0) 266{ 267 TestCmdLine curCmdLine; 268 (void)memset_s(&curCmdLine, sizeof(curCmdLine), 0, sizeof(curCmdLine)); 269 270 ParseCmdLine("start InitTestService", &curCmdLine); 271 EXPECT_EQ(0, strcmp("start ", curCmdLine.name)); 272 EXPECT_EQ(0, strcmp("InitTestService", curCmdLine.cmdContent)); 273 274 ParseCmdLine("mkdir InitTestDir", &curCmdLine); 275 EXPECT_EQ(0, strcmp("mkdir ", curCmdLine.name)); 276 EXPECT_EQ(0, strcmp("InitTestDir", curCmdLine.cmdContent)); 277 278 ParseCmdLine("chmod 0500 /bin/InitTestBin", &curCmdLine); 279 EXPECT_EQ(0, strcmp("chmod ", curCmdLine.name)); 280 EXPECT_EQ(0, strcmp("0500 /bin/InitTestBin", curCmdLine.cmdContent)); 281 282 ParseCmdLine("chown 1000 1000 /bin/InitTestBin", &curCmdLine); 283 EXPECT_EQ(0, strcmp("chown ", curCmdLine.name)); 284 EXPECT_EQ(0, strcmp("1000 1000 /bin/InitTestBin", curCmdLine.cmdContent)); 285 286 ParseCmdLine("mount vfat /dev/mmcblk1 /sdcard rw,umask=000", &curCmdLine); 287 EXPECT_EQ(0, strcmp("mount ", curCmdLine.name)); 288 EXPECT_EQ(0, strcmp("vfat /dev/mmcblk1 /sdcard rw,umask=000", curCmdLine.cmdContent)); 289}; 290 291/* 292 * @tc.name: cmdFuncDoCmdTest_001 293 * @tc.desc: do cmd function, nullptr test 294 * @tc.type: FUNC 295 */ 296HWTEST_F(StartupInitUTest, cmdFuncDoCmdTest_001, TestSize.Level0) 297{ 298 // do not crash here 299 DoCmd(nullptr); 300} 301 302/* 303 * @tc.name: cmdFuncDoCmdTest_002 304 * @tc.desc: do cmd function, do start fail test 305 * @tc.type: FUNC 306 */ 307HWTEST_F(StartupInitUTest, cmdFuncDoCmdTest_002, TestSize.Level0) 308{ 309 TestCmdLine curCmdLine; 310 (void)memset_s(&curCmdLine, sizeof(curCmdLine), 0, sizeof(curCmdLine)); 311 312 std::string cmdStr = "start "; 313 std::string cmdContentStr = "NameNotExist"; 314 std::string command = cmdStr + cmdContentStr; 315 ParseCmdLine(command.c_str(), &curCmdLine); 316 EXPECT_EQ(0, strcmp(cmdStr.c_str(), curCmdLine.name)); 317 EXPECT_EQ(0, strcmp(cmdContentStr.c_str(), curCmdLine.cmdContent)); 318 DoCmd(&curCmdLine); 319} 320 321/* 322 * @tc.name: cmdFuncDoCmdTest_003 323 * @tc.desc: do cmd function, do mkdir fail test 324 * @tc.type: FUNC 325 */ 326HWTEST_F(StartupInitUTest, cmdFuncDoCmdTest_003, TestSize.Level0) 327{ 328 TestCmdLine curCmdLine; 329 (void)memset_s(&curCmdLine, sizeof(curCmdLine), 0, sizeof(curCmdLine)); 330 331 std::string cmdStr = "mkdir "; 332 std::string cmdContentStr = "/DirNotExist/DirNotExist/DirNotExist"; 333 std::string command = cmdStr + cmdContentStr; 334 ParseCmdLine(command.c_str(), &curCmdLine); 335 EXPECT_EQ(0, strcmp(cmdStr.c_str(), curCmdLine.name)); 336 EXPECT_EQ(0, strcmp(cmdContentStr.c_str(), curCmdLine.cmdContent)); 337 DoCmd(&curCmdLine); 338 339 // make sure that the directory does not exist 340 DIR *dirTmp = opendir(cmdContentStr.c_str()); 341 EXPECT_TRUE(dirTmp == nullptr); 342 EXPECT_TRUE(errno == ENOENT); 343 if (dirTmp != nullptr) { // just in case 344 closedir(dirTmp); 345 dirTmp = nullptr; 346 } 347 348 // error argument count, bad format 349 cmdContentStr = " /storage/data/cmdFuncDoCmdTest003 0755 system"; 350 command = cmdStr + cmdContentStr; 351 ParseCmdLine(command.c_str(), &curCmdLine); 352 EXPECT_EQ(0, strcmp(cmdStr.c_str(), curCmdLine.name)); 353 EXPECT_EQ(0, strcmp(cmdContentStr.c_str(), curCmdLine.cmdContent)); 354 DoCmd(&curCmdLine); 355 356 // make sure that the directory does not exist 357 dirTmp = opendir("/storage/data/cmdFuncDoCmdTest003"); 358 EXPECT_TRUE(dirTmp == nullptr); 359 EXPECT_TRUE(errno == ENOENT); 360 if (dirTmp != nullptr) { // just in case 361 closedir(dirTmp); 362 dirTmp = nullptr; 363 } 364} 365 366/* 367 * @tc.name: cmdFuncDoCmdTest_004 368 * @tc.desc: do cmd function, do chmod fail test 369 * @tc.type: FUNC 370 */ 371HWTEST_F(StartupInitUTest, cmdFuncDoCmdTest_004, TestSize.Level0) 372{ 373 TestCmdLine curCmdLine; 374 (void)memset_s(&curCmdLine, sizeof(curCmdLine), 0, sizeof(curCmdLine)); 375 376 std::string cmdStr = "chmod "; 377 std::string cmdContentStr = "755 " + TEST_FILE; // should be 0755, wrong format here 378 std::string command = cmdStr + cmdContentStr; 379 ParseCmdLine(command.c_str(), &curCmdLine); 380 EXPECT_EQ(0, strcmp(cmdStr.c_str(), curCmdLine.name)); 381 EXPECT_EQ(0, strcmp(cmdContentStr.c_str(), curCmdLine.cmdContent)); 382 DoCmd(&curCmdLine); 383 384 cmdContentStr = "0855 " + TEST_FILE; // should not exceed 0777, wrong format here 385 command = cmdStr + cmdContentStr; 386 ParseCmdLine(command .c_str(), &curCmdLine); 387 EXPECT_EQ(0, strcmp(cmdStr.c_str(), curCmdLine.name)); 388 EXPECT_EQ(0, strcmp(cmdContentStr.c_str(), curCmdLine.cmdContent)); 389 DoCmd(&curCmdLine); 390 391 cmdContentStr = "07b5 " + TEST_FILE; // non-digital character, wrong format here 392 command = cmdStr + cmdContentStr; 393 ParseCmdLine(command.c_str(), &curCmdLine); 394 EXPECT_EQ(0, strcmp(cmdStr.c_str(), curCmdLine.name)); 395 EXPECT_EQ(0, strcmp(cmdContentStr.c_str(), curCmdLine.cmdContent)); 396 DoCmd(&curCmdLine); 397 398 cmdContentStr = "075 " + TEST_FILE; // should be 0xxx, wrong format here 399 command = cmdStr + cmdContentStr; 400 ParseCmdLine(command.c_str(), &curCmdLine); 401 EXPECT_EQ(0, strcmp(cmdStr.c_str(), curCmdLine.name)); 402 EXPECT_EQ(0, strcmp(cmdContentStr.c_str(), curCmdLine.cmdContent)); 403 DoCmd(&curCmdLine); 404 405 cmdContentStr = "0755 " + TEST_FILE; // too many spaces, wrong format here 406 command = cmdStr + cmdContentStr; 407 ParseCmdLine(command.c_str(), &curCmdLine); 408 EXPECT_EQ(0, strcmp(cmdStr.c_str(), curCmdLine.name)); 409 EXPECT_EQ(0, strcmp(cmdContentStr.c_str(), curCmdLine.cmdContent)); 410 DoCmd(&curCmdLine); 411 412 struct stat testFileStat = {0}; 413 EXPECT_EQ(0, stat(TEST_FILE.c_str(), &testFileStat)); 414 415#ifndef USE_EMMC_STORAGE // emmc storage does not support chmod/chown 416 417 EXPECT_EQ(TEST_FILE_MODE, testFileStat.st_mode & TEST_FILE_MODE); // file mode is not changed 418 419#endif // USE_EMMC_STORAGE 420} 421 422/* 423 * @tc.name: cmdFuncDoCmdTest_005 424 * @tc.desc: do cmd function, do chown fail test 425 * @tc.type: FUNC 426 */ 427HWTEST_F(StartupInitUTest, cmdFuncDoCmdTest_005, TestSize.Level0) 428{ 429 TestCmdLine curCmdLine; 430 (void)memset_s(&curCmdLine, sizeof(curCmdLine), 0, sizeof(curCmdLine)); 431 432 std::string cmdStr = "chown "; 433 std::string cmdContentStr = "888 " + TEST_FILE; // uid or gid missing, wrong format here 434 std::string command = cmdStr + cmdContentStr; 435 ParseCmdLine(command.c_str(), &curCmdLine); 436 EXPECT_EQ(0, strcmp(cmdStr.c_str(), curCmdLine.name)); 437 EXPECT_EQ(0, strcmp(cmdContentStr.c_str(), curCmdLine.cmdContent)); 438 DoCmd(&curCmdLine); 439 440 cmdContentStr = "888 8b9 " + TEST_FILE; // non-digital character, wrong format here 441 command = cmdStr + cmdContentStr; 442 ParseCmdLine(command.c_str(), &curCmdLine); 443 EXPECT_EQ(0, strcmp(cmdStr.c_str(), curCmdLine.name)); 444 EXPECT_EQ(0, strcmp(cmdContentStr.c_str(), curCmdLine.cmdContent)); 445 DoCmd(&curCmdLine); 446 447 struct stat testFileStat = {0}; 448 EXPECT_EQ(0, stat(TEST_FILE.c_str(), &testFileStat)); 449 450#ifndef USE_EMMC_STORAGE // emmc storage does not support chmod/chown 451 452 EXPECT_EQ(testFileStat.st_uid, TEST_FILE_UID); // uid not changed 453 EXPECT_EQ(testFileStat.st_gid, TEST_FILE_GID); // gid not changed 454 455#endif // USE_EMMC_STORAGE 456} 457 458/* 459 * @tc.name: cmdFuncDoCmdTest_006 460 * @tc.desc: do cmd function, do success test 461 * @tc.type: FUNC 462 */ 463HWTEST_F(StartupInitUTest, cmdFuncDoCmdTest_006, TestSize.Level0) 464{ 465 TestCmdLine curCmdLine; 466 467 // mkdir success 468 std::string cmdStr = "mkdir "; 469 std::string cmdContentStr = TEST_DRI + "/cmdFuncDoCmdTest006"; 470 std::string command = cmdStr + cmdContentStr; 471 ParseCmdLine(command.c_str(), &curCmdLine); 472 EXPECT_EQ(0, strcmp(cmdStr.c_str(), curCmdLine.name)); 473 EXPECT_EQ(0, strcmp(cmdContentStr.c_str(), curCmdLine.cmdContent)); 474 475 DoCmd(&curCmdLine); 476 DIR* dirTmp = opendir(cmdContentStr.c_str()); 477 EXPECT_TRUE(dirTmp != nullptr); 478 if (dirTmp != nullptr) { 479 closedir(dirTmp); 480 dirTmp = nullptr; 481 } 482 483 remove(cmdContentStr.c_str()); 484 // chmod success 485 cmdStr = "chmod "; 486 cmdContentStr = "0440 " + TEST_FILE; 487 command = cmdStr + cmdContentStr; 488 ParseCmdLine(command.c_str(), &curCmdLine); 489 EXPECT_EQ(0, strcmp(cmdStr.c_str(), curCmdLine.name)); 490 EXPECT_EQ(0, strcmp(cmdContentStr.c_str(), curCmdLine.cmdContent)); 491 492#ifndef USE_EMMC_STORAGE // emmc storage does not support chmod/chown 493 494 DoCmd(&curCmdLine); 495 struct stat testFileStat = {0}; 496 EXPECT_EQ(0, stat(TEST_FILE.c_str(), &testFileStat)); 497 mode_t targetMode = S_IRUSR | S_IRGRP; 498 EXPECT_EQ(targetMode, testFileStat.st_mode & targetMode); // changed 499 500#endif // USE_EMMC_STORAGE 501 502 // chown success 503 cmdStr = "chown "; 504 cmdContentStr = "888 888 " + TEST_FILE; 505 command = cmdStr + cmdContentStr; 506 ParseCmdLine(command.c_str(), &curCmdLine); 507 EXPECT_EQ(0, strcmp(cmdStr.c_str(), curCmdLine.name)); 508 EXPECT_EQ(0, strcmp(cmdContentStr.c_str(), curCmdLine.cmdContent)); 509 510#ifndef USE_EMMC_STORAGE // emmc storage does not support chmod/chown 511 512 DoCmd(&curCmdLine); 513 EXPECT_EQ(0, stat(TEST_FILE.c_str(), &testFileStat)); 514 EXPECT_EQ(testFileStat.st_uid, 888); // changed 515 EXPECT_EQ(testFileStat.st_gid, 888); // changed 516 517#endif // USE_EMMC_STORAGE 518} 519 520/* 521 * @tc.name: cfgCheckStat_001 522 * @tc.desc: init.cfg file state check 523 * @tc.type: FUNC 524 */ 525HWTEST_F(StartupInitUTest, cfgCheckStat_001, TestSize.Level0) 526{ 527 struct stat fileStat = {0}; 528 EXPECT_EQ(0, stat(CFG_FILE.c_str(), &fileStat)); 529 EXPECT_EQ(CFG_FILE_UID, fileStat.st_uid); 530 EXPECT_EQ(CFG_FILE_GID, fileStat.st_gid); 531 EXPECT_EQ(CFG_FILE_MODE, CFG_FILE_MODE & fileStat.st_mode); 532 EXPECT_TRUE(fileStat.st_size > 0); 533 EXPECT_TRUE(fileStat.st_size <= MAX_JSON_FILE_LEN); 534}; 535 536static char* ReadFileToBuf() 537{ 538 char *buffer = nullptr; 539 FILE *fd = nullptr; 540 struct stat fileStat = {0}; 541 (void)stat(CFG_FILE.c_str(), &fileStat); 542 do { 543 fd = fopen(CFG_FILE.c_str(), "r"); 544 if (fd == nullptr) { 545 break; 546 } 547 548 buffer = static_cast<char*>(malloc(static_cast<size_t>(fileStat.st_size) + 1)); 549 if (buffer == nullptr) { 550 break; 551 } 552 553 if (fread(buffer, fileStat.st_size, 1, fd) != 1) { 554 free(buffer); 555 buffer = nullptr; 556 break; 557 } 558 buffer[fileStat.st_size] = '\0'; 559 } while (0); 560 561 if (fd != nullptr) { 562 fclose(fd); 563 fd = nullptr; 564 } 565 return buffer; 566} 567 568static cJSON *GetArrItem(const cJSON *fileRoot, int &arrSize, const std::string &arrName) 569{ 570 cJSON *arrItem = cJSON_GetObjectItemCaseSensitive(fileRoot, arrName.c_str()); 571 arrSize = cJSON_GetArraySize(arrItem); 572 if (arrSize <= 0) { 573 return nullptr; 574 } 575 return arrItem; 576} 577 578static int IsForbidden(const char *fieldStr) 579{ 580 size_t fieldLen = strlen(fieldStr); 581 size_t forbidStrLen = strlen("/bin/sh"); 582 if (fieldLen == forbidStrLen) { 583 if (strncmp(fieldStr, "/bin/sh", fieldLen) == 0) { 584 return 1; 585 } 586 return 0; 587 } else if (fieldLen > forbidStrLen) { 588 // "/bin/shxxxx" is valid but "/bin/sh xxxx" is invalid 589 if (strncmp(fieldStr, "/bin/sh", forbidStrLen) == 0) { 590 if (fieldStr[forbidStrLen] == ' ') { 591 return 1; 592 } 593 } 594 return 0; 595 } else { 596 return 0; 597 } 598} 599 600static void CheckService(const cJSON* curItem) 601{ 602 if (curItem == nullptr) { 603 return; 604 } 605 606 char *nameStr = cJSON_GetStringValue(cJSON_GetObjectItem(curItem, "name")); 607 if (nameStr == nullptr) { 608 EXPECT_TRUE(nameStr != nullptr); 609 } else { 610 EXPECT_TRUE(strlen(nameStr) > 0); 611 } 612 613 cJSON *pathArgsItem = cJSON_GetObjectItem(curItem, "path"); 614 EXPECT_TRUE(cJSON_IsArray(pathArgsItem)); 615 616 int pathArgsCnt = cJSON_GetArraySize(pathArgsItem); 617 EXPECT_TRUE(pathArgsCnt > 0); 618 EXPECT_TRUE(pathArgsCnt <= TEST_MAX_PATH_ARGS_CNT); 619 620 for (int i = 0; i < pathArgsCnt; ++i) { 621 char *curParam = cJSON_GetStringValue(cJSON_GetArrayItem(pathArgsItem, i)); 622 EXPECT_TRUE(curParam != nullptr); 623 EXPECT_TRUE(strlen(curParam) > 0); 624 EXPECT_TRUE(strlen(curParam) <= TEST_MAX_ONE_ARG_LEN); 625 if (i == 0) { 626 EXPECT_TRUE(IsForbidden(curParam) == 0); 627 } 628 } 629 630 cJSON *filedJ = cJSON_GetObjectItem(curItem, "uid"); 631 EXPECT_TRUE(cJSON_IsNumber(filedJ) || cJSON_IsString(filedJ)); 632 EXPECT_TRUE(cJSON_GetNumberValue(filedJ) >= 0.0 || cJSON_GetStringValue(filedJ)); 633 634 filedJ = cJSON_GetObjectItem(curItem, "gid"); 635 EXPECT_TRUE(cJSON_IsNumber(filedJ) || cJSON_IsArray(filedJ)); 636 EXPECT_TRUE(cJSON_GetNumberValue(filedJ) >= 0.0 || cJSON_GetArraySize(filedJ) >= 0); 637 638 filedJ = cJSON_GetObjectItem(curItem, "once"); 639 EXPECT_TRUE(cJSON_IsNumber(filedJ)); 640 641 filedJ = cJSON_GetObjectItem(curItem, "importance"); 642 EXPECT_TRUE(cJSON_IsNumber(filedJ)); 643 644 filedJ = cJSON_GetObjectItem(curItem, "caps"); 645 EXPECT_TRUE(cJSON_IsArray(filedJ)); 646 int capsCnt = cJSON_GetArraySize(filedJ); 647 EXPECT_TRUE(capsCnt <= MAX_CAPS_CNT_FOR_ONE_SERVICE); 648 for (int i = 0; i < capsCnt; ++i) { 649 cJSON *capJ = cJSON_GetArrayItem(filedJ, i); 650 EXPECT_TRUE(cJSON_IsNumber(capJ) || cJSON_GetStringValue(capJ)); 651 EXPECT_TRUE(cJSON_GetNumberValue(capJ) >= 0.0 || cJSON_GetStringValue(capJ)); 652 } 653} 654 655static void CheckServices(const cJSON *fileRoot) 656{ 657 int servArrSize = 0; 658 cJSON *serviceArr = GetArrItem(fileRoot, servArrSize, SERVICE_ARR_NAME_IN_JSON); 659 EXPECT_TRUE(serviceArr != nullptr); 660 EXPECT_TRUE(servArrSize <= MAX_SERVICES_COUNT_IN_FILE); 661 662 for (int i = 0; i < servArrSize; ++i) { 663 cJSON *curItem = cJSON_GetArrayItem(serviceArr, i); 664 EXPECT_TRUE(curItem != nullptr); 665 CheckService(curItem); 666 } 667} 668 669static void CheckCmd(const TestCmdLine *resCmd) 670{ 671 EXPECT_TRUE(strlen(resCmd->name) > 0); 672 EXPECT_TRUE(strlen(resCmd->cmdContent) > 0); 673 674 if (strcmp("start ", resCmd->name) == 0) { 675 for (size_t i = 0; i < strlen(resCmd->cmdContent); ++i) { 676 EXPECT_NE(' ', resCmd->cmdContent[i]); // no spaces in service name 677 } 678 } else if (strcmp("mkdir ", resCmd->name) == 0) { 679 for (size_t i = 0; i < strlen(resCmd->cmdContent); ++i) { 680 EXPECT_NE('.', resCmd->cmdContent[i]); // no dots in path string 681 } 682 } else if (strcmp("chmod ", resCmd->name) == 0) { 683 EXPECT_TRUE(strlen(resCmd->cmdContent) >= 6); // 0xxx x at least 6 characters 684 EXPECT_EQ('0', resCmd->cmdContent[0]); 685 EXPECT_EQ(' ', resCmd->cmdContent[4]); // 4 bytes, after 0xxx must be space 686 for (int i = 1; i < 4; ++i) { // 4 bytes, 0xxx, xxx must be digits 687 EXPECT_TRUE(resCmd->cmdContent[i] >= '0' && resCmd->cmdContent[i] <= '7'); 688 } 689 for (size_t i = 5; i < strlen(resCmd->cmdContent); ++i) { // target starts from index 5 690 EXPECT_NE(' ', resCmd->cmdContent[i]); // no spaces allowed 691 } 692 } else if (strcmp("chown ", resCmd->name) == 0) { 693 EXPECT_TRUE(strlen(resCmd->cmdContent) >= 5); // x y z at least 5 characters 694 EXPECT_NE(' ', resCmd->cmdContent[0]); // should not start with space 695 EXPECT_NE(' ', resCmd->cmdContent[strlen(resCmd->cmdContent) - 1]); // should not end with space 696 size_t spacePos = 0; 697 size_t spaceCnt = 0; 698 for (size_t i = 1; i < strlen(resCmd->cmdContent); ++i) { 699 if (resCmd->cmdContent[i] != ' ') { 700 continue; 701 } 702 ++spaceCnt; 703 if (spacePos != 0) { 704 EXPECT_NE(spacePos + 1, i); // consecutive spaces should not appear 705 } 706 spacePos = i; 707 } 708 EXPECT_EQ(spaceCnt, 2); // 2 spaces allowed in cmd content 709 } else if (strcmp("mount ", resCmd->name) == 0) { 710 EXPECT_NE(' ', resCmd->cmdContent[0]); // should not start with space 711 } else if (strcmp("loadcfg ", resCmd->name) == 0) { 712 EXPECT_NE(' ', resCmd->cmdContent[0]); // should not start with space 713 } else if (strcmp("export ", resCmd->name) == 0) { 714 EXPECT_NE(' ', resCmd->cmdContent[0]); // should not start with space 715 } else if (strcmp("exec ", resCmd->name) == 0) { 716 EXPECT_NE(' ', resCmd->cmdContent[0]); // should not start with space 717 } else { // unknown cmd 718 EXPECT_TRUE(false); 719 } 720} 721 722static void CheckJob(const cJSON *jobItem) 723{ 724 if (jobItem == nullptr) { 725 return; 726 } 727 728 cJSON *cmdsItem = cJSON_GetObjectItem(jobItem, CMDS_ARR_NAME_IN_JSON.c_str()); 729 EXPECT_TRUE(cmdsItem != nullptr); 730 EXPECT_TRUE(cJSON_IsArray(cmdsItem)); 731 732 int cmdLinesCnt = cJSON_GetArraySize(cmdsItem); 733 EXPECT_TRUE(cmdLinesCnt <= MAX_CMD_CNT_IN_ONE_JOB); 734 735 for (int i = 0; i < cmdLinesCnt; ++i) { 736 char *cmdLineStr = cJSON_GetStringValue(cJSON_GetArrayItem(cmdsItem, i)); 737 EXPECT_TRUE(cmdLineStr != nullptr); 738 EXPECT_TRUE(strlen(cmdLineStr) > 0); 739 740 TestCmdLine resCmd; 741 (void)memset_s(&resCmd, sizeof(resCmd), 0, sizeof(resCmd)); 742 ParseCmdLine(cmdLineStr, &resCmd); 743 CheckCmd(&resCmd); 744 } 745} 746 747static void CheckJobs(const cJSON* fileRoot) 748{ 749 int jobArrSize = 0; 750 cJSON *jobArr = GetArrItem(fileRoot, jobArrSize, JOBS_ARR_NAME_IN_JSON); 751 EXPECT_TRUE(jobArr != nullptr); 752 EXPECT_TRUE(jobArrSize == JOBS_IN_FILE_COUNT); 753 754 bool findPreInit = false; 755 bool findInit = false; 756 bool findPostInit = false; 757 for (int i = 0; i < jobArrSize; ++i) { 758 cJSON *jobItem = cJSON_GetArrayItem(jobArr, i); 759 EXPECT_TRUE(jobItem != nullptr); 760 char *jobNameStr = cJSON_GetStringValue(cJSON_GetObjectItem(jobItem, "name")); 761 EXPECT_TRUE(jobNameStr != nullptr); 762 if (strcmp(jobNameStr, "pre-init") == 0) { 763 findPreInit = true; 764 } else if (strcmp(jobNameStr, "init") == 0) { 765 findInit = true; 766 } else if (strcmp(jobNameStr, "post-init") == 0) { 767 findPostInit = true; 768 } else { 769 EXPECT_TRUE(false); // unknown job name 770 continue; 771 } 772 773 CheckJob(jobItem); 774 } 775 776 EXPECT_TRUE(findPreInit && findInit && findPostInit); 777} 778 779/* 780 * @tc.name: cfgCheckContent_001 781 * @tc.desc: init.cfg file content check 782 * @tc.type: FUNC 783 */ 784HWTEST_F(StartupInitUTest, cfgCheckContent_001, TestSize.Level0) 785{ 786 char *fileBuf = ReadFileToBuf(); 787 if (fileBuf == nullptr) { 788 EXPECT_TRUE(fileBuf != nullptr); 789 return; 790 } 791 792 cJSON *fileRoot = cJSON_Parse(fileBuf); 793 free(fileBuf); 794 fileBuf = nullptr; 795 796 EXPECT_TRUE(fileRoot != nullptr); 797 798 CheckServices(fileRoot); 799 CheckJobs(fileRoot); 800 cJSON_Delete(fileRoot); 801 fileRoot = nullptr; 802} 803 804/* 805 * @tc.name: CreateIllegalCfg 806 * @tc.desc: Create illegal Config file for testing 807 * @tc.type: FUNC 808 */ 809static void CreateIllegalCfg() 810{ 811 FILE *testCfgFile = fopen(TEST_CFG_ILLEGAL.c_str(), "w+"); 812 if (testCfgFile == nullptr) { 813 return; 814 } 815 816 std::string writeContent = "mount zpfs /patch/etc:/etc /etc"; 817 if (fwrite(writeContent.c_str(), writeContent.length(), 1, testCfgFile) != 1) { 818 (void)fclose(testCfgFile); 819 return; 820 } 821 822 (void)fclose(testCfgFile); 823} 824 825/* 826 * @tc.name: cmdFuncDoLoadCfgTest_001 827 * @tc.desc: parse function, parse success test 828 * @tc.type: FUNC 829 */ 830HWTEST_F(StartupInitUTest, cmdFuncDoLoadCfgTest_001, TestSize.Level0) 831{ 832 TestCmdLine curCmdLine; 833 (void)memset_s(&curCmdLine, sizeof(curCmdLine), 0, sizeof(curCmdLine)); 834 835 ParseCmdLine("loadcfg /patch/fstab.cfg", &curCmdLine); 836 EXPECT_EQ(0, strcmp("loadcfg ", curCmdLine.name)); 837 EXPECT_EQ(0, strcmp("/patch/fstab.cfg", curCmdLine.cmdContent)); 838}; 839 840/* 841 * @tc.name: cmdFuncDoLoadCfgTest_002 842 * @tc.desc: fstab.cfg file fail test 843 * @tc.type: FUNC 844 */ 845HWTEST_F(StartupInitUTest, cmdFuncDoLoadCfgTest_002, TestSize.Level0) 846{ 847 TestCmdLine curCmdLine; 848 std::string cmdStr = "loadcfg "; 849 std::string cmdContentStr = "/patch/file_not_exist.cfg"; 850 struct stat testCfgStat = {0}; 851 852 (void)memset_s(&curCmdLine, sizeof(curCmdLine), 0, sizeof(curCmdLine)); 853 std::string command = cmdStr + cmdContentStr; 854 ParseCmdLine(command.c_str(), &curCmdLine); 855 EXPECT_EQ(0, strcmp(cmdStr.c_str(), curCmdLine.name)); 856 EXPECT_EQ(0, strcmp(cmdContentStr.c_str(), curCmdLine.cmdContent)); 857 stat(cmdContentStr.c_str(), &testCfgStat); 858 EXPECT_TRUE(testCfgStat.st_size == 0); 859 DoCmd(&curCmdLine); 860 861 cmdContentStr = TEST_CFG_ILLEGAL; 862 CreateIllegalCfg(); 863 (void)memset_s(&curCmdLine, sizeof(curCmdLine), 0, sizeof(curCmdLine)); 864 command = cmdStr + cmdContentStr; 865 ParseCmdLine(command.c_str(), &curCmdLine); 866 EXPECT_EQ(0, strcmp(cmdStr.c_str(), curCmdLine.name)); 867 EXPECT_EQ(0, strcmp(cmdContentStr.c_str(), curCmdLine.cmdContent)); 868 EXPECT_EQ(0, stat(cmdContentStr.c_str(), &testCfgStat)); 869 EXPECT_TRUE(testCfgStat.st_size > 0); 870 DoCmd(&curCmdLine); 871 872 remove(TEST_CFG_ILLEGAL.c_str()); 873} 874 875/* 876 * @tc.name: cmdFuncDoLoadCfgTest_003 877 * @tc.desc: fstab.cfg file success test 878 * @tc.type: FUNC 879 */ 880HWTEST_F(StartupInitUTest, cmdFuncDoLoadCfgTest_003, TestSize.Level0) 881{ 882 TestCmdLine curCmdLine; 883 std::string cmdStr = "loadcfg "; 884 std::string cmdContentStr = "/patch/fstab.cfg"; 885 char buf[CAT_BUF_SIZE] = {0}; 886 struct stat testCfgStat = {0}; 887 FILE *fd = nullptr; 888 size_t size; 889 bool hasZpfs = false; 890 std::string command = cmdStr + cmdContentStr; 891 ParseCmdLine(command.c_str(), &curCmdLine); 892 EXPECT_EQ(0, strcmp(cmdStr.c_str(), curCmdLine.name)); 893 EXPECT_EQ(0, strcmp(cmdContentStr.c_str(), curCmdLine.cmdContent)); 894 895 DoCmd(&curCmdLine); 896 897 stat(cmdContentStr.c_str(), &testCfgStat); 898 if (testCfgStat.st_size > 0) { 899 fd = fopen(TEST_PROC_MOUNTS.c_str(), "r"); 900 901 if (fd == nullptr) { 902 EXPECT_TRUE(fd != nullptr); 903 return; 904 } 905 906 do { 907 size = fread(buf, 1, CAT_BUF_SIZE - 1, fd); 908 if (size < 0) { 909 EXPECT_TRUE(size >= 0); 910 break; 911 } 912 buf[CAT_BUF_SIZE - 1] = 0; 913 if (strstr(buf, "zpfs") != nullptr) { 914 hasZpfs = true; 915 break; 916 } 917 } while (size > 0); 918 EXPECT_TRUE(hasZpfs); 919 fclose(fd); 920 } 921} 922 923/* 924 * @tc.name: cmdJobTest_001 925 * @tc.desc: job functions test 926 * @tc.type: FUNC 927 */ 928HWTEST_F(StartupInitUTest, cmdJobTest_001, TestSize.Level0) 929{ 930 // functions do not crash 931 ParseAllJobs(nullptr, nullptr); 932 DoJob(nullptr); 933 DoJob("job name does not exist"); 934 ReleaseAllJobs(); 935 StartServiceByName("service name does not exist"); 936 StopAllServices(0, nullptr, 0, nullptr); 937 ServiceReap(nullptr); 938 EXPECT_NE(0, ServiceStart(nullptr, nullptr)); 939 EXPECT_NE(0, ServiceStop(nullptr)); 940} 941 942/* 943 * @tc.name: cmdJobTest_002 944 * @tc.desc: job functions test 945 * @tc.type: FUNC 946 */ 947HWTEST_F(StartupInitUTest, cmdJobTest_002, TestSize.Level0) 948{ 949 std::string cfgJson = "{\"jobs\":[{\"name\":\"pre-init\",\"cmds\":[\"mkdir " + 950 PRE_INIT_DIR + "\"]},{\"name\":\"init\",\"cmds\":[\"mkdir " + INIT_DIR + 951 "\"]},{\"name\":\"post-init\",\"cmds\":[\"mkdir " + POST_INIT_DIR + "\"]}]}"; 952 cJSON* jobItem = cJSON_Parse(cfgJson.c_str()); 953 EXPECT_NE(nullptr, jobItem); 954 if (jobItem == nullptr) { 955 return; 956 } 957 ConfigContext context = { INIT_CONTEXT_MAIN }; 958 ParseAllJobs(jobItem, &context); 959 DoJob("pre-init"); 960 DoJob("init"); 961 DoJob("post-init"); 962 963 // check if dir exists 964 struct stat postDirStat = {0}; 965 EXPECT_EQ(0, stat(POST_INIT_DIR.c_str(), &postDirStat)); 966 967 // release resource 968 cJSON_Delete(jobItem); 969 if (remove(POST_INIT_DIR.c_str()) != 0 || 970 remove(INIT_DIR.c_str()) != 0 || 971 remove(PRE_INIT_DIR.c_str()) != 0) { 972 } 973 ReleaseAllJobs(); 974} 975} // namespace OHOS 976