/* * Copyright (c) 2020-2021 Huawei Device Co., Ltd. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ // tested api in this file: getpid getppid getpgrp setpgrp getpgid setpgid #include #include #include #include #include "log.h" #include "utils.h" #include "KernelConstants.h" using namespace testing::ext; class PidTest : public testing::Test { protected: const char* mChildELF = RES_DIR_KERNEL "process/executor"; }; /** * @tc.number SUB_KERNEL_PM_PID_Getppid_0100 * @tc.name getpid and getppid test * @tc.desc [C- SOFTWARE -0200] */ HWTEST_F(PidTest, testGetPpid, Function | MediumTest | Level1) { pid_t parentPid = getpid(); pid_t pid = fork(); ASSERT_TRUE(pid >= 0) << "======== Fork Error! ========="; if (pid == 0) { // child pid_t pPid = getppid(); if (pPid != parentPid) { LOG("getppid fail, expect:%d, but get:%d", parentPid, pPid); exit(1); } exit(0); } else { // parent Msleep(20); WaitProcExitedOK(pid); } } /** * @tc.number SUB_KERNEL_PM_PID_Getppid_0200 * @tc.name test that a orphaned process will inherite by init. * @tc.desc [C- SOFTWARE -0200] */ HWTEST_F(PidTest, testOrphanProcess, Function | MediumTest | Level1) { const int retPass = 1; const int retFail = 2; const int memSize = 32; int shmID = shmget(IPC_PRIVATE, memSize, 0666 | IPC_CREAT); ASSERT_NE(shmID, -1) << "get share mem fail, errno = " << errno; int *shared = (int*)(shmat(shmID, nullptr, 0)); ASSERT_NE(shared, reinterpret_cast(-1)) << "shmat fail, errno = " << errno; *shared = retPass; LOG("parent process id:%d", getpid()); pid_t pid = fork(); EXPECT_TRUE(pid >= 0) << "======== Fork Error! ========="; if (pid == 0) { // child LOG("sub parent process id:%d", getpid()); pid_t pid2 = fork(); if (pid2 < 0) { LOG("======== Fork Error! ========="); *shared = 1; exit(1); } if (pid2 == 0) { // child LOG("orphane process id:%d", getpid()); Msleep(100); pid_t pPid = getppid(); if (pPid != 1) { LOG("getppid orphaned process fail, expect:1, but get:%d", pPid); // transfer result to main process int *shmAddr = (int*)(shmat(shmID, nullptr, 0)); *shmAddr = retFail; shmdt(shmAddr); exit(0); } exit(0); } else { // sub parent exit(0); } } // parent WaitProcExitedOK(pid); Msleep(200); EXPECT_EQ(*shared, retPass); shmdt(shared); shmctl(shmID, IPC_RMID, nullptr); } /** * @tc.number SUB_KERNEL_PM_PID_SetGetPgrp_0100 * @tc.name setpgrp and getpgrp test * @tc.desc [C- SOFTWARE -0200] */ HWTEST_F(PidTest, testSetGetPgrp, Function | MediumTest | Level1) { pid_t parentPid = getpid(); int rt = setpgrp(); ASSERT_EQ(rt, 0); pid_t pgid = getpgrp(); ASSERT_EQ(pgid, parentPid); pid_t pid = fork(); ASSERT_TRUE(pid >= 0) << "======== Fork Error! ========="; if (pid == 0) { // child pid_t childPgid = getpgrp(); if (childPgid != pgid) { LOG("child getpgrp fail, expect:%d, but get:%d", pgid, childPgid); exit(1); } exit(0); } else { // parent Msleep(20); WaitProcExitedOK(pid); } } /** * @tc.number SUB_KERNEL_PM_PID_SetGetPgid_0100 * @tc.name setpgid and getpgid basic test * @tc.desc [C- SOFTWARE -0200] */ HWTEST_F(PidTest, testSetGetPgid, Function | MediumTest | Level1) { pid_t parentPid = getpid(); int rt = setpgid(0, parentPid); ASSERT_EQ(rt, 0); rt = setpgid(0, 0); ASSERT_EQ(rt, 0); pid_t pgid = getpgid(0); ASSERT_EQ(pgid, parentPid); pid_t pid1 = fork(); ASSERT_TRUE(pid1 >= 0) << "======== Fork Error! ========="; if (pid1 == 0) { // child pid_t childPgid = getpgid(0); if (childPgid != pgid) { LOG("child getpgid fail, expect:%d, but get:%d", pgid, childPgid); exit(1); } Msleep(40); childPgid = getpgid(0); pid_t childPid = getpid(); if (childPgid != childPid) { LOG("child new pgid check fail, pid=%d, pgid:%d", childPid, childPgid); exit(1); } exit(0); } else { // parent Msleep(30); rt = setpgid(pid1, pid1); ASSERT_EQ(rt, 0); pid_t pgid2 = getpgid(pid1); ASSERT_EQ(pgid2, pid1); Msleep(50); WaitProcExitedOK(pid1); } } /** * @tc.number SUB_KERNEL_PM_PID_SetGetPgid_0200 * @tc.name setpgid and getpgid test for sibling process * @tc.desc [C- SOFTWARE -0200] */ HWTEST_F(PidTest, testSetGetSiblingPgid, Function | MediumTest | Level1) { pid_t parentPid = getpid(); int rt = setpgid(0, parentPid); ASSERT_EQ(rt, 0); rt = setpgid(0, 0); ASSERT_EQ(rt, 0); pid_t pgid = getpgid(0); ASSERT_EQ(pgid, parentPid); pid_t pid1 = fork(); ASSERT_TRUE(pid1 >= 0) << "======== Fork Error! ========="; if (pid1 == 0) { // child1 Msleep(20); exit(0); } else { // parent pid_t pid2 = fork(); ASSERT_TRUE(pid2 >= 0) << "======== Fork Error! ========="; if (pid2 == 0) { // child2 int exitCode = 0; pid_t siblingPgid = getpgid(pid1); if (siblingPgid != parentPid) { LOG("child2: get sibling pgid fail, rt=%d, errno=%d", siblingPgid, errno); exitCode = 1; } rt = setpgid(pid1, pid1); if (rt != -1) { LOG("child2: setpgid for sibling should fail"); exitCode = 1; } if (errno != ESRCH) { LOG("child2: setpgid errno fail, expected %d, but get %d", ESRCH, errno); exitCode = 1; } exit(exitCode); } // parent Msleep(50); WaitProcExitedOK(pid1); WaitProcExitedOK(pid2); } } /** * @tc.number SUB_KERNEL_PM_PID_SetGetPgid_0300 * @tc.name getpgid fail test * @tc.desc [C- SOFTWARE -0200] */ HWTEST_F(PidTest, testGetpgidFail, Function | MediumTest | Level3) { pid_t pgid = getpgid(-1); EXPECT_EQ(pgid, -1); EXPECT_EQ(errno, EINVAL); pgid = getpgid(-1000001); EXPECT_EQ(pgid, -1); EXPECT_EQ(errno, EINVAL); pid_t nonExitPid = GetNonExistPid(); // valid but not exist pid if (nonExitPid != -1) { pgid = getpgid(nonExitPid); EXPECT_EQ(pgid, -1); EXPECT_EQ(errno, ESRCH); } pgid = getpgid(MAX_PROCESS_NUMBER + 1); EXPECT_EQ(pgid, -1); EXPECT_EQ(errno, EINVAL); pgid = getpgid(100000); EXPECT_EQ(pgid, -1); EXPECT_EQ(errno, EINVAL); pgid = getpgid(1); EXPECT_EQ(pgid, 1) << "get init process-groups-ID fail\n"; } /** * @tc.number SUB_KERNEL_PM_PID_SetGetPgid_0400 * @tc.name setpgid fail test * @tc.desc [C- SOFTWARE -0200] */ HWTEST_F(PidTest, testSetpgidFail, Function | MediumTest | Level3) { pid_t pid = getpid(); int rt = setpgrp(); ASSERT_EQ(rt, 0); LOG("invalid pid test..."); rt = setpgid(-1, 0); EXPECT_EQ(rt, -1); EXPECT_EQ(errno, EINVAL); rt = setpgid(-1000001, 0); EXPECT_EQ(rt, -1); EXPECT_EQ(errno, EINVAL); pid_t nonExitPid = GetNonExistPid(); // valid but not exist pid if (nonExitPid != -1) { rt = setpgid(nonExitPid, 0); EXPECT_EQ(rt, -1); EXPECT_EQ(errno, ESRCH); } rt = setpgid(MAX_PROCESS_NUMBER + 1, 0); EXPECT_EQ(rt, -1); EXPECT_EQ(errno, EINVAL); rt = setpgid(100000, 0); EXPECT_EQ(rt, -1); EXPECT_EQ(errno, EINVAL); rt = setpgid(1, pid); // init EXPECT_EQ(rt, -1); EXPECT_EQ(errno, EPERM); rt = setpgid(2, pid); // kProcess EXPECT_EQ(rt, -1); EXPECT_EQ(errno, EPERM); LOG("invalid pgid test..."); rt = setpgid(0, -1); EXPECT_EQ(rt, -1); EXPECT_EQ(errno, EINVAL); nonExitPid = GetNonExistPid(); // valid but not exist pid if (nonExitPid != -1) { rt = setpgid(0, nonExitPid); EXPECT_EQ(rt, -1); EXPECT_EQ(errno, EPERM); } rt = setpgid(0, 10001); EXPECT_EQ(rt, -1); EXPECT_EQ(errno, EINVAL); rt = setpgid(0, 1); // init EXPECT_EQ(rt, -1); EXPECT_EQ(errno, EPERM); rt = setpgid(0, 2); // kProcess EXPECT_EQ(rt, -1); EXPECT_EQ(errno, EPERM); } /** * @tc.number SUB_KERNEL_PM_PID_SetGetPgid_0500 * @tc.name setpgid fail test: EACCES * @tc.desc [C- SOFTWARE -0200] */ HWTEST_F(PidTest, testSetpgidFailEACCES, Function | MediumTest | Level3) { pid_t pid = fork(); ASSERT_TRUE(pid >= 0) << "======== Fork Error! ========="; if (pid == 0) { // child int rt = execve(mChildELF, NULL, NULL); if (rt == -1) { LOG("ERROR: execve return -1, errno=%d, err=%s\n", errno, strerror(errno)); } exit(1); } else { // parent sleep(2); AssertProcAlive(pid); int rt = setpgid(pid, pid); EXPECT_EQ(rt, -1) << "setpgid should fail after child execve."; EXPECT_EQ(errno, EACCES) << "set errno fail."; // recycle child int status; waitpid(pid, &status, 0); } }