git.cappig.dev / apheleiaOS.git master

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(&current) < 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
}