Last active
July 27, 2018 09:49
-
-
Save basinilya/9320b806efacece314c2ad16524993c1 to your computer and use it in GitHub Desktop.
makelog.sh
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/bin/bash | |
# usage: ./makelog.sh -m make.log /usr/bin/make all | |
startdate=$(date +"%F %T.%3N%z") | |
makemode= | |
servermode= | |
target= | |
prereqs=() | |
while [ $# != 0 ]; do | |
case $1 in | |
'--') | |
shift | |
break | |
;; | |
'-s') | |
servermode=x | |
shift | |
;; | |
'-m') | |
makemode=x | |
export MAKELOG=${2:?} | |
shift 2 | |
;; | |
'-t') | |
target=${2:?} | |
shift 2 | |
;; | |
'-p') | |
prereqs+=("${2:?}") | |
shift 2 | |
;; | |
'-c') | |
break | |
;; | |
-*) | |
>&2 echo "unknown option $1" | |
exit 1 | |
;; | |
*) | |
break | |
;; | |
esac | |
done | |
if [ "$servermode" ]; then | |
exec 2>&4 | |
trap '' HUP # although we are detached, parent bash may still HUP us | |
cat >"${MAKELOG:?}" # wait pipe EOF | |
>&2 printf '\nfinished\n' | |
exit 0 | |
fi | |
if [ "$makemode" ]; then | |
set -e | |
THISDIR=$(cd -- "$(dirname -- "$MAKELOG")" && pwd) | |
THISFILE=${MAKELOG##*/} | |
export MAKELOG_LOCK="$THISDIR/$THISFILE.lck" | |
THISDIR=$(cd -- "$(dirname -- "$0")" && pwd) | |
THISFILE=${0##*/} | |
exec 4>&2 | |
# create pipe handle to share across all processes | |
coproc ( | |
read s # to avoid race condition do not die until we disown/do stuff with $COPROC | |
# detach from tty | |
setsid "$THISDIR/$THISFILE" -s <&0 # create grandchild and die | |
) | |
disown | |
export MAKELOG_FD=${COPROC[1]} | |
# clear FD_CLOEXEC for write side of the pipe and unblock the child | |
eval "exec ${COPROC[0]}>&-; exec ${COPROC[0]}>&1 1>&${COPROC[1]} ${COPROC[1]}>&-; exec ${COPROC[1]}>&1 1>&${COPROC[0]} ${COPROC[0]}>&-; echo >&${COPROC[1]}" | |
export MAKELOG_STOP_AT_PID=$$ | |
exec -- "$@" SHELL="$THISDIR/$THISFILE"' $(@:%=-t %) $(^:%=-p %) --' | |
fi | |
fn_now() { | |
# linux,cygwin,msys | |
read ms x </proc/uptime | |
ms=${ms/./}0 | |
} | |
fn_now | |
old_ms=$ms | |
# output consists of name:value pairs and lists | |
# the colon is chosen to not interfere with the equal sign in environ | |
# each token is separated by nul character | |
# values may contain newlines | |
# lists with unknown number of elements end with a name:value pair with an empty name | |
# a whole record also ends with a name:value pair with an empty name, but the value contains double newline for cosmetic purpose | |
LF=' | |
' | |
pid=$$ | |
${MAKELOG_SHELL:-/bin/sh} "$@" | |
ret=$? | |
set -e | |
exec 41>>"${MAKELOG_LOCK:?}" | |
flock 41 | |
exec 1>&"${MAKELOG_FD:?}" | |
printf 'date:%s\0' "$startdate" | |
printf 'target:%s\0' "$target" | |
# nprereqs followed by n prereqs delimited by nul | |
printf 'nprereqs:%s\0' ${#prereqs[@]} | |
if [ ${#prereqs[@]} != 0 ]; then | |
printf '%s\0' "${prereqs[@]}" | |
fi | |
printf 'cwd:%s\0' "$PWD" | |
# TODO: currently, args are always: -c "cmd1 && cmd2 && cmd3 && ..." | |
# nargs followed by n args delimited by nul | |
printf 'nargs:%s\0' $# | |
if [ $# != 0 ]; then | |
printf '%s\0' "$@" | |
fi | |
# process hierarchy list with unknown number of elements; terminated with just a colon | |
savepid=$pid | |
printf 'pidstack:\0' | |
# in /proc/self/status command can contain spaces, but newlines are escaped | |
while true; do | |
name= | |
ppid= | |
shouldbreak=": : break" | |
while read -r key val; do | |
case $key in | |
'Name:') | |
name=$val | |
;; | |
'PPid:') | |
ppid=$val | |
;; | |
*) continue;; | |
esac | |
shouldbreak=${shouldbreak:2} | |
$shouldbreak | |
done </proc/${pid:?}/status | |
printf '%s:%s\0' "${pid}" "$name" | |
[ 0 != "$ppid" -a x"$MAKELOG_STOP_AT_PID" != "x$pid" ] || break | |
pid=$ppid | |
done | |
printf ':\0' | |
pid=$savepid | |
printf 'environ:\0' | |
# env var list with unknown number of elements; terminated with just a colon | |
cat /proc/${pid:?}/environ | |
printf ':\0' | |
fn_now | |
ms=$((ms - old_ms)) | |
printf 'millis:%s\0' $ms | |
printf 'ret:%s\0' $ret | |
printf ':\n\n\0' | |
exit $ret |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment