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