diff mbox series

Generate signal names at runtime

Message ID 20240421204648.1156887-1-henrik@lxm.se (mailing list archive)
State Changes Requested
Delegated to: Herbert Xu
Headers show
Series Generate signal names at runtime | expand

Commit Message

Henrik Lindström April 21, 2024, 8:46 p.m. UTC
They were previously generated at buildtime by mksignames.c, but that
approach had two flaws:
1. The signal names were generated for the host system rather than the
   target system, resulting in broken cross-compiled builds.
2. The SIGRTMIN and SIGRTMAX macros are usually implemented as
   function calls and can only be surely known at runtime.

The new implementation has been tested to generate identical signal names
as before on these systems:
* Debian 12 (glibc, odd number of realtime signals)
* Alpine 3.18 (musl, even number of realtime signals)
* FreeBSD 14

Signed-off-by: Henrik Lindström <henrik@lxm.se>
---
 COPYING          |  24 ---
 src/.gitignore   |   2 -
 src/Makefile.am  |  17 +-
 src/TOUR         |   1 -
 src/jobs.c       |   6 +-
 src/mksignames.c | 415 -----------------------------------------------
 src/signalname.c | 150 +++++++++++++++++
 src/signalname.h |   4 +
 src/trap.c       |   7 +-
 9 files changed, 167 insertions(+), 459 deletions(-)
 delete mode 100644 src/mksignames.c
 create mode 100644 src/signalname.c
 create mode 100644 src/signalname.h

Comments

Herbert Xu April 27, 2024, 11:47 a.m. UTC | #1
Henrik Lindström <henrik@lxm.se> wrote:
> They were previously generated at buildtime by mksignames.c, but that
> approach had two flaws:
> 1. The signal names were generated for the host system rather than the
>   target system, resulting in broken cross-compiled builds.
> 2. The SIGRTMIN and SIGRTMAX macros are usually implemented as
>   function calls and can only be surely known at runtime.
> 
> The new implementation has been tested to generate identical signal names
> as before on these systems:
> * Debian 12 (glibc, odd number of realtime signals)
> * Alpine 3.18 (musl, even number of realtime signals)
> * FreeBSD 14
> 
> Signed-off-by: Henrik Lindström <henrik@lxm.se>

Now that glibc has sigabbrev_np we should switch to using that
on Linux, perhaps with the existing code as a fallback.  BSD
has always had ways of getting the signal name, though it may
not be very portable so we'd need different flavours if people
cared enough to add them.

Thanks,
Steffen Nurpmeso April 27, 2024, 7:44 p.m. UTC | #2
Just in case of interest..

Herbert Xu wrote in
 <Zizl53et9J5Hg2D5@gondor.apana.org.au>:
 |Henrik Lindström <henrik@lxm.se> wrote:
 |> They were previously generated at buildtime by mksignames.c, but that
 |> approach had two flaws:
 |> 1. The signal names were generated for the host system rather than the
 |>   target system, resulting in broken cross-compiled builds.
 |> 2. The SIGRTMIN and SIGRTMAX macros are usually implemented as
 |>   function calls and can only be surely known at runtime.
 |> 
 |> The new implementation has been tested to generate identical signal names
 |> as before on these systems:
 |> * Debian 12 (glibc, odd number of realtime signals)
 |> * Alpine 3.18 (musl, even number of realtime signals)
 |> * FreeBSD 14
 |> 
 |> Signed-off-by: Henrik Lindström <henrik@lxm.se>
 |
 |Now that glibc has sigabbrev_np we should switch to using that
 |on Linux, perhaps with the existing code as a fallback.  BSD
 |has always had ways of getting the signal name, though it may
 |not be very portable so we'd need different flavours if people
 |cared enough to add them.

I can only offer a script of mine again which does this for me.
It does more as my MUA can do things like "echo $^ERRDOC-42" ->
"No message of desired type", "echo $^ERRNAME-42" -> "NOMSG",
"echo $^ERR-NOMSG" -> "42", etc, but is a solid foundation base
for whatever dash would need.
It needs perl (tarball time) and $CC and $awk at compile time.
It is portable (Linux, BSD, SunOS/Solaris [with right sh(1) and
awk(1)]).  What you want is likely a variation of

  TARGET=/tmp/errlist sh mk/su-make-signals.sh compile_time

