breakpointHook: several improvements
1. Implement pgrep in bash to get rid of procps dependency 2. dump env vars one more time to make sure /build/env-vars includes everything at the point of failure 3. Load env vars via `--init-file /build/env-vars` when executing the interacitve bash session to include bash native variables 4. Use buildPackages for tools used in attach script, to allow usage in cross compiling screnarios 5. use util-linuxMinimal instead of util-linux to get rid of systemd dependency 6. add flags to nsenter: --ipc --uts --pid
This commit is contained in:
parent
52a2bfcee4
commit
4a478ad081
@ -2,16 +2,36 @@
|
||||
|
||||
set -eu -o pipefail
|
||||
|
||||
id="$1"
|
||||
pids="$(pgrep -f "sleep $id" || :)"
|
||||
if [ -z "$pids" ]; then
|
||||
echo "Error: No process found for 'sleep $id'. The build must still be running in order to attach. Also make sure it's not on a remote builder." >&2
|
||||
exit 1
|
||||
elif [ "$(echo "$pids" | wc -l)" -ne 1 ]; then
|
||||
echo "Error: Multiple processes found matching 'sleep $id'" >&2
|
||||
exit 1
|
||||
fi
|
||||
pid="$(echo "$pids" | head -n1)"
|
||||
# A shell implementation for pgrep as we don't want to depend on procps
|
||||
pgrep(){
|
||||
PATTERN="$1"
|
||||
for pid_dir in /proc/[0-9]*; do
|
||||
pid="${pid_dir##*/}"
|
||||
|
||||
# Attempt to open /proc/<PID>/cmdline for reading on a new file descriptor
|
||||
# If we can't read it (no permission or doesn't exist), skip
|
||||
exec {fd}< "$pid_dir/cmdline" 2>/dev/null || continue
|
||||
|
||||
cmdline=""
|
||||
# Read each null-delimited token from /proc/<PID>/cmdline
|
||||
# and join them with a space for easier pattern matching
|
||||
while IFS= read -r -d $'\0' arg <&$fd; do
|
||||
if [[ -z "$cmdline" ]]; then
|
||||
cmdline="$arg"
|
||||
else
|
||||
cmdline="$cmdline $arg"
|
||||
fi
|
||||
done
|
||||
|
||||
# Close the file descriptor
|
||||
exec {fd}>&-
|
||||
|
||||
# If cmdline is non-empty and matches the pattern, print the PID
|
||||
if [[ -n "$cmdline" && "$cmdline" =~ $PATTERN ]]; then
|
||||
echo "$pid"
|
||||
fi
|
||||
done
|
||||
}
|
||||
|
||||
# helper to extract variables from the build env
|
||||
getVar(){
|
||||
@ -25,6 +45,17 @@ getVar(){
|
||||
| cut -d "=" -f 2
|
||||
}
|
||||
|
||||
id="$1"
|
||||
pids="$(pgrep "sleep $id" || :)"
|
||||
if [ -z "$pids" ]; then
|
||||
echo "Error: No process found for 'sleep $id'. The build must still be running in order to attach. Also make sure it's not on a remote builder." >&2
|
||||
exit 1s
|
||||
elif [ "$(echo "$pids" | wc -l)" -ne 1 ]; then
|
||||
echo "Error: Multiple processes found matching 'sleep $id'" >&2
|
||||
exit 1
|
||||
fi
|
||||
pid="$(echo "$pids" | head -n1)"
|
||||
|
||||
# bash is needed to load the env vars, as we do not know the syntax of the debug shell.
|
||||
# bashInteractive is used instead of bash, as we depend on it anyways, due to it being
|
||||
# the default debug shell
|
||||
@ -35,12 +66,16 @@ debugShell="$(getVar debugShell)"
|
||||
pwd="$(readlink /proc/$pid/cwd)"
|
||||
|
||||
# enter the namespace of the failed build
|
||||
exec nsenter --mount --net --target "$pid" "$bashInteractive" -c "
|
||||
# bash needs to be executed with --init-file /build/env-vars to include the bash native
|
||||
# variables like ones declared via `declare -a`.
|
||||
# If another shell is chosen via `debugShell`, it will only have simple env vars avaialable.
|
||||
exec nsenter --mount --ipc --uts --pid --net --target "$pid" "$bashInteractive" -c "
|
||||
set -eu -o pipefail
|
||||
while IFS= read -r -d \$'\0' line; do
|
||||
export \"\$line\"
|
||||
done <&3
|
||||
exec 3>&-
|
||||
source /build/env-vars
|
||||
cd \"$pwd\"
|
||||
exec \"$debugShell\"
|
||||
" 3< /proc/$pid/environ
|
||||
if [ -n \"$debugShell\" ]; then
|
||||
exec \"$debugShell\"
|
||||
else
|
||||
exec \"$bashInteractive\" --init-file /build/env-vars
|
||||
fi
|
||||
"
|
||||
|
||||
@ -6,9 +6,7 @@ breakpointHook() {
|
||||
|
||||
# provide the user with an interactive shell for better experience
|
||||
export bashInteractive="@bashInteractive@"
|
||||
if [ -z "$debugShell" ]; then
|
||||
export debugShell="@bashInteractive@"
|
||||
fi
|
||||
dumpVars
|
||||
|
||||
local id
|
||||
id="$(shuf -i 999999-9999999 -n1)"
|
||||
|
||||
@ -1,24 +1,19 @@
|
||||
{
|
||||
lib,
|
||||
stdenv,
|
||||
buildPackages,
|
||||
|
||||
bash,
|
||||
bashInteractive,
|
||||
coreutils,
|
||||
makeSetupHook,
|
||||
procps,
|
||||
util-linux,
|
||||
writeShellScriptBin,
|
||||
}:
|
||||
|
||||
let
|
||||
attach = writeShellScriptBin "attach" ''
|
||||
attach = buildPackages.writeShellScriptBin "attach" ''
|
||||
export PATH="${
|
||||
lib.makeBinPath [
|
||||
bash
|
||||
coreutils
|
||||
procps # needed for pgrep
|
||||
util-linux # needed for nsenter
|
||||
buildPackages.bash
|
||||
buildPackages.coreutils
|
||||
buildPackages.util-linuxMinimal # needed for nsenter
|
||||
]
|
||||
}"
|
||||
exec bash ${./attach.sh} "$@"
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user