1/*
2 * Copyright (c) 2022 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
16#include <cinttypes>
17#include <sys/mount.h>
18#include "fs_manager/fs_manager.h"
19#include "init_log.h"
20#include "init_param.h"
21#include "param_stub.h"
22#include "securec.h"
23#include "systemcapability.h"
24#include "service_control.h"
25#include "control_fd.h"
26#include "loop_event.h"
27#include "fd_holder.h"
28#include "fd_holder_internal.h"
29
30using namespace testing::ext;
31using namespace std;
32
33namespace init_ut {
34
35extern "C" {
36void CmdDisConnectComplete(const TaskHandle client);
37void CmdOnSendMessageComplete(const TaskHandle task, const BufferHandle handle);
38void CmdOnClose(const TaskHandle task);
39void CmdOnConnectComplete(const TaskHandle client);
40void CmdOnRecvMessage(const TaskHandle task, const uint8_t *buffer, uint32_t buffLen);
41void ProcessPtyRead(const WatcherHandle taskHandle, int fd, uint32_t *events, const void *context);
42void ProcessPtyWrite(const WatcherHandle taskHandle, int fd, uint32_t *events, const void *context);
43int CmdOnIncommingConnect(const LoopHandle loop, const TaskHandle server);
44CmdAgent *CmdAgentCreate(const char *server);
45void CmdClientOnRecvMessage(const TaskHandle task, const uint8_t *buffer, uint32_t buffLen);
46int SendCmdMessage(const CmdAgent *agent, uint16_t type, const char *cmd, const char *ptyName);
47int SendMessage(LoopHandle loop, TaskHandle task, const char *message);
48int *GetFdsFromMsg(size_t *outFdCount, pid_t *requestPid, struct msghdr msghdr);
49int BuildSendData(char *buffer, size_t size, const char *serviceName, bool hold, bool poll);
50int CheckSocketPermission(const TaskHandle task);
51}
52
53class InnerkitsUnitTest : public testing::Test {
54public:
55    static void SetUpTestCase(void) {};
56    static void TearDownTestCase(void) {};
57    void SetUp() {};
58    void TearDown() {};
59};
60
61static int CallbackSendMsgProcessTest(const CmdAgent *agent, uint16_t type, const char *cmd, const char *ptyName)
62{
63    return 0;
64}
65
66/**
67* @tc.name: ReadFstabFromFile_unitest
68* @tc.desc: read fstab from test file.
69* @tc.type: FUNC
70* @tc.require:
71* @tc.author:
72*/
73HWTEST_F(InnerkitsUnitTest, Init_InnerkitsTest_ReadFstabFromFile001, TestSize.Level1)
74{
75    Fstab *fstab = nullptr;
76    const std::string fstabFile1 = "/data/fstab.updater1";
77    fstab = ReadFstabFromFile(fstabFile1.c_str(), false);
78    EXPECT_EQ(fstab, nullptr);
79    const std::string fstabFile2 = STARTUP_INIT_UT_PATH"/mount_unitest/ReadFstabFromFile1.fstable";
80    fstab = ReadFstabFromFile(fstabFile2.c_str(), false);
81    EXPECT_NE(fstab, nullptr);
82    ParseFstabPerLine(const_cast<char *>("test"), fstab, true, nullptr);
83    ReleaseFstab(fstab);
84}
85
86/**
87* @tc.name: FindFstabItemForPath_unitest
88* @tc.desc: read fstab from test file, then find item according to path.
89* @tc.type: FUNC
90* @tc.require:
91* @tc.author:
92*/
93HWTEST_F(InnerkitsUnitTest, Init_InnerkitsTest_FindFstabItemForPath001, TestSize.Level1)
94{
95    const std::string fstabFile1 = STARTUP_INIT_UT_PATH"/mount_unitest/ReadFstabFromFile1.fstable";
96    Fstab *fstab = nullptr;
97    fstab = ReadFstabFromFile(fstabFile1.c_str(), false);
98    ASSERT_NE(fstab, nullptr);
99    FstabItem* item = nullptr;
100    const std::string path1 = "";
101    item = FindFstabItemForPath(*fstab, path1.c_str());
102    if (item == nullptr) {
103        SUCCEED();
104    }
105    const std::string path2 = "/data";
106    item = FindFstabItemForPath(*fstab, path2.c_str());
107    if (item != nullptr) {
108        SUCCEED();
109    }
110    const std::string path3 = "/data2";
111    item = FindFstabItemForPath(*fstab, path3.c_str());
112    if (item == nullptr) {
113        SUCCEED();
114    }
115    const std::string path4 = "/data2/test";
116    item = FindFstabItemForPath(*fstab, path4.c_str());
117    if (item != nullptr) {
118        SUCCEED();
119    }
120    ReleaseFstab(fstab);
121    fstab = nullptr;
122}
123
124/**
125* @tc.name: FindFstabItemForMountPoint_unitest
126* @tc.desc: read fstab from test file, then find item that matches with the mount point.
127* @tc.type: FUNC
128* @tc.require:
129* @tc.author:
130*/
131HWTEST_F(InnerkitsUnitTest, Init_InnerkitsTest_FindFstabItemForMountPoint001, TestSize.Level1)
132{
133    const std::string fstabFile1 = STARTUP_INIT_UT_PATH"/mount_unitest/ReadFstabFromFile1.fstable";
134    Fstab *fstab = nullptr;
135    fstab = ReadFstabFromFile(fstabFile1.c_str(), false);
136    ASSERT_NE(fstab, nullptr);
137    FstabItem* item = nullptr;
138    const std::string mp1 = "/data";
139    const std::string mp2 = "/data2";
140    item = FindFstabItemForMountPoint(*fstab, mp2.c_str());
141    if (item == nullptr) {
142        SUCCEED();
143    }
144    const std::string mp3 = "/data";
145    item = FindFstabItemForMountPoint(*fstab, mp3.c_str());
146    if (item != nullptr) {
147        SUCCEED();
148    }
149    ReleaseFstab(fstab);
150    fstab = nullptr;
151}
152
153/**
154* @tc.name: GetMountFlags_unitest
155* @tc.desc: read fstab from test file, then find the item and get mount flags.
156* @tc.type: FUNC
157* @tc.require:
158* @tc.author:
159*/
160HWTEST_F(InnerkitsUnitTest, Init_InnerkitsTest_GetMountFlags001, TestSize.Level1)
161{
162    const std::string fstabFile1 = STARTUP_INIT_UT_PATH"/mount_unitest/ReadFstabFromFile1.fstable";
163    Fstab *fstab = nullptr;
164    fstab = ReadFstabFromFile(fstabFile1.c_str(), true);
165    ASSERT_NE(fstab, nullptr);
166    struct FstabItem* item = nullptr;
167    const std::string mp = "/hos";
168    item = FindFstabItemForMountPoint(*fstab, mp.c_str());
169    if (item == nullptr) {
170        SUCCEED();
171    }
172    const int bufferSize = 512;
173    char fsSpecificOptions[bufferSize] = {0};
174    unsigned long flags = GetMountFlags(item->mountOptions, fsSpecificOptions, bufferSize, item->mountPoint);
175    EXPECT_EQ(flags, static_cast<unsigned long>(MS_NOSUID | MS_NODEV | MS_NOATIME));
176    ReleaseFstab(fstab);
177    fstab = nullptr;
178}
179
180/**
181* @tc.name: GetSlotInfo_unittest
182* @tc.desc: get the number of slots and get current slot.
183* @tc.type: FUNC
184* @tc.require:issueI5NTX2
185* @tc.author:
186*/
187HWTEST_F(InnerkitsUnitTest, Init_InnerkitsTest_GetSlotInfo001, TestSize.Level1)
188{
189    EXPECT_NE(GetBootSlots(), -1);
190    EXPECT_NE(GetCurrentSlot(), -1);
191}
192
193/**
194* @tc.name: LoadFstabFromCommandLine_unittest
195* @tc.desc: get fstab from command line.
196* @tc.type: FUNC
197* @tc.require:issueI5NTX2
198* @tc.author:
199*/
200HWTEST_F(InnerkitsUnitTest, Init_InnerkitsTest_LoadFstabFromCommandLine001, TestSize.Level1)
201{
202    EXPECT_NE(LoadFstabFromCommandLine(), (Fstab *)nullptr);
203}
204
205/**
206* @tc.name: GetBlockDevicePath_unittest
207* @tc.desc: get block device path according to valid or invalid partition.
208* @tc.type: FUNC
209* @tc.require:issueI5NTX2
210* @tc.author:
211*/
212HWTEST_F(InnerkitsUnitTest, Init_InnerkitsTest_GetBlockDevicePath001, TestSize.Level1)
213{
214    char devicePath[MAX_BUFFER_LEN] = {0};
215    EXPECT_EQ(GetBlockDevicePath("/vendor", devicePath, MAX_BUFFER_LEN), 0);
216    EXPECT_EQ(GetBlockDevicePath("/misc", devicePath, MAX_BUFFER_LEN), 0);
217    EXPECT_EQ(GetBlockDevicePath("/invalid", devicePath, MAX_BUFFER_LEN), -1);
218    unlink(BOOT_CMD_LINE);
219    EXPECT_EQ(GetBlockDevicePath("/invalid", devicePath, MAX_BUFFER_LEN), -1);
220    GetCurrentSlot();
221    // restore cmdline
222    PrepareCmdLineData();
223}
224
225/**
226* @tc.name: DoFormat_unittest
227* @tc.desc: format file system, includes ext4 and f2fs type.
228* @tc.type: FUNC
229* @tc.require:
230* @tc.author:
231*/
232HWTEST_F(InnerkitsUnitTest, Init_InnerkitsTest_DoFormat001, TestSize.Level1)
233{
234    EXPECT_NE(DoFormat("/testpath", "ext4"), -1);
235    EXPECT_NE(DoFormat("/testpath", "f2fs"), -1);
236    EXPECT_EQ(DoFormat("/testpath", "notFs"), -1);
237    EXPECT_EQ(DoFormat(nullptr, nullptr), -1);
238}
239
240/**
241* @tc.name: MountAllWithFstabFile_unittest
242* @tc.desc: mount partitions according to fstab that read from file.
243* @tc.type: FUNC
244* @tc.require:issueI5NTX2
245* @tc.author:
246*/
247HWTEST_F(InnerkitsUnitTest, Init_InnerkitsTest_MountAllWithFstabFile001, TestSize.Level1)
248{
249    EXPECT_NE(MountAllWithFstabFile(STARTUP_INIT_UT_PATH"/etc/fstab.required", 0), 1);
250    EXPECT_NE(UmountAllWithFstabFile(STARTUP_INIT_UT_PATH"/etc/fstab.required"), 1);
251    EXPECT_EQ(MountAllWithFstabFile("/testErrorFile", 0), -1);
252    EXPECT_EQ(MountAllWithFstabFile(nullptr, 0), -1);
253    EXPECT_EQ(GetMountStatusForMountPoint(nullptr), -1);
254    FstabItem fstabItem = {};
255    fstabItem.fsType = strdup("notSupport");
256    fstabItem.mountPoint = strdup("");
257    EXPECT_EQ(MountOneItem(nullptr), -1);
258    EXPECT_EQ(MountOneItem(&fstabItem), 0);
259    if (fstabItem.fsType != nullptr) {
260        free(fstabItem.fsType);
261        fstabItem.fsType = nullptr;
262    }
263    if (fstabItem.mountPoint != nullptr) {
264        free(fstabItem.mountPoint);
265        fstabItem.mountPoint = nullptr;
266    }
267}
268
269#define SYSCAP_MAX_SIZE 100
270
271// TestSysCap
272HWTEST_F(InnerkitsUnitTest, Init_InnerkitsTest_TestSysCap001, TestSize.Level1)
273{
274    bool ret = HasSystemCapability("test.cap");
275    EXPECT_EQ(ret, false);
276    ret = HasSystemCapability(nullptr);
277    EXPECT_EQ(ret, false);
278    ret = HasSystemCapability("ArkUI.ArkUI.Napi");
279    EXPECT_EQ(ret, true);
280    ret = HasSystemCapability("SystemCapability.ArkUI.ArkUI.Napi");
281    EXPECT_EQ(ret, true);
282    char *wrongName = reinterpret_cast<char *>(malloc(SYSCAP_MAX_SIZE));
283    ASSERT_NE(wrongName, nullptr);
284    EXPECT_EQ(memset_s(wrongName, SYSCAP_MAX_SIZE, 1, SYSCAP_MAX_SIZE), 0);
285    HasSystemCapability(wrongName);
286    free(wrongName);
287}
288
289// TestControlService
290HWTEST_F(InnerkitsUnitTest, Init_InnerkitsTest_ControlService001, TestSize.Level1)
291{
292    TestSetParamCheckResult("startup.service.ctl.", 0777, 0);
293    ServiceControl("deviceinfoservice", START);
294    SystemWriteParam("startup.service.ctl.deviceinfoservice", "2");
295    ServiceControl("deviceinfoservice", RESTART);
296    ServiceControl("deviceinfoservice", STOP);
297    SystemWriteParam("startup.service.ctl.deviceinfoservice", "0");
298    ServiceControl("param_watcher", RESTART);
299    EXPECT_EQ(ServiceControl(nullptr, RESTART), -1);
300    const char *argv[] = {"testArg"};
301    ServiceControlWithExtra("deviceinfoservice", RESTART, argv, 1);
302    ServiceControlWithExtra(nullptr, RESTART, argv, 1);
303    ServiceControlWithExtra(nullptr, 3, argv, 1); // 3 is action
304    ServiceControlWithExtra("notservie", RESTART, argv, 1);
305    ServiceControlWithExtra("deviceinfoservice", 3, argv, 1); // 3 is action
306    ServiceSetReady("deviceinfoservice");
307    ServiceSetReady(nullptr);
308    ServiceWaitForStatus("deviceinfoservice", SERVICE_READY, 1);
309    ServiceWaitForStatus("deviceinfoservice", SERVICE_READY, -1);
310    ServiceWaitForStatus(nullptr, SERVICE_READY, 1);
311    StartServiceByTimer("deviceinfoservice", 1);
312    StartServiceByTimer("deviceinfoservice", 0);
313    StartServiceByTimer(nullptr, 0);
314    StopServiceTimer("deviceinfoservice");
315}
316
317static int TestIncommingConnect(const LoopHandle loop, const TaskHandle server)
318{
319    UNUSED(loop);
320    UNUSED(server);
321    return 0;
322}
323
324// TestControlFd
325HWTEST_F(InnerkitsUnitTest, Init_InnerkitsTest_ControlFd001, TestSize.Level1)
326{
327    CmdClientInit("/data/testSock1", ACTION_DUMP, "cmd", nullptr);
328    CmdClientInit("/data/testSock1", ACTION_DUMP, "cmd", CallbackSendMsgProcessTest);
329    CmdClientInit(INIT_CONTROL_FD_SOCKET_PATH, ACTION_DUMP, nullptr, nullptr);
330    CmdClientInit(nullptr, ACTION_DUMP, "cmd", nullptr);
331
332    CmdDisConnectComplete(nullptr);
333    CmdOnSendMessageComplete(nullptr, nullptr);
334    CmdOnConnectComplete(nullptr);
335    CmdClientOnRecvMessage(nullptr, nullptr, 0);
336    CmdAgentCreate(nullptr);
337    CmdAgent *agent = CmdAgentCreate(INIT_CONTROL_FD_SOCKET_PATH);
338    EXPECT_NE(agent, nullptr);
339    SendCmdMessage(agent, ACTION_DUMP, "cmd", "test");
340    SendCmdMessage(agent, ACTION_DUMP, "cmd", nullptr);
341    SendMessage(nullptr, nullptr, nullptr);
342    uint32_t events = 0;
343    InitPtyInterface(agent, 0, "cmd", nullptr);
344    InitPtyInterface(agent, 0, "cmd", CallbackSendMsgProcessTest);
345    InitPtyInterface(agent, 0, nullptr, nullptr);
346    InitPtyInterface(nullptr, 0, nullptr, nullptr);
347    mode_t mode = S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH;
348    CheckAndCreatFile("/data/init_ut/testInput", mode);
349    int fd = open("/data/init_ut/testInput", O_RDWR);
350    perror("write failed");
351    EXPECT_GT(fd, 0);
352    EXPECT_GT(write(fd, "test", strlen("test")), 0);
353    perror("write failed");
354    lseek(fd, 0, SEEK_SET);
355    ProcessPtyRead(nullptr, fd, &events, (void *)agent);
356    ProcessPtyRead(nullptr, fd, &events, (void *)agent);
357    ProcessPtyRead(nullptr, STDERR_FILENO, &events, nullptr);
358    lseek(fd, 0, SEEK_SET);
359    ProcessPtyWrite(nullptr, fd, &events, (void *)agent);
360    ProcessPtyWrite(nullptr, fd, &events, (void *)agent);
361    ProcessPtyWrite(nullptr, STDERR_FILENO, &events, nullptr);
362    close(fd);
363
364    if (agent) {
365        CmdOnClose(agent->task);
366    }
367}
368
369HWTEST_F(InnerkitsUnitTest, Init_InnerkitsTest_ControlFdServer001, TestSize.Level1)
370{
371    CmdServiceInit(nullptr, nullptr, nullptr);
372    CmdServiceInit("/data/testSock1", [](uint16_t type, const char *serviceCmd, const void *context) {
373        UNUSED(type);
374        UNUSED(serviceCmd);
375        UNUSED(context);
376        }, LE_GetDefaultLoop());
377
378    TaskHandle testServer = nullptr;
379    LE_StreamServerInfo info = {};
380    info.baseInfo.flags = TASK_STREAM | TASK_SERVER | TASK_PIPE | TASK_TEST;
381    info.server = (char *)"/data/testSock1";
382    info.socketId = -1;
383    info.baseInfo.close = nullptr;
384    info.disConnectComplete = nullptr;
385    info.incommingConnect = TestIncommingConnect;
386    info.sendMessageComplete = nullptr;
387    info.recvMessage = nullptr;
388    (void)LE_CreateStreamServer(LE_GetDefaultLoop(), &testServer, &info);
389    CmdOnIncommingConnect(LE_GetDefaultLoop(), testServer);
390
391    CmdOnRecvMessage(testServer, nullptr, 0);
392    CmdMessage *cmdMsg = (CmdMessage *)malloc(sizeof(CmdMessage) + strlen("test"));
393    cmdMsg->type = ACTION_DUMP;
394    cmdMsg->ptyName[0] = '\0';;
395    CmdOnRecvMessage(testServer, (uint8_t *)(&cmdMsg), 0);
396    cmdMsg->type = ACTION_DUMP;
397    cmdMsg->cmd[0] = 'a';
398    cmdMsg->ptyName[0] = 'a';
399    CmdOnRecvMessage(testServer, (uint8_t *)(&cmdMsg), 0);
400    CmdServiceProcessDelClient(0);
401    CmdServiceProcessDelClient(0);
402    free(cmdMsg);
403}
404
405HWTEST_F(InnerkitsUnitTest, Init_InnerkitsTest_HoldFd001, TestSize.Level1)
406{
407    CheckSocketPermission(nullptr);
408    CmdServiceProcessDestroyClient();
409}
410
411HWTEST_F(InnerkitsUnitTest, Init_InnerkitsTest_HoldFd002, TestSize.Level1)
412{
413    int fds1[] = {1, 0};
414    ServiceSaveFd("testServiceName", fds1, ARRAY_LENGTH(fds1));
415    ServiceSaveFd(nullptr, fds1, ARRAY_LENGTH(fds1));
416    ServiceSaveFdWithPoll("testServiceName", fds1, 0);
417    ServiceSaveFdWithPoll(nullptr, fds1, 0);
418    ServiceSaveFdWithPoll("testServiceName", fds1, ARRAY_LENGTH(fds1));
419    EXPECT_EQ(setenv("OHOS_FD_HOLD_testServiceName", "1 0", 0), 0);
420
421    size_t fdCount = 0;
422    int *fds = nullptr;
423    ServiceGetFd("testService", nullptr);
424    ServiceGetFd("testService", &fdCount);
425    char *wrongName = (char *)malloc(MAX_FD_HOLDER_BUFFER + 1);
426    ASSERT_NE(wrongName, nullptr);
427    EXPECT_EQ(memset_s(wrongName, MAX_FD_HOLDER_BUFFER + 1, 1, MAX_FD_HOLDER_BUFFER + 1), 0);
428    ServiceGetFd(wrongName, &fdCount);
429    BuildSendData(wrongName, 1, "testService", 0, 1);
430    BuildSendData(wrongName, 1, "testService", 0, 0);
431    BuildSendData(nullptr, 1, "testService", 0, 0);
432    free(wrongName);
433
434    fds = ServiceGetFd("testServiceName", &fdCount);
435    EXPECT_NE(fds, nullptr);
436    struct msghdr msghdr = {};
437    BuildControlMessage(nullptr, nullptr, 1, 0);
438    BuildControlMessage(&msghdr, nullptr, 1, 0);
439    if (msghdr.msg_control != nullptr) {
440        free(msghdr.msg_control);
441        msghdr.msg_control = nullptr;
442    }
443    BuildControlMessage(&msghdr, fds, -1, 0);
444    if (msghdr.msg_control != nullptr) {
445        free(msghdr.msg_control);
446        msghdr.msg_control = nullptr;
447    }
448    BuildControlMessage(&msghdr, fds, -1, 1);
449    if (msghdr.msg_control != nullptr) {
450        free(msghdr.msg_control);
451        msghdr.msg_control = nullptr;
452    }
453    if (fds != nullptr)
454    {
455        free(fds);
456        fds = nullptr;
457    }
458}
459
460HWTEST_F(InnerkitsUnitTest, Init_InnerkitsTest_HoldFd003, TestSize.Level1)
461{
462    size_t fdCount = 0;
463    int *fds = nullptr;
464    char buffer[MAX_FD_HOLDER_BUFFER + 1] = {};
465    pid_t requestPid = -1;
466    struct msghdr msghdr = {};
467    GetFdsFromMsg(&fdCount, &requestPid, msghdr);
468    msghdr.msg_flags = MSG_TRUNC;
469    GetFdsFromMsg(&fdCount, &requestPid, msghdr);
470    struct iovec iovec = {
471        .iov_base = buffer,
472        .iov_len = MAX_FD_HOLDER_BUFFER,
473    };
474    ReceiveFds(0, iovec, &fdCount, false, &requestPid);
475    fds = ReceiveFds(0, iovec, &fdCount, true, &requestPid);
476    if (fds != nullptr)
477    {
478        free(fds);
479        fds = nullptr;
480    }
481    if (msghdr.msg_control != nullptr) {
482        free(msghdr.msg_control);
483    }
484}
485
486} // namespace init_ut
487