nixpkgs mirror (for testing) github.com/NixOS/nixpkgs
nix
at python-updates 85 lines 2.7 kB view raw
1#! /usr/bin/env bash 2 3set -eu -o pipefail 4 5# A shell implementation for pgrep as we don't want to depend on procps 6pgrep(){ 7 PATTERN="$1" 8 for pid_dir in /proc/[0-9]*; do 9 pid="${pid_dir##*/}" 10 11 # Attempt to open /proc/<PID>/cmdline for reading on a new file descriptor 12 # If we can't read it (no permission or doesn't exist), skip 13 exec {fd}< "$pid_dir/cmdline" 2>/dev/null || continue 14 15 cmdline="" 16 # Read each null-delimited token from /proc/<PID>/cmdline 17 # and join them with a space for easier pattern matching 18 while IFS= read -r -d $'\0' arg <&$fd; do 19 if [[ -z "$cmdline" ]]; then 20 cmdline="$arg" 21 else 22 cmdline="$cmdline $arg" 23 fi 24 done 25 26 # Close the file descriptor 27 exec {fd}>&- 28 29 # If cmdline is non-empty and matches the pattern, print the PID 30 if [[ -n "$cmdline" && "$cmdline" =~ $PATTERN ]]; then 31 echo "$pid" 32 fi 33 done 34} 35 36# helper to extract variables from the build env 37getVar(){ 38 while IFS= read -r -d $'\0' line; do 39 case "$line" in 40 *"$1="* ) 41 echo "$line" 42 ;; 43 esac 44 done < /proc/$pid/environ \ 45 | cut -d "=" -f 2 46} 47 48id="$1" 49pids="$(pgrep "sleep $id" || :)" 50if [ -z "$pids" ]; then 51 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 52 exit 1s 53elif [ "$(echo "$pids" | wc -l)" -ne 1 ]; then 54 echo "Error: Multiple processes found matching 'sleep $id'" >&2 55 exit 1 56fi 57pid="$(echo "$pids" | head -n1)" 58 59 60# get the build top level directory inside the sandbox (eg. /build) 61buildDir=$(getVar NIX_BUILD_TOP) 62 63# bash is needed to load the env vars, as we do not know the syntax of the debug shell. 64# bashInteractive is used instead of bash, as we depend on it anyways, due to it being 65# the default debug shell 66bashInteractive="$(getVar bashInteractive)" 67# the debug shell will be started as interactive shell after loading the env vars 68debugShell="$(getVar debugShell)" 69# to drop the user into the working directory at the point of failure 70pwd="$(readlink /proc/$pid/cwd)" 71 72# enter the namespace of the failed build 73# bash needs to be executed with --init-file /build/env-vars to include the bash native 74# variables like ones declared via `declare -a`. 75# If another shell is chosen via `debugShell`, it will only have simple env vars avaialable. 76exec nsenter --mount --ipc --uts --pid --user --setuid follow --setgid follow --net --target "$pid" "$bashInteractive" -c " 77 set -eu -o pipefail 78 source \"$buildDir/env-vars\" 79 cd \"$pwd\" 80 if [ -n \"$debugShell\" ]; then 81 exec \"$debugShell\" 82 else 83 exec \"$bashInteractive\" --init-file \"$buildDir/env-vars\" 84 fi 85"