--steffen
|
|Der Kragenbaer,                The moon bear,
|der holt sich munter           he cheerfully and one by one
|einen nach dem anderen runter  wa.ks himself off
|(By Robert Gernhardt)
Henrik Lindström April 29, 2024, 4:28 p.m. UTC | #3
Getting the names from libc sounds ideal, but i don't think there's any way
to do that with musl, which is what i'm trying to cross compile to. That's
why i attempted a more universal solution in my patch, but perhaps there
would be interest in musl to add sigabbrev_np instead.

As for a fallback, shouldn't the goal be something more similar to my
attempt rather than the existing code? Silently building a broken version
of dash when cross compiling isn't ideal.

Thanks
Henrik

On 2024-04-27 13:47, Herbert Xu wrote:
> Henrik Lindström <henrik@lxm.se> wrote:
>> They were previously generated at buildtime by mksignames.c, but that
>> approach had two flaws:
>> 1. The signal names were generated for the host system rather than the
>>   target system, resulting in broken cross-compiled builds.
>> 2. The SIGRTMIN and SIGRTMAX macros are usually implemented as
>>   function calls and can only be surely known at runtime.
>>
>> The new implementation has been tested to generate identical signal names
>> as before on these systems:
>> * Debian 12 (glibc, odd number of realtime signals)
>> * Alpine 3.18 (musl, even number of realtime signals)
>> * FreeBSD 14
>>
>> Signed-off-by: Henrik Lindström <henrik@lxm.se>
> 
> Now that glibc has sigabbrev_np we should switch to using that
> on Linux, perhaps with the existing code as a fallback.  BSD
> has always had ways of getting the signal name, though it may
> not be very portable so we'd need different flavours if people
> cared enough to add them.
> 
> Thanks,
Steffen Nurpmeso April 29, 2024, 5:17 p.m. UTC | #4
Henrik Lindström wrote in
 <d28c0015-3fff-412a-bdb2-39cae101e57f@lxm.se>:
 |Getting the names from libc sounds ideal, but i don't think there's any way
 |to do that with musl, which is what i'm trying to cross compile to. That's
 |why i attempted a more universal solution in my patch, but perhaps there
 |would be interest in musl to add sigabbrev_np instead.
 |
 |As for a fallback, shouldn't the goal be something more similar to my
 |attempt rather than the existing code? Silently building a broken version
 |of dash when cross compiling isn't ideal.

People, adjust that fucking if that is possible on an american
list script of mine (or take it as-is), it requires nothing but
a C compiler (preprocessor) and POSIX (Solaris: xpg4) tools, and
it generates a superset of exactly what you want.  Bug reports
welcome.  I have the same for errno values, too.

--steffen
|
|Der Kragenbaer,                The moon bear,
|der holt sich munter           he cheerfully and one by one
|einen nach dem anderen runter  wa.ks himself off
|(By Robert Gernhardt)
diff mbox series

Patch

diff --git a/COPYING b/COPYING
index 37f8189..c591477 100644
--- a/COPYING
+++ b/COPYING
@@ -30,27 +30,3 @@  HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 SUCH DAMAGE.
-
-mksignames.c:
-
-This file is not directly linked with dash.  However, its output is.
-
-Copyright (C) 1992 Free Software Foundation, Inc.
-
-This file is part of GNU Bash, the Bourne Again SHell.
-
-Bash is free software; you can redistribute it and/or modify it under
-the terms of the GNU General Public License as published by the Free
-Software Foundation; either version 2, or (at your option) any later
-version.
-
-Bash 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 General Public License
-for more details.
-
-You should have received a copy of the GNU General Public License with
-your Debian GNU/Linux system, in /usr/share/common-licenses/GPL, or with the
-Debian GNU/Linux hello source package as the file COPYING.  If not,
-write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
-Boston, MA 02111 USA.
diff --git a/src/.gitignore b/src/.gitignore
index 644eccb..660bbdd 100644
--- a/src/.gitignore
+++ b/src/.gitignore
@@ -5,9 +5,7 @@  dash
 init.c
 mkinit
 mknodes
-mksignames
 mksyntax
 nodes.[ch]
-signames.c
 syntax.[ch]
 token.h
diff --git a/src/Makefile.am b/src/Makefile.am
index 1732465..8d1dc37 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -6,20 +6,20 @@  COMMON_CPPFLAGS = \
 
 AM_CFLAGS = $(COMMON_CFLAGS)
 AM_CPPFLAGS = -include $(top_builddir)/config.h $(COMMON_CPPFLAGS)
