Serenity Operating System
1/*
2 * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
3 *
4 * SPDX-License-Identifier: BSD-2-Clause
5 */
6
7#include <AK/StringView.h>
8#include <assert.h>
9#include <bits/pthread_cancel.h>
10#include <errno.h>
11#include <setjmp.h>
12#include <signal.h>
13#include <string.h>
14#include <sys/select.h>
15#include <syscall.h>
16#include <unistd.h>
17
18extern "C" {
19
20// https://pubs.opengroup.org/onlinepubs/9699919799/functions/kill.html
21int kill(pid_t pid, int sig)
22{
23 int rc = syscall(SC_kill, pid, sig);
24 __RETURN_WITH_ERRNO(rc, rc, -1);
25}
26
27// https://pubs.opengroup.org/onlinepubs/9699919799/functions/killpg.html
28int killpg(int pgrp, int sig)
29{
30 int rc = syscall(SC_killpg, pgrp, sig);
31 __RETURN_WITH_ERRNO(rc, rc, -1);
32}
33
34// https://pubs.opengroup.org/onlinepubs/9699919799/functions/raise.html
35int raise(int sig)
36{
37 // FIXME: Support multi-threaded programs.
38 return kill(getpid(), sig);
39}
40
41// https://pubs.opengroup.org/onlinepubs/9699919799/functions/signal.html
42sighandler_t signal(int signum, sighandler_t handler)
43{
44 struct sigaction new_act;
45 struct sigaction old_act;
46 new_act.sa_handler = handler;
47 new_act.sa_flags = 0;
48 new_act.sa_mask = 0;
49 int rc = sigaction(signum, &new_act, &old_act);
50 if (rc < 0)
51 return SIG_ERR;
52 return old_act.sa_handler;
53}
54
55// https://pubs.opengroup.org/onlinepubs/9699919799/functions/sigaction.html
56int sigaction(int signum, const struct sigaction* act, struct sigaction* old_act)
57{
58 int rc = syscall(SC_sigaction, signum, act, old_act);
59 __RETURN_WITH_ERRNO(rc, rc, -1);
60}
61
62// https://pubs.opengroup.org/onlinepubs/9699919799/functions/sigemptyset.html
63int sigemptyset(sigset_t* set)
64{
65 *set = 0;
66 return 0;
67}
68
69// https://pubs.opengroup.org/onlinepubs/9699919799/functions/sigfillset.html
70int sigfillset(sigset_t* set)
71{
72 *set = 0xffffffff;
73 return 0;
74}
75
76// https://pubs.opengroup.org/onlinepubs/9699919799/functions/sigaddset.html
77int sigaddset(sigset_t* set, int sig)
78{
79 if (sig < 1 || sig > 32) {
80 errno = EINVAL;
81 return -1;
82 }
83 *set |= 1 << (sig - 1);
84 return 0;
85}
86
87// https://pubs.opengroup.org/onlinepubs/9699919799/functions/sigaltstack.html
88int sigaltstack(stack_t const* ss, stack_t* old_ss)
89{
90 int rc = syscall(SC_sigaltstack, ss, old_ss);
91 __RETURN_WITH_ERRNO(rc, rc, -1);
92}
93
94// https://pubs.opengroup.org/onlinepubs/9699919799/functions/sigdelset.html
95int sigdelset(sigset_t* set, int sig)
96{
97 if (sig < 1 || sig > 32) {
98 errno = EINVAL;
99 return -1;
100 }
101 *set &= ~(1 << (sig - 1));
102 return 0;
103}
104
105// https://pubs.opengroup.org/onlinepubs/9699919799/functions/sigismember.html
106int sigismember(sigset_t const* set, int sig)
107{
108 if (sig < 1 || sig > 32) {
109 errno = EINVAL;
110 return -1;
111 }
112 if (*set & (1 << (sig - 1)))
113 return 1;
114 return 0;
115}
116
117// https://pubs.opengroup.org/onlinepubs/9699919799/functions/sigprocmask.html
118int sigprocmask(int how, sigset_t const* set, sigset_t* old_set)
119{
120 int rc = syscall(SC_sigprocmask, how, set, old_set);
121 __RETURN_WITH_ERRNO(rc, rc, -1);
122}
123
124// https://pubs.opengroup.org/onlinepubs/9699919799/functions/sigpending.html
125int sigpending(sigset_t* set)
126{
127 int rc = syscall(SC_sigpending, set);
128 __RETURN_WITH_ERRNO(rc, rc, -1);
129}
130
131char const* sys_siglist[NSIG] = {
132 "Invalid signal number",
133 "Hangup",
134 "Interrupt",
135 "Quit",
136 "Illegal instruction",
137 "Trap",
138 "Aborted",
139 "Bus error",
140 "Division by zero",
141 "Killed",
142 "User signal 1",
143 "Segmentation violation",
144 "User signal 2",
145 "Broken pipe",
146 "Alarm clock",
147 "Terminated",
148 "Stack fault",
149 "Child exited",
150 "Continued",
151 "Stopped (signal)",
152 "Stopped",
153 "Stopped (tty input)",
154 "Stopped (tty output)",
155 "Urgent I/O condition)",
156 "CPU limit exceeded",
157 "File size limit exceeded",
158 "Virtual timer expired",
159 "Profiling timer expired",
160 "Window changed",
161 "I/O possible",
162 "Power failure",
163 "Bad system call",
164};
165
166// https://pubs.opengroup.org/onlinepubs/9699919799/functions/siglongjmp.html
167void siglongjmp(jmp_buf env, int val)
168{
169 if (env->did_save_signal_mask) {
170 int rc = sigprocmask(SIG_SETMASK, &env->saved_signal_mask, nullptr);
171 assert(rc == 0);
172 }
173 longjmp(env, val);
174}
175
176// https://pubs.opengroup.org/onlinepubs/9699919799/functions/sigsuspend.html
177int sigsuspend(sigset_t const* set)
178{
179 __pthread_maybe_cancel();
180
181 int rc = syscall(SC_sigsuspend, set);
182 __RETURN_WITH_ERRNO(rc, rc, -1);
183}
184
185// https://pubs.opengroup.org/onlinepubs/009604499/functions/sigwait.html
186int sigwait(sigset_t const* set, int* sig)
187{
188 __pthread_maybe_cancel();
189
190 int rc = syscall(Syscall::SC_sigtimedwait, set, nullptr, nullptr);
191 VERIFY(rc != 0);
192 if (rc < 0)
193 return -rc;
194 *sig = rc;
195 return 0;
196}
197
198// https://pubs.opengroup.org/onlinepubs/9699919799/functions/sigwaitinfo.html
199int sigwaitinfo(sigset_t const* set, siginfo_t* info)
200{
201 return sigtimedwait(set, info, nullptr);
202}
203
204// https://pubs.opengroup.org/onlinepubs/9699919799/functions/sigtimedwait.html
205int sigtimedwait(sigset_t const* set, siginfo_t* info, struct timespec const* timeout)
206{
207 __pthread_maybe_cancel();
208
209 int rc = syscall(Syscall::SC_sigtimedwait, set, info, timeout);
210 __RETURN_WITH_ERRNO(rc, rc, -1);
211}
212
213char const* sys_signame[] = {
214 "INVAL",
215 "HUP",
216 "INT",
217 "QUIT",
218 "ILL",
219 "TRAP",
220 "ABRT",
221 "BUS",
222 "FPE",
223 "KILL",
224 "USR1",
225 "SEGV",
226 "USR2",
227 "PIPE",
228 "ALRM",
229 "TERM",
230 "STKFLT",
231 "CHLD",
232 "CONT",
233 "STOP",
234 "TSTP",
235 "TTIN",
236 "TTOU",
237 "URG",
238 "XCPU",
239 "XFSZ",
240 "VTALRM",
241 "PROF",
242 "WINCH",
243 "IO",
244 "INFO",
245 "SYS",
246};
247
248static_assert(sizeof(sys_signame) == sizeof(char const*) * NSIG);
249
250int getsignalbyname(char const* name)
251{
252 VERIFY(name);
253 StringView name_sv { name, strlen(name) };
254 for (size_t i = 0; i < NSIG; ++i) {
255 StringView signal_name { sys_signame[i], sizeof(sys_signame[i]) - 1 };
256 if (signal_name == name_sv || (name_sv.starts_with("SIG"sv) && signal_name == name_sv.substring_view(3)))
257 return i;
258 }
259 errno = EINVAL;
260 return -1;
261}
262
263char const* getsignalname(int signal)
264{
265 if (signal < 0 || signal >= NSIG) {
266 errno = EINVAL;
267 return nullptr;
268 }
269 return sys_signame[signal];
270}
271}