Skip to content

Resolve sh from PATH for generated stub scripts#189

Open
gtbuchanan wants to merge 1 commit into
kward:masterfrom
gtbuchanan:stub-shebang-from-path
Open

Resolve sh from PATH for generated stub scripts#189
gtbuchanan wants to merge 1 commit into
kward:masterfrom
gtbuchanan:stub-shebang-from-path

Conversation

@gtbuchanan

@gtbuchanan gtbuchanan commented Jun 16, 2026

Copy link
Copy Markdown

Problem

_shunit_mktempFunc writes its stub scripts with a hardcoded #!/bin/sh. On systems that don't provide /bin/sh, the kernel can't exec the stubs, so the noexec probe fails and shUnit2 aborts at startup with:

shunit2:FATAL Please declare TMPDIR with path on partition with exec permission.

The real cause (/bin/sh: bad interpreter: No such file or directory) is masked because the probe runs with 2>/dev/null.

This affects any non-FHS layout — e.g. NixOS (#185) and Termux, where sh lives under $PREFIX/bin.

Fix

Resolve sh from PATH via command -v sh and use that as the stub interpreter. This is POSIX, and unlike #!/usr/bin/env sh it doesn't assume /usr/bin/env exists either (also absent on Termux). On FHS systems command -v sh resolves to /bin/sh, so behavior is unchanged there.

Refs #185.

_shunit_mktempFunc writes its stub scripts (including the noexec
exec-permission probe) with a hardcoded #!/bin/sh. On systems without
/bin/sh the stubs cannot exec, so the noexec probe fails and shUnit2
aborts with a misleading "declare TMPDIR ... exec permission" error
even when TMPDIR is executable. This affects non-FHS layouts such as
NixOS (kward#185) and Termux (where sh lives under $PREFIX/bin).

Resolve sh from PATH via `command -v sh`. Unlike #!/usr/bin/env sh it
does not assume /usr/bin/env exists either, and on FHS systems it
still resolves to /bin/sh, so behavior is unchanged there.

Refs kward#185.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Signed-off-by: Taylor Buchanan <me+dev.git@taylorbuchanan.com>
gtbuchanan added a commit to gtbuchanan/claude-code-termux that referenced this pull request Jun 16, 2026
The e2e script was a flat set -e sequence: one failed assertion aborted
the run and masked the rest, and checks were unlabeled. Rewrite it as a
shUnit2 suite: the one-shot install moves to oneTimeSetUp, each behavior
is a definition-ordered test_* function (state-mutating checks last).
shUnit2 reports every check instead of stopping at the first failure.

Scope nullglob to the .deb glob: left on, it breaks shUnit2's unquoted
${_SHUNIT_LINENO_} expansion and spams "unexpected EOF" on every assert.

Vendor shUnit2 from master (pinned @ f39734a; no release since 2.1.8)
so the egrep→grep -E fix comes from upstream. One local patch remains:
stub scripts resolve sh via PATH (Termux has no /bin/sh), submitted
upstream as kward/shunit2#189.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
gtbuchanan added a commit to gtbuchanan/claude-code-termux that referenced this pull request Jun 16, 2026
The e2e script was a flat set -e sequence: one failed assertion aborted
the run and masked the rest, and checks were unlabeled. Rewrite it as a
shUnit2 suite: the one-shot install moves to oneTimeSetUp, each behavior
is a definition-ordered test_* function (state-mutating checks last).
shUnit2 reports every check instead of stopping at the first failure.

Scope nullglob to the .deb glob: left on, it breaks shUnit2's unquoted
${_SHUNIT_LINENO_} expansion and spams "unexpected EOF" on every assert.

Vendor shUnit2 from master (pinned @ f39734a; no release since 2.1.8)
so the egrep→grep -E fix comes from upstream. One local patch remains:
stub scripts resolve sh via PATH (Termux has no /bin/sh), submitted
upstream as kward/shunit2#189.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
gtbuchanan added a commit to gtbuchanan/claude-code-termux that referenced this pull request Jun 16, 2026
The e2e script was a flat set -e sequence: one failed assertion aborted
the run and masked the rest, and checks were unlabeled. Rewrite it as a
shUnit2 suite: the one-shot install moves to oneTimeSetUp, each behavior
is a definition-ordered test_* function (state-mutating checks last).
shUnit2 reports every check instead of stopping at the first failure.

Scope nullglob to the .deb glob: left on, it breaks shUnit2's unquoted
${_SHUNIT_LINENO_} expansion and spams "unexpected EOF" on every assert.

Vendor shUnit2 from master (pinned @ f39734a; no release since 2.1.8)
so the egrep→grep -E fix comes from upstream. One local patch remains:
stub scripts resolve sh via PATH (Termux has no /bin/sh), submitted
upstream as kward/shunit2#189.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
gtbuchanan added a commit to gtbuchanan/claude-code-termux that referenced this pull request Jun 16, 2026
The e2e script was a flat set -e sequence: one failed assertion aborted
the run and masked the rest, and checks were unlabeled. Rewrite it as a
shUnit2 suite: the one-shot install moves to oneTimeSetUp, each behavior
is a definition-ordered test_* function (state-mutating checks last).
shUnit2 reports every check instead of stopping at the first failure.

Scope nullglob to the .deb glob: left on, it breaks shUnit2's unquoted
${_SHUNIT_LINENO_} expansion and spams "unexpected EOF" on every assert.

Vendor shUnit2 from master (pinned @ f39734a; no release since 2.1.8)
so the egrep→grep -E fix comes from upstream. One local patch remains:
stub scripts resolve sh via PATH (Termux has no /bin/sh), submitted
upstream as kward/shunit2#189.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
gtbuchanan added a commit to gtbuchanan/claude-code-termux that referenced this pull request Jun 16, 2026
The e2e script was a flat set -e sequence: one failed assertion aborted
the run and masked the rest, and checks were unlabeled. Rewrite it as a
shUnit2 suite: the one-shot install moves to oneTimeSetUp, each behavior
is a definition-ordered test_* function (state-mutating checks last).
shUnit2 reports every check instead of stopping at the first failure.

Scope nullglob to the .deb glob: left on, it breaks shUnit2's unquoted
${_SHUNIT_LINENO_} expansion and spams "unexpected EOF" on every assert.

Vendor shUnit2 from master (pinned @ f39734a; no release since 2.1.8)
so the egrep→grep -E fix comes from upstream. One local patch remains:
stub scripts resolve sh via PATH (Termux has no /bin/sh), submitted
upstream as kward/shunit2#189.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant