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