@@ -240,6 +240,77 @@ if [ -s /etc/acode_motd ]; then
240240 cat /etc/acode_motd
241241fi
242242
243+ check_binary_execution() {
244+ local cmd="$1"
245+ local cmd_path=""
246+
247+ # Ignore shell builtins, keywords, etc.
248+ [[ -z "$cmd" ]] && return
249+
250+ # If user executed a path directly (./foo, /path/foo)
251+ if [[ "$cmd" == */* ]]; then
252+ cmd_path="$(realpath "$cmd" 2>/dev/null)"
253+ else
254+ cmd_path="$(command -v "$cmd" 2>/dev/null)"
255+
256+ # Resolve symlinks/relative paths
257+ if [[ -n "$cmd_path" ]]; then
258+ cmd_path="$(realpath "$cmd_path" 2>/dev/null)"
259+ fi
260+ fi
261+
262+ [[ -z "$cmd_path" ]] && return
263+ [[ ! -f "$cmd_path" ]] && return
264+
265+ if [[ "$cmd_path" == /storage/* ]] || \
266+ [[ "$cmd_path" == /sdcard/* ]]; then
267+ echo -e "\e[1;31m[!] ATTENTION REQUIRED\e[0m
268+
269+ \e[1;31mThe binary is located in:\e[0m
270+ \e[36m$cmd_path\e[0m
271+
272+ \e[1;31mBinaries cannot be executed reliably from /sdcard or /storage.\e[0m
273+ These locations are backed by Android's external storage layer and do not support normal Linux executable permissions.
274+
275+ Move your project or binary to a directory under:
276+ \e[1;32m/home/\e[0m
277+
278+ Example:
279+ \e[1;32mmv myproject ~/myproject\e[0m
280+ \e[1;32mcd ~/myproject\e[0m
281+
282+ Then run the binary again.
283+ " >&2
284+ fi
285+ }
286+
287+ _acode_preexec() {
288+ # Skip commands executed by the trap itself
289+ [[ "$BASH_COMMAND" == trap* ]] && return
290+
291+ local cmd="${BASH_COMMAND%% *}"
292+ check_binary_execution "$cmd"
293+ }
294+
295+ # Preserve any existing DEBUG trap and append our handler instead of overwriting it.
296+ # This avoids clobbering user-installed preexec hooks (starship, fzf, bash-preexec, etc.).
297+ __acode_existing_debug_trap="$(trap -p DEBUG 2>/dev/null)"
298+ if [[ -n "${__acode_existing_debug_trap}" ]]; then
299+ __acode_existing_cmd="$(printf "%s" "${__acode_existing_debug_trap}" | sed -E "s/.*'((.*)?)'.*/\1/")"
300+ else
301+ __acode_existing_cmd=""
302+ fi
303+
304+ # Only add our handler if it's not already present
305+ if [[ "${__acode_existing_cmd}" != *"_acode_preexec"* ]]; then
306+ if [[ -n "${__acode_existing_cmd}" ]]; then
307+ trap "${__acode_existing_cmd}; _acode_preexec" DEBUG
308+ else
309+ trap '_acode_preexec' DEBUG
310+ fi
311+ fi
312+ unset __acode_existing_debug_trap __acode_existing_cmd
313+
243314# Command-not-found handler
244315command_not_found_handle() {
245316 cmd="$1"
0 commit comments