1/*
2 * Copyright (c) 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#include <unistd.h>
17#include <string.h>
18#include <sys/types.h>
19#include <sys/shm.h>
20#include <fcntl.h>
21#include "log.h"
22#include "utils.h"
23#include "SignalTest.h"
24
25using namespace testing::ext;
26
27// static member must init before use.
28int IpcSignalTest::mReceivedSignal = 0;
29int IpcSignalTest::mShmid = 0;
30siginfo_t IpcSignalTest::mSiginfo;
31
32
33// special signal handler for function 'abort'
34void IpcSignalTest::SigAbortHandler(int signum)
35{
36    LOG("handler: recv a signal: %d", signum);
37    int *shared = static_cast<int*>(shmat(mShmid, nullptr, 0));
38    if (shared == reinterpret_cast<int*>(-1)) {
39        LOG("SigAbortHandler: shmat fail, errno = %d", errno);
40    } else {
41        LOG("shared: %p", shared);
42        *shared = signum;
43        if (shmdt(shared) == -1) {
44            LOG("SigAbortHandler: shmdt errno = %d", errno);
45        }
46    }
47}
48
49// special signal handler for function 'sigaction'
50void IpcSignalTest::SigactionHandler(int signum, siginfo_t* si, void* ucontext)
51{
52    LOG("handler recv a signal: %s(%d)", ALL_SIGNALS[signum].signame, signum);
53    mReceivedSignal = signum;
54    // siginfo_t para is not supported yet
55}
56
57// general signal handler. note: not thread-safe
58void IpcSignalTest::SignalHandler(int signum)
59{
60    LOG("handler recv a signal: %s(%d)", ALL_SIGNALS[signum].signame, signum);
61    mReceivedSignal = signum;
62}
63
64SignalNameAction const ALL_SIGNALS[MAX_SIGNAL] = {
65    {"NA",      "Unknown signal",           TERMINATE},
66    {"SIGHUP",  "Hangup",                   TERMINATE}, //  1
67    {"SIGINT",  "Interrupt",                TERMINATE},
68    {"SIGQUIT", "Quit",                     COREDUMP},
69    {"SIGILL",  "Illegal instruction",      COREDUMP},
70    {"SIGTRAP", "Trace/breakpoint trap",    COREDUMP},
71    {"SIGABRT", "Aborted",                  COREDUMP},  //  alias:  SIGIOT
72    {"SIGBUS",  "Bus error",                COREDUMP},
73    {"SIGFPE",  "Arithmetic exception",     COREDUMP},
74    {"SIGKILL", "Killed",                   TERMINATE},
75    {"SIGUSR1", "User defined signal 1",    TERMINATE}, //  10
76    {"SIGSEGV", "Segmentation fault",       COREDUMP},
77    {"SIGUSR2", "User defined signal 2",    TERMINATE},
78    {"SIGPIPE", "Broken pipe",              TERMINATE},
79    {"SIGALRM", "Alarm clock",              TERMINATE},
80    {"SIGTERM", "Terminated",               TERMINATE},
81    {"SIGSTKFLT", "Stack fault",            TERMINATE},
82    {"SIGCHLD", "Child process status",     IGNORE},    //  alias:  SIGCLD
83    {"SIGCONT", "Continued",                CONTINUE},
84    {"SIGSTOP", "Stopped (signal)",         STOP},
85    {"SIGTSTP", "Stopped",                  STOP},      //  20
86    {"SIGTTIN", "Stopped (tty input)",      STOP},
87    {"SIGTTOU", "Stopped (tty output)",     STOP},
88    {"SIGURG",  "Urgent I/O condition",     IGNORE},
89    {"SIGXCPU", "CPU time limit exceeded",  COREDUMP},
90    {"SIGXFSZ", "File size limit exceeded", COREDUMP},
91    {"SIGVTALRM", "Virtual timer expired",  TERMINATE},
92    {"SIGPROF", "Profiling timer expired",  TERMINATE},
93    {"SIGWINCH",  "Window changed",         IGNORE},
94    {"SIGIO",   "I/O possible",             TERMINATE}, //  alias:  SIGPOLL
95    {"SIGPWR",  "Power failure",            TERMINATE}, //  alias:  SIGINFO,    30
96};
97
98void IpcSignalTest::DefaultActionTest(const int signum, const bool expectStop, const bool coredump)
99{
100    pid_t pid = fork();
101    ASSERT_TRUE(pid >= 0) << "======== Fork Error! =========";
102    if (pid > 0) { // parent
103        Msleep(20);
104        LOGD("before kill");
105        kill(pid, signum);
106        if (!expectStop) {
107            Msleep(20);
108            AssertProcAlive(pid);
109            Msleep(20);
110            WaitProcExitedOK(pid);
111        } else {
112            WaitProcKilled(pid, signum);
113            if (coredump) {
114                // check codedump, liteos not support yet
115            }
116        }
117    } else { // child
118        LOGD("child start");
119        KeepRun(KEEP_RUN_TIME);
120        if (expectStop) {
121            LOG("Child should has been Terminated, but still alive.");
122            exit(1);
123        }
124        exit(0);
125    }
126}
127
128void IpcSignalTest::SendAndRecvTest(const int signum)
129{
130    pid_t pid1, pid2;
131    bool useBrother = GetRandom(100) % 2; // if use brother to send the signal
132    pid1 = fork();
133    ASSERT_TRUE(pid1 >= 0) << "======== Fork1 Error! =========";
134    if (pid1 > 0) { // parent
135        LOGD("in parent...");
136        if (useBrother) {
137            pid2 = fork();
138            ASSERT_TRUE(pid2 >= 0) << "======== Fork2 Error! =========";
139            if (pid2 == 0) { // child 2
140                Msleep(50);
141                kill(pid1, signum);
142                exit(0);
143            }
144            // parent
145            Msleep(20);
146            LOG("check if child2 exited OK");
147            WaitProcExitedOK(pid2);
148        } else {
149            Msleep(100);
150            kill(pid1, signum);
151        }
152        AssertProcAlive(pid1);
153
154        Msleep(20); // child should exited now
155        LOG("check if child exited OK");
156        WaitProcExitedOK(pid1);
157    } else { // child 1, the receiver
158        LOGD("in child, pid=%d", getpid());
159        handler_type rt = signal(signum, SignalHandler);
160        if (rt == SIG_ERR) {
161            LOG("set %d signal handler failed, errno=%d", signum, errno);
162            exit(1);
163        }
164        Msleep(150);
165        if (mReceivedSignal != signum) {
166            LOG("SignalHandler check fail, expected=%d, received=%d", signum, mReceivedSignal);
167            exit(1);
168        }
169        LOGD("child sleeping....");
170        Msleep(20);
171        LOGD("child exit 0....");
172        exit(0);
173    }
174}
175
176int IpcSignalTest::CheckSigString(const char* outfile, const char* expectStr)
177{
178    const int bufLen = 64;
179    char buffer[bufLen];
180
181    FILE *fp = fopen(outfile, "rb");
182    size_t bytes = fread(buffer, 1, bufLen, fp);
183    buffer[bytes] = 0;
184    LOGD("%d bytes read from logfile:%s", bytes, buffer);
185    fclose(fp);
186    size_t expectLen = strlen(expectStr);
187    LOGD("expect string len = %d", expectLen);
188    if (bytes != (expectLen + 1)) {
189        LOG("bytes number read from stderr file error, expect:%d, actual:%d",
190            expectLen + 1, bytes);
191        return 1;
192    }
193    return strncmp(expectStr, buffer, expectLen);
194}
195
196void IpcSignalTest::SignalFailTest(int signum, handler_type h, int expectErrno)
197{
198    errno = 0;
199    handler_type rt = signal(signum, h);
200    ASSERT_EQ(rt, SIG_ERR) << "signal error for " << signum;
201    ASSERT_EQ(errno, expectErrno) << "signal error for " << signum;
202}
203void IpcSignalTest::SigpendingFailTest(sigset_t* pset)
204{
205    errno = 0;
206    int rt = sigpending(pset);
207    ASSERT_EQ(rt, -1);
208    ASSERT_EQ(errno, EFAULT);
209}
210void IpcSignalTest::SigtimedwaitFailTest(const sigset_t *set, siginfo_t* info, const timespec* timeout, int expectErrno)
211{
212    errno = 0;
213    int rt = sigtimedwait(set, info, timeout);
214    ASSERT_EQ(rt, -1);
215    ASSERT_EQ(errno, expectErrno);
216}
217
218// thread function for testcase: 'testPthreadkill'
219void* IpcSignalTest::ThreadFunc1(void* arg)
220{
221    int sigNo = (int)((uintptr_t)arg);
222    signal(sigNo, SignalHandler);
223    Msleep(60);
224    return nullptr;
225}
226
227// thread function for testcase: 'testPthreadkillMain'
228void* IpcSignalTest::ThreadFunc2(void* arg)
229{
230    pthread_t* tid = (pthread_t*)arg;
231    int ret = pthread_kill(*tid, SIGINT);
232    if (ret != 0) {
233        LOG("pthread_kill failed, errno=%d", ret);
234        return (void*)1;
235    }
236    LOG("pthread_kill send signal(%d) ok", SIGINT);
237    return nullptr;
238}
239
240// thread function for testcase: 'testPthreadSigmask'
241void* IpcSignalTest::ThreadFuncForSigmask1(void* arg)
242{
243    int rt;
244    int type = (int)((uintptr_t)arg);
245    if (type == 1) {
246        signal(SIGINT, SignalHandler);
247    }
248
249    LOG("block SIGINT");
250    sigset_t sigmask, oldmask;
251    sigemptyset(&sigmask);
252    sigemptyset(&oldmask);
253    sigaddset(&sigmask, SIGINT);
254    sigaddset(&sigmask, SIGUSR1);
255    rt = pthread_sigmask(SIG_BLOCK, &sigmask, &oldmask);
256    EXPECT_EQ(rt, 0);
257    raise(SIGINT);
258    EXPECT_EQ(mReceivedSignal, 0) << "SignalHandler check fail, SIGINT should has blocked!";
259
260    LOG("unblock SIGINT");
261    sigemptyset(&sigmask);
262    sigaddset(&sigmask, SIGINT);
263    rt = pthread_sigmask(SIG_UNBLOCK, &sigmask, nullptr);
264    EXPECT_EQ(rt, 0);
265
266    LOG("check the new block set");
267    sigemptyset(&oldmask);
268    pthread_sigmask(SIG_UNBLOCK, nullptr, &oldmask);
269    EXPECT_EQ(sigismember(&oldmask, SIGINT), 0) << "SIGINT should has deleted from block set!";
270    EXPECT_EQ(sigismember(&oldmask, SIGUSR1), 1) << "SIGUSR1 should still in block set!";
271
272    EXPECT_EQ(mReceivedSignal, SIGINT) << "SignalHandler check fail, SIGINT should deliver after unblock!";
273    return nullptr;
274}
275
276// thread function for testcase: 'testPthreadSigmaskInherit'
277void* IpcSignalTest::ThreadFuncForSigmask2(void* arg)
278{
279    sigset_t sigmask, oldmask;
280    sigemptyset(&sigmask);
281    sigemptyset(&oldmask);
282
283    LOG("SubThread: check the block set is inherited");
284    pthread_sigmask(SIG_BLOCK, nullptr, &oldmask);
285    if (!sigismember(&oldmask, SIGUSR1)) {
286        LOG("initial block set should include SIGUSR1!");
287        return (void*)1;
288    }
289
290    LOG("SubThread: add SIGINT to block set");
291    sigaddset(&sigmask, SIGINT);
292    int rt = pthread_sigmask(SIG_BLOCK, &sigmask, &oldmask);
293    EXPECT_EQ(rt, 0);
294
295    LOG("SubThread: check the new block set");
296    sigemptyset(&oldmask);
297    pthread_sigmask(SIG_UNBLOCK, nullptr, &oldmask);
298    if (!sigismember(&oldmask, SIGINT)) {
299        LOG("failed to add SIGINT to block set!");
300        return (void*)1;
301    }
302    if (!sigismember(&oldmask, SIGUSR1)) {
303        LOG("SIGUSR1 should still in block set!");
304        return (void*)1;
305    }
306    return nullptr;
307}