1/*
2 * Copyright (c) 2020-2021 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// tested api in this file: getpid getppid getpgrp setpgrp  getpgid setpgid
17
18#include <unistd.h>
19#include <sys/types.h>
20#include <sys/shm.h>
21#include <gtest/gtest.h>
22#include "log.h"
23#include "utils.h"
24#include "KernelConstants.h"
25
26using namespace testing::ext;
27
28class PidTest : public testing::Test {
29protected:
30    const char* mChildELF = RES_DIR_KERNEL "process/executor";
31};
32
33/**
34 * @tc.number SUB_KERNEL_PM_PID_Getppid_0100
35 * @tc.name   getpid and getppid test
36 * @tc.desc   [C- SOFTWARE -0200]
37 */
38HWTEST_F(PidTest, testGetPpid, Function | MediumTest | Level1)
39{
40    pid_t parentPid = getpid();
41    pid_t pid = fork();
42    ASSERT_TRUE(pid >= 0) << "======== Fork Error! =========";
43    if (pid == 0) { // child
44        pid_t pPid = getppid();
45        if (pPid != parentPid) {
46            LOG("getppid fail, expect:%d, but get:%d", parentPid, pPid);
47            exit(1);
48        }
49        exit(0);
50    } else { // parent
51        Msleep(20);
52        WaitProcExitedOK(pid);
53    }
54}
55
56/**
57 * @tc.number SUB_KERNEL_PM_PID_Getppid_0200
58 * @tc.name   test that a orphaned process will inherite by init.
59 * @tc.desc   [C- SOFTWARE -0200]
60 */
61HWTEST_F(PidTest, testOrphanProcess, Function | MediumTest | Level1)
62{
63    const int retPass = 1;
64    const int retFail = 2;
65    const int memSize = 32;
66    int shmID = shmget(IPC_PRIVATE, memSize, 0666 | IPC_CREAT);
67    ASSERT_NE(shmID, -1) << "get share mem fail, errno = " << errno;
68    int *shared = (int*)(shmat(shmID, nullptr, 0));
69    ASSERT_NE(shared, reinterpret_cast<int*>(-1)) << "shmat fail, errno = " << errno;
70    shared[0] = retPass;
71    shared[1] = 0;
72
73    LOG("parent process id:%d", getpid());
74    pid_t pid = fork();
75    EXPECT_TRUE(pid >= 0) << "======== Fork Error! =========";
76    if (pid == 0) { // child
77        LOG("sub parent process id:%d", getpid());
78        pid_t pid2 = fork();
79        if (pid2 < 0) {
80            LOG("======== Fork Error! =========");
81            exit(1);
82        }
83
84        if (pid2 == 0) { // child
85            LOG("orphane process id:%d", getpid());
86            int *shmAddr = (int*)(shmat(shmID, nullptr, 0));
87            LOG("before while child child %d", shmAddr[1]);
88            while (shmAddr[1] != 1) {
89                Msleep(50);
90            }
91            LOG("after while child child %d", shmAddr[1]);
92            pid_t pPid = getppid();
93            if (pPid != 1) {
94                LOG("getppid orphaned process fail, expect:1, but get:%d", pPid);
95                // transfer result to main process
96                shmAddr[0] = retFail;
97            }
98            shmAddr[1] =2;
99            LOG("child child exit %d", shmAddr[1]);
100            shmdt(shmAddr);
101            exit(0);
102        } else { // sub parent
103            exit(0);
104        }
105    }
106    // parent
107    WaitProcExitedOK(pid);
108    shared[1] = 1;
109    Msleep(200);
110    EXPECT_EQ(shared[0], retPass);
111    LOG("before while paret %d", shared[1]);
112    while (shared[1] != 2) {
113        Msleep(50);
114    }
115    shmdt(shared);
116    shmctl(shmID, IPC_RMID, nullptr);
117}
118
119/**
120 * @tc.number SUB_KERNEL_PM_PID_SetGetPgrp_0100
121 * @tc.name   setpgrp and getpgrp test
122 * @tc.desc   [C- SOFTWARE -0200]
123 */
124HWTEST_F(PidTest, testSetGetPgrp, Function | MediumTest | Level1)
125{
126    pid_t parentPid = getpid();
127    int rt = setpgrp();
128    ASSERT_EQ(rt, 0);
129
130    pid_t pgid = getpgrp();
131    ASSERT_EQ(pgid, parentPid);
132
133    pid_t pid = fork();
134    ASSERT_TRUE(pid >= 0) << "======== Fork Error! =========";
135    if (pid == 0) { // child
136        pid_t childPgid = getpgrp();
137        if (childPgid != pgid) {
138            LOG("child getpgrp fail, expect:%d, but get:%d", pgid, childPgid);
139            exit(1);
140        }
141        exit(0);
142    } else { // parent
143        Msleep(20);
144        WaitProcExitedOK(pid);
145    }
146}
147
148/**
149 * @tc.number SUB_KERNEL_PM_PID_SetGetPgid_0100
150 * @tc.name   setpgid and getpgid basic test
151 * @tc.desc   [C- SOFTWARE -0200]
152 */
153HWTEST_F(PidTest, testSetGetPgid, Function | MediumTest | Level1)
154{
155    pid_t parentPid = getpid();
156    int rt = setpgid(0, parentPid);
157    ASSERT_EQ(rt, 0);
158    rt = setpgid(0, 0);
159    ASSERT_EQ(rt, 0);
160
161    pid_t pgid = getpgid(0);
162    ASSERT_EQ(pgid, parentPid);
163
164    pid_t pid1 = fork();
165    ASSERT_TRUE(pid1 >= 0) << "======== Fork Error! =========";
166    if (pid1 == 0) { // child
167        pid_t childPgid = getpgid(0);
168        if (childPgid != pgid) {
169            LOG("child getpgid fail, expect:%d, but get:%d", pgid, childPgid);
170            exit(1);
171        }
172        Msleep(40);
173        childPgid = getpgid(0);
174        pid_t childPid = getpid();
175        if (childPgid != childPid) {
176            LOG("child new pgid check fail, pid=%d, pgid:%d", childPid, childPgid);
177            exit(1);
178        }
179        exit(0);
180    } else { // parent
181        Msleep(30);
182        rt = setpgid(pid1, pid1);
183        ASSERT_EQ(rt, 0);
184        pid_t pgid2 = getpgid(pid1);
185        ASSERT_EQ(pgid2, pid1);
186        Msleep(50);
187        WaitProcExitedOK(pid1);
188    }
189}
190/**
191 * @tc.number SUB_KERNEL_PM_PID_SetGetPgid_0200
192 * @tc.name   setpgid and getpgid test for sibling process
193 * @tc.desc   [C- SOFTWARE -0200]
194 */
195HWTEST_F(PidTest, testSetGetSiblingPgid, Function | MediumTest | Level1)
196{
197    pid_t parentPid = getpid();
198    int rt = setpgid(0, parentPid);
199    ASSERT_EQ(rt, 0);
200    rt = setpgid(0, 0);
201    ASSERT_EQ(rt, 0);
202    pid_t pgid = getpgid(0);
203    ASSERT_EQ(pgid, parentPid);
204
205    pid_t pid1 = fork();
206    ASSERT_TRUE(pid1 >= 0) << "======== Fork Error! =========";
207    if (pid1 == 0) { // child1
208        Msleep(20);
209        exit(0);
210    } else { // parent
211        pid_t pid2 = fork();
212        ASSERT_TRUE(pid2 >= 0) << "======== Fork Error! =========";
213        if (pid2 == 0) { // child2
214            int exitCode = 0;
215            pid_t siblingPgid = getpgid(pid1);
216            if (siblingPgid != parentPid) {
217                LOG("child2: get sibling pgid fail, rt=%d, errno=%d", siblingPgid, errno);
218                exitCode = 1;
219            }
220            rt = setpgid(pid1, pid1);
221            if (rt != -1) {
222                LOG("child2: setpgid for sibling should fail");
223                exitCode = 1;
224            }
225            if (errno != ESRCH) {
226                LOG("child2: setpgid errno fail, expected %d, but get %d", ESRCH, errno);
227                exitCode = 1;
228            }
229            exit(exitCode);
230        }
231        // parent
232        Msleep(50);
233        WaitProcExitedOK(pid1);
234        WaitProcExitedOK(pid2);
235    }
236}
237/**
238 * @tc.number SUB_KERNEL_PM_PID_SetGetPgid_0300
239 * @tc.name   getpgid fail test
240 * @tc.desc   [C- SOFTWARE -0200]
241 */
242HWTEST_F(PidTest, testGetpgidFail, Function | MediumTest | Level3)
243{
244    pid_t pgid = getpgid(-1);
245    EXPECT_EQ(pgid, -1);
246    EXPECT_EQ(errno, EINVAL);
247
248    pgid = getpgid(-1000001);
249    EXPECT_EQ(pgid, -1);
250    EXPECT_EQ(errno, EINVAL);
251
252    pid_t nonExitPid = GetNonExistPid(); // valid but not exist pid
253    if (nonExitPid != -1) {
254        pgid = getpgid(nonExitPid);
255        EXPECT_EQ(pgid, -1);
256        EXPECT_EQ(errno, ESRCH);
257    }
258
259    pgid = getpgid(MAX_PROCESS_NUMBER + 1);
260    EXPECT_EQ(pgid, -1);
261    EXPECT_EQ(errno, EINVAL);
262
263    pgid = getpgid(100000);
264    EXPECT_EQ(pgid, -1);
265    EXPECT_EQ(errno, EINVAL);
266
267    pgid = getpgid(1);
268    EXPECT_EQ(pgid, 1) << "get init process-groups-ID fail\n";
269}
270
271/**
272 * @tc.number SUB_KERNEL_PM_PID_SetGetPgid_0400
273 * @tc.name   setpgid fail test
274 * @tc.desc   [C- SOFTWARE -0200]
275 */
276HWTEST_F(PidTest, testSetpgidFail, Function | MediumTest | Level3)
277{
278    pid_t pid = getpid();
279    int rt = setpgrp();
280    ASSERT_EQ(rt, 0);
281
282    LOG("invalid pid test...");
283    rt = setpgid(-1, 0);
284    EXPECT_EQ(rt, -1);
285    EXPECT_EQ(errno, EINVAL);
286
287    rt = setpgid(-1000001, 0);
288    EXPECT_EQ(rt, -1);
289    EXPECT_EQ(errno, EINVAL);
290
291    pid_t nonExitPid = GetNonExistPid(); // valid but not exist pid
292    if (nonExitPid != -1) {
293        rt = setpgid(nonExitPid, 0);
294        EXPECT_EQ(rt, -1);
295        EXPECT_EQ(errno, ESRCH);
296    }
297
298    rt = setpgid(MAX_PROCESS_NUMBER + 1, 0);
299    EXPECT_EQ(rt, -1);
300    EXPECT_EQ(errno, EINVAL);
301
302    rt = setpgid(100000, 0);
303    EXPECT_EQ(rt, -1);
304    EXPECT_EQ(errno, EINVAL);
305
306    rt = setpgid(1, pid); // init
307    EXPECT_EQ(rt, -1);
308    EXPECT_EQ(errno, EPERM);
309
310    rt = setpgid(2, pid); // kProcess
311    EXPECT_EQ(rt, -1);
312    EXPECT_EQ(errno, EPERM);
313
314    LOG("invalid pgid test...");
315    rt = setpgid(0, -1);
316    EXPECT_EQ(rt, -1);
317    EXPECT_EQ(errno, EINVAL);
318
319    nonExitPid = GetNonExistPid(); // valid but not exist pid
320    if (nonExitPid != -1) {
321        rt = setpgid(0, nonExitPid);
322        EXPECT_EQ(rt, -1);
323        EXPECT_EQ(errno, EPERM);
324    }
325
326    rt = setpgid(0, 10001);
327    EXPECT_EQ(rt, -1);
328    EXPECT_EQ(errno, EINVAL);
329
330    rt = setpgid(0, 1); // init
331    EXPECT_EQ(rt, -1);
332    EXPECT_EQ(errno, EPERM);
333
334    rt = setpgid(0, 2); // kProcess
335    EXPECT_EQ(rt, -1);
336    EXPECT_EQ(errno, EPERM);
337}
338
339/**
340 * @tc.number SUB_KERNEL_PM_PID_SetGetPgid_0500
341 * @tc.name   setpgid fail test: EACCES
342 * @tc.desc   [C- SOFTWARE -0200]
343 */
344HWTEST_F(PidTest, testSetpgidFailEACCES, Function | MediumTest | Level3)
345{
346    pid_t pid = fork();
347    ASSERT_TRUE(pid >= 0) << "======== Fork Error! =========";
348    if (pid == 0) { // child
349        int rt = execve(mChildELF, NULL, NULL);
350        if (rt == -1) {
351            LOG("ERROR: execve return -1, errno=%d, err=%s\n", errno, strerror(errno));
352        }
353        exit(1);
354    } else { // parent
355        sleep(2);
356        AssertProcAlive(pid);
357        int rt = setpgid(pid, pid);
358        EXPECT_EQ(rt, -1) << "setpgid should fail after child execve.";
359        EXPECT_EQ(errno, EACCES) << "set errno fail.";
360
361        // recycle child
362        int status;
363        waitpid(pid, &status, 0);
364    }
365}
366