feat: add warning for /sdcard exec#2147
Conversation
Greptile SummaryThis PR adds a Bash
Confidence Score: 3/5The shell init script changes need rework before merging — the DEBUG trap unconditionally overwrites hooks set by user tools in .bashrc, breaking Starship, fzf, and bash-preexec setups silently. The core feature logic (detecting /sdcard binaries) is sound, but the implementation overwrites the DEBUG trap after sourcing .bashrc, meaning any user with Starship or another prompt framework that relies on bash-preexec will lose their prompt hooks without any error message. The JS and lockfile changes are clean and safe. src/plugins/terminal/scripts/init-alpine.sh — specifically the trap setup at line 295 and the function naming at line 287. Important Files Changed
Flowchart%%{init: {'theme': 'neutral'}}%%
flowchart TD
A[bash --rcfile /initrc starts] --> B[Source /etc/profile]
B --> C[Source ~/.bashrc]
C --> D{.bashrc sets DEBUG trap?\ne.g. Starship/bash-preexec}
D -- Yes --> E[User's DEBUG trap active]
D -- No --> F[No DEBUG trap]
E --> G[Display MOTD]
F --> G
G --> H[Define check_binary_execution]
H --> I[Define preexec]
I --> J["trap 'preexec' DEBUG overwrites user trap"]
J --> K[Interactive shell ready]
K --> L[User types command]
L --> M[DEBUG trap fires, preexec called]
M --> N[Extract first word from BASH_COMMAND]
N --> O{cmd contains /}
O -- Yes --> P[realpath cmd]
O -- No --> Q[command -v cmd then realpath]
P --> R{path starts with /sdcard or /storage?}
Q --> R
R -- Yes --> S[Print ANSI warning to stderr]
R -- No --> T[Silent, command executes]
Reviews (1): Last reviewed commit: "format" | Re-trigger Greptile |
| check_binary_execution "$cmd" | ||
| } | ||
|
|
||
| trap 'preexec' DEBUG |
There was a problem hiding this comment.
DEBUG trap overwrites any existing trap set by
.bashrc
.bashrc is sourced at line 229-231, before trap 'preexec' DEBUG is set at line 295. Any tool that sets its own DEBUG trap inside .bashrc — Starship, fzf, bash-preexec, or similar prompt frameworks — will have its trap silently overwritten, breaking prompt timing, history hooks, and preexec callbacks entirely. The existing trap should be read with trap -p DEBUG and chained rather than replaced outright.
| preexec() { | ||
| # Skip commands executed by the trap itself | ||
| [[ "$BASH_COMMAND" == trap* ]] && return | ||
|
|
||
| local cmd="${BASH_COMMAND%% *}" | ||
| check_binary_execution "$cmd" | ||
| } |
There was a problem hiding this comment.
preexec function name collides with bash-preexec convention
The function name preexec is the standard hook name used by the bash-preexec library, which Starship, fzf, and many other tools hook into. Using this exact name means any .bashrc that sources bash-preexec will silently override this function (or vice versa), producing unpredictable results. Rename it to something app-specific to avoid the collision.
| preexec() { | |
| # Skip commands executed by the trap itself | |
| [[ "$BASH_COMMAND" == trap* ]] && return | |
| local cmd="${BASH_COMMAND%% *}" | |
| check_binary_execution "$cmd" | |
| } | |
| _acode_preexec() { | |
| # Skip commands executed by the trap itself | |
| [[ "$BASH_COMMAND" == trap* ]] && return | |
| local cmd="${BASH_COMMAND%% *}" | |
| check_binary_execution "$cmd" | |
| } |
Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!
| # Skip commands executed by the trap itself | ||
| [[ "$BASH_COMMAND" == trap* ]] && return | ||
|
|
||
| local cmd="${BASH_COMMAND%% *}" | ||
| check_binary_execution "$cmd" | ||
| } |
There was a problem hiding this comment.
BASH_COMMAND == trap* guard comment is misleading
The comment says "Skip commands executed by the trap itself", but bash automatically suppresses DEBUG trap re-entrancy — the trap can't fire recursively inside its own handler. What this guard actually does is skip the warning when a user types a command that starts with trap (the builtin). The comment should reflect this, or the guard should be removed if trapping trap commands is not the intent.
Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!
| check_binary_execution() { | ||
| local cmd="$1" | ||
| local cmd_path="" | ||
|
|
||
| # Ignore shell builtins, keywords, etc. | ||
| [[ -z "$cmd" ]] && return | ||
|
|
||
| # If user executed a path directly (./foo, /path/foo) | ||
| if [[ "$cmd" == */* ]]; then | ||
| cmd_path="$(realpath "$cmd" 2>/dev/null)" | ||
| else | ||
| cmd_path="$(command -v "$cmd" 2>/dev/null)" | ||
|
|
||
| # Resolve symlinks/relative paths | ||
| if [[ -n "$cmd_path" ]]; then | ||
| cmd_path="$(realpath "$cmd_path" 2>/dev/null)" | ||
| fi | ||
| fi | ||
|
|
||
| [[ -z "$cmd_path" ]] && return | ||
| [[ ! -f "$cmd_path" ]] && return | ||
|
|
||
| if [[ "$cmd_path" == /storage/* ]] || \ | ||
| [[ "$cmd_path" == /sdcard/* ]]; then | ||
| echo -e "\e[1;31m[!] ATTENTION REQUIRED\e[0m | ||
|
|
||
| \e[1;31mThe binary is located in:\e[0m | ||
| \e[36m$cmd_path\e[0m | ||
|
|
||
| \e[1;31mBinaries cannot be executed reliably from /sdcard or /storage.\e[0m | ||
| These locations are backed by Android's external storage layer and do not support normal Linux executable permissions. | ||
|
|
||
| Move your project or binary to a directory under: | ||
| \e[1;32m/home/\e[0m | ||
|
|
||
| Example: | ||
| \e[1;32mmv myproject ~/myproject\e[0m | ||
| \e[1;32mcd ~/myproject\e[0m | ||
|
|
||
| Then run the binary again. | ||
| " >&2 | ||
| fi | ||
| } | ||
|
|
||
| preexec() { | ||
| # Skip commands executed by the trap itself | ||
| [[ "$BASH_COMMAND" == trap* ]] && return | ||
|
|
||
| local cmd="${BASH_COMMAND%% *}" | ||
| check_binary_execution "$cmd" | ||
| } | ||
|
|
||
| trap 'preexec' DEBUG |
There was a problem hiding this comment.
DEBUG trap spawns subprocesses on every command
The check_binary_execution function calls command -v and realpath (both fork a process) for every single command typed in the shell. Because the DEBUG trap fires before each simple command — including those inside loops, pipelines, and subshells — this adds measurable latency to every interactive command. Consider guarding early on cheap heuristics (e.g., only enter the expensive path when cmd contains /) before calling command -v and realpath.
No description provided.