/*
* Copyright 1998-2002 by Albert Cahalan; all rights resered.
* This file may be used subject to the terms and conditions of the
* GNU Library General Public License Version 2, or any later version
* at your option, as published by the Free Software Foundation.
* This program 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 Library General Public License for more details.
*/
#include <signal.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include "sig.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 SIGLOST SIGCLD
* (popular ones are handled as aliases)
* 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. */
#ifndef 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},
{"PIPE", SIGPIPE},
{"POLL", SIGPOLL}, /* IO */
{"PROF", SIGPROF},
{"PWR", SIGPWR},
{"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}
};
static const int number_of_signals = sizeof(sigtable) / sizeof(mapstruct);
static int compare_signal_names(const void *a, const void *b)
{
return strcasecmp(((const mapstruct *)a)->name,
((const mapstruct *)b)->name);
}
/* 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 + SIGRTMIN > 127)
return -1; /* not valid */
return val + offset;
}
static 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 print_given_signals(int argc, const char *restrict const *restrict argv,
int max_line)
{
char buf[1280]; /* 128 signals, "RTMIN+xx" is largest */
int ret = 0; /* to be used as exit code by caller */
int place = 0; /* position on this line */
int amt;
if (argc > 128)
return 1;
while (argc--) {
char tmpbuf[16];
const char *restrict const txt = *argv;
if (*txt >= '0' && *txt <= '9') {
long val;
char *endp;
val = strtol(txt, &endp, 10);
if (*endp) {
fprintf(stderr, "Signal \"%s\" not known.\n",
txt);
ret = 1;
goto end;
}
amt = sprintf(tmpbuf, "%s", signal_number_to_name(val));
} else {
int sno;
sno = signal_name_to_number(txt);
if (sno == -1) {
fprintf(stderr, "Signal \"%s\" not known.\n",
txt);
ret = 1;
goto end;
}
amt = sprintf(tmpbuf, "%d", sno);
}
if (!place) {
strcpy(buf, tmpbuf);
place = amt;
goto end;
}
if (amt + place + 1 > max_line) {
printf("%s\n", buf);
strcpy(buf, tmpbuf);
place = amt;
goto end;
}
sprintf(buf + place, " %s", tmpbuf);
place += amt + 1;
end:
argv++;
}
if (place)
printf("%s\n", buf);
return ret;
}
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 (i % 7)
printf
(" \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");
}
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");
}
/* sanity check */
static int init_signal_list(void) __attribute__ ((constructor));
static int init_signal_list(void)
{
if (number_of_signals != 31) {
fprintf(stderr,
"WARNING: %d signals -- adjust and recompile.\n",
number_of_signals);
}
return 0;
}