-AM_CFLAGS_FOR_BUILD = -g -O2 $(COMMON_CFLAGS) 
+AM_CFLAGS_FOR_BUILD = -g -O2 $(COMMON_CFLAGS)
 AM_CPPFLAGS_FOR_BUILD = $(COMMON_CPPFLAGS)
 
 COMPILE_FOR_BUILD = \
 	$(CC_FOR_BUILD) $(DEFAULT_INCLUDES) $(AM_CPPFLAGS_FOR_BUILD) \
 	$(CPPFLAGS_FOR_BUILD) \
-	$(AM_CFLAGS_FOR_BUILD) $(CFLAGS_FOR_BUILD) 
+	$(AM_CFLAGS_FOR_BUILD) $(CFLAGS_FOR_BUILD)
 
 bin_PROGRAMS = dash
 
 dash_CFILES = \
 	alias.c arith_yacc.c arith_yylex.c cd.c error.c eval.c exec.c expand.c \
 	histedit.c input.c jobs.c mail.c main.c memalloc.c miscbltin.c \
-	mystring.c options.c parser.c redir.c show.c trap.c output.c \
+	mystring.c options.c parser.c redir.c show.c signalname.c trap.c output.c \
 	bltin/printf.c system.c bltin/test.c bltin/times.c var.c
 dash_SOURCES = \
 	$(dash_CFILES) \
@@ -27,10 +27,10 @@  dash_SOURCES = \
 	expand.h \
 	init.h input.h jobs.h machdep.h mail.h main.h memalloc.h miscbltin.h \
 	myhistedit.h mystring.h options.h output.h parser.h redir.h shell.h \
-	show.h system.h trap.h var.h
-dash_LDADD = builtins.o init.o nodes.o signames.o syntax.o
+	show.h signalname.h system.h trap.h var.h
+dash_LDADD = builtins.o init.o nodes.o syntax.o
 
-HELPERS = mkinit mksyntax mknodes mksignames
+HELPERS = mkinit mksyntax mknodes
 
 BUILT_SOURCES = builtins.h nodes.h syntax.h token.h token_vars.h
 CLEANFILES = \
@@ -41,7 +41,7 @@  man_MANS = dash.1
 EXTRA_DIST = \
 	$(man_MANS) \
 	mktokens mkbuiltins builtins.def.in mkinit.c \
-	mknodes.c nodetypes nodes.c.pat mksyntax.c mksignames.c
+	mknodes.c nodetypes nodes.c.pat mksyntax.c
 
 token.h token_vars.h: mktokens
 	$(AM_V_GEN)$(SHELL) $^
@@ -61,9 +61,6 @@  nodes.c nodes.h: mknodes nodetypes nodes.c.pat
 syntax.c syntax.h: mksyntax
 	$(AM_V_GEN)./$^
 
-signames.c: mksignames
-	$(AM_V_GEN)./$^
-
 mksyntax: token.h
 
 $(HELPERS): %: %.c
diff --git a/src/TOUR b/src/TOUR
index e30836e..b554f13 100644
--- a/src/TOUR
+++ b/src/TOUR
@@ -26,7 +26,6 @@  programs is:
         mkbuiltins      builtins            builtins.h builtins.c
         mkinit          *.c                 init.c
         mknodes         nodetypes           nodes.h nodes.c
-        mksignames          -               signames.h signames.c
         mksyntax            -               syntax.h syntax.c
         mktokens            -               token.h
         bltin/mkexpr    unary_op binary_op  operators.h operators.c
diff --git a/src/jobs.c b/src/jobs.c
index 2a2fe22..6430cb3 100644
--- a/src/jobs.c
+++ b/src/jobs.c
@@ -71,6 +71,7 @@ 
 #include "error.h"
 #include "mystring.h"
 #include "system.h"
+#include "signalname.h"
 
 /* mode flags for set_curjob */
 #define CUR_DELETE 2
