#!/bin/sh

# Show the process's signal-handling state, including threads.
# Effectively a handy filter on /proc/X/status.

if [ $# -lt 1 ]; then
    echo "Usage: `basename $0` <pid> [...]"
    exit 1
fi

# Signal sets (as integers) exceed the integer range of awk,
# so we do them a nybble at a time.  Inelegant.

sigmask()
{
    echo $1 | awk \
      '{b = 1;\
	m=1; s=("0x" substr($1, length($1)))+0; $1=substr($1,1,length($1)-1);\
	if (and(s, m)) printf("\t%2d SIGHUP\n",    b); m *= 2; b++;\
	if (and(s, m)) printf("\t%2d SIGINT\n",    b); m *= 2; b++;\
	if (and(s, m)) printf("\t%2d SIGQUIT\n",   b); m *= 2; b++;\
	if (and(s, m)) printf("\t%2d SIGILL\n",    b); m *= 2; b++;\
	m=1; s=("0x" substr($1, length($1)))+0; $1=substr($1,1,length($1)-1);\
	if (and(s, m)) printf("\t%2d SIGTRAP\n",   b); m *= 2; b++;\
	if (and(s, m)) printf("\t%2d SIGABRT\n",   b); m *= 2; b++;\
	if (and(s, m)) printf("\t%2d SIGEMT\n",    b); m *= 2; b++;\
	if (and(s, m)) printf("\t%2d SIGFPE\n",    b); m *= 2; b++;\
	m=1; s=("0x" substr($1, length($1)))+0; $1=substr($1,1,length($1)-1);\
	if (and(s, m)) printf("\t%2d SIGKILL\n",   b); m *= 2; b++;\
	if (and(s, m)) printf("\t%2d SIGBUS\n",    b); m *= 2; b++;\
	if (and(s, m)) printf("\t%2d SIGSEGV\n",   b); m *= 2; b++;\
	if (and(s, m)) printf("\t%2d SIGSYS\n",    b); m *= 2; b++;\
	m=1; s=("0x" substr($1, length($1)))+0; $1=substr($1,1,length($1)-1);\
	if (and(s, m)) printf("\t%2d SIGPIPE\n",   b); m *= 2; b++;\
	if (and(s, m)) printf("\t%2d SIGALRM\n",   b); m *= 2; b++;\
	if (and(s, m)) printf("\t%2d SIGTERM\n",   b); m *= 2; b++;\
	if (and(s, m)) printf("\t%2d SIGUSR1\n",   b); m *= 2; b++;\
	m=1; s=("0x" substr($1, length($1)))+0; $1=substr($1,1,length($1)-1);\
	if (and(s, m)) printf("\t%2d SIGUSR2\n",   b); m *= 2; b++;\
	if (and(s, m)) printf("\t%2d SIGCHLD\n",   b); m *= 2; b++;\
	if (and(s, m)) printf("\t%2d SIGPWR\n",    b); m *= 2; b++;\
	if (and(s, m)) printf("\t%2d SIGWINCH\n",  b); m *= 2; b++;\
	m=1; s=("0x" substr($1, length($1)))+0; $1=substr($1,1,length($1)-1);\
	if (and(s, m)) printf("\t%2d SIGURG\n",    b); m *= 2; b++;\
	if (and(s, m)) printf("\t%2d SIGIO\n",     b); m *= 2; b++;\
	if (and(s, m)) printf("\t%2d SIGSTOP\n",   b); m *= 2; b++;\
	if (and(s, m)) printf("\t%2d SIGTSTP\n",   b); m *= 2; b++;\
	m=1; s=("0x" substr($1, length($1)))+0; $1=substr($1,1,length($1)-1);\
	if (and(s, m)) printf("\t%2d SIGCONT\n",   b); m *= 2; b++;\
	if (and(s, m)) printf("\t%2d SIGTTIN\n",   b); m *= 2; b++;\
	if (and(s, m)) printf("\t%2d SIGTTOU\n",   b); m *= 2; b++;\
	if (and(s, m)) printf("\t%2d SIGVTALRM\n", b); m *= 2; b++;\
	m=1; s=("0x" substr($1, length($1)))+0; $1=substr($1,1,length($1)-1);\
	if (and(s, m)) printf("\t%2d SIGPROF\n",   b); m *= 2; b++;\
	if (and(s, m)) printf("\t%2d SIGXCPU\n",   b); m *= 2; b++;\
	if (and(s, m)) printf("\t%2d SIGXFSZ\n",   b); m *= 2; b++;\
	if (and(s, m)) printf("\t%2d SIG????\n",   b); m *= 2; b++;\
	m=1; s=("0x" substr($1, length($1)))+0; $1=substr($1,1,length($1)-1);\
	if (and(s, m)) printf("\t%2d SIG????\n",   b); m *= 2; b++;\
	if (and(s, m)) printf("\t%2d SIGRT[0]\n",  b); m *= 2; b++;\
	if (and(s, m)) printf("\t%2d SIGRT[1]\n",  b); m *= 2; b++;\
	if (and(s, m)) printf("\t%2d SIGRT[2]\n",  b); m *= 2; b++;\
	m=1; s=("0x" substr($1, length($1)))+0; $1=substr($1,1,length($1)-1);\
	if (and(s, m)) printf("\t%2d SIGRT[3]\n",  b); m *= 2; b++;\
	if (and(s, m)) printf("\t%2d SIGRT[4]\n",  b); m *= 2; b++;\
	if (and(s, m)) printf("\t%2d SIGRT[5]\n",  b); m *= 2; b++;\
	if (and(s, m)) printf("\t%2d SIGRT[6]\n",  b); m *= 2; b++;\
      }'
}

sigmasks()
{
    sigs=`fgrep SigPnd: $1 | sed 's/.*:[	 ]*//'`
    echo "    PENDING ($sigs)"
    sigmask $sigs
    sigs=`fgrep SigBlk: $1 | sed 's/.*:[	 ]*//'`
    echo "    BLOCKED ($sigs)"
    sigmask $sigs
    sigs=`fgrep SigIgn: $1 | sed 's/.*:[	 ]*//'`
    echo "    IGNORED ($sigs)"
    sigmask $sigs
    sigs=`fgrep SigCgt: $1 | sed 's/.*:[	 ]*//'`
    echo "    CAUGHT  ($sigs)"
    sigmask $sigs
    echo
}

thread()
{
    echo "  THREAD $1 $2 signals:"
}

process()
{
    echo "PROCESS $1 $2 signals:"
}

for PID in $@; do
    if [ -d /proc/$PID ] ; then
	process `cat /proc/$PID/stat`
	sigmasks /proc/$PID/status
	if [ `ls /proc/$PID/task/ | wc -l` -gt 1 ]; then
	    cd /proc/$PID/task
	    for TID in *; do
		if [ $TID -ne $PID ]; then
		    thread `cat $TID/stat`
		    sigmasks $TID/status
		fi
	    done
	fi
    fi
done
