Add sig2str()/str2sig() from POSIX Issue 8.
Change-Id: I3b2c1601bd667af6b8f736e03a6e94035b812ff7
diff --git a/libc/bionic/strsignal.cpp b/libc/bionic/strsignal.cpp
index f18b6d0..29c22e2 100644
--- a/libc/bionic/strsignal.cpp
+++ b/libc/bionic/strsignal.cpp
@@ -27,29 +27,29 @@
*/
#include <signal.h>
+#include <stdlib.h>
#include <string.h>
#include "bionic/pthread_internal.h"
+// Maps regular signals like SIGSEGV to strings like "Segmentation fault".
+// Signal 0 and all the real-time signals are just nullptr, but that's the ABI.
const char* const sys_siglist[NSIG] = {
#define __BIONIC_SIGDEF(signal_number, signal_description) [signal_number] = signal_description,
#include "private/bionic_sigdefs.h"
};
+// Maps regular signals like SIGSEGV to strings like "SEGV".
+// Signal 0 and all the real-time signals are just nullptr, but that's the ABI.
const char* const sys_signame[NSIG] = {
#define __BIONIC_SIGDEF(signal_number, unused) [signal_number] = &(#signal_number)[3],
#include "private/bionic_sigdefs.h"
};
extern "C" __LIBC_HIDDEN__ const char* __strsignal(int signal_number, char* buf, size_t buf_len) {
- const char* signal_name = nullptr;
- if (signal_number >= 0 && signal_number < NSIG) {
- signal_name = sys_siglist[signal_number];
+ if (signal_number >= SIGHUP && signal_number < SIGSYS) {
+ return sys_siglist[signal_number];
}
- if (signal_name != nullptr) {
- return signal_name;
- }
-
const char* prefix = "Unknown";
if (signal_number >= SIGRTMIN && signal_number <= SIGRTMAX) {
prefix = "Real-time";
@@ -66,3 +66,72 @@
bionic_tls& tls = __get_bionic_tls();
return const_cast<char*>(__strsignal(signal_number, tls.strsignal_buf, sizeof(tls.strsignal_buf)));
}
+
+int sig2str(int sig, char* str) {
+ if (sig >= SIGHUP && sig <= SIGSYS) {
+ strcpy(str, sys_signame[sig]);
+ return 0;
+ }
+ if (sig == SIGRTMIN) {
+ strcpy(str, "RTMIN");
+ return 0;
+ }
+ if (sig == SIGRTMAX) {
+ strcpy(str, "RTMAX");
+ return 0;
+ }
+ if (sig > SIGRTMIN && sig < SIGRTMAX) {
+ if (sig - SIGRTMIN <= SIGRTMAX - sig) {
+ sprintf(str, "RTMIN+%d", sig - SIGRTMIN);
+ } else {
+ sprintf(str, "RTMAX-%d", SIGRTMAX - sig);
+ }
+ return 0;
+ }
+ return -1;
+}
+
+int str2sig(const char* str, int* sig) {
+ // A name in our list, like "SEGV"?
+ for (size_t i = SIGHUP; i <= SIGSYS; ++i) {
+ if (!strcmp(str, sys_signame[i])) {
+ *sig = i;
+ return 0;
+ }
+ }
+
+ // The two named special cases?
+ if (!strcmp(str, "RTMIN")) {
+ *sig = SIGRTMIN;
+ return 0;
+ }
+ if (!strcmp(str, "RTMAX")) {
+ *sig = SIGRTMAX;
+ return 0;
+ }
+
+ // Must be either an integer corresponding to a regular signal such as "9",
+ // or a string of the form "RTMIN+%d" or "RTMAX-%d".
+ int base = 0;
+ if (!strncmp(str, "RTMIN+", 6)) {
+ base = SIGRTMIN;
+ str += 5;
+ } else if (!strncmp(str, "RTMAX-", 6)) {
+ base = SIGRTMAX;
+ str += 5;
+ }
+ char* end = nullptr;
+ errno = 0;
+ int offset = strtol(str, &end, 10);
+ if (errno || *end) return -1;
+
+ // Reject out of range integers (like "666"),
+ // and out of range real-time signals (like "RTMIN+666" or "RTMAX-666").
+ int result = base + offset;
+ bool regular = (base == 0 && result >= SIGHUP && result <= SIGSYS);
+ bool realtime = (result >= SIGRTMIN && result <= SIGRTMAX);
+ if (!regular && !realtime) return -1;
+
+ *sig = result;
+ return 0;
+}