Skip to content

Commit

Permalink
trap: Implement POSIX.1-2024 requirements (#115)
Browse files Browse the repository at this point in the history
  • Loading branch information
magicant authored Feb 11, 2025
2 parents 8d0366c + bc76c43 commit 245d7fd
Show file tree
Hide file tree
Showing 7 changed files with 99 additions and 37 deletions.
10 changes: 10 additions & 0 deletions NEWS
Original file line number Diff line number Diff line change
@@ -1,5 +1,15 @@
# History of Yash

## Yash 2.59 (Unreleased)

- Improved POSIX.1-2024 support:
- The `trap` built-in now supports the `-p` option in the POSIXly-
correct mode. When the `-p` option is used, the built-in prints
all traps without filtering out traps that are not set.
- The `trap` built-in now also reports signals that are ignored
because the program that invoked the shell has set the signal
to be ignored.

## Yash 2.58.1 (2025-02-04)

- Updated the sample initialization script (yashrc):
Expand Down
9 changes: 9 additions & 0 deletions NEWS.ja
Original file line number Diff line number Diff line change
@@ -1,5 +1,14 @@
# Yash 更新履歴

## Yash 2.59 (未リリース)

- POSIX.1-2024 のサポートを強化:
- POSIX 準拠モードで `trap` 組込みに `-p` オプションを使えるように
なった。 `-p` オプションを使用する場合、設定が変更されていないもの
も含めて全てのトラップを表示する。
- `trap` 組込みはシェルが起動された時点で最初から無視されていた
シグナルも表示するようになった

## Yash 2.58.1 (2025-02-04)

- 初期化スクリプト (yashrc) のサンプルを更新:
Expand Down
11 changes: 5 additions & 6 deletions doc/_trap.txt
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,9 @@ When executed with the +-p+ (+--print+) option or with no operands, the
built-in prints currently set traps to the standard output in a format that
can be executed as commands that restore the current traps.
If one or more {{signal}}s are specified, only those signals are printed.
Otherwise, all signals with non-default actions are printed.
If no {{signal}} is specified but the +-p+ option is given, all signals are
printed. If no {{signal}} is specified and the +-p+ option is not given, only
signals with non-default actions are printed.
(In some situations, however, the built-in may print previous trap settings
instead of the current. See notes below.)
Expand Down Expand Up @@ -77,11 +79,8 @@ The exit status of the trap built-in is zero unless there is any error.
The trap built-in is a link:builtin.html#types[special built-in].
The POSIX standard defines no options for the trap built-in;
the built-in accepts no options in the link:posix.html[POSIXly-correct mode].
The POSIX standard requires that signal names must be specified without the
+SIG+-prefix, like +INT+ and +QUIT+.
The POSIX standard requires that signal names must be specified in uppercase
without the +SIG+-prefix, like +INT+ and +QUIT+.
As an extension, yash accepts +SIG+-prefixed names like +SIGINT+ and +SIGQUIT+
and treats signal names case-insensitively.
Expand Down
6 changes: 2 additions & 4 deletions doc/ja/_trap.txt
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ Trap コマンドはシェルプロセスがシグナルを受信したときの

オペランドに{{動作}}と{{シグナル}}を指定して trap コマンドを実行すると、シェルが{{シグナル}}を受信した際に指定した{{動作}}を行うようになります。最初のオペランドが{{シグナル番号}}の場合、それと残りの{{シグナル}}に対する動作は、動作として +-+ が指定されたときと同様に標準の動作に設定されます。

+-p+ (+--print+) オプションを指定した場合またはオペランドを一つも指定していない場合は、trap コマンドは現在のトラップの設定状況をコマンドとして解釈可能な形式で標準出力に出力します。{{シグナル}}が与えられているときはそのシグナルに関する設定を、与えられていないときは全ての設定を出力します。ただし、特定の状況では trap コマンドは現在の設定ではなく以前の設定を表示します (下記補足参照)。
+-p+ (+--print+) オプションを指定した場合またはオペランドを一つも指定していない場合は、trap コマンドは現在のトラップの設定状況をコマンドとして解釈可能な形式で標準出力に出力します。{{シグナル}}が与えられているときはそのシグナルに関する設定を出力します。{{シグナル}}なしで +-p+ オプションを使用した場合、全てのシグナルの設定を出力します。{{シグナル}}を指定せず +-p+ オプションも使用しない場合、標準以外の動作が設定された全てのシグナルを出力します。ただし、特定の状況では trap コマンドは現在の設定ではなく以前の設定を表示します (下記補足参照)。

[[options]]
== オプション
Expand Down Expand Up @@ -53,9 +53,7 @@ Trap コマンドはシェルプロセスがシグナルを受信したときの

Trap コマンドは{zwsp}link:builtin.html#types[特殊組込みコマンド]です。

POSIX には +-p+ (+--print+) オプションに関する規定はありません。よってこのオプションは link:posix.html[POSIX 準拠モード]では使えません。

POSIX は、シグナル名は +INT+ や +QUIT+ のように最初の SIG を除いた形で指定しなければならないと規定しています。Yash では、拡張として SIG を付けた形でも指定できますし、シグナル名の大文字と小文字を区別しません (このような拡張は POSIX でも認められています)。
POSIX は、シグナル名は +INT+ や +QUIT+ のように最初の SIG を除いた形で大文字で指定しなければならないと規定しています。Yash では、拡張として SIG を付けた形でも指定できますし、シグナル名の大文字と小文字を区別しません (このような拡張は POSIX でも認められています)。

=== 出力の再利用

Expand Down
48 changes: 30 additions & 18 deletions sig.c
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/* Yash: yet another shell */
/* sig.c: signal handling */
/* (C) 2007-2020 magicant */
/* (C) 2007-2025 magicant */

/* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
Expand Down Expand Up @@ -953,11 +953,9 @@ void set_trap(int signum, const wchar_t *command)
}

/* Checks if the specified signal was originally ignored when the shell was
* invoked. Asserts the shell is not interactive. */
* invoked. */
bool is_originally_ignored(int signum)
{
assert(!is_interactive_now);

if (signum == 0)
return false;

Expand Down Expand Up @@ -1153,16 +1151,17 @@ void sig_new_candidate(

/********** Built-in **********/

static bool print_trap(const wchar_t *signame, const wchar_t *command)
__attribute__((nonnull(1)));
static bool print_trap(
int signum, const wchar_t *signame, const wchar_t *command, bool force)
__attribute__((nonnull(2)));
static bool print_signal(int signum, const wchar_t *name, bool verbose)
__attribute__((nonnull));
static void signal_job(int signum, const wchar_t *jobname)
__attribute__((nonnull));

/* Options for the "trap" built-in. */
const struct xgetopt_T trap_options[] = {
{ L'p', L"print", OPTARG_NONE, false, NULL, },
{ L'p', L"print", OPTARG_NONE, true, NULL, },
#if YASH_ENABLE_HELP
{ L'-', L"help", OPTARG_NONE, false, NULL, },
#endif
Expand Down Expand Up @@ -1191,24 +1190,29 @@ int trap_builtin(int argc, void **argv)
}

if (xoptind == argc) {
/* print all traps */
/* print all traps but KILL and STOP */
sigset_t printed;
sigemptyset(&printed);
if (!print_trap(L"EXIT", trap_command[sigindex(0)]))
sigaddset(&printed, SIGKILL);
sigaddset(&printed, SIGSTOP);
if (!print_trap(0, L"EXIT", trap_command[sigindex(0)], print))
return Exit_FAILURE;
for (const signal_T *s = signals; s->no != 0; s++) {
if (!sigismember(&printed, s->no)) {
sigaddset(&printed, s->no);
if (!print_trap(s->name, trap_command[sigindex(s->no)]))
if (!print_trap(s->no, s->name, trap_command[sigindex(s->no)],
print))
return special_builtin_error(Exit_FAILURE);
}
}
#if defined SIGRTMIN && defined SIGRTMAX
int sigrtmin = SIGRTMIN, sigrtmax = SIGRTMAX;
for (int i = 0; i < RTSIZE; i++) {
if (sigrtmin + i > sigrtmax)
int signum = sigrtmin + i;
if (signum > sigrtmax)
break;
if (!print_trap(get_signal_name(sigrtmin + i), rttrap_command[i]))
if (!print_trap(signum, get_signal_name(signum), rttrap_command[i],
print))
return special_builtin_error(Exit_FAILURE);
}
#endif
Expand All @@ -1229,12 +1233,13 @@ int trap_builtin(int argc, void **argv)
if (sigrtmin <= signum && signum <= sigrtmax) {
int index = signum - sigrtmin;
if (index < RTSIZE)
if (!print_trap(name, rttrap_command[index]))
if (!print_trap(signum, name, rttrap_command[index], true))
return special_builtin_error(Exit_FAILURE);
} else
#endif
{
if (!print_trap(name, trap_command[sigindex(signum)]))
if (!print_trap(
signum, name, trap_command[sigindex(signum)], true))
return special_builtin_error(Exit_FAILURE);
}
} while (++xoptind < argc);
Expand Down Expand Up @@ -1274,14 +1279,21 @@ int trap_builtin(int argc, void **argv)

/* Prints trap to the standard output in a format that can be used to restore
* the current signal handler for the specified signal.
* If the `command' is NULL, this function does nothing.
* If the `command' is NULL and `force` is false, this function does nothing.
* Otherwise, the `command' is properly single-quoted and printed.
* Returns true iff successful (no error). On error, an error message is printed
* to the standard error. */
bool print_trap(const wchar_t *signame, const wchar_t *command)
bool print_trap(
int signum, const wchar_t *signame, const wchar_t *command, bool force)
{
if (command == NULL)
return true;
if (command == NULL) {
if (is_originally_ignored(signum))
command = L"";
else if (!force)
return true;
else
command = L"-";
}

wchar_t *q = quote_as_word(command);
bool ok = xprintf("trap -- %ls %ls\n", q, signame);
Expand Down
32 changes: 32 additions & 0 deletions tests/trap-p.tst
Original file line number Diff line number Diff line change
Expand Up @@ -251,6 +251,38 @@ __IN__
abc
__OUT__

test_oE -e 0 'without -p, only non-default traps are printed' -e
trap - USR1
trap >printed_trap_1 # should not print USR1
trap 'echo trapped' USR1
. ./printed_trap_1
kill -s USR1 $$
__IN__
trapped
__OUT__

test_OE -e USR1 'with -p, all traps are printed' -e
trap - USR1
trap -p >printed_trap_2 # should print USR1
trap 'echo trapped' USR1
. ./printed_trap_2
kill -s USR1 $$
__IN__

test_oE -e QUIT 'with -p and operands, only specified traps are printed' -e
trap '' INT TERM
trap -p TERM QUIT >printed_trap_3 # should not print INT
trap 'echo INT' INT
trap 'echo TERM' TERM
trap '' QUIT
. ./printed_trap_3 # TERM is ignored again, QUIT is now default
kill -s INT $$ # should print INT
kill -s TERM $$ # should be ignored
kill -s QUIT $$
__IN__
INT
__OUT__

echo 'echo "$@"' > ./-
chmod a+x ./-

Expand Down
20 changes: 11 additions & 9 deletions tests/trap-y.tst
Original file line number Diff line number Diff line change
Expand Up @@ -102,26 +102,28 @@ __OUT__

test_oE -e 0 'printing all traps (with -p)'
trap 'echo "a"'"'b'"'\c' USR1
trap 'echo 1 &
echo 2 ;' USR2
trap -p
trap --print
trap 'echo USR2' USR2
trap -p | grep 'INT\|QUIT\|KILL\|STOP\|USR'
trap --print | grep 'INT\|QUIT\|KILL\|STOP\|USR'
__IN__
trap -- - INT
trap -- - QUIT
trap -- 'echo "a"'\'b\''\c' USR1
trap -- 'echo 1 &
echo 2 ;' USR2
trap -- 'echo USR2' USR2
trap -- - INT
trap -- - QUIT
trap -- 'echo "a"'\'b\''\c' USR1
trap -- 'echo 1 &
echo 2 ;' USR2
trap -- 'echo USR2' USR2
__OUT__

test_oE -e 0 'printing specific traps (with -p)'
trap 'echo X' USR1 USR2 HUP
trap 'echo Y' INT QUIT
trap -p QUIT USR1
trap -p QUIT USR1 TERM
__IN__
trap -- 'echo Y' QUIT
trap -- 'echo X' USR1
trap -- - TERM
__OUT__

test_oE -e 0 'specifying signal with SIG-prefix'
Expand Down

0 comments on commit 245d7fd

Please sign in to comment.