• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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