summaryrefslogtreecommitdiffstats
path: root/local/signals.c
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--local/signals.c316
1 files changed, 316 insertions, 0 deletions
diff --git a/local/signals.c b/local/signals.c
new file mode 100644
index 0000000..caff420
--- /dev/null
+++ b/local/signals.c
@@ -0,0 +1,316 @@
+/*
+ * signals.c - signal name, and number, conversions
+ * Copyright 1998-2003 by Albert Cahalan
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <ctype.h>
+#include <signal.h>
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include "signals.h"
+#include "c.h"
+
+/* Linux signals:
+ *
+ * SIGSYS is required by Unix98.
+ * SIGEMT is part of SysV, BSD, and ancient UNIX tradition.
+ *
+ * They are provided by these Linux ports: alpha, mips, sparc, and sparc64.
+ * You get SIGSTKFLT and SIGUNUSED instead on i386, m68k, ppc, and arm.
+ * (this is a Linux & libc bug -- both must be fixed)
+ *
+ * Total garbage: SIGIO SIGINFO SIGIOT SIGCLD
+ * (popular ones are handled as aliases)
+ * SIGLOST
+ * (except on the Hurd; reused to mean a server died)
+ * Nearly garbage: SIGSTKFLT SIGUNUSED (nothing else to fill slots)
+ */
+
+/* Linux 2.3.29 replaces SIGUNUSED with the standard SIGSYS signal */
+#ifndef SIGSYS
+# warning Standards require that <signal.h> define SIGSYS
+# define SIGSYS SIGUNUSED
+#endif
+
+/* If we see both, it is likely SIGSTKFLT (junk) was replaced. */
+#ifdef SIGEMT
+# undef SIGSTKFLT
+#endif
+
+#ifndef SIGRTMIN
+# warning Standards require that <signal.h> define SIGRTMIN; assuming 32
+# define SIGRTMIN 32
+#endif
+
+/* It seems the SPARC libc does not know the kernel supports SIGPWR. */
+#if defined(__linux__) && !defined(SIGPWR)
+# warning Your header files lack SIGPWR. (assuming it is number 29)
+# define SIGPWR 29
+#endif
+
+typedef struct mapstruct {
+ const char *name;
+ int num;
+} mapstruct;
+
+
+static const mapstruct sigtable[] = {
+ {"ABRT", SIGABRT}, /* IOT */
+ {"ALRM", SIGALRM},
+ {"BUS", SIGBUS},
+ {"CHLD", SIGCHLD}, /* CLD */
+ {"CONT", SIGCONT},
+#ifdef SIGEMT
+ {"EMT", SIGEMT},
+#endif
+ {"FPE", SIGFPE},
+ {"HUP", SIGHUP},
+ {"ILL", SIGILL},
+ {"INT", SIGINT},
+ {"KILL", SIGKILL},
+#if defined(__GNU__)
+ {"LOST", SIGLOST}, /* Hurd-specific */
+#endif
+ {"PIPE", SIGPIPE},
+ {"POLL", SIGPOLL}, /* IO */
+ {"PROF", SIGPROF},
+#ifdef SIGPWR
+ {"PWR", SIGPWR},
+#endif
+ {"QUIT", SIGQUIT},
+ {"SEGV", SIGSEGV},
+#ifdef SIGSTKFLT
+ {"STKFLT", SIGSTKFLT},
+#endif
+ {"STOP", SIGSTOP},
+ {"SYS", SIGSYS}, /* UNUSED */
+ {"TERM", SIGTERM},
+ {"TRAP", SIGTRAP},
+ {"TSTP", SIGTSTP},
+ {"TTIN", SIGTTIN},
+ {"TTOU", SIGTTOU},
+ {"URG", SIGURG},
+ {"USR1", SIGUSR1},
+ {"USR2", SIGUSR2},
+ {"VTALRM", SIGVTALRM},
+ {"WINCH", SIGWINCH},
+ {"XCPU", SIGXCPU},
+ {"XFSZ", SIGXFSZ}
+};
+
+
+#define number_of_signals (sizeof(sigtable)/sizeof(mapstruct))
+
+#define XJOIN(a, b) JOIN(a, b)
+#define JOIN(a, b) a##b
+#define STATIC_ASSERT(x) typedef int XJOIN(static_assert_on_line_,__LINE__)[(x) ? 1 : -1]
+
+/* sanity check */
+#if defined(__linux__)
+STATIC_ASSERT(number_of_signals == 31);
+#elif defined(__FreeBSD_kernel__) || defined(__FreeBSD__)
+STATIC_ASSERT(number_of_signals == 30);
+#elif defined(__GNU__)
+STATIC_ASSERT(number_of_signals == 31);
+#elif defined(__CYGWIN__)
+STATIC_ASSERT(number_of_signals == 31);
+#else
+# warning Unknown operating system; assuming number_of_signals is correct
+#endif
+
+static int compare_signal_names(const void *a, const void *b){
+ return strcasecmp( ((const mapstruct*)a)->name, ((const mapstruct*)b)->name );
+}
+
+
+const char *get_sigtable_name(int row)
+{
+ if (row < 0 || row >= number_of_signals)
+ return NULL;
+ return sigtable[row].name;
+}
+
+const int get_sigtable_num(int row)
+{
+ if (row < 0 || row >= number_of_signals)
+ return -1;
+ return sigtable[row].num;
+}
+
+/* return -1 on failure */
+int signal_name_to_number(const char *restrict name){
+ long val;
+ int offset;
+
+ /* clean up name */
+ if(!strncasecmp(name,"SIG",3))
+ name += 3;
+
+ if(!strcasecmp(name,"CLD"))
+ return SIGCHLD;
+ if(!strcasecmp(name,"IO"))
+ return SIGPOLL;
+ if(!strcasecmp(name,"IOT"))
+ return SIGABRT;
+ /* search the table */
+ {
+ const mapstruct ms = {name,0};
+ const mapstruct *restrict const ptr = bsearch(
+ &ms,
+ sigtable,
+ number_of_signals,
+ sizeof(mapstruct),
+ compare_signal_names);
+ if(ptr)
+ return ptr->num;
+ }
+
+ if(!strcasecmp(name,"RTMIN"))
+ return SIGRTMIN;
+ if(!strcasecmp(name,"EXIT"))
+ return 0;
+ if(!strcasecmp(name,"NULL"))
+ return 0;
+
+ offset = 0;
+ if(!strncasecmp(name,"RTMIN+",6)) {
+ name += 6;
+ offset = SIGRTMIN;
+ }
+
+ /* not found, so try as a number */
+ {
+ char *endp;
+ val = strtol(name,&endp,10);
+ if(*endp || endp==name)
+ return -1; /* not valid */
+ }
+ if(val<0 || val+SIGRTMIN>127)
+ return -1; /* not valid */
+ return val+offset;
+}
+
+const char *signal_number_to_name(int signo)
+{
+ static char buf[32];
+ int n = number_of_signals;
+ signo &= 0x7f; /* need to process exit values too */
+ while (n--) {
+ if(sigtable[n].num==signo)
+ return sigtable[n].name;
+ }
+ if (signo == SIGRTMIN)
+ return "RTMIN";
+ if (signo)
+ sprintf(buf, "RTMIN+%d", signo-SIGRTMIN);
+ else
+ strcpy(buf,"0"); /* AIX has NULL; Solaris has EXIT */
+ return buf;
+}
+
+int skill_sig_option(int *argc, char **argv)
+{
+ int i;
+ int signo = -1;
+ for (i = 1; i < *argc; i++) {
+ if (argv[i][0] == '-') {
+ signo = signal_name_to_number(argv[i] + 1);
+ if (-1 < signo) {
+ memmove(argv + i, argv + i + 1,
+ sizeof(char *) * (*argc - i));
+ (*argc)--;
+ return signo;
+ }
+ }
+ }
+ return signo;
+}
+
+
+/* strtosig is similar to print_given_signals() with exception, that
+ * this function takes a string, and converts it to a signal name or
+ * a number string depending on which way a round conversion is
+ * queried. Non-existing signals return NULL. Notice that the
+ * returned string should be freed after use.
+ */
+char *strtosig(const char *restrict s)
+{
+ char *converted = NULL, *copy, *p, *endp;
+ int i, numsignal = 0;
+
+ copy = strdup(s);
+ if (!copy)
+ xerrx(EXIT_FAILURE, "cannot duplicate string");
+ for (p = copy; *p != '\0'; p++)
+ *p = toupper(*p);
+ p = copy;
+ if (p[0] == 'S' && p[1] == 'I' && p[2] == 'G')
+ p += 3;
+ if (isdigit(*p)){
+ numsignal = strtol(s,&endp,10);
+ if(*endp || endp==s){
+ free(p);
+ return NULL; /* not valid */
+ }
+ }
+ if (numsignal){
+ for (i = 0; i < number_of_signals; i++){
+ if (numsignal == get_sigtable_num(i)){
+ converted = strdup(get_sigtable_name(i));
+ break;
+ }
+ }
+ } else {
+ for (i = 0; i < number_of_signals; i++){
+ if (strcmp(p, get_sigtable_name(i)) == 0){
+ converted = malloc(12);
+ if (converted)
+ snprintf(converted, 12, "%d", sigtable[i].num);
+ break;
+ }
+ }
+ }
+ free(copy);
+ return converted;
+}
+
+void unix_print_signals(void)
+{
+ int pos = 0;
+ int i = 0;
+ while(++i <= number_of_signals){
+ if(i-1) printf("%c", (pos>73)?(pos=0,'\n'):(pos++,' ') );
+ pos += printf("%s", signal_number_to_name(i));
+ }
+ printf("\n");
+}
+
+void pretty_print_signals(void)
+{
+ int i = 0;
+ while(++i <= number_of_signals){
+ int n;
+ n = printf("%2d %s", i, signal_number_to_name(i));
+ if(n>0 && i%7)
+ printf("%s", " \0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + n);
+ else
+ printf("\n");
+ }
+ if((i-1)%7) printf("\n");
+}
+