1
#include <apheleia/syscall.h>
2
#include <arch/sys.h>
3
#include <errno.h>
4
#include <fcntl.h>
5
#include <libc_usr/signal.h>
6
#include <stdio.h>
7
#include <stdlib.h>
8
#include <string.h>
9
#include <sys/proc.h>
10
#include <unistd.h>
11
12
static void signal_trampoline(void) {
13
syscall0(SYS_SIGRETURN);
14
15
for (;;) {
16
;17
}18
}19
20
static struct sigaction signal_actions[NSIG];
21
22
static int _sig_valid(int signum) {
23
return signum > 0 && signum < NSIG;
24
}25
26
int sigemptyset(sigset_t *set) {
27
if (!set) {
28
errno = EINVAL;
29
return -1;
30
}31
32
*set = 0;
33
return 0;
34
}35
36
int sigfillset(sigset_t *set) {
37
if (!set) {
38
errno = EINVAL;
39
return -1;
40
}41
42
sigset_t full = 0;
43
for (int sig = 1; sig < NSIG; sig++) {
44
full |= (sigset_t)(1u << (sig - 1));
45
}46
47
*set = full;
48
return 0;
49
}50
51
int sigaddset(sigset_t *set, int signum) {
52
if (!set || !_sig_valid(signum)) {
53
errno = EINVAL;
54
return -1;
55
}56
57
*set |= (sigset_t)(1u << (signum - 1));
58
return 0;
59
}60
61
int sigdelset(sigset_t *set, int signum) {
62
if (!set || !_sig_valid(signum)) {
63
errno = EINVAL;
64
return -1;
65
}66
67
*set &= (sigset_t) ~(1u << (signum - 1));
68
return 0;
69
}70
71
int sigismember(const sigset_t *set, int signum) {
72
if (!set || !_sig_valid(signum)) {
73
errno = EINVAL;
74
return -1;
75
}76
77
return ((*set & (sigset_t)(1u << (signum - 1))) != 0) ? 1 : 0;
78
}79
80
sighandler_t signal(int signum, sighandler_t handler) {
81
if (!_sig_valid(signum)) {
82
errno = EINVAL;
83
return SIG_ERR;
84
}85
86
long ret = syscall3(SYS_SIGNAL, (uintptr_t)signum, (uintptr_t)handler, (uintptr_t)signal_trampoline);
87
88
if (ret < 0) {
89
errno = (int)-ret;
90
return SIG_ERR;
91
}92
93
signal_actions[signum].sa_handler = handler;
94
signal_actions[signum].sa_flags = 0;
95
signal_actions[signum].sa_mask = 0;
96
signal_actions[signum].sa_restorer = NULL;
97
98
return (sighandler_t)ret;
99
}100
101
int sigaction(int signum, const struct sigaction *act, struct sigaction *oldact) {
102
if (!_sig_valid(signum)) {
103
errno = EINVAL;
104
return -1;
105
}106
107
if (oldact) {
108
memset(oldact, 0, sizeof(*oldact));
109
oldact->sa_handler = signal_actions[signum].sa_handler;
110
oldact->sa_mask = signal_actions[signum].sa_mask;
111
oldact->sa_flags = signal_actions[signum].sa_flags;
112
oldact->sa_restorer = signal_actions[signum].sa_restorer;
113
}114
115
if (!act) {
116
return 0;
117
}118
119
sighandler_t next = act->sa_handler ? act->sa_handler : SIG_DFL;
120
if (signal(signum, next) == SIG_ERR) {
121
return -1;
122
}123
124
signal_actions[signum] = *act;
125
return 0;
126
}127
128
static int _read_sigmask(sigset_t *mask_out) {
129
if (!mask_out) {
130
errno = EINVAL;
131
return -1;
132
}133
134
int fd = open("/proc/self/sigmask", O_RDONLY, 0);
135
if (fd < 0) {
136
return -1;
137
}138
139
char text[64];
140
ssize_t n = read(fd, text, sizeof(text) - 1);
141
int saved_errno = errno;
142
close(fd);
143
errno = saved_errno;
144
145
if (n < 0) {
146
return -1;
147
}148
149
text[n] = '\0';
150
151
char *end = NULL;
152
unsigned long value = strtoul(text, &end, 10);
153
if (end == text) {
154
errno = EIO;
155
return -1;
156
}157
158
while (*end == ' ' || *end == '\t' || *end == '\r' || *end == '\n') {
159
end++;
160
}161
if (*end != '\0') {
162
errno = EIO;
163
return -1;
164
}165
166
*mask_out = (sigset_t)value;
167
return 0;
168
}169
170
static int _write_sigmask(sigset_t mask) {
171
int fd = open("/proc/self/sigmask", O_WRONLY, 0);
172
if (fd < 0) {
173
return -1;
174
}175
176
char text[32];
177
int text_len = snprintf(text, sizeof(text), "%u\n", (unsigned int)mask);
178
if (text_len <= 0 || (size_t)text_len >= sizeof(text)) {
179
close(fd);
180
errno = EIO;
181
return -1;
182
}183
184
size_t written = 0;
185
while (written < (size_t)text_len) {
186
ssize_t rc = write(fd, text + written, (size_t)text_len - written);
187
if (rc < 0) {
188
int saved_errno = errno;
189
close(fd);
190
errno = saved_errno;
191
return -1;
192
}193
194
if (rc == 0) {
195
close(fd);
196
errno = EIO;
197
return -1;
198
}199
200
written += (size_t)rc;
201
}202
203
return close(fd);
204
}205
206
int sigprocmask(int how, const sigset_t *set, sigset_t *oldset) {
207
sigset_t current = 0;
208
if (_read_sigmask(¤t) < 0) {
209
return -1;
210
}211
212
if (oldset) {
213
*oldset = current;
214
}215
216
if (!set) {
217
return 0;
218
}219
220
const sigset_t blockable_mask = ((sigset_t)0x7fffffffU) & (sigset_t) ~(1u << (SIGKILL - 1)) &
221
(sigset_t) ~(1u << (SIGSTOP - 1));
222
223
sigset_t incoming = *set & blockable_mask;
224
sigset_t next = current;
225
226
switch (how) {
227
case SIG_BLOCK:
228
next |= incoming;
229
break;
230
case SIG_UNBLOCK:
231
next &= (sigset_t)~incoming;
232
break;
233
case SIG_SETMASK:
234
next = incoming;
235
break;
236
default:
237
errno = EINVAL;
238
return -1;
239
}240
241
next &= blockable_mask;
242
return _write_sigmask(next);
243
}244
245
int sigpending(sigset_t *set) {
246
if (!set) {
247
errno = EINVAL;
248
return -1;
249
}250
251
proc_stat_t stat = { 0 };
252
if (proc_stat_read_path("/proc/self/stat", &stat) < 0) {
253
return -1;
254
}255
256
*set = (sigset_t)stat.signal_pending;
257
return 0;
258
}259
260
int kill(pid_t pid, int signum) {
261
long ret = syscall2(SYS_KILL, (uintptr_t)pid, (uintptr_t)signum);
262
263
if (ret < 0) {
264
errno = (int)-ret;
265
return -1;
266
}267
268
return 0;
269
}270
271
int raise(int signum) {
272
return kill(getpid(), signum);
273
}