@@ -262,7 +263,6 @@  out:
 
 int killcmd(int argc, char **argv)
 {
-	extern char *signal_names[];
 	int signo = -1;
 	int list = 0;
 	int i;
@@ -320,7 +320,7 @@  usage:
 		if (!*argv) {
 			outstr("0\n", out);
 			for (i = 1; i < NSIG; i++) {
-				outfmt(out, snlfmt, signal_names[i]);
+				outfmt(out, snlfmt, signalname(i));
 			}
 			return 0;
 		}
@@ -328,7 +328,7 @@  usage:
 		if (signo > 128)
 			signo -= 128;
 		if (0 < signo && signo < NSIG)
-			outfmt(out, snlfmt, signal_names[signo]);
+			outfmt(out, snlfmt, signalname(signo));
 		else
 			sh_error("invalid signal number or exit status: %s",
 				 *argv);
diff --git a/src/mksignames.c b/src/mksignames.c
deleted file mode 100644
index 192728b..0000000
--- a/src/mksignames.c
+++ /dev/null
@@ -1,415 +0,0 @@ 
-/* signames.c -- Create and write `signames.c', which contains an array of
-   signal names. */
-
-/* Copyright (C) 1992 Free Software Foundation, Inc.
-
-   This file is part of GNU Bash, the Bourne Again SHell.
-
-   Bash is free software; you can redistribute it and/or modify it under
-   the terms of the GNU General Public License as published by the Free
-   Software Foundation; either version 2, or (at your option) any later
-   version.
-
-   Bash 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 General Public License
-   for more details.
-
-   You should have received a copy of the GNU General Public License along
-   with Bash; see the file COPYING.  If not, write to the Free Software
-   Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */
-
-#include <stdio.h>
-#include <sys/types.h>
-#include <signal.h>
-#include <stdlib.h>
-
-#if !defined (NSIG)
-#  define NSIG 64
-#endif
-
-/*
- * Special traps:
- *	EXIT == 0
- */
-#define LASTSIG NSIG-1
-
-char *signal_names[2 * NSIG + 3];
-
-#define signal_names_size (sizeof(signal_names)/sizeof(signal_names[0]))
-
-char *progname;
-
-/* AIX 4.3 defines SIGRTMIN and SIGRTMAX as 888 and 999 respectively.
-   I don't want to allocate so much unused space for the intervening signal
-   numbers, so we just punt if SIGRTMAX is past the bounds of the
-   signal_names array (handled in configure). */
-#if defined (SIGRTMAX) && defined (UNUSABLE_RT_SIGNALS)
-#  undef SIGRTMAX
-#  undef SIGRTMIN
-#endif
-
-#if defined (SIGRTMAX) || defined (SIGRTMIN)
-#  define RTLEN 14
-#  define RTLIM 256
-#endif
-
-void
-initialize_signames ()
-{
-  register int i;
-#if defined (SIGRTMAX) || defined (SIGRTMIN)
-  int rtmin, rtmax, rtcnt;
-#endif
-
-  for (i = 1; i < signal_names_size; i++)
-    signal_names[i] = (char *)NULL;
-
-  /* `signal' 0 is what we do on exit. */
-  signal_names[0] = "EXIT";
-
-  /* Place signal names which can be aliases for more common signal
-     names first.  This allows (for example) SIGABRT to overwrite SIGLOST. */
-
-  /* POSIX 1003.1b-1993 real time signals, but take care of incomplete
-     implementations. Acoording to the standard, both, SIGRTMIN and
-     SIGRTMAX must be defined, SIGRTMIN must be stricly less than
-     SIGRTMAX, and the difference must be at least 7, that is, there
-     must be at least eight distinct real time signals. */
-
-  /* The generated signal names are SIGRTMIN, SIGRTMIN+1, ...,
-     SIGRTMIN+x, SIGRTMAX-x, ..., SIGRTMAX-1, SIGRTMAX. If the number
-     of RT signals is odd, there is an extra SIGRTMIN+(x+1).
-     These names are the ones used by ksh and /usr/xpg4/bin/sh on SunOS5. */
-
-#if defined (SIGRTMIN)
-  rtmin = SIGRTMIN;
-  signal_names[rtmin] = "RTMIN";
-#endif
-
-#if defined (SIGRTMAX)
-  rtmax = SIGRTMAX;
-  signal_names[rtmax] = "RTMAX";
-#endif
-
-#if defined (SIGRTMAX) && defined (SIGRTMIN)
-  if (rtmax > rtmin)
-    {
-      rtcnt = (rtmax - rtmin - 1) / 2;
-      /* croak if there are too many RT signals */
-      if (rtcnt >= RTLIM/2)
-	{
-	  rtcnt = RTLIM/2-1;
-	  fprintf(stderr, "%s: error: more than %i real time signals, fix `%s'\n",
-		  progname, RTLIM, progname);
-	}
-
-      for (i = 1; i <= rtcnt; i++)
-	{
-	  signal_names[rtmin+i] = (char *)malloc(RTLEN);
-	  if (signal_names[rtmin+i])
-	    sprintf (signal_names[rtmin+i], "RTMIN+%d", i);
-	  signal_names[rtmax-i] = (char *)malloc(RTLEN);
-	  if (signal_names[rtmax-i])
-	    sprintf (signal_names[rtmax-i], "RTMAX-%d", i);
-	}
-
-      if (rtcnt < RTLIM/2-1 && rtcnt != (rtmax-rtmin)/2)
-	{
-	  /* Need an extra RTMIN signal */
-	  signal_names[rtmin+rtcnt+1] = (char *)malloc(RTLEN);
-	  if (signal_names[rtmin+rtcnt+1])
-	    sprintf (signal_names[rtmin+rtcnt+1], "RTMIN+%d", rtcnt+1);
-	}
-    }
-#endif /* SIGRTMIN && SIGRTMAX */
-
-/* AIX */
-#if defined (SIGLOST)	/* resource lost (eg, record-lock lost) */
-  signal_names[SIGLOST] = "LOST";
-#endif
-
-#if defined (SIGMSG)	/* HFT input data pending */
-  signal_names[SIGMSG] = "MSG";
-#endif
-
-#if defined (SIGDANGER)	/* system crash imminent */
-  signal_names[SIGDANGER] = "DANGER";
-#endif
-
-#if defined (SIGMIGRATE) /* migrate process to another CPU */
-  signal_names[SIGMIGRATE] = "MIGRATE";
-#endif
-
-#if defined (SIGPRE)	/* programming error */
-  signal_names[SIGPRE] = "PRE";
-#endif
-
-#if defined (SIGVIRT)	/* AIX virtual time alarm */
-  signal_names[SIGVIRT] = "VIRT";
-#endif
-
-#if defined (SIGALRM1)	/* m:n condition variables */
-  signal_names[SIGALRM1] = "ALRM1";
-#endif
-
-#if defined (SIGWAITING)	/* m:n scheduling */
-  signal_names[SIGWAITING] = "WAITING";
-#endif
-
-#if defined (SIGGRANT)	/* HFT monitor mode granted */
-  signal_names[SIGGRANT] = "GRANT";
-#endif
-
-#if defined (SIGKAP)	/* keep alive poll from native keyboard */
-  signal_names[SIGKAP] = "KAP";
-#endif
-
-#if defined (SIGRETRACT) /* HFT monitor mode retracted */
-  signal_names[SIGRETRACT] = "RETRACT";
-#endif
-
-#if defined (SIGSOUND)	/* HFT sound sequence has completed */
-  signal_names[SIGSOUND] = "SOUND";
-#endif
-
-#if defined (SIGSAK)	/* Secure Attention Key */
-  signal_names[SIGSAK] = "SAK";
-#endif
-
-/* SunOS5 */
-#if defined (SIGLWP)	/* special signal used by thread library */
-  signal_names[SIGLWP] = "LWP";
-#endif
-
-#if defined (SIGFREEZE)	/* special signal used by CPR */
-  signal_names[SIGFREEZE] = "FREEZE";
-#endif
-
-#if defined (SIGTHAW)	/* special signal used by CPR */
-  signal_names[SIGTHAW] = "THAW";
-#endif
-
-#if defined (SIGCANCEL)	/* thread cancellation signal used by libthread */
-  signal_names[SIGCANCEL] = "CANCEL";
-#endif
-
-/* HP-UX */
-#if defined (SIGDIL)	/* DIL signal (?) */
-  signal_names[SIGDIL] = "DIL";
-#endif
-
-/* System V */
-#if defined (SIGCLD)	/* Like SIGCHLD.  */
-  signal_names[SIGCLD] = "CLD";
-#endif
-
-#if defined (SIGPWR)	/* power state indication */
-  signal_names[SIGPWR] = "PWR";
-#endif
-
-#if defined (SIGPOLL)	/* Pollable event (for streams)  */
-  signal_names[SIGPOLL] = "POLL";
-#endif
-
-/* Unknown */
-#if defined (SIGWINDOW)
-  signal_names[SIGWINDOW] = "WINDOW";
-#endif
-
-/* Common */
-#if defined (SIGHUP)	/* hangup */
-  signal_names[SIGHUP] = "HUP";
-#endif
-
-#if defined (SIGINT)	/* interrupt */
-  signal_names[SIGINT] = "INT";
-#endif
-
-#if defined (SIGQUIT)	/* quit */
-  signal_names[SIGQUIT] = "QUIT";
-#endif
-
-#if defined (SIGILL)	/* illegal instruction (not reset when caught) */
-  signal_names[SIGILL] = "ILL";
-#endif
-
-#if defined (SIGTRAP)	/* trace trap (not reset when caught) */
-  signal_names[SIGTRAP] = "TRAP";
-#endif
-
-#if defined (SIGIOT)	/* IOT instruction */
-  signal_names[SIGIOT] = "IOT";
-#endif
-
-#if defined (SIGABRT)	/* Cause current process to dump core. */
-  signal_names[SIGABRT] = "ABRT";
-#endif
-
-#if defined (SIGEMT)	/* EMT instruction */
-  signal_names[SIGEMT] = "EMT";
-#endif
-
-#if defined (SIGFPE)	/* floating point exception */
-  signal_names[SIGFPE] = "FPE";
-#endif
-
-#if defined (SIGKILL)	/* kill (cannot be caught or ignored) */
-  signal_names[SIGKILL] = "KILL";
-#endif
-
-#if defined (SIGBUS)	/* bus error */
-  signal_names[SIGBUS] = "BUS";
-#endif
-
-#if defined (SIGSEGV)	/* segmentation violation */
-  signal_names[SIGSEGV] = "SEGV";
-#endif
-
-#if defined (SIGSYS)	/* bad argument to system call */
-  signal_names[SIGSYS] = "SYS";
-#endif
-
-#if defined (SIGPIPE)	/* write on a pipe with no one to read it */
-  signal_names[SIGPIPE] = "PIPE";
-#endif
-
-#if defined (SIGALRM)	/* alarm clock */
-  signal_names[SIGALRM] = "ALRM";
-#endif
-
-#if defined (SIGTERM)	/* software termination signal from kill */
-  signal_names[SIGTERM] = "TERM";
-#endif
-
-#if defined (SIGURG)	/* urgent condition on IO channel */
-  signal_names[SIGURG] = "URG";
-#endif
-
-#if defined (SIGSTOP)	/* sendable stop signal not from tty */
-  signal_names[SIGSTOP] = "STOP";
-#endif
-
-#if defined (SIGTSTP)	/* stop signal from tty */
-  signal_names[SIGTSTP] = "TSTP";
-#endif
-
-#if defined (SIGCONT)	/* continue a stopped process */
-  signal_names[SIGCONT] = "CONT";
-#endif
-
-#if defined (SIGCHLD)	/* to parent on child stop or exit */
-  signal_names[SIGCHLD] = "CHLD";
-#endif
-
-#if defined (SIGTTIN)	/* to readers pgrp upon background tty read */
-  signal_names[SIGTTIN] = "TTIN";
-#endif
-
-#if defined (SIGTTOU)	/* like TTIN for output if (tp->t_local&LTOSTOP) */
-  signal_names[SIGTTOU] = "TTOU";
-#endif
-
-#if defined (SIGIO)	/* input/output possible signal */
-  signal_names[SIGIO] = "IO";
-#endif
-
-#if defined (SIGXCPU)	/* exceeded CPU time limit */
-  signal_names[SIGXCPU] = "XCPU";
-#endif
-
-#if defined (SIGXFSZ)	/* exceeded file size limit */
-  signal_names[SIGXFSZ] = "XFSZ";
-#endif
-
-#if defined (SIGVTALRM)	/* virtual time alarm */
-  signal_names[SIGVTALRM] = "VTALRM";
-#endif
-
-#if defined (SIGPROF)	/* profiling time alarm */
-  signal_names[SIGPROF] = "PROF";
-#endif
-
-#if defined (SIGWINCH)	/* window changed */
-  signal_names[SIGWINCH] = "WINCH";
-#endif
-
-/* 4.4 BSD */
-#if defined (SIGINFO) && !defined (_SEQUENT_)	/* information request */
-  signal_names[SIGINFO] = "INFO";
-#endif
-
-#if defined (SIGUSR1)	/* user defined signal 1 */
-  signal_names[SIGUSR1] = "USR1";
-#endif
-
-#if defined (SIGUSR2)	/* user defined signal 2 */
-  signal_names[SIGUSR2] = "USR2";
-#endif
-
-#if defined (SIGKILLTHR)	/* BeOS: Kill Thread */
-  signal_names[SIGKILLTHR] = "KILLTHR";
-#endif
-
-  for (i = 0; i < NSIG; i++)
-    if (signal_names[i] == (char *)NULL)
-      {
-	signal_names[i] = (char *)malloc (18);
-	if (signal_names[i])
-	  sprintf (signal_names[i], "%d", i);
-      }
-}
-
-void write_signames(FILE *stream)
-{
-  register int i;
-
-  fprintf (stream, "/* This file was automatically created by %s.\n",
-	   progname);
-  fprintf (stream, "   Do not edit.  Edit support/mksignames.c instead. */\n\n");
-  fprintf (stream, "#include <signal.h>\n\n");
-  fprintf (stream,
-	   "/* A translation list so we can be polite to our users. */\n");
-  fprintf (stream, "const char *const signal_names[NSIG + 1] = {\n");
-
-  for (i = 0; i <= LASTSIG; i++)
-    fprintf (stream, "    \"%s\",\n", signal_names[i]);
-
-  fprintf (stream, "    (char *)0x0\n");
-  fprintf (stream, "};\n");
-}
-
-int
-main(int argc, char **argv)
-{
-  char *stream_name;
-  FILE *stream;
-
-  progname = argv[0];
-
-  if (argc == 1)
-    {
-      stream_name = "signames.c";
-    }
-  else if (argc == 2)
-    {
-      stream_name = argv[1];
-    }
-  else
-    {
-      fprintf (stderr, "Usage: %s [output-file]\n", progname);
-      exit (1);
-    }
-
-  stream = fopen (stream_name, "w");
-  if (!stream)
-    {
-      fprintf (stderr, "%s: %s: cannot open for writing\n",
-	       progname, stream_name);
-      exit (2);
-    }
-
-  initialize_signames ();
-  write_signames (stream);
-  exit (0);
-}
diff --git a/src/signalname.c b/src/signalname.c
new file mode 100644
index 0000000..437e07c
--- /dev/null
+++ b/src/signalname.c
@@ -0,0 +1,150 @@ 
+// This file is in the Public Domain.
+#include <signal.h>
+
+#include "shell.h"
+#include "output.h"
+#include "signalname.h"
+
+MKINIT char *signal_names[NSIG] = {0};
+#if defined(SIGRTMIN) && defined(SIGRTMAX)
+MKINIT int sigrtmin;
+MKINIT int sigrtmax;
+#endif
+
+char *signalname(int signo) {
+	static char buf[16];
+
+	if ((unsigned)signo < NSIG && signal_names[signo])
+		return signal_names[signo];
+
+#if defined(SIGRTMIN) && defined(SIGRTMAX)
+	if (signo > sigrtmin && signo < sigrtmax) {
+		int last_rtmin_signo = sigrtmin + (sigrtmax - sigrtmin) / 2;
+		if (signo <= last_rtmin_signo)
+			fmtstr(buf, sizeof(buf), "RTMIN+%d", signo - sigrtmin);
+		else
+			fmtstr(buf, sizeof(buf), "RTMAX-%d", sigrtmax - signo);
+		return buf;
+	}
+#endif
+
+	fmtstr(buf, sizeof(buf), "%d", signo);
+	return buf;
+}
+
+#ifdef mkinit
+INIT {
+#define set_name(signo, name) if (signo < NSIG) signal_names[signo] = name
+	// 0 is no signal, but the trap command needs this to parse EXIT as 0.
+	set_name(0, "EXIT");
+
+	// Posix signals
+#if defined(SIGRTMIN) && defined(SIGRTMAX)
+	sigrtmin = SIGRTMIN;
+	set_name(sigrtmin, "RTMIN");
+	sigrtmax = SIGRTMAX;
+	set_name(sigrtmax, "RTMAX");
+#endif
+#ifdef SIGABRT
+	set_name(SIGABRT, "ABRT");
+#endif
+#ifdef SIGALRM
+	set_name(SIGALRM, "ALRM");
+#endif
+#ifdef SIGBUS
+	set_name(SIGBUS, "BUS");
+#endif
+#ifdef SIGCHLD
+	set_name(SIGCHLD, "CHLD");
+#endif
+#ifdef SIGCONT
+	set_name(SIGCONT, "CONT");
+#endif
+#ifdef SIGFPE
+	set_name(SIGFPE, "FPE");
+#endif
+#ifdef SIGHUP
+	set_name(SIGHUP, "HUP");
+#endif
+#ifdef SIGILL
+	set_name(SIGILL, "ILL");
+#endif
+#ifdef SIGINT
+	set_name(SIGINT, "INT");
+#endif
+#ifdef SIGKILL
+	set_name(SIGKILL, "KILL");
+#endif
+#ifdef SIGPIPE
+	set_name(SIGPIPE, "PIPE");
+#endif
+#ifdef SIGQUIT
+	set_name(SIGQUIT, "QUIT");
+#endif
+#ifdef SIGSEGV
+	set_name(SIGSEGV, "SEGV");
+#endif
+#ifdef SIGSTOP
+	set_name(SIGSTOP, "STOP");
+#endif
+#ifdef SIGTERM
+	set_name(SIGTERM, "TERM");
+#endif
+#ifdef SIGTSTP
+	set_name(SIGTSTP, "TSTP");
+#endif
+#ifdef SIGTTIN
+	set_name(SIGTTIN, "TTIN");
+#endif
+#ifdef SIGTTOU
+	set_name(SIGTTOU, "TTOU");
+#endif
+#ifdef SIGUSR1
+	set_name(SIGUSR1, "USR1");
+#endif
+#ifdef SIGUSR2
+	set_name(SIGUSR2, "USR2");
+#endif
+#ifdef SIGPOLL
+	set_name(SIGPOLL, "POLL");
+#endif
+#ifdef SIGPROF
+	set_name(SIGPROF, "PROF");
+#endif
+#ifdef SIGSYS
+	set_name(SIGSYS, "SYS");
+#endif
+#ifdef SIGTRAP
+	set_name(SIGTRAP, "TRAP");
+#endif
+#ifdef SIGURG
+	set_name(SIGURG, "URG");
+#endif
+#ifdef SIGVTALRM
+	set_name(SIGVTALRM, "VTALRM");
+#endif
+#ifdef SIGXCPU
+	set_name(SIGXCPU, "XCPU");
+#endif
+#ifdef SIGXFSZ
+	set_name(SIGXFSZ, "XFSZ");
+#endif
+
+	// Non-posix signals
+#ifdef SIGIO
+	set_name(SIGIO, "IO");
+#endif
+#ifdef SIGWINCH
+	set_name(SIGWINCH, "WINCH");
+#endif
+#ifdef SIGPWR
+	set_name(SIGPWR, "PWR");
+#endif
+#ifdef SIGINFO
+	set_name(SIGINFO, "INFO");
+#endif
+#ifdef SIGEMT
+	set_name(SIGEMT, "EMT");
+#endif
+}
+#endif
diff --git a/src/signalname.h b/src/signalname.h
new file mode 100644
index 0000000..1d8e238
--- /dev/null
+++ b/src/signalname.h
@@ -0,0 +1,4 @@ 
+// This file is in the Public Domain.
+
+// Returned string is valid until the next call to signalname.
+char *signalname(int signo);
diff --git a/src/trap.c b/src/trap.c
index cd84814..9f6bdb3 100644
--- a/src/trap.c
+++ b/src/trap.c
@@ -51,6 +51,7 @@ 
 #include "error.h"
 #include "trap.h"
 #include "mystring.h"
+#include "signalname.h"
 
 /*
  * Sigmode records the current value of the signal handlers for the various
@@ -78,8 +79,6 @@  volatile sig_atomic_t pending_sig;
 /* received SIGCHLD */
 volatile sig_atomic_t gotsigchld;
 
-extern char *signal_names[];
-
 static int decode_signum(const char *);
 
 #ifdef mkinit
@@ -127,7 +126,7 @@  trapcmd(int argc, char **argv)
 				out1fmt(
 					"trap -- %s %s\n",
 					single_quote(trap[signo]),
-					signal_names[signo]
+					signalname(signo)
 				);
 			}
 		}
@@ -429,7 +428,7 @@  int decode_signal(const char *string, int minsig)
 		return signo;
 
 	for (signo = minsig; signo < NSIG; signo++) {
-		if (!strcasecmp(string, signal_names[signo])) {
+		if (!strcasecmp(string, signalname(signo))) {
 			return signo;
 		}
 	}