• 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 
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