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
165 /*
166 * @tc.name: cmdFuncParseCmdTest_001
167 * @tc.desc: parse function, nullptr test
168 * @tc.type: FUNC
169 */
170 HWTEST_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 */
181 HWTEST_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 */
208 HWTEST_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 */
225 HWTEST_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 */
265 HWTEST_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 */
296 HWTEST_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 */
307 HWTEST_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 */
326 HWTEST_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 */
371 HWTEST_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 */
427 HWTEST_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 */
463 HWTEST_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 */
525 HWTEST_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
ReadFileToBuf()536 static 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
GetArrItem(const cJSON * fileRoot,int & arrSize,const std::string & arrName)568 static 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
IsForbidden(const char * fieldStr)578 static 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
CheckService(const cJSON * curItem)600 static 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
CheckServices(const cJSON * fileRoot)655 static 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
CheckCmd(const TestCmdLine * resCmd)669 static 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
CheckJob(const cJSON * jobItem)722 static 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
CheckJobs(const cJSON * fileRoot)747 static 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 */
784 HWTEST_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 */
CreateIllegalCfg()809 static 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 */
830 HWTEST_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 */
845 HWTEST_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 */
880 HWTEST_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 */
928 HWTEST_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 */
947 HWTEST_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