forked from aristanetworks/bst
-
Notifications
You must be signed in to change notification settings - Fork 0
/
sig.c
110 lines (94 loc) · 2.28 KB
/
sig.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
/* Copyright © 2020 Arista Networks, Inc. All rights reserved.
*
* Use of this source code is governed by the MIT license that can be found
* in the LICENSE file.
*/
#include <err.h>
#include <errno.h>
#include <stddef.h>
#include <sys/epoll.h>
#include <sys/prctl.h>
#include <sys/signalfd.h>
#include <sys/wait.h>
#include <unistd.h>
#include "sig.h"
void sig_wait(const sigset_t *set, siginfo_t *info)
{
retry:
if (sigwaitinfo(set, info) == -1) {
if (errno == EINTR) {
goto retry;
}
err(1, "sigwaitinfo");
}
}
void sig_forward(const siginfo_t *info, pid_t pid)
{
if (info->si_code != SI_USER) {
return;
}
if (kill(pid, info->si_signo) == -1) {
err(1, "kill");
}
}
void sig_read(int sigfd, siginfo_t *info)
{
struct signalfd_siginfo sigfd_info;
ssize_t rd = read(sigfd, &sigfd_info, sizeof (sigfd_info));
if (rd == -1) {
err(1, "read signalfd");
}
if (rd != sizeof(sigfd_info)) {
errx(1, "read signalfd: expected reading size %zu, got %zu", sizeof (sigfd_info), (size_t) rd);
}
info->si_signo = (int) sigfd_info.ssi_signo;
info->si_code = sigfd_info.ssi_code;
}
void sig_setup(int epollfd, const sigset_t *set, pid_t helper_pid, epoll_handler_fn *fn)
{
int sigfd = signalfd(-1, set, SFD_CLOEXEC);
if (sigfd == -1) {
err(1, "signalfd");
}
static struct epoll_handler handler;
handler.fn = fn;
handler.fd = sigfd;
handler.helper_pid = helper_pid;
handler.priority = PRIORITY_LAST;
struct epoll_event event = {
.events = EPOLLIN,
.data = {
.ptr = &handler,
},
};
if (epoll_ctl(epollfd, EPOLL_CTL_ADD, sigfd, &event) == -1) {
err(1, "epoll_ctl_add signalfd");
}
}
void sig_setpdeathsig(int signo, int parent_handle)
{
if (prctl(PR_SET_PDEATHSIG, signo) == -1) {
err(1, "prctl PR_SET_PDEATHSIG");
}
errno = 0;
int unused;
ssize_t ret = read(parent_handle, &unused, sizeof(unused));
if (ret == -1) {
ret = -errno;
}
switch (ret) {
case 0:
/* The parent process died unexpectedly and we got reparented to the
nearest subreaper. We won't get killed by the kernel anymore, because
our new parent might be long lived, so just do it ourselves. */
raise(signo);
#if EWOULDBLOCK != EAGAIN
case -EWOULDBLOCK:
#endif
case -EAGAIN:
/* The parent process is alive; continue on */
return;
default:
err(1, "sig_setpdeathsig: read");
}
}