diff --git a/Build.sh b/Build.sh index 88f4e91..ea63e5e 100644 --- a/Build.sh +++ b/Build.sh @@ -1,5 +1,5 @@ #!/bin/sh -srcversion='$MirOS: src/bin/mksh/Build.sh,v 1.677 2015/04/29 20:39:00 tg Exp $' +srcversion='$MirOS: src/bin/mksh/Build.sh,v 1.678 2015/04/29 20:44:31 tg Exp $' #- # Copyright (c) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, # 2011, 2012, 2013, 2014, 2015 @@ -2248,20 +2248,22 @@ if test 0 = $HAVE_SYS_SIGNAME; then sigseenone=: sigseentwo=: echo '#include -#ifndef NSIG -#if defined(_NSIG) -#define NSIG _NSIG +#if defined(NSIG_MAX) +#define cfg_NSIG NSIG_MAX +#elif defined(NSIG) +#define cfg_NSIG NSIG +#elif defined(_NSIG) +#define cfg_NSIG _NSIG #elif defined(SIGMAX) -#define NSIG (SIGMAX+1) +#define cfg_NSIG (SIGMAX + 1) #elif defined(_SIGMAX) -#define NSIG (_SIGMAX+1) +#define cfg_NSIG (_SIGMAX + 1) #else -/* XXX better error out, see sh.h */ -#define NSIG 64 -#endif +/*XXX better error out, see sh.h */ +#define cfg_NSIG 64 #endif int -mksh_cfg= NSIG +mksh_cfg= cfg_NSIG ;' >conftest.c # GNU sed 2.03 segfaults when optimising this to sed -n NSIG=`vq "$CPP $CFLAGS $CPPFLAGS $NOWARN conftest.c" | \ @@ -2310,7 +2312,7 @@ mksh_cfg= NSIG sed 's/^ *mksh_cfg *=[ ]*\([0-9][0-9x]*\).*$/:\1 '$name/ done | sed -n '/^:[^ ]/s/^://p' | while read nr name; do test $printf = echo || nr=`printf %d "$nr" 2>/dev/null` - test $nr -gt 0 && test $nr -le $NSIG || continue + test $nr -gt 0 && test $nr -lt $NSIG || continue case $sigseentwo in *:$nr:*) ;; *) echo " { \"$name\", $nr }," diff --git a/check.t b/check.t index b0d5e92..ca44d34 100644 --- a/check.t +++ b/check.t @@ -1,4 +1,4 @@ -# $MirOS: src/bin/mksh/check.t,v 1.692 2015/04/29 20:13:47 tg Exp $ +# $MirOS: src/bin/mksh/check.t,v 1.693 2015/04/29 20:44:32 tg Exp $ # -*- mode: sh -*- #- # Copyright © 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, @@ -30,7 +30,7 @@ # (2013/12/02 20:39:44) http://openbsd.cs.toronto.edu/cgi-bin/cvsweb/src/regress/bin/ksh/?sortby=date expected-stdout: - @(#)MIRBSD KSH R51 2015/04/19 + @(#)MIRBSD KSH R51 2015/04/29 description: Check version of shell. stdin: @@ -39,7 +39,7 @@ name: KSH_VERSION category: shell:legacy-no --- expected-stdout: - @(#)LEGACY KSH R51 2015/04/19 + @(#)LEGACY KSH R51 2015/04/29 description: Check version of legacy shell. stdin: @@ -4837,7 +4837,7 @@ expected-stdout: PROG: trap: bad signal 'UNKNOWNSIGNAL' PROG: trap: bad signal '999999' PROG: trap: bad signal 'FNORD' - = 3 + = 1 trap 2 executed --- name: read-IFS-1 diff --git a/funcs.c b/funcs.c index dea8fa6..70edb1b 100644 --- a/funcs.c +++ b/funcs.c @@ -38,7 +38,7 @@ #endif #endif -__RCSID("$MirOS: src/bin/mksh/funcs.c,v 1.270 2015/04/29 20:07:32 tg Exp $"); +__RCSID("$MirOS: src/bin/mksh/funcs.c,v 1.271 2015/04/29 20:44:34 tg Exp $"); #if HAVE_KILLPG /* @@ -1331,7 +1331,7 @@ c_kill(const char **wp) /* assume old style options if -digits or -UPPERCASE */ if ((p = wp[1]) && *p == '-' && (ksh_isdigit(p[1]) || ksh_isupper(p[1]))) { - if (!(t = gettrap(p + 1, false))) { + if (!(t = gettrap(p + 1, false, false))) { bi_errorf("bad signal '%s'", p + 1); return (1); } @@ -1345,7 +1345,8 @@ c_kill(const char **wp) lflag = true; break; case 's': - if (!(t = gettrap(builtin_opt.optarg, true))) { + if (!(t = gettrap(builtin_opt.optarg, + true, false))) { bi_errorf("bad signal '%s'", builtin_opt.optarg); return (1); @@ -1371,24 +1372,25 @@ c_kill(const char **wp) for (; wp[i]; i++) { if (!bi_getn(wp[i], &n)) return (1); -#if (NSIG < 128) - if (n > 128 && n < 128 + NSIG) +#if (ksh_NSIG < 128) + if (n > 128 && n < 128 + ksh_NSIG) n -= 128; #endif - if (n > 0 && n < NSIG) + if (n > 0 && n < ksh_NSIG) shprintf("%s\n", sigtraps[n].name); else shprintf("%d\n", n); } } else { - ssize_t w, mess_cols, mess_octs; - int j; - struct kill_info ki; + ssize_t w, mess_cols = 0, mess_octs = 0; + int j = ksh_NSIG; + struct kill_info ki = { 0, 0 }; - for (j = NSIG, ki.num_width = 1; j >= 10; j /= 10) + do { ki.num_width++; - ki.name_width = mess_cols = mess_octs = 0; - for (j = 0; j < NSIG; j++) { + } while ((j /= 10)); + + for (j = 1; j < ksh_NSIG; j++) { w = strlen(sigtraps[j].name); if (w > ki.name_width) ki.name_width = w; @@ -1400,7 +1402,7 @@ c_kill(const char **wp) mess_cols = w; } - print_columns(shl_stdout, (unsigned int)(NSIG - 1), + print_columns(shl_stdout, (unsigned int)(ksh_NSIG - 1), kill_fmt_entry, (void *)&ki, ki.num_width + 1 + ki.name_width + 1 + mess_octs, ki.num_width + 1 + ki.name_width + 1 + mess_cols, @@ -2286,41 +2288,44 @@ c_eval(const char **wp) int c_trap(const char **wp) { - int i; + Trap *p = sigtraps; + int i = ksh_NSIG + 1; const char *s; - Trap *p; if (ksh_getopt(wp, &builtin_opt, null) == '?') return (1); wp += builtin_opt.optind; if (*wp == NULL) { - for (p = sigtraps, i = NSIG + 1; --i >= 0; p++) - if (p->trap != NULL) { + do { + if (p->trap) { shf_puts("trap -- ", shl_stdout); print_value_quoted(shl_stdout, p->trap); shprintf(" %s\n", p->name); } + ++p; + } while (--i); return (0); } - /* - * Use case sensitive lookup for first arg so the - * command 'exit' isn't confused with the pseudo-signal - * 'EXIT'. - */ - /* get command */ - s = (gettrap(*wp, false) == NULL) ? *wp++ : NULL; - if (s != NULL && ksh_isdash(s)) + if (getn(*wp, &i)) { + /* first argument is a signal number, reset them all */ s = NULL; + } else { + /* first argument must be a command, then */ + s = *wp++; + /* reset traps? */ + if (ksh_isdash(s)) + s = NULL; + } - /* set/clear traps */ + /* set/clear the traps */ i = 0; - while (*wp != NULL) - if ((p = gettrap(*wp++, true)) == NULL) { + while (*wp) + if (!(p = gettrap(*wp++, true, true))) { warningf(true, "%s: %s '%s'", builtin_argv0, "bad signal", wp[-1]); - ++i; + i = 1; } else settrap(p, s); return (i); diff --git a/histrap.c b/histrap.c index 2cd36b0..37ee258 100644 --- a/histrap.c +++ b/histrap.c @@ -27,9 +27,9 @@ #include #endif -__RCSID("$MirOS: src/bin/mksh/histrap.c,v 1.142 2015/04/29 19:11:57 tg Exp $"); +__RCSID("$MirOS: src/bin/mksh/histrap.c,v 1.143 2015/04/29 20:44:35 tg Exp $"); -Trap sigtraps[NSIG + 1]; +Trap sigtraps[ksh_NSIG + 1]; static struct sigaction Sigact_ign; #if HAVE_PERSISTENT_HISTORY @@ -980,55 +980,53 @@ inittraps(void) trap_exstat = -1; /* Populate sigtraps based on sys_signame and sys_siglist. */ - /*XXX this is idiotic, use a multi-key/value hashtable! */ - for (i = 0; i <= NSIG; i++) { + for (i = 1; i < ksh_NSIG; i++) { sigtraps[i].signal = i; - if (i == ksh_SIGERR) { - sigtraps[i].name = "ERR"; - sigtraps[i].mess = "Error handler"; - } else { #if HAVE_SYS_SIGNAME - cs = sys_signame[i]; + cs = sys_signame[i]; #else - const struct mksh_sigpair *pair = mksh_sigpairs; - while ((pair->nr != i) && (pair->name != NULL)) - ++pair; - cs = pair->name; + const struct mksh_sigpair *pair = mksh_sigpairs; + while ((pair->nr != i) && (pair->name != NULL)) + ++pair; + cs = pair->name; #endif - if ((cs == NULL) || - (cs[0] == '\0')) - sigtraps[i].name = shf_smprintf("%d", i); - else { - char *s; + if ((cs == NULL) || + (cs[0] == '\0')) + sigtraps[i].name = shf_smprintf("%d", i); + else { + char *s; - /* this is not optimal, what about SIGSIG1? */ - if ((cs[0] & 0xDF) == 'S' && - (cs[1] & 0xDF) == 'I' && - (cs[2] & 0xDF) == 'G' && - cs[3] != '\0') { - /* skip leading "SIG" */ - cs += 3; - } - strdupx(s, cs, APERM); - sigtraps[i].name = s; - while ((*s = ksh_toupper(*s))) - ++s; + /* this is not optimal, what about SIGSIG1? */ + if (ksh_eq(cs[0], 'S', 's') && + ksh_eq(cs[1], 'I', 'i') && + ksh_eq(cs[2], 'G', 'g') && + cs[3] != '\0') { + /* skip leading "SIG" */ + cs += 3; } -#if HAVE_SYS_SIGLIST - sigtraps[i].mess = sys_siglist[i]; -#elif HAVE_STRSIGNAL - sigtraps[i].mess = strsignal(i); -#else - sigtraps[i].mess = NULL; -#endif - if ((sigtraps[i].mess == NULL) || - (sigtraps[i].mess[0] == '\0')) - sigtraps[i].mess = shf_smprintf("%s %d", - "Signal", i); + strdupx(s, cs, APERM); + sigtraps[i].name = s; + while ((*s = ksh_toupper(*s))) + ++s; } +#if HAVE_SYS_SIGLIST + sigtraps[i].mess = sys_siglist[i]; +#elif HAVE_STRSIGNAL + sigtraps[i].mess = strsignal(i); +#else + sigtraps[i].mess = NULL; +#endif + if ((sigtraps[i].mess == NULL) || + (sigtraps[i].mess[0] == '\0')) + sigtraps[i].mess = shf_smprintf("%s %d", + "Signal", i); } - /* our name for signal 0 */ + sigtraps[ksh_SIGEXIT].signal = ksh_SIGEXIT; sigtraps[ksh_SIGEXIT].name = "EXIT"; + sigtraps[ksh_SIGEXIT].mess = "Exit trap"; + sigtraps[ksh_SIGERR].signal = ksh_SIGERR; + sigtraps[ksh_SIGERR].name = "ERR"; + sigtraps[ksh_SIGERR].mess = "Error handler"; (void)sigemptyset(&Sigact_ign.sa_mask); Sigact_ign.sa_flags = 0; /* interruptible */ @@ -1076,21 +1074,24 @@ alarm_catcher(int sig MKSH_A_UNUSED) } Trap * -gettrap(const char *cs, bool igncase) +gettrap(const char *cs, bool igncase, bool allsigs) { int i; Trap *p; char *as; - if (ksh_isdigit(*cs)) { - return ((getn(cs, &i) && 0 <= i && i < NSIG) ? + /* signal number (1..ksh_NSIG) or 0? */ + + if (ksh_isdigit(*cs)) + return ((getn(cs, &i) && 0 <= i && i < ksh_NSIG) ? (&sigtraps[i]) : NULL); - } + + /* do a lookup by name then */ /* this breaks SIGSIG1, but we do that above anyway */ - if ((cs[0] & 0xDF) == 'S' && - (cs[1] & 0xDF) == 'I' && - (cs[2] & 0xDF) == 'G' && + if (ksh_eq(cs[0], 'S', 's') && + ksh_eq(cs[1], 'I', 'i') && + ksh_eq(cs[2], 'G', 'g') && cs[3] != '\0') { /* skip leading "SIG" */ cs += 3; @@ -1105,14 +1106,24 @@ gettrap(const char *cs, bool igncase) } else as = NULL; + /* this is idiotic, we really want a hashtable here */ + p = sigtraps; - for (i = 0; i <= NSIG; i++) { + i = ksh_NSIG + 1; + do { if (!strcmp(p->name, cs)) goto found; ++p; - } - p = NULL; + } while (--i); + goto notfound; + found: + if (!allsigs) { + if (p->signal == ksh_SIGEXIT || p->signal == ksh_SIGERR) { + notfound: + p = NULL; + } + } afree(as, ATEMP); return (p); } @@ -1156,14 +1167,16 @@ intrcheck(void) int fatal_trap_check(void) { - int i; - Trap *p; + Trap *p = sigtraps; + int i = ksh_NSIG + 1; /* todo: should check if signal is fatal, not the TF_DFL_INTR flag */ - for (p = sigtraps, i = NSIG+1; --i >= 0; p++) + do { if (p->set && (p->flags & (TF_DFL_INTR|TF_FATAL))) /* return value is used as an exit code */ return (128 + p->signal); + ++p; + } while (--i); return (0); } @@ -1175,13 +1188,15 @@ fatal_trap_check(void) int trap_pending(void) { - int i; - Trap *p; + Trap *p = sigtraps; + int i = ksh_NSIG + 1; - for (p = sigtraps, i = NSIG+1; --i >= 0; p++) + do { if (p->set && ((p->trap && p->trap[0]) || ((p->flags & (TF_DFL_INTR|TF_FATAL)) && !p->trap))) return (p->signal); + ++p; + } while (--i); return (0); } @@ -1192,8 +1207,8 @@ trap_pending(void) void runtraps(int flag) { - int i; - Trap *p; + Trap *p = sigtraps; + int i = ksh_NSIG + 1; if (ksh_tmout_state == TMOUT_LEAVING) { ksh_tmout_state = TMOUT_EXECUTING; @@ -1212,10 +1227,12 @@ runtraps(int flag) if (flag & TF_FATAL) fatal_trap = 0; ++trap_nested; - for (p = sigtraps, i = NSIG+1; --i >= 0; p++) + do { if (p->set && (!flag || ((p->flags & flag) && p->trap == NULL))) runtrap(p, false); + ++p; + } while (--i); if (!--trap_nested) runtrap(NULL, true); } @@ -1284,30 +1301,34 @@ runtrap(Trap *p, bool is_last) void cleartraps(void) { - int i; - Trap *p; + Trap *p = sigtraps; + int i = ksh_NSIG + 1; trap = 0; intrsig = 0; fatal_trap = 0; - for (i = NSIG+1, p = sigtraps; --i >= 0; p++) { + + do { p->set = 0; if ((p->flags & TF_USER_SET) && (p->trap && p->trap[0])) settrap(p, NULL); - } + ++p; + } while (--i); } /* restore signals just before an exec(2) */ void restoresigs(void) { - int i; - Trap *p; + Trap *p = sigtraps; + int i = ksh_NSIG + 1; - for (i = NSIG+1, p = sigtraps; --i >= 0; p++) + do { if (p->flags & (TF_EXEC_IGN|TF_EXEC_DFL)) setsig(p, (p->flags & TF_EXEC_IGN) ? SIG_IGN : SIG_DFL, SS_RESTORE_CURR|SS_FORCE); + ++p; + } while (--i); } void diff --git a/mksh.1 b/mksh.1 index adb1b2c..4e56de6 100644 --- a/mksh.1 +++ b/mksh.1 @@ -1,4 +1,4 @@ -.\" $MirOS: src/bin/mksh/mksh.1,v 1.365 2015/04/29 20:13:26 tg Exp $ +.\" $MirOS: src/bin/mksh/mksh.1,v 1.366 2015/04/29 20:44:36 tg Exp $ .\" $OpenBSD: ksh.1,v 1.159 2015/03/25 12:10:52 jca Exp $ .\"- .\" Copyright © 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, @@ -4631,54 +4631,60 @@ The format of the output is: 0m0.00s 0m0.00s .Ed .Pp +.It Ic trap Ar n Op Ar signal ... +If the first operand is a decimal unsigned integer, this resets all +specified signals to the default action, i.e. is the same as calling +.Ic trap +with a minus sign +.Pq Sq \- +as +.Ar handler , +followed by the arguments +.Pq Ar n Op Ar signal ... , +all of which are treated as signals. +.Pp .It Ic trap Op Ar handler signal ... -Sets a trap handler that is to be executed when any of the specified signals are -received. +Sets a trap handler that is to be executed when any of the specified +.Ar signal Ns s +are received. .Ar handler -is either a -.Dv NULL -string, indicating the signals are to be ignored, a minus sign +is either an empty string, indicating the signals are to be ignored, +a minus sign .Pq Sq \- , -indicating that the default action is to be taken for the signals (see -.Xr signal 3 ) , -or a string containing shell commands to be evaluated and executed at the first -opportunity (i.e. when the current command completes, or before printing the -next +indicating that the default action is to be taken for the signals +.Pq see Xr signal 3 , +or a string containing shell commands to be executed at the first opportunity +(i.e. when the current command completes, or before printing the next .Ev PS1 prompt) after receipt of one of the signals. .Ar signal -is the name of a signal (e.g.\& -.Dv PIPE -or -.Dv ALRM ) +is the name of a signal +.Pq e.g.\& Dv PIPE or Dv ALRM or the number of the signal (see the -.Ic kill \-l +.Ic kill Fl l command above). .Pp There are two special signals: .Dv EXIT -(also known as 0) which is executed when the shell is about to exit, and +.Pq also known as 0 , +which is executed when the shell is about to exit, and .Dv ERR , -which is executed after an error occurs (an error is something that would cause -the shell to exit if the -.Fl e +which is executed after an error occurs; an error is something +that would cause the shell to exit if the +.Ic set Fl e or -.Ic errexit -option were set \*(en see the -.Ic set -command above). +.Ic set Fl o Ic errexit +option were set. .Dv EXIT handlers are executed in the environment of the last executed command. -Note -that for non-interactive shells, the trap handler cannot be changed for signals -that were ignored when the shell started. .Pp -With no arguments, +Note that, for non-interactive shells, the trap handler cannot be changed +for signals that were ignored when the shell started. +.Pp +With no arguments, the current state of the traps that have been set since +the shell started is shown as a series of .Ic trap -lists, as a series of -.Ic trap -commands, the current state of the traps that have been set since the shell -started. +commands. Note that the output of .Ic trap cannot be usefully piped to another process (an artifact of the fact that diff --git a/sh.h b/sh.h index 05552a6..074d3b4 100644 --- a/sh.h +++ b/sh.h @@ -169,9 +169,9 @@ #endif #ifdef EXTERN -__RCSID("$MirOS: src/bin/mksh/sh.h,v 1.728 2015/04/29 20:07:34 tg Exp $"); +__RCSID("$MirOS: src/bin/mksh/sh.h,v 1.729 2015/04/29 20:44:37 tg Exp $"); #endif -#define MKSH_VERSION "R51 2015/04/19" +#define MKSH_VERSION "R51 2015/04/29" /* arithmetic types: C implementation */ #if !HAVE_CAN_INTTYPES @@ -329,24 +329,47 @@ struct rusage { #define DEFFILEMODE (S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH) #endif -#ifndef NSIG -#if defined(_NSIG) -#define NSIG _NSIG + +/* determine ksh_NSIG: first, use the traditional definitions */ +#undef ksh_NSIG +#if defined(NSIG) +#define ksh_NSIG NSIG +#elif defined(_NSIG) +#define ksh_NSIG _NSIG #elif defined(SIGMAX) -#define NSIG (SIGMAX+1) +#define ksh_NSIG (SIGMAX + 1) #elif defined(_SIGMAX) -#define NSIG (_SIGMAX+1) +#define ksh_NSIG (_SIGMAX + 1) +#elif defined(NSIG_MAX) +#define ksh_NSIG NSIG_MAX #else # error Please have your platform define NSIG. -#define NSIG 64 #endif -#endif - -/* get rid of this (and awk/printf(1) in Build.sh) later */ -#if (NSIG < 1) +/* range-check them */ +#if (ksh_NSIG < 1) # error Your NSIG value is not positive. -#unset NSIG -#define NSIG 64 +#undef ksh_NSIG +#endif +/* second, see if the new POSIX definition is available */ +#ifdef NSIG_MAX +#if (NSIG_MAX < 2) +/* and usable */ +# error Your NSIG_MAX value is too small. +#undef NSIG_MAX +#elif (ksh_NSIG > NSIG_MAX) +/* and realistic */ +# error Your NSIG value is larger than your NSIG_MAX value. +#undef NSIG_MAX +#else +/* since it’s usable, prefer it */ +#undef ksh_NSIG +#define ksh_NSIG NSIG_MAX +#endif +/* if NSIG_MAX is now still defined, use sysconf(_SC_NSIG) at runtime */ +#endif +/* third, for cpp without the error directive, default */ +#ifndef ksh_NSIG +#define ksh_NSIG 64 #endif @@ -878,13 +901,13 @@ typedef struct trap { #define SS_USER BIT(4) /* user is doing the set (ie, trap command) */ #define SS_SHTRAP BIT(5) /* trap for internal use (ALRM, CHLD, WINCH) */ -#define ksh_SIGEXIT 0 /* for trap EXIT */ -#define ksh_SIGERR NSIG /* for trap ERR */ +#define ksh_SIGEXIT 0 /* for trap EXIT */ +#define ksh_SIGERR ksh_NSIG /* for trap ERR */ EXTERN volatile sig_atomic_t trap; /* traps pending? */ EXTERN volatile sig_atomic_t intrsig; /* pending trap interrupts command */ EXTERN volatile sig_atomic_t fatal_trap; /* received a fatal signal */ -extern Trap sigtraps[NSIG+1]; +extern Trap sigtraps[ksh_NSIG + 1]; /* got_winch = 1 when we need to re-adjust the window size */ #ifdef SIGWINCH @@ -1745,7 +1768,7 @@ int findhist(int, int, const char *, bool) MKSH_A_PURE; char **hist_get_newest(bool); void inittraps(void); void alarm_init(void); -Trap *gettrap(const char *, bool); +Trap *gettrap(const char *, bool, bool); void trapsig(int); void intrcheck(void); int fatal_trap_check